Image_FreeImageStream (std::istream& theStream)
: myIStream (&theStream), myOStream (NULL), myInitPos (theStream.tellg()) {}
+ //! Construct wrapper over output stream.
+ Image_FreeImageStream (std::ostream& theStream)
+ : myIStream (NULL), myOStream (&theStream), myInitPos (theStream.tellp()) {}
+
//! Get io object.
FreeImageIO GetFiIO() const
{
if (myIStream != NULL)
{
anIo.read_proc = readProc;
- anIo.seek_proc = seekProc;
- anIo.tell_proc = tellProc;
+ anIo.seek_proc = seekProcIn;
+ anIo.tell_proc = tellProcIn;
}
if (myOStream != NULL)
{
anIo.write_proc = writeProc;
+ // seek and tell are also used for saving in some formats (.tif for example)
+ anIo.seek_proc = seekProcOut;
+ anIo.tell_proc = tellProcOut;
}
return anIo;
}
}
//! Simulate fseek().
- static int DLL_CALLCONV seekProc (fi_handle theHandle, long theOffset, int theOrigin)
+ static int DLL_CALLCONV seekProcIn (fi_handle theHandle, long theOffset, int theOrigin)
{
Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
if (aThis->myIStream == NULL)
return isSeekDone ? 0 : -1;
}
+ static int DLL_CALLCONV seekProcOut (fi_handle theHandle, long theOffset, int theOrigin)
+ {
+ Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
+ if (aThis->myOStream == NULL)
+ {
+ return -1;
+ }
+
+ bool isSeekDone = false;
+ switch (theOrigin)
+ {
+ case SEEK_SET:
+ if (aThis->myOStream->seekp ((std::streamoff )aThis->myInitPos + theOffset, std::ios::beg))
+ {
+ isSeekDone = true;
+ }
+ break;
+ case SEEK_CUR:
+ if (aThis->myOStream->seekp (theOffset, std::ios::cur))
+ {
+ isSeekDone = true;
+ }
+ break;
+ case SEEK_END:
+ if (aThis->myOStream->seekp (theOffset, std::ios::end))
+ {
+ isSeekDone = true;
+ }
+ break;
+ }
+ return isSeekDone ? 0 : -1;
+ }
+
//! Simulate ftell().
- static long DLL_CALLCONV tellProc (fi_handle theHandle)
+ static long DLL_CALLCONV tellProcIn (fi_handle theHandle)
{
Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
const long aPos = aThis->myIStream != NULL ? (long )(aThis->myIStream->tellg() - aThis->myInitPos) : 0;
return aPos;
}
+
+ static long DLL_CALLCONV tellProcOut (fi_handle theHandle)
+ {
+ Image_FreeImageStream* aThis = (Image_FreeImageStream* )theHandle;
+ const long aPos = aThis->myOStream != NULL ? (long )(aThis->myOStream->tellp() - aThis->myInitPos) : 0;
+ return aPos;
+ }
private:
std::istream* myIStream;
std::ostream* myOStream;
return aGuid;
}
+ //! Returns GUID of image format from file name
+ static GUID getFileFormatFromName (const TCollection_AsciiString& theFileName)
+ {
+ TCollection_AsciiString aFileNameLower = theFileName;
+ aFileNameLower.LowerCase();
+ GUID aFileFormat = getNullGuid();
+ if (aFileNameLower.EndsWith (".bmp"))
+ {
+ aFileFormat = GUID_ContainerFormatBmp;
+ }
+ else if (aFileNameLower.EndsWith (".png"))
+ {
+ aFileFormat = GUID_ContainerFormatPng;
+ }
+ else if (aFileNameLower.EndsWith (".jpg")
+ || aFileNameLower.EndsWith (".jpeg"))
+ {
+ aFileFormat = GUID_ContainerFormatJpeg;
+ }
+ else if (aFileNameLower.EndsWith (".tiff")
+ || aFileNameLower.EndsWith (".tif"))
+ {
+ aFileFormat = GUID_ContainerFormatTiff;
+ }
+ else if (aFileNameLower.EndsWith (".gif"))
+ {
+ aFileFormat = GUID_ContainerFormatGif;
+ }
+ return aFileFormat;
+ }
+
//! Sentry over IUnknown pointer.
template<class T> class Image_ComPtr
{
// purpose :
// =======================================================================
Image_AlienPixMap::Image_AlienPixMap()
+#ifdef HAVE_WINCODEC
+: myPalette (NULL)
+#else
: myLibImage (NULL)
+#endif
{
SetTopDown (false);
}
FreeImage_Unload (myLibImage);
myLibImage = NULL;
}
+#elif defined(HAVE_WINCODEC)
+ if (myPalette != NULL)
+ {
+ myPalette->Release();
+ myPalette = NULL;
+ }
#elif defined(__EMSCRIPTEN__)
if (myLibImage != NULL)
{
// =======================================================================
#ifdef HAVE_FREEIMAGE
bool Image_AlienPixMap::Load (const Standard_Byte* theData,
- Standard_Size theLength,
+ const Standard_Size theLength,
const TCollection_AsciiString& theImagePath)
{
Clear();
#elif defined(HAVE_WINCODEC)
bool Image_AlienPixMap::Load (const Standard_Byte* theData,
- Standard_Size theLength,
+ const Standard_Size theLength,
const TCollection_AsciiString& theFileName)
{
Clear();
|| aFrameCount < 1
|| aWicDecoder->GetFrame (0, &aWicFrameDecode.ChangePtr()) != S_OK
|| aWicFrameDecode->GetSize (&aFrameSizeX, &aFrameSizeY) != S_OK
- || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat))
+ || aWicFrameDecode->GetPixelFormat (&aWicPixelFormat) != S_OK)
{
Message::SendFail ("Error: cannot get WIC Image Frame");
return false;
Message::SendFail ("Error: cannot convert WIC Image Frame to RGB format");
return false;
}
- aWicFrameDecode.Nullify();
}
if (!Image_PixMap::InitTrash (aPixelFormat, aFrameSizeX, aFrameSizeY))
return false;
}
+ TCollection_AsciiString aFileNameLower = theFileName;
+ aFileNameLower.LowerCase();
+ if (aFileNameLower.EndsWith (".gif")
+ && (aWicImgFactory->CreatePalette (&myPalette) != S_OK
+ || aWicFrameDecode->CopyPalette (myPalette) != S_OK))
+ {
+ Message::SendFail ("Error: cannot get palette for GIF image");
+ return false;
+ }
+
IWICBitmapSource* aWicSrc = aWicFrameDecode.get();
if(!aWicConvertedFrame.IsNull())
{
aWicSrc = aWicConvertedFrame.get();
}
+
+ IWICBitmapFlipRotator* aRotator;
+ bool isTopDown = true;
+ if (aWicImgFactory->CreateBitmapFlipRotator (&aRotator) == S_OK
+ && aRotator->Initialize (aWicSrc, WICBitmapTransformFlipVertical) == S_OK)
+ {
+ isTopDown = false;
+ aWicSrc = aRotator;
+ }
+
if (aWicSrc->CopyPixels (NULL, (UINT )SizeRowBytes(), (UINT )SizeBytes(), ChangeData()) != S_OK)
{
Message::SendFail ("Error: cannot copy pixels from WIC Image");
return false;
}
- SetTopDown (true);
+ SetTopDown (isTopDown);
return true;
}
bool Image_AlienPixMap::Load (std::istream& theStream,
return false;
}
bool Image_AlienPixMap::Load (const Standard_Byte* theData,
- Standard_Size theLength,
+ const Standard_Size theLength,
const TCollection_AsciiString& theImagePath)
{
Clear();
return false;
}
bool Image_AlienPixMap::Load (const Standard_Byte* ,
- Standard_Size ,
+ const Standard_Size ,
const TCollection_AsciiString& )
{
Clear();
return true;
}
+// =======================================================================
+// function : convertData
+// purpose :
+// =======================================================================
+#ifdef HAVE_WINCODEC
+static bool convertData (const Image_AlienPixMap& theSrcPixMapData,
+ const WICPixelFormatGUID& theFormat,
+ IWICImagingFactory& theWicImgFactory,
+ Image_PixMapData& theDstPixMapData)
+{
+ const UINT aSizeRowBytes = (UINT)theSrcPixMapData.SizeRowBytes();
+ const UINT aSizeBytes = (UINT)theSrcPixMapData.SizeBytes();
+
+ Image_ComPtr<IWICBitmap> anSrcImg;
+ Image_ComPtr<IWICFormatConverter> aWicFormatConverter;
+ HRESULT anHResult = theWicImgFactory.CreateBitmapFromMemory ((UINT)theSrcPixMapData.SizeX(), (UINT)theSrcPixMapData.SizeY(),
+ convertToWicFormat (theSrcPixMapData.Format()),
+ aSizeRowBytes, aSizeBytes,
+ (BYTE*)theSrcPixMapData.Data(), &anSrcImg.ChangePtr());
+ if (anHResult != S_OK
+ || theWicImgFactory.CreateFormatConverter (&aWicFormatConverter.ChangePtr()) != S_OK
+ || aWicFormatConverter->Initialize (anSrcImg.get(), theFormat, WICBitmapDitherTypeNone, theSrcPixMapData.GetPalette(), 0.0f, WICBitmapPaletteTypeCustom) != S_OK)
+ {
+ Message::SendFail ("Error: cannot convert WIC Image Frame to required format");
+ return false;
+ }
+
+ theDstPixMapData.Init (Image_PixMap::DefaultAllocator(), 1, theSrcPixMapData.SizeXYZ(), aSizeRowBytes, NULL);
+
+ if (aWicFormatConverter->CopyPixels (NULL, aSizeRowBytes, aSizeBytes, theDstPixMapData.ChangeData()) != S_OK)
+ {
+ Message::SendFail ("Error: cannot copy pixels from WIC Image");
+ return false;
+ }
+
+ return true;
+}
+#endif
+
// =======================================================================
// function : Save
// purpose :
// =======================================================================
-bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName)
+bool Image_AlienPixMap::Save (Standard_Byte* theBuffer,
+ const Standard_Size theLength,
+ const TCollection_AsciiString& theFileName)
{
#ifdef HAVE_FREEIMAGE
if (myLibImage == NULL)
SetTopDown (false);
}
- // FreeImage doesn't provide flexible format conversion API
- // so we should perform multiple conversions in some cases!
- FIBITMAP* anImageToDump = myLibImage;
- switch (anImageFormat)
- {
- case FIF_PNG:
- case FIF_BMP:
- {
- if (Format() == Image_Format_BGR32
- || Format() == Image_Format_RGB32)
- {
- // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
- for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
- {
- for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
- {
- myData.ChangeValue (aRow, aCol)[3] = 0xFF;
- }
- }
- }
- else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
- {
- anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
- }
- break;
- }
- case FIF_GIF:
- {
- FIBITMAP* aTmpBitmap = myLibImage;
- if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
- {
- aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
- if (aTmpBitmap == NULL)
- {
- return false;
- }
- }
-
- if (FreeImage_GetBPP (aTmpBitmap) != 24)
- {
- FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
- if (aTmpBitmap != myLibImage)
- {
- FreeImage_Unload (aTmpBitmap);
- }
- if (aTmpBitmap24 == NULL)
- {
- return false;
- }
- aTmpBitmap = aTmpBitmap24;
- }
-
- // need conversion to image with palette (requires 24bit bitmap)
- anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
- if (aTmpBitmap != myLibImage)
- {
- FreeImage_Unload (aTmpBitmap);
- }
- break;
- }
- case FIF_HDR:
- case FIF_EXR:
- {
- if (Format() == Image_Format_Gray
- || Format() == Image_Format_Alpha)
- {
- anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
- }
- else if (Format() == Image_Format_RGBA
- || Format() == Image_Format_BGRA)
- {
- anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
- }
- else
- {
- FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
- if (aImgTypeFI != FIT_RGBF
- && aImgTypeFI != FIT_RGBAF
- && aImgTypeFI != FIT_FLOAT)
- {
- anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
- }
- }
- break;
- }
- default:
- {
- if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
- {
- anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
- if (anImageToDump == NULL)
- {
- return false;
- }
- }
-
- if (FreeImage_GetBPP (anImageToDump) != 24)
- {
- FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
- if (anImageToDump != myLibImage)
- {
- FreeImage_Unload (anImageToDump);
- }
- if (aTmpBitmap24 == NULL)
- {
- return false;
- }
- anImageToDump = aTmpBitmap24;
- }
- break;
- }
- }
+ FIBITMAP* anImageToDump = getImageToDump (anImageFormat);
if (anImageToDump == NULL)
{
return false;
}
+ bool isSaved = false;
+ if (theBuffer != NULL)
+ {
+ // a memory buffer wrapped by FreeImage is read only (images can be loaded but not be saved)
+ // so we call FreeImage_OpenMemory() with default arguments and just memcpy in requsted buffer.
+ FIMEMORY* aFiMem = FreeImage_OpenMemory();
+ isSaved = (FreeImage_SaveToMemory (anImageFormat, anImageToDump, aFiMem) != FALSE);
+ BYTE* aData = NULL;
+ DWORD aSize;
+ FreeImage_AcquireMemory (aFiMem, &aData, &aSize);
+ if (aSize > theLength)
+ {
+ Message::SendFail ("Error: memory buffer too small for storing image");
+ return false;
+ }
+ memcpy (theBuffer, aData, aSize);
+ FreeImage_CloseMemory (aFiMem);
+ }
+ else
+ {
#ifdef _WIN32
- bool isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString()) != FALSE);
+ isSaved = (FreeImage_SaveU (anImageFormat, anImageToDump, aFileNameW.ToWideString ()) != FALSE);
#else
- bool isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString()) != FALSE);
+ isSaved = (FreeImage_Save (anImageFormat, anImageToDump, theFileName.ToCString ()) != FALSE);
#endif
+ }
if (anImageToDump != myLibImage)
{
FreeImage_Unload (anImageToDump);
TCollection_AsciiString aFileNameLower = theFileName;
aFileNameLower.LowerCase();
- GUID aFileFormat = getNullGuid();
if (aFileNameLower.EndsWith (".ppm"))
{
return savePPM (theFileName);
}
- else if (aFileNameLower.EndsWith (".bmp"))
+
+ GUID aFileFormat = getFileFormatFromName (theFileName);
+ if (aFileFormat == getNullGuid())
+ {
+ Message::SendFail ("Error: unsupported image format");
+ return false;
+ }
+
+ Image_ComPtr<IWICImagingFactory> aWicImgFactory;
+ CoInitializeEx (NULL, COINIT_MULTITHREADED);
+ if (CoCreateInstance (CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&aWicImgFactory.ChangePtr())) != S_OK)
+ {
+ Message::SendFail ("Error: cannot initialize WIC Imaging Factory");
+ return false;
+ }
+
+ WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
+ if (aWicPixelFormat == getNullGuid())
+ {
+ Message::SendFail ("Error: unsupported pixel format");
+ return false;
+ }
+
+ Image_PixMapData* aPixMapData = &myData;
+ Image_PixMapData aConvertedData;
+ if (aFileFormat == GUID_ContainerFormatGif)
+ {
+ aWicPixelFormat = GUID_WICPixelFormat8bppIndexed;
+ convertData (*this, aWicPixelFormat, *aWicImgFactory, aConvertedData);
+ aPixMapData = &aConvertedData;
+ }
+
+ Image_ComPtr<IWICStream> aWicStream;
+ Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
+ const TCollection_ExtendedString aFileNameW (theFileName);
+ if (theBuffer != NULL)
+ {
+ if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
+ || aWicStream->InitializeFromMemory (theBuffer,(DWORD )theLength) != S_OK)
+ {
+ Message::SendFail ("Error: cannot create WIC Memory Stream");
+ return false;
+ }
+ }
+ else
+ {
+ if (aWicImgFactory->CreateStream (&aWicStream.ChangePtr()) != S_OK
+ || aWicStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
+ {
+ Message::SendFail ("Error: cannot create WIC File Stream");
+ return false;
+ }
+ }
+ if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
+ || aWicEncoder->Initialize (aWicStream.get(), WICBitmapEncoderNoCache) != S_OK)
+ {
+ Message::SendFail ("Error: cannot create WIC Encoder");
+ return false;
+ }
+
+ WICPixelFormatGUID aWicPixelFormatRes = aWicPixelFormat;
+ Image_ComPtr<IWICBitmapFrameEncode> aWicFrameEncode;
+ if (aWicEncoder->CreateNewFrame (&aWicFrameEncode.ChangePtr(), NULL) != S_OK
+ || aWicFrameEncode->Initialize (NULL) != S_OK
+ || aWicFrameEncode->SetSize ((UINT )SizeX(), (UINT )SizeY()) != S_OK
+ || aWicFrameEncode->SetPixelFormat (&aWicPixelFormatRes) != S_OK)
+ {
+ Message::SendFail ("Error: cannot create WIC Frame");
+ return false;
+ }
+
+ if (aFileFormat == GUID_ContainerFormatGif
+ && (myPalette == NULL
+ || aWicFrameEncode->SetPalette (myPalette) != S_OK))
+ {
+ Message::SendFail ("Error: cannot set palette");
+ return false;
+ }
+
+ if (aWicPixelFormatRes != aWicPixelFormat)
+ {
+ Message::SendFail ("Error: pixel format is unsupported by image format");
+ return false;
+ }
+
+ if (IsTopDown())
+ {
+ if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )aPixMapData->Data()) != S_OK)
+ {
+ Message::SendFail ("Error: cannot write pixels to WIC Frame");
+ return false;
+ }
+ }
+ else
+ {
+ for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
+ {
+ if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )aPixMapData->Row (aRow)) != S_OK)
+ {
+ Message::SendFail ("Error: cannot write pixels to WIC Frame");
+ return false;
+ }
+ }
+ }
+ if (aWicFrameEncode->Commit() != S_OK
+ || aWicEncoder->Commit() != S_OK)
+ {
+ Message::SendFail ("Error: cannot commit data to WIC Frame");
+ return false;
+ }
+ if (aWicStream->Commit (STGC_DEFAULT) != S_OK)
{
- aFileFormat = GUID_ContainerFormatBmp;
+ //Message::Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
+ //return false;
}
- else if (aFileNameLower.EndsWith (".png"))
+ return true;
+#else
+ if (theBuffer != NULL)
{
- aFileFormat = GUID_ContainerFormatPng;
+ Message::SendFail ("Error: no image library available");
+ return false;
}
- else if (aFileNameLower.EndsWith (".jpg")
- || aFileNameLower.EndsWith (".jpeg"))
+ const Standard_Integer aLen = theFileName.Length();
+ if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
+ && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
{
- aFileFormat = GUID_ContainerFormatJpeg;
+ return savePPM (theFileName);
}
- else if (aFileNameLower.EndsWith (".tiff")
- || aFileNameLower.EndsWith (".tif"))
+ Message::SendTrace ("Image_PixMap, no image library available! Image saved in PPM format");
+ return savePPM (theFileName);
+#endif
+}
+
+bool Image_AlienPixMap::Save (std::ostream& theStream, const TCollection_AsciiString& theExtension)
+{
+#ifdef HAVE_FREEIMAGE
+ if (myLibImage == NULL)
{
- aFileFormat = GUID_ContainerFormatTiff;
+ return false;
}
- else if (aFileNameLower.EndsWith (".gif"))
+
+#ifdef _WIN32
+ const TCollection_ExtendedString anExtW (theExtension.ToCString(), Standard_True);
+ FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilenameU (anExtW.ToWideString());
+#else
+ FREE_IMAGE_FORMAT anImageFormat = FreeImage_GetFIFFromFilename (theExtension.ToCString());
+#endif
+ if (anImageFormat == FIF_UNKNOWN)
{
- aFileFormat = GUID_ContainerFormatGif;
+#ifdef OCCT_DEBUG
+ std::cerr << "Image_PixMap, image format doesn't supported!\n";
+#endif
+ return false;
}
+ if (IsTopDown())
+ {
+ FreeImage_FlipVertical (myLibImage);
+ SetTopDown (false);
+ }
+
+ FIBITMAP* anImageToDump = getImageToDump (anImageFormat);
+
+ if (anImageToDump == NULL)
+ {
+ return false;
+ }
+
+ bool isSaved = false;
+ Image_FreeImageStream aStream (theStream);
+ FreeImageIO anIO = aStream.GetFiIO();
+
+ isSaved = (FreeImage_SaveToHandle(anImageFormat, anImageToDump, &anIO, &aStream) != FALSE);
+
+ if (anImageToDump != myLibImage)
+ {
+ FreeImage_Unload (anImageToDump);
+ }
+ return isSaved;
+#elif defined(HAVE_WINCODEC)
+ GUID aFileFormat = getFileFormatFromName (theExtension);
if (aFileFormat == getNullGuid())
{
Message::SendFail ("Error: unsupported image format");
return false;
}
- Image_ComPtr<IWICStream> aWicFileStream;
- Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
- const TCollection_ExtendedString aFileNameW (theFileName);
- if (aWicImgFactory->CreateStream (&aWicFileStream.ChangePtr()) != S_OK
- || aWicFileStream->InitializeFromFilename (aFileNameW.ToWideString(), GENERIC_WRITE) != S_OK)
+ WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
+ if (aWicPixelFormat == getNullGuid())
{
- Message::SendFail ("Error: cannot create WIC File Stream");
+ Message::SendFail ("Error: unsupported pixel format");
return false;
}
- if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
- || aWicEncoder->Initialize (aWicFileStream.get(), WICBitmapEncoderNoCache) != S_OK)
+
+ Image_PixMapData* aPixMapData = &myData;
+ Image_PixMapData aConvertedData;
+ if (aFileFormat == GUID_ContainerFormatGif)
{
- Message::SendFail ("Error: cannot create WIC Encoder");
+ aWicPixelFormat = GUID_WICPixelFormat8bppIndexed;
+ convertData (*this, aWicPixelFormat, *aWicImgFactory, aConvertedData);
+ aPixMapData = &aConvertedData;
+ }
+
+ Image_ComPtr<IStream> aStream;
+ Image_ComPtr<IWICBitmapEncoder> aWicEncoder;
+
+ if (CreateStreamOnHGlobal (NULL, Standard_True, &aStream.ChangePtr()) != S_OK)
+ {
+ Message::SendFail ("Error: cannot create Stream on global");
return false;
}
- const WICPixelFormatGUID aWicPixelFormat = convertToWicFormat (myImgFormat);
- if (aWicPixelFormat == getNullGuid())
+ if (aWicImgFactory->CreateEncoder (aFileFormat, NULL, &aWicEncoder.ChangePtr()) != S_OK
+ || aWicEncoder->Initialize (aStream.get(), WICBitmapEncoderNoCache) != S_OK)
{
- Message::SendFail ("Error: unsupported pixel format");
+ Message::SendFail ("Error: cannot create WIC Encoder");
return false;
}
return false;
}
+ if (aFileFormat == GUID_ContainerFormatGif
+ && (myPalette == NULL
+ || aWicFrameEncode->SetPalette (myPalette) != S_OK))
+ {
+ Message::SendFail ("Error: cannot set palette");
+ return false;
+ }
+
if (aWicPixelFormatRes != aWicPixelFormat)
{
Message::SendFail ("Error: pixel format is unsupported by image format");
if (IsTopDown())
{
- if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )Data()) != S_OK)
+ if (aWicFrameEncode->WritePixels ((UINT )SizeY(), (UINT )SizeRowBytes(), (UINT )SizeBytes(), (BYTE* )aPixMapData->Data()) != S_OK)
{
Message::SendFail ("Error: cannot write pixels to WIC Frame");
return false;
{
for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
{
- if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )Row (aRow)) != S_OK)
+ if (aWicFrameEncode->WritePixels (1, (UINT )SizeRowBytes(), (UINT )SizeRowBytes(), (BYTE* )aPixMapData->Row (aRow)) != S_OK)
{
Message::SendFail ("Error: cannot write pixels to WIC Frame");
return false;
}
}
}
-
if (aWicFrameEncode->Commit() != S_OK
|| aWicEncoder->Commit() != S_OK)
{
Message::SendFail ("Error: cannot commit data to WIC Frame");
return false;
}
- if (aWicFileStream->Commit (STGC_DEFAULT) != S_OK)
+ if (aStream->Commit (STGC_DEFAULT) != S_OK)
{
- //Message::Send ("Error: cannot commit data to WIC File Stream", Message_Fail);
+ //Message::Send ("Error: cannot commit data to Stream", Message_Fail);
//return false;
}
- return true;
-#else
- const Standard_Integer aLen = theFileName.Length();
- if ((aLen >= 4) && (theFileName.Value (aLen - 3) == '.')
- && strcasecmp( theFileName.ToCString() + aLen - 3, "ppm") == 0 )
+
+ // WIC doesn't have the way to encode image directly in std::ostream
+ // so we use a workaround to transfer data from IStream to std::ostream
+ STATSTG aStat;
+ if (aStream->Stat (&aStat, STATFLAG_NONAME) != S_OK)
{
- return savePPM (theFileName);
+ Message::SendFail ("Error: cannot get stat from stream");
+ return false;
}
- Message::SendTrace ("Image_PixMap, no image library available! Image saved in PPM format");
- return savePPM (theFileName);
+ HGLOBAL aMem;
+ if (GetHGlobalFromStream (aStream.get(), &aMem) != S_OK)
+ {
+ Message::SendFail ("Error: cannot get global from stream");
+ return false;
+ }
+
+ LPVOID aData = GlobalLock (aMem);
+ if (aData == NULL)
+ {
+ Message::SendFail ("Error: cannot lock global");
+ return false;
+ }
+ if (!theStream.write ((const char* )aData, aStat.cbSize.QuadPart))
+ {
+ Message::SendFail ("Error: cannot write data to ostream");
+ return false;
+ }
+ if (GlobalUnlock (aMem) == 0 && GetLastError() != NO_ERROR)
+ {
+ Message::SendFail ("Error: cannot unlock global");
+ return false;
+ }
+ return true;
+#else
+ Message::SendFail ("Error: no image library available");
+ return false;
#endif
}
return false;
#endif
}
+
+#ifdef HAVE_FREEIMAGE
+// =======================================================================
+// function : GetImageToDump
+// purpose :
+// =======================================================================
+FIBITMAP* Image_AlienPixMap::getImageToDump (const Standard_Integer theFormat)
+{
+ FIBITMAP* anImageToDump = myLibImage;
+ // FreeImage doesn't provide flexible format conversion API
+ // so we should perform multiple conversions in some cases!
+ switch (theFormat)
+ {
+ case FIF_PNG:
+ case FIF_BMP:
+ {
+ if (Format() == Image_Format_BGR32
+ || Format() == Image_Format_RGB32)
+ {
+ // stupid FreeImage treats reserved byte as alpha if some bytes not set to 0xFF
+ for (Standard_Size aRow = 0; aRow < SizeY(); ++aRow)
+ {
+ for (Standard_Size aCol = 0; aCol < SizeX(); ++aCol)
+ {
+ myData.ChangeValue (aRow, aCol)[3] = 0xFF;
+ }
+ }
+ }
+ else if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
+ {
+ anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
+ }
+ break;
+ }
+ case FIF_GIF:
+ {
+ FIBITMAP* aTmpBitmap = myLibImage;
+ if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
+ {
+ aTmpBitmap = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
+ if (aTmpBitmap == NULL)
+ {
+ return NULL;
+ }
+ }
+
+ if (FreeImage_GetBPP (aTmpBitmap) != 24)
+ {
+ FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (aTmpBitmap);
+ if (aTmpBitmap != myLibImage)
+ {
+ FreeImage_Unload (aTmpBitmap);
+ }
+ if (aTmpBitmap24 == NULL)
+ {
+ return NULL;
+ }
+ aTmpBitmap = aTmpBitmap24;
+ }
+
+ // need conversion to image with palette (requires 24bit bitmap)
+ anImageToDump = FreeImage_ColorQuantize (aTmpBitmap, FIQ_NNQUANT);
+ if (aTmpBitmap != myLibImage)
+ {
+ FreeImage_Unload (aTmpBitmap);
+ }
+ break;
+ }
+ case FIF_HDR:
+ case FIF_EXR:
+ {
+ if (Format() == Image_Format_Gray
+ || Format() == Image_Format_Alpha)
+ {
+ anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT);
+ }
+ else if (Format() == Image_Format_RGBA
+ || Format() == Image_Format_BGRA)
+ {
+ anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBAF);
+ }
+ else
+ {
+ FREE_IMAGE_TYPE aImgTypeFI = FreeImage_GetImageType (myLibImage);
+ if (aImgTypeFI != FIT_RGBF
+ && aImgTypeFI != FIT_RGBAF
+ && aImgTypeFI != FIT_FLOAT)
+ {
+ anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_RGBF);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if (FreeImage_GetImageType (myLibImage) != FIT_BITMAP)
+ {
+ anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_BITMAP);
+ if (anImageToDump == NULL)
+ {
+ return NULL;
+ }
+ }
+
+ if (FreeImage_GetBPP (anImageToDump) != 24)
+ {
+ FIBITMAP* aTmpBitmap24 = FreeImage_ConvertTo24Bits (anImageToDump);
+ if (anImageToDump != myLibImage)
+ {
+ FreeImage_Unload (anImageToDump);
+ }
+ if (aTmpBitmap24 == NULL)
+ {
+ return NULL;
+ }
+ anImageToDump = aTmpBitmap24;
+ }
+ break;
+ }
+ }
+ return anImageToDump;
+}
+#endif
//function : OCC30182
//purpose : Testing different interfaces of Image_AlienPixMap::Load()
//=======================================================================
-static Standard_Integer OCC30182 (Draw_Interpretor& , Standard_Integer theNbArgs, const char** theArgVec)
+static Standard_Integer OCC30182 (Draw_Interpretor& di, Standard_Integer theNbArgs, const char** theArgVec)
{
if (ViewerTest::CurrentView().IsNull())
{
- std::cout << "Error: no active view\n";
+ di << "Error: no active view\n";
return 1;
}
}
else
{
- std::cout << "Syntax error at '" << anArg << "'\n";
+ di << "Syntax error at '" << anArg << "'\n";
return 1;
}
}
if (anImgPath.IsEmpty())
{
- std::cout << "Syntax error: wrong number of arguments\n";
+ di << "Syntax error: wrong number of arguments\n";
return 1;
}
std::shared_ptr<std::istream> aFile = aFileSystem->OpenIStream (anImgPath, std::ios::in | std::ios::binary);
if (aFile.get() == NULL)
{
- std::cout << "Syntax error: image file '" << anImgPath << "' cannot be found\n";
+ di << "Syntax error: image file '" << anImgPath << "' cannot be found\n";
return 1;
}
if (anOffset != 0)
aFile->seekg (anOffset);
if (aLen <= 0)
{
- std::cout << "Syntax error: wrong offset\n";
+ di << "Syntax error: wrong offset\n";
return 1;
}
NCollection_Array1<Standard_Byte> aBuff (1, aLen);
if (!aFile->read ((char* )&aBuff.ChangeFirst(), aBuff.Size()))
{
- std::cout << "Error: unable to read file\n";
+ di << "Error: unable to read file\n";
return 1;
}
if (!anImage->Load (&aBuff.ChangeFirst(), aBuff.Size(), anImgPath))
return 0;
}
+//=======================================================================
+//function : OCC31956
+//purpose : Testing Image_AlienPixMap::Save() overload for saving into a memory buffer or stream
+//=======================================================================
+static Standard_Integer OCC31956 (Draw_Interpretor& di, Standard_Integer theNbArgs, const char** theArgVec)
+{
+ if (ViewerTest::CurrentView().IsNull())
+ {
+ di << "Error: no active view\n";
+ return 1;
+ }
+ if (theNbArgs != 3 && theNbArgs != 5)
+ {
+ di << "Syntax error: wrong number of arguments\n";
+ return 1;
+ }
+
+ bool useStream = false;
+ TCollection_AsciiString aTempImgPath;
+ if (theNbArgs == 5)
+ {
+ TCollection_AsciiString anArg (theArgVec[3]);
+ anArg.LowerCase();
+ if (anArg == "-stream")
+ {
+ useStream = true;
+ aTempImgPath = theArgVec[4];
+ }
+ else
+ {
+ di << "Syntax error at '" << anArg << "'\n";
+ return 1;
+ }
+ }
+
+ TCollection_AsciiString aPrsName, anImgPath;
+ aPrsName = theArgVec[1];
+ anImgPath = theArgVec[2];
+ Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
+ const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
+ opencascade::std::shared_ptr<std::istream> aFile = aFileSystem->OpenIStream (anImgPath, std::ios::in | std::ios::binary);
+ if (aFile.get() == NULL)
+ {
+ di << "Syntax error: image file '" << anImgPath << "' cannot be found\n";
+ return 1;
+ }
+
+ aFile->seekg (0, std::ios::end);
+ Standard_Integer aLen = (Standard_Integer )aFile->tellg();
+ aFile->seekg (0);
+ if (!anImage->Load (*aFile, anImgPath))
+ {
+ return 0;
+ }
+
+ Handle(Image_AlienPixMap) aControlImg = new Image_AlienPixMap();
+ if (useStream)
+ {
+ opencascade::std::shared_ptr<std::ostream> aTempFile = aFileSystem->OpenOStream (aTempImgPath, std::ios::out | std::ios::binary);
+ if (aTempFile.get() == NULL)
+ {
+ di << "Error: image file '" << aTempImgPath << "' cannot be open\n";
+ return 0;
+ }
+ if (!anImage->Save (*aTempFile, aTempImgPath))
+ {
+ di << "Error: failed saving file using stream '" << aTempImgPath << "'\n";
+ return 0;
+ }
+ aTempFile.reset();
+ aControlImg->Load (aTempImgPath);
+ }
+ else
+ {
+ NCollection_Array1<Standard_Byte> aBuff (1, aLen + 2048);
+ if (!anImage->Save (&aBuff.ChangeFirst(), aBuff.Size(), anImgPath))
+ {
+ di << "Error: failed saving file using buffer'" << anImgPath << "'\n";
+ return 0;
+ }
+ aControlImg->Load (&aBuff.ChangeFirst(), aBuff.Size(), anImgPath);
+ }
+
+ TopoDS_Shape aShape = BRepPrimAPI_MakeBox (100.0 * aControlImg->Ratio(), 100.0, 1.0).Shape();
+ Handle(AIS_Shape) aPrs = new AIS_Shape (aShape);
+ aPrs->SetDisplayMode (AIS_Shaded);
+ aPrs->Attributes()->SetupOwnShadingAspect();
+ const Handle(Graphic3d_AspectFillArea3d)& anAspect = aPrs->Attributes()->ShadingAspect()->Aspect();
+ anAspect->SetShadingModel (Graphic3d_TOSM_UNLIT);
+ anAspect->SetTextureMapOn (true);
+ anAspect->SetTextureMap (new Graphic3d_Texture2D(aControlImg));
+ if (aControlImg->IsTopDown())
+ {
+ anAspect->TextureMap()->GetParams()->SetTranslation (Graphic3d_Vec2 (0.0f, -1.0f));
+ anAspect->TextureMap()->GetParams()->SetScale (Graphic3d_Vec2 (1.0f, -1.0f));
+ }
+
+ ViewerTest::Display (aPrsName, aPrs, true, true);
+ return 0;
+}
+
void QABugs::Commands_1(Draw_Interpretor& theCommands) {
const char *group = "QABugs";
theCommands.Add ("OCC30182",
"OCC30182 name image [-offset Start] [-fileName] [-stream] [-memory]\n"
"Decodes image either by passing file name, file stream or memory stream", __FILE__, OCC30182, group);
+ theCommands.Add ("OCC31956", "OCC31956 name image [-stream tempImage]\n"
+ "Loads image and saves it into memory buffer or stream then loads it back", __FILE__, OCC31956, group);
return;
}