summaryrefslogtreecommitdiff
path: root/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/AdvaImg/src/FreeImage/PluginJXR.cpp')
-rw-r--r--plugins/AdvaImg/src/FreeImage/PluginJXR.cpp1475
1 files changed, 0 insertions, 1475 deletions
diff --git a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp b/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
deleted file mode 100644
index 0e14e09ac9..0000000000
--- a/plugins/AdvaImg/src/FreeImage/PluginJXR.cpp
+++ /dev/null
@@ -1,1475 +0,0 @@
-// ==========================================================
-// JPEG XR Loader & Writer
-//
-// Design and implementation by
-// - Herve Drolon (drolon@infonie.fr)
-//
-// This file is part of FreeImage 3
-//
-// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
-// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
-// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
-// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
-// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
-// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
-// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
-// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
-// THIS DISCLAIMER.
-//
-// Use at your own risk!
-// ==========================================================
-
-#include "FreeImage.h"
-#include "Utilities.h"
-#include "../Metadata/FreeImageTag.h"
-
-#include "../LibJXR/jxrgluelib/JXRGlue.h"
-
-// ==========================================================
-// Plugin Interface
-// ==========================================================
-
-static int s_format_id;
-
-// ==========================================================
-// FreeImageIO interface (I/O streaming functions)
-// ==========================================================
-
-/**
-JXR wrapper for FreeImage I/O handle
-*/
-typedef struct tagFreeImageJXRIO {
- FreeImageIO *io;
- fi_handle handle;
-} FreeImageJXRIO;
-
-static ERR
-_jxr_io_Read(WMPStream* pWS, void* pv, size_t cb) {
- FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
- return (fio->io->read_proc(pv, (unsigned)cb, 1, fio->handle) == 1) ? WMP_errSuccess : WMP_errFileIO;
-}
-
-static ERR
-_jxr_io_Write(WMPStream* pWS, const void* pv, size_t cb) {
- FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
- if(0 != cb) {
- return (fio->io->write_proc((void*)pv, (unsigned)cb, 1, fio->handle) == 1) ? WMP_errSuccess : WMP_errFileIO;
- }
- return WMP_errFileIO;
-}
-
-static ERR
-_jxr_io_SetPos(WMPStream* pWS, size_t offPos) {
- FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
- return (fio->io->seek_proc(fio->handle, (long)offPos, SEEK_SET) == 0) ? WMP_errSuccess : WMP_errFileIO;
-}
-
-static ERR
-_jxr_io_GetPos(WMPStream* pWS, size_t* poffPos) {
- FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
- long lOff = fio->io->tell_proc(fio->handle);
- if(lOff == -1) {
- return WMP_errFileIO;
- }
- *poffPos = (size_t)lOff;
- return WMP_errSuccess;
-}
-
-static Bool
-_jxr_io_EOS(WMPStream* pWS) {
- FreeImageJXRIO *fio = (FreeImageJXRIO*)pWS->state.pvObj;
- long currentPos = fio->io->tell_proc(fio->handle);
- fio->io->seek_proc(fio->handle, 0, SEEK_END);
- long fileRemaining = fio->io->tell_proc(fio->handle) - currentPos;
- fio->io->seek_proc(fio->handle, currentPos, SEEK_SET);
- return (fileRemaining > 0);
-}
-
-static ERR
-_jxr_io_Close(WMPStream** ppWS) {
- WMPStream *pWS = *ppWS;
- // HACK : we use fMem to avoid a stream destruction by the library
- // because FreeImage MUST HAVE the ownership of the stream
- // see _jxr_io_Create
- if(pWS && pWS->fMem) {
- free(pWS);
- *ppWS = NULL;
- }
- return WMP_errSuccess;
-}
-
-static ERR
-_jxr_io_Create(WMPStream **ppWS, FreeImageJXRIO *jxr_io) {
- *ppWS = (WMPStream*)calloc(1, sizeof(**ppWS));
- if(*ppWS) {
- WMPStream *pWS = *ppWS;
-
- pWS->state.pvObj = jxr_io;
- pWS->Close = _jxr_io_Close;
- pWS->EOS = _jxr_io_EOS;
- pWS->Read = _jxr_io_Read;
- pWS->Write = _jxr_io_Write;
- pWS->SetPos = _jxr_io_SetPos;
- pWS->GetPos = _jxr_io_GetPos;
-
- // HACK : we use fMem to avoid a stream destruction by the library
- // because FreeImage MUST HAVE the ownership of the stream
- // see _jxr_io_Close
- pWS->fMem = FALSE;
-
- return WMP_errSuccess;
- }
- return WMP_errOutOfMemory;
-}
-
-// ==========================================================
-// JPEG XR Error handling
-// ==========================================================
-
-static const char*
-JXR_ErrorMessage(const int error) {
- switch(error) {
- case WMP_errNotYetImplemented:
- case WMP_errAbstractMethod:
- return "Not yet implemented";
- case WMP_errOutOfMemory:
- return "Out of memory";
- case WMP_errFileIO:
- return "File I/O error";
- case WMP_errBufferOverflow:
- return "Buffer overflow";
- case WMP_errInvalidParameter:
- return "Invalid parameter";
- case WMP_errInvalidArgument:
- return "Invalid argument";
- case WMP_errUnsupportedFormat:
- return "Unsupported format";
- case WMP_errIncorrectCodecVersion:
- return "Incorrect codec version";
- case WMP_errIndexNotFound:
- return "Format converter: Index not found";
- case WMP_errOutOfSequence:
- return "Metadata: Out of sequence";
- case WMP_errMustBeMultipleOf16LinesUntilLastCall:
- return "Must be multiple of 16 lines until last call";
- case WMP_errPlanarAlphaBandedEncRequiresTempFile:
- return "Planar alpha banded encoder requires temp files";
- case WMP_errAlphaModeCannotBeTranscoded:
- return "Alpha mode cannot be transcoded";
- case WMP_errIncorrectCodecSubVersion:
- return "Incorrect codec subversion";
- case WMP_errFail:
- case WMP_errNotInitialized:
- default:
- return "Invalid instruction - please contact the FreeImage team";
- }
-}
-
-// ==========================================================
-// Helper functions & macro
-// ==========================================================
-
-#define JXR_CHECK(error_code) \
- if(error_code < 0) { \
- const char *error_message = JXR_ErrorMessage(error_code); \
- throw error_message; \
- }
-
-// --------------------------------------------------------------------------
-
-/**
-Input conversions natively understood by FreeImage
-@see GetNativePixelFormat
-*/
-typedef struct tagJXRInputConversion {
- BITDEPTH_BITS bdBitDepth;
- U32 cbitUnit;
- FREE_IMAGE_TYPE image_type;
- unsigned red_mask;
- unsigned green_mask;
- unsigned blue_mask;
-} JXRInputConversion;
-
-/**
-Conversion table for native FreeImage formats
-@see GetNativePixelFormat
-*/
-static JXRInputConversion s_FreeImagePixelInfo[] = {
- // 1-bit bitmap
- { BD_1, 1, FIT_BITMAP, 0, 0, 0 },
- // 8-, 24-, 32-bit bitmap
- { BD_8, 8, FIT_BITMAP, 0, 0, 0 },
- { BD_8, 24, FIT_BITMAP, 0, 0, 0 },
- { BD_8, 32, FIT_BITMAP, 0, 0, 0 },
- // 16-bit RGB 565
- { BD_565, 16, FIT_BITMAP, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK },
- // 16-bit RGB 555
- { BD_5, 16, FIT_BITMAP, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK },
- // 16-bit greyscale, RGB16, RGBA16 bitmap
- { BD_16, 16, FIT_UINT16, 0, 0, 0 },
- { BD_16, 48, FIT_RGB16, 0, 0, 0 },
- { BD_16, 64, FIT_RGBA16, 0, 0, 0 },
- // 32-bit float, RGBF, RGBAF bitmap
- { BD_32F, 32, FIT_FLOAT, 0, 0, 0 },
- { BD_32F, 96, FIT_RGBF, 0, 0, 0 },
- { BD_32F, 128, FIT_RGBAF, 0, 0, 0 }
-};
-
-/**
-Scan input pixelInfo specifications and return the equivalent FreeImage info for loading
-@param pixelInfo Image specifications
-@param out_guid_format (returned value) output pixel format
-@param image_type (returned value) Image type
-@param bpp (returned value) Image bit depth
-@param red_mask (returned value) RGB mask
-@param green_mask (returned value) RGB mask
-@param blue_mask (returned value) RGB mask
-@return Returns WMP_errSuccess if successful, returns WMP_errFail otherwise
-@see GetInputPixelFormat
-*/
-static ERR
-GetNativePixelFormat(const PKPixelInfo *pixelInfo, PKPixelFormatGUID *out_guid_format, FREE_IMAGE_TYPE *image_type, unsigned *bpp, unsigned *red_mask, unsigned *green_mask, unsigned *blue_mask) {
- const unsigned s_FreeImagePixelInfoSize = (unsigned)sizeof(s_FreeImagePixelInfo) / sizeof(*(s_FreeImagePixelInfo));
-
- for(unsigned i = 0; i < s_FreeImagePixelInfoSize; i++) {
- if(pixelInfo->bdBitDepth == s_FreeImagePixelInfo[i].bdBitDepth) {
- if(pixelInfo->cbitUnit == s_FreeImagePixelInfo[i].cbitUnit) {
- // found ! now get dst image format specifications
- memcpy(out_guid_format, pixelInfo->pGUIDPixFmt, sizeof(PKPixelFormatGUID));
- *image_type = s_FreeImagePixelInfo[i].image_type;
- *bpp = s_FreeImagePixelInfo[i].cbitUnit;
- *red_mask = s_FreeImagePixelInfo[i].red_mask;
- *green_mask = s_FreeImagePixelInfo[i].green_mask;
- *blue_mask = s_FreeImagePixelInfo[i].blue_mask;
- return WMP_errSuccess;
- }
- }
- }
-
- // not found : need pixel format conversion
- return WMP_errFail;
-}
-
-/**
-Scan input file guid format and return the equivalent FreeImage info & target guid format for loading
-@param pDecoder Decoder handle
-@param guid_format (returned value) Output pixel format
-@param image_type (returned value) Image type
-@param bpp (returned value) Image bit depth
-@param red_mask (returned value) RGB mask
-@param green_mask (returned value) RGB mask
-@param blue_mask (returned value) RGB mask
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static ERR
-GetInputPixelFormat(PKImageDecode *pDecoder, PKPixelFormatGUID *guid_format, FREE_IMAGE_TYPE *image_type, unsigned *bpp, unsigned *red_mask, unsigned *green_mask, unsigned *blue_mask) {
- ERR error_code = 0; // error code as returned by the interface
- PKPixelInfo pixelInfo; // image specifications
-
- try {
- // get input file pixel format ...
- PKPixelFormatGUID pguidSourcePF;
- error_code = pDecoder->GetPixelFormat(pDecoder, &pguidSourcePF);
- JXR_CHECK(error_code);
- pixelInfo.pGUIDPixFmt = &pguidSourcePF;
- // ... check for a supported format and get the format specifications
- error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
- JXR_CHECK(error_code);
-
- // search for an equivalent native FreeImage format
- error_code = GetNativePixelFormat(&pixelInfo, guid_format, image_type, bpp, red_mask, green_mask, blue_mask);
-
- if(error_code != WMP_errSuccess) {
- // try to find a suitable conversion function ...
- const PKPixelFormatGUID *ppguidTargetPF = NULL; // target pixel format
- unsigned iIndex = 0; // first available conversion function
- do {
- error_code = PKFormatConverter_EnumConversions(&pguidSourcePF, iIndex, &ppguidTargetPF);
- if(error_code == WMP_errSuccess) {
- // found a conversion function, is the converted format a native FreeImage format ?
- pixelInfo.pGUIDPixFmt = ppguidTargetPF;
- error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
- JXR_CHECK(error_code);
- error_code = GetNativePixelFormat(&pixelInfo, guid_format, image_type, bpp, red_mask, green_mask, blue_mask);
- if(error_code == WMP_errSuccess) {
- break;
- }
- }
- // try next conversion function
- iIndex++;
- } while(error_code != WMP_errIndexNotFound);
-
- }
-
- return (error_code == WMP_errSuccess) ? WMP_errSuccess : WMP_errUnsupportedFormat;
-
- } catch(...) {
- return error_code;
- }
-}
-
-// --------------------------------------------------------------------------
-
-/**
-Scan input dib format and return the equivalent PKPixelFormatGUID format for saving
-@param dib Image to be saved
-@param guid_format (returned value) GUID format
-@param bHasAlpha (returned value) TRUE if an alpha layer is present
-@return Returns TRUE if successful, returns FALSE otherwise
-*/
-static ERR
-GetOutputPixelFormat(FIBITMAP *dib, PKPixelFormatGUID *guid_format, BOOL *bHasAlpha) {
- const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
- const unsigned bpp = FreeImage_GetBPP(dib);
- const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
-
- *guid_format = GUID_PKPixelFormatDontCare;
- *bHasAlpha = FALSE;
-
- switch(image_type) {
- case FIT_BITMAP: // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit
- switch(bpp) {
- case 1:
- // assume FIC_MINISBLACK
- if(color_type == FIC_MINISBLACK) {
- *guid_format = GUID_PKPixelFormatBlackWhite;
- }
- break;
- case 8:
- // assume FIC_MINISBLACK
- if(color_type == FIC_MINISBLACK) {
- *guid_format = GUID_PKPixelFormat8bppGray;
- }
- break;
- case 16:
- if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
- *guid_format = GUID_PKPixelFormat16bppRGB565;
- } else {
- // includes case where all the masks are 0
- *guid_format = GUID_PKPixelFormat16bppRGB555;
- }
- break;
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- case 24:
- *guid_format = GUID_PKPixelFormat24bppBGR;
- break;
- case 32:
- *guid_format = GUID_PKPixelFormat32bppBGRA;
- *bHasAlpha = TRUE;
- break;
-#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
- case 24:
- *guid_format = GUID_PKPixelFormat24bppRGB;
- break;
- case 32:
- *guid_format = GUID_PKPixelFormat32bppRGBA;
- *bHasAlpha = TRUE;
- break;
-#endif
- case 4:
- default:
- // not supported
- break;
- }
- break;
- case FIT_UINT16: // array of unsigned short : unsigned 16-bit
- *guid_format = GUID_PKPixelFormat16bppGray;
- break;
- case FIT_FLOAT: // array of float : 32-bit IEEE floating point
- *guid_format = GUID_PKPixelFormat32bppGrayFloat;
- break;
- case FIT_RGB16: // 48-bit RGB image : 3 x 16-bit
- *guid_format = GUID_PKPixelFormat48bppRGB;
- break;
- case FIT_RGBA16: // 64-bit RGBA image : 4 x 16-bit
- *guid_format = GUID_PKPixelFormat64bppRGBA;
- *bHasAlpha = TRUE;
- break;
- case FIT_RGBF: // 96-bit RGB float image : 3 x 32-bit IEEE floating point
- *guid_format = GUID_PKPixelFormat96bppRGBFloat;
- break;
- case FIT_RGBAF: // 128-bit RGBA float image : 4 x 32-bit IEEE floating point
- *guid_format = GUID_PKPixelFormat128bppRGBAFloat;
- *bHasAlpha = TRUE;
- break;
-
- case FIT_INT16: // array of short : signed 16-bit
- case FIT_UINT32: // array of unsigned long : unsigned 32-bit
- case FIT_INT32: // array of long : signed 32-bit
- case FIT_DOUBLE: // array of double : 64-bit IEEE floating point
- case FIT_COMPLEX: // array of FICOMPLEX : 2 x 64-bit IEEE floating point
-
- default:
- // unsupported format
- break;
- }
-
- return (*guid_format != GUID_PKPixelFormatDontCare) ? WMP_errSuccess : WMP_errUnsupportedFormat;
-}
-
-// ==========================================================
-// Metadata loading
-// ==========================================================
-
-/**
-Read a JPEG-XR IFD as a buffer
-@see ReadMetadata
-*/
-static ERR
-ReadProfile(WMPStream* pStream, unsigned cbByteCount, unsigned uOffset, BYTE **ppbProfile) {
- // (re-)allocate profile buffer
- BYTE *pbProfile = *ppbProfile;
- pbProfile = (BYTE*)realloc(pbProfile, cbByteCount);
- if(!pbProfile) {
- return WMP_errOutOfMemory;
- }
- // read the profile
- if(WMP_errSuccess == pStream->SetPos(pStream, uOffset)) {
- if(WMP_errSuccess == pStream->Read(pStream, pbProfile, cbByteCount)) {
- *ppbProfile = pbProfile;
- return WMP_errSuccess;
- }
- }
- return WMP_errFileIO;
-}
-
-/**
-Convert a DPKPROPVARIANT to a FITAG, then store the tag as FIMD_EXIF_MAIN
-@see ReadDescriptiveMetadata
-*/
-static BOOL
-ReadPropVariant(WORD tag_id, const DPKPROPVARIANT & varSrc, FIBITMAP *dib) {
- DWORD dwSize;
-
- if(varSrc.vt == DPKVT_EMPTY) {
- return FALSE;
- }
-
- // get the tag key
- TagLib& s = TagLib::instance();
- const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL);
- if(!key) {
- return FALSE;
- }
-
- // create a tag
- FITAG *tag = FreeImage_CreateTag();
- if(tag) {
- // set tag ID
- FreeImage_SetTagID(tag, tag_id);
- // set tag type, count, length and value
- switch (varSrc.vt) {
- case DPKVT_LPSTR:
- FreeImage_SetTagType(tag, FIDT_ASCII);
- dwSize = (DWORD)strlen(varSrc.VT.pszVal) + 1;
- FreeImage_SetTagCount(tag, dwSize);
- FreeImage_SetTagLength(tag, dwSize);
- FreeImage_SetTagValue(tag, varSrc.VT.pszVal);
- break;
-
- case DPKVT_LPWSTR:
- FreeImage_SetTagType(tag, FIDT_UNDEFINED);
- dwSize = (DWORD)(sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1)); // +1 for NULL term
- FreeImage_SetTagCount(tag, dwSize);
- FreeImage_SetTagLength(tag, dwSize);
- FreeImage_SetTagValue(tag, varSrc.VT.pwszVal);
- break;
-
- case DPKVT_UI2:
- FreeImage_SetTagType(tag, FIDT_SHORT);
- FreeImage_SetTagCount(tag, 1);
- FreeImage_SetTagLength(tag, 2);
- FreeImage_SetTagValue(tag, &varSrc.VT.uiVal);
- break;
-
- case DPKVT_UI4:
- FreeImage_SetTagType(tag, FIDT_LONG);
- FreeImage_SetTagCount(tag, 1);
- FreeImage_SetTagLength(tag, 4);
- FreeImage_SetTagValue(tag, &varSrc.VT.ulVal);
- break;
-
- default:
- assert(FALSE); // This case is not handled
- break;
- }
- // get the tag desctiption
- const char *description = s.getTagDescription(TagLib::EXIF_MAIN, tag_id);
- FreeImage_SetTagDescription(tag, description);
-
- // store the tag
- FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, key, tag);
-
- FreeImage_DeleteTag(tag);
- }
- return TRUE;
-}
-
-/**
-Read JPEG-XR descriptive metadata and store as EXIF_MAIN metadata
-@see ReadPropVariant
-*/
-static ERR
-ReadDescriptiveMetadata(PKImageDecode *pID, FIBITMAP *dib) {
- // get Exif TIFF metadata
- const DESCRIPTIVEMETADATA *pDescMetadata = &pID->WMP.sDescMetadata;
- // convert metadata to FITAG and store into the EXIF_MAIN metadata model
- ReadPropVariant(WMP_tagImageDescription, pDescMetadata->pvarImageDescription, dib);
- ReadPropVariant(WMP_tagCameraMake, pDescMetadata->pvarCameraMake, dib);
- ReadPropVariant(WMP_tagCameraModel, pDescMetadata->pvarCameraModel, dib);
- ReadPropVariant(WMP_tagSoftware, pDescMetadata->pvarSoftware, dib);
- ReadPropVariant(WMP_tagDateTime, pDescMetadata->pvarDateTime, dib);
- ReadPropVariant(WMP_tagArtist, pDescMetadata->pvarArtist, dib);
- ReadPropVariant(WMP_tagCopyright, pDescMetadata->pvarCopyright, dib);
- ReadPropVariant(WMP_tagRatingStars, pDescMetadata->pvarRatingStars, dib);
- ReadPropVariant(WMP_tagRatingValue, pDescMetadata->pvarRatingValue, dib);
- ReadPropVariant(WMP_tagCaption, pDescMetadata->pvarCaption, dib);
- ReadPropVariant(WMP_tagDocumentName, pDescMetadata->pvarDocumentName, dib);
- ReadPropVariant(WMP_tagPageName, pDescMetadata->pvarPageName, dib);
- ReadPropVariant(WMP_tagPageNumber, pDescMetadata->pvarPageNumber, dib);
- ReadPropVariant(WMP_tagHostComputer, pDescMetadata->pvarHostComputer, dib);
- return WMP_errSuccess;
-}
-
-/**
-Read ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
-@see ReadProfile, ReadDescriptiveMetadata
-*/
-static ERR
-ReadMetadata(PKImageDecode *pID, FIBITMAP *dib) {
- ERR error_code = 0; // error code as returned by the interface
- size_t currentPos = 0; // current stream position
-
- WMPStream *pStream = pID->pStream;
- WmpDEMisc *wmiDEMisc = &pID->WMP.wmiDEMisc;
- BYTE *pbProfile = NULL;
-
- try {
- // save current position
- error_code = pStream->GetPos(pStream, &currentPos);
- JXR_CHECK(error_code);
-
- // ICC profile
- if(0 != wmiDEMisc->uColorProfileByteCount) {
- unsigned cbByteCount = wmiDEMisc->uColorProfileByteCount;
- unsigned uOffset = wmiDEMisc->uColorProfileOffset;
- error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
- JXR_CHECK(error_code);
- FreeImage_CreateICCProfile(dib, pbProfile, cbByteCount);
- }
-
- // XMP metadata
- if(0 != wmiDEMisc->uXMPMetadataByteCount) {
- unsigned cbByteCount = wmiDEMisc->uXMPMetadataByteCount;
- unsigned uOffset = wmiDEMisc->uXMPMetadataOffset;
- error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
- JXR_CHECK(error_code);
- // store the tag as XMP
- FITAG *tag = FreeImage_CreateTag();
- if(tag) {
- FreeImage_SetTagLength(tag, cbByteCount);
- FreeImage_SetTagCount(tag, cbByteCount);
- FreeImage_SetTagType(tag, FIDT_ASCII);
- FreeImage_SetTagValue(tag, pbProfile);
- FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
- FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
- FreeImage_DeleteTag(tag);
- }
- }
-
- // IPTC metadata
- if(0 != wmiDEMisc->uIPTCNAAMetadataByteCount) {
- unsigned cbByteCount = wmiDEMisc->uIPTCNAAMetadataByteCount;
- unsigned uOffset = wmiDEMisc->uIPTCNAAMetadataOffset;
- error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
- JXR_CHECK(error_code);
- // decode the IPTC profile
- read_iptc_profile(dib, pbProfile, cbByteCount);
- }
-
- // Exif metadata
- if(0 != wmiDEMisc->uEXIFMetadataByteCount) {
- unsigned cbByteCount = wmiDEMisc->uEXIFMetadataByteCount;
- unsigned uOffset = wmiDEMisc->uEXIFMetadataOffset;
- error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
- JXR_CHECK(error_code);
- // decode the Exif profile
- jpegxr_read_exif_profile(dib, pbProfile, cbByteCount, uOffset);
- }
-
- // Exif-GPS metadata
- if(0 != wmiDEMisc->uGPSInfoMetadataByteCount) {
- unsigned cbByteCount = wmiDEMisc->uGPSInfoMetadataByteCount;
- unsigned uOffset = wmiDEMisc->uGPSInfoMetadataOffset;
- error_code = ReadProfile(pStream, cbByteCount, uOffset, &pbProfile);
- JXR_CHECK(error_code);
- // decode the Exif-GPS profile
- jpegxr_read_exif_gps_profile(dib, pbProfile, cbByteCount, uOffset);
- }
-
- // free profile buffer
- free(pbProfile);
- // restore initial position
- error_code = pID->pStream->SetPos(pID->pStream, currentPos);
- JXR_CHECK(error_code);
-
- // as a LAST STEP, read descriptive metadata
- // these metadata overwrite possible identical Exif-TIFF metadata
- // that could have been read inside the Exif IFD
-
- return ReadDescriptiveMetadata(pID, dib);
-
- } catch(...) {
- // free profile buffer
- free(pbProfile);
- if(currentPos) {
- // restore initial position
- pStream->SetPos(pStream, currentPos);
- }
- return error_code;
- }
-}
-
-// ==========================================================
-// Metadata saving
-// ==========================================================
-
-/**
-Convert a FITAG (coming from FIMD_EXIF_MAIN) to a DPKPROPVARIANT.
-No allocation is needed here, the function just copy pointers when needed.
-@see WriteDescriptiveMetadata
-*/
-static BOOL
-WritePropVariant(FIBITMAP *dib, WORD tag_id, DPKPROPVARIANT & varDst) {
- FITAG *tag = NULL;
-
- TagLib& s = TagLib::instance();
-
- // clear output DPKPROPVARIANT
- varDst.vt = DPKVT_EMPTY;
-
- // given the tag id, get the tag key
- const char *key = s.getTagFieldName(TagLib::EXIF_MAIN, tag_id, NULL);
- // then, get the tag info
- if(!FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, key, &tag)) {
- return FALSE;
- }
-
- // set the tag value
- switch(FreeImage_GetTagType(tag)) {
- case FIDT_ASCII:
- varDst.vt = DPKVT_LPSTR;
- varDst.VT.pszVal = (char*)FreeImage_GetTagValue(tag);
- break;
- case FIDT_BYTE:
- case FIDT_UNDEFINED:
- varDst.vt = DPKVT_LPWSTR;
- varDst.VT.pwszVal = (U16*)FreeImage_GetTagValue(tag);
- break;
- case FIDT_SHORT:
- varDst.vt = DPKVT_UI2;
- varDst.VT.uiVal = *((U16*)FreeImage_GetTagValue(tag));
- break;
- case FIDT_LONG:
- varDst.vt = DPKVT_UI4;
- varDst.VT.ulVal = *((U32*)FreeImage_GetTagValue(tag));
- break;
- default:
- break;
- }
-
- return TRUE;
-}
-
-/**
-Write EXIF_MAIN metadata to JPEG-XR descriptive metadata
-@see WritePropVariant
-*/
-static ERR
-WriteDescriptiveMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
- ERR error_code = 0; // error code as returned by the interface
- DESCRIPTIVEMETADATA DescMetadata;
-
- // fill the DESCRIPTIVEMETADATA structure (use pointers to arrays when needed)
- WritePropVariant(dib, WMP_tagImageDescription, DescMetadata.pvarImageDescription);
- WritePropVariant(dib, WMP_tagCameraMake, DescMetadata.pvarCameraMake);
- WritePropVariant(dib, WMP_tagCameraModel, DescMetadata.pvarCameraModel);
- WritePropVariant(dib, WMP_tagSoftware, DescMetadata.pvarSoftware);
- WritePropVariant(dib, WMP_tagDateTime, DescMetadata.pvarDateTime);
- WritePropVariant(dib, WMP_tagArtist, DescMetadata.pvarArtist);
- WritePropVariant(dib, WMP_tagCopyright, DescMetadata.pvarCopyright);
- WritePropVariant(dib, WMP_tagRatingStars, DescMetadata.pvarRatingStars);
- WritePropVariant(dib, WMP_tagRatingValue, DescMetadata.pvarRatingValue);
- WritePropVariant(dib, WMP_tagCaption, DescMetadata.pvarCaption);
- WritePropVariant(dib, WMP_tagDocumentName, DescMetadata.pvarDocumentName);
- WritePropVariant(dib, WMP_tagPageName, DescMetadata.pvarPageName);
- WritePropVariant(dib, WMP_tagPageNumber, DescMetadata.pvarPageNumber);
- WritePropVariant(dib, WMP_tagHostComputer, DescMetadata.pvarHostComputer);
-
- // copy the structure to the encoder
- error_code = pIE->SetDescriptiveMetadata(pIE, &DescMetadata);
-
- // no need to free anything here
- return error_code;
-}
-
-/**
-Write ICC, XMP, Exif, Exif-GPS, IPTC, descriptive (i.e. Exif-TIFF) metadata
-*/
-static ERR
-WriteMetadata(PKImageEncode *pIE, FIBITMAP *dib) {
- ERR error_code = 0; // error code as returned by the interface
- BYTE *profile = NULL;
- unsigned profile_size = 0;
-
- try {
- // write ICC profile
- {
- FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
- if(iccProfile->data) {
- error_code = pIE->SetColorContext(pIE, (U8*)iccProfile->data, iccProfile->size);
- JXR_CHECK(error_code);
- }
- }
-
- // write descriptive metadata
- if(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib)) {
- error_code = WriteDescriptiveMetadata(pIE, dib);
- JXR_CHECK(error_code);
- }
-
- // write IPTC metadata
- if(FreeImage_GetMetadataCount(FIMD_IPTC, dib)) {
- // create a binary profile
- if(write_iptc_profile(dib, &profile, &profile_size)) {
- // write the profile
- error_code = PKImageEncode_SetIPTCNAAMetadata_WMP(pIE, profile, profile_size);
- JXR_CHECK(error_code);
- // release profile
- free(profile);
- profile = NULL;
- }
- }
-
- // write XMP metadata
- {
- FITAG *tag_xmp = NULL;
- if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag_xmp)) {
- error_code = PKImageEncode_SetXMPMetadata_WMP(pIE, (BYTE*)FreeImage_GetTagValue(tag_xmp), FreeImage_GetTagLength(tag_xmp));
- JXR_CHECK(error_code);
- }
- }
-
- // write Exif metadata
- {
- if(tiff_get_ifd_profile(dib, FIMD_EXIF_EXIF, &profile, &profile_size)) {
- error_code = PKImageEncode_SetEXIFMetadata_WMP(pIE, profile, profile_size);
- JXR_CHECK(error_code);
- // release profile
- free(profile);
- profile = NULL;
- }
- }
-
- // write Exif GPS metadata
- {
- if(tiff_get_ifd_profile(dib, FIMD_EXIF_GPS, &profile, &profile_size)) {
- error_code = PKImageEncode_SetGPSInfoMetadata_WMP(pIE, profile, profile_size);
- JXR_CHECK(error_code);
- // release profile
- free(profile);
- profile = NULL;
- }
- }
-
- return WMP_errSuccess;
-
- } catch(...) {
- free(profile);
- return error_code;
- }
-}
-
-
-
-// ==========================================================
-// Quantization tables (Y, U, V, YHP, UHP, VHP),
-// optimized for PSNR
-// ==========================================================
-
-static const int DPK_QPS_420[11][6] = { // for 8 bit only
- { 66, 65, 70, 72, 72, 77 },
- { 59, 58, 63, 64, 63, 68 },
- { 52, 51, 57, 56, 56, 61 },
- { 48, 48, 54, 51, 50, 55 },
- { 43, 44, 48, 46, 46, 49 },
- { 37, 37, 42, 38, 38, 43 },
- { 26, 28, 31, 27, 28, 31 },
- { 16, 17, 22, 16, 17, 21 },
- { 10, 11, 13, 10, 10, 13 },
- { 5, 5, 6, 5, 5, 6 },
- { 2, 2, 3, 2, 2, 2 }
-};
-
-static const int DPK_QPS_8[12][6] = {
- { 67, 79, 86, 72, 90, 98 },
- { 59, 74, 80, 64, 83, 89 },
- { 53, 68, 75, 57, 76, 83 },
- { 49, 64, 71, 53, 70, 77 },
- { 45, 60, 67, 48, 67, 74 },
- { 40, 56, 62, 42, 59, 66 },
- { 33, 49, 55, 35, 51, 58 },
- { 27, 44, 49, 28, 45, 50 },
- { 20, 36, 42, 20, 38, 44 },
- { 13, 27, 34, 13, 28, 34 },
- { 7, 17, 21, 8, 17, 21 }, // Photoshop 100%
- { 2, 5, 6, 2, 5, 6 }
-};
-
-static const int DPK_QPS_16[11][6] = {
- { 197, 203, 210, 202, 207, 213 },
- { 174, 188, 193, 180, 189, 196 },
- { 152, 167, 173, 156, 169, 174 },
- { 135, 152, 157, 137, 153, 158 },
- { 119, 137, 141, 119, 138, 142 },
- { 102, 120, 125, 100, 120, 124 },
- { 82, 98, 104, 79, 98, 103 },
- { 60, 76, 81, 58, 76, 81 },
- { 39, 52, 58, 36, 52, 58 },
- { 16, 27, 33, 14, 27, 33 },
- { 5, 8, 9, 4, 7, 8 }
-};
-
-static const int DPK_QPS_16f[11][6] = {
- { 148, 177, 171, 165, 187, 191 },
- { 133, 155, 153, 147, 172, 181 },
- { 114, 133, 138, 130, 157, 167 },
- { 97, 118, 120, 109, 137, 144 },
- { 76, 98, 103, 85, 115, 121 },
- { 63, 86, 91, 62, 96, 99 },
- { 46, 68, 71, 43, 73, 75 },
- { 29, 48, 52, 27, 48, 51 },
- { 16, 30, 35, 14, 29, 34 },
- { 8, 14, 17, 7, 13, 17 },
- { 3, 5, 7, 3, 5, 6 }
-};
-
-static const int DPK_QPS_32f[11][6] = {
- { 194, 206, 209, 204, 211, 217 },
- { 175, 187, 196, 186, 193, 205 },
- { 157, 170, 177, 167, 180, 190 },
- { 133, 152, 156, 144, 163, 168 },
- { 116, 138, 142, 117, 143, 148 },
- { 98, 120, 123, 96, 123, 126 },
- { 80, 99, 102, 78, 99, 102 },
- { 65, 79, 84, 63, 79, 84 },
- { 48, 61, 67, 45, 60, 66 },
- { 27, 41, 46, 24, 40, 45 },
- { 3, 22, 24, 2, 21, 22 }
-};
-
-// ==========================================================
-// Plugin Implementation
-// ==========================================================
-
-static const char * DLL_CALLCONV
-Format() {
- return "JPEG-XR";
-}
-
-static const char * DLL_CALLCONV
-Description() {
- return "JPEG XR image format";
-}
-
-static const char * DLL_CALLCONV
-Extension() {
- return "jxr,wdp,hdp";
-}
-
-static const char * DLL_CALLCONV
-RegExpr() {
- return NULL;
-}
-
-static const char * DLL_CALLCONV
-MimeType() {
- return "image/vnd.ms-photo";
-}
-
-static BOOL DLL_CALLCONV
-Validate(FreeImageIO *io, fi_handle handle) {
- BYTE jxr_signature[3] = { 0x49, 0x49, 0xBC };
- BYTE signature[3] = { 0, 0, 0 };
-
- io->read_proc(&signature, 1, 3, handle);
-
- return (memcmp(jxr_signature, signature, 3) == 0);
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportDepth(int depth) {
- return (
- (depth == 1) ||
- (depth == 8) ||
- (depth == 16) ||
- (depth == 24) ||
- (depth == 32)
- );
-}
-
-static BOOL DLL_CALLCONV
-SupportsExportType(FREE_IMAGE_TYPE type) {
- return (
- (type == FIT_BITMAP) ||
- (type == FIT_UINT16) ||
- (type == FIT_RGB16) ||
- (type == FIT_RGBA16) ||
- (type == FIT_FLOAT) ||
- (type == FIT_RGBF) ||
- (type == FIT_RGBAF)
- );
-}
-
-static BOOL DLL_CALLCONV
-SupportsICCProfiles() {
- return TRUE;
-}
-
-static BOOL DLL_CALLCONV
-SupportsNoPixels() {
- return TRUE;
-}
-
-// ==========================================================
-// Open & Close
-// ==========================================================
-
-static void * DLL_CALLCONV
-Open(FreeImageIO *io, fi_handle handle, BOOL read) {
- WMPStream *pStream = NULL; // stream interface
- if(io && handle) {
- // allocate the FreeImageIO stream wrapper
- FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)malloc(sizeof(FreeImageJXRIO));
- if(jxr_io) {
- jxr_io->io = io;
- jxr_io->handle = handle;
- // create a JXR stream wrapper
- if(_jxr_io_Create(&pStream, jxr_io) != WMP_errSuccess) {
- free(jxr_io);
- return NULL;
- }
- }
- }
- return pStream;
-}
-
-static void DLL_CALLCONV
-Close(FreeImageIO *io, fi_handle handle, void *data) {
- WMPStream *pStream = (WMPStream*)data;
- if(pStream) {
- // free the FreeImageIO stream wrapper
- FreeImageJXRIO *jxr_io = (FreeImageJXRIO*)pStream->state.pvObj;
- free(jxr_io);
- // free the JXR stream wrapper
- pStream->fMem = TRUE;
- _jxr_io_Close(&pStream);
- }
-}
-
-// ==========================================================
-// Load
-// ==========================================================
-
-/**
-Set decoder parameters
-@param pDecoder Decoder handle
-@param flags FreeImage load flags
-*/
-static void
-SetDecoderParameters(PKImageDecode *pDecoder, int flags) {
- // load image & alpha for formats with alpha
- pDecoder->WMP.wmiSCP.uAlphaMode = 2;
- // more options to come ...
-}
-
-/**
-Copy or convert & copy decoded pixels into the dib
-@param pDecoder Decoder handle
-@param out_guid_format Target guid format
-@param dib Output dib
-@param width Image width
-@param height Image height
-@return Returns 0 if successful, returns ERR otherwise
-*/
-static ERR
-CopyPixels(PKImageDecode *pDecoder, PKPixelFormatGUID out_guid_format, FIBITMAP *dib, int width, int height) {
- PKFormatConverter *pConverter = NULL; // pixel format converter
- ERR error_code = 0; // error code as returned by the interface
- BYTE *pb = NULL; // local buffer used for pixel format conversion
-
- // image dimensions
- const PKRect rect = {0, 0, width, height};
-
- try {
- // get input file pixel format ...
- PKPixelFormatGUID in_guid_format;
- error_code = pDecoder->GetPixelFormat(pDecoder, &in_guid_format);
- JXR_CHECK(error_code);
-
- // is a format conversion needed ?
-
- if(IsEqualGUID(out_guid_format, in_guid_format)) {
- // no conversion, load bytes "as is" ...
-
- // get a pointer to dst pixel data
- BYTE *dib_bits = FreeImage_GetBits(dib);
-
- // get dst pitch (count of BYTE for stride)
- const unsigned cbStride = FreeImage_GetPitch(dib);
-
- // decode and copy bits to dst array
- error_code = pDecoder->Copy(pDecoder, &rect, dib_bits, cbStride);
- JXR_CHECK(error_code);
- }
- else {
- // we need to use the conversion API ...
-
- // allocate the pixel format converter
- error_code = PKCodecFactory_CreateFormatConverter(&pConverter);
- JXR_CHECK(error_code);
-
- // set the conversion function
- error_code = pConverter->Initialize(pConverter, pDecoder, NULL, out_guid_format);
- JXR_CHECK(error_code);
-
- // get the maximum stride
- unsigned cbStride = 0;
- {
- PKPixelInfo pPIFrom;
- PKPixelInfo pPITo;
-
- pPIFrom.pGUIDPixFmt = &in_guid_format;
- error_code = PixelFormatLookup(&pPIFrom, LOOKUP_FORWARD);
- JXR_CHECK(error_code);
-
- pPITo.pGUIDPixFmt = &out_guid_format;
- error_code = PixelFormatLookup(&pPITo, LOOKUP_FORWARD);
- JXR_CHECK(error_code);
-
- unsigned cbStrideFrom = ((pPIFrom.cbitUnit + 7) >> 3) * width;
- unsigned cbStrideTo = ((pPITo.cbitUnit + 7) >> 3) * width;
- cbStride = MAX(cbStrideFrom, cbStrideTo);
- }
-
- // allocate a local decoder / encoder buffer
- error_code = PKAllocAligned((void **) &pb, cbStride * height, 128);
- JXR_CHECK(error_code);
-
- // copy / convert pixels
- error_code = pConverter->Copy(pConverter, &rect, pb, cbStride);
- JXR_CHECK(error_code);
-
- // now copy pixels into the dib
- const size_t line_size = FreeImage_GetLine(dib);
- for(int y = 0; y < height; y++) {
- BYTE *src_bits = (BYTE*)(pb + y * cbStride);
- BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, y);
- memcpy(dst_bits, src_bits, line_size);
- }
-
- // free the local buffer
- PKFreeAligned((void **) &pb);
-
- // free the pixel format converter
- PKFormatConverter_Release(&pConverter);
- }
-
- // FreeImage DIB are upside-down relative to usual graphic conventions
- FreeImage_FlipVertical(dib);
-
- // post-processing ...
- // -------------------
-
- // swap RGB as needed
-
-#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
- if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppRGB) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppRGB)) {
- SwapRedBlue32(dib);
- }
-#elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
- if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppBGR) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppBGR)) {
- SwapRedBlue32(dib);
- }
-#endif
-
- return WMP_errSuccess;
-
- } catch(...) {
- // free the local buffer
- PKFreeAligned((void **) &pb);
- // free the pixel format converter
- PKFormatConverter_Release(&pConverter);
-
- return error_code;
- }
-}
-
-// --------------------------------------------------------------------------
-
-static FIBITMAP * DLL_CALLCONV
-Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
- PKImageDecode *pDecoder = NULL; // decoder interface
- ERR error_code = 0; // error code as returned by the interface
- PKPixelFormatGUID guid_format; // loaded pixel format (== input file pixel format if no conversion needed)
-
- FREE_IMAGE_TYPE image_type = FIT_UNKNOWN; // input image type
- unsigned bpp = 0; // input image bit depth
- FIBITMAP *dib = NULL;
-
- // get the I/O stream wrapper
- WMPStream *pDecodeStream = (WMPStream*)data;
-
- if(!handle || !pDecodeStream) {
- return NULL;
- }
-
- BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
-
- try {
- int width, height; // image dimensions (in pixels)
-
- // create a JXR decoder interface and initialize function pointers with *_WMP functions
- error_code = PKImageDecode_Create_WMP(&pDecoder);
- JXR_CHECK(error_code);
-
- // attach the stream to the decoder ...
- // ... then read the image container and the metadata
- error_code = pDecoder->Initialize(pDecoder, pDecodeStream);
- JXR_CHECK(error_code);
-
- // set decoder parameters
- SetDecoderParameters(pDecoder, flags);
-
- // get dst image format specifications
- unsigned red_mask = 0, green_mask = 0, blue_mask = 0;
- error_code = GetInputPixelFormat(pDecoder, &guid_format, &image_type, &bpp, &red_mask, &green_mask, &blue_mask);
- JXR_CHECK(error_code);
-
- // get image dimensions
- pDecoder->GetSize(pDecoder, &width, &height);
-
- // allocate dst image
- {
- dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, bpp, red_mask, green_mask, blue_mask);
- if(!dib) {
- throw FI_MSG_ERROR_DIB_MEMORY;
- }
- if(FreeImage_GetBPP(dib) == 1) {
- // BD_1 - build a FIC_MINISBLACK palette
- RGBQUAD *pal = FreeImage_GetPalette(dib);
- pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
- pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
- }
- }
-
- // get image resolution
- {
- float resX, resY; // image resolution (in dots per inch)
- // convert from English units, i.e. dots per inch to universal units, i.e. dots per meter
- pDecoder->GetResolution(pDecoder, &resX, &resY);
- FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX / 0.0254F + 0.5F));
- FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY / 0.0254F + 0.5F));
- }
-
- // get metadata & ICC profile
- error_code = ReadMetadata(pDecoder, dib);
- JXR_CHECK(error_code);
-
- if(header_only) {
- // header only mode ...
-
- // free the decoder
- pDecoder->Release(&pDecoder);
- assert(pDecoder == NULL);
-
- return dib;
- }
-
- // copy pixels into the dib, perform pixel conversion if needed
- error_code = CopyPixels(pDecoder, guid_format, dib, width, height);
- JXR_CHECK(error_code);
-
- // free the decoder
- pDecoder->Release(&pDecoder);
- assert(pDecoder == NULL);
-
- return dib;
-
- } catch (const char *message) {
- // unload the dib
- FreeImage_Unload(dib);
- // free the decoder
- pDecoder->Release(&pDecoder);
-
- if(NULL != message) {
- FreeImage_OutputMessageProc(s_format_id, message);
- }
- }
-
- return NULL;
-}
-
-// ==========================================================
-// Save
-// ==========================================================
-
-/**
-Configure compression parameters
-
-ImageQuality Q (BD==1) Q (BD==8) Q (BD==16) Q (BD==32F) Subsample Overlap
-[0.0, 0.4] 8-IQ*5 (see table) (see table) (see table) 4:4:4 2
-(0.4, 0.8) 8-IQ*5 (see table) (see table) (see table) 4:4:4 1
-[0.8, 1.0) 8-IQ*5 (see table) (see table) (see table) 4:4:4 1
-[1.0, 1.0] 1 1 1 1 4:4:4 0
-
-@param wmiSCP Encoder parameters
-@param pixelInfo Image specifications
-@param fltImageQuality Image output quality in [0..1), 1 means lossless
-*/
-static void
-SetCompression(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, float fltImageQuality) {
- if(fltImageQuality < 1.0F) {
- // overlap
- if(fltImageQuality >= 0.5F) {
- wmiSCP->olOverlap = OL_ONE;
- } else {
- wmiSCP->olOverlap = OL_TWO;
- }
- // chroma sub-sampling
- if(fltImageQuality >= 0.5F || pixelInfo->uBitsPerSample > 8) {
- wmiSCP->cfColorFormat = YUV_444;
- } else {
- wmiSCP->cfColorFormat = YUV_420;
- }
-
- // bit depth
- if(pixelInfo->bdBitDepth == BD_1) {
- wmiSCP->uiDefaultQPIndex = (U8)(8 - 5.0F * fltImageQuality + 0.5F);
- }
- else {
- // remap [0.8, 0.866, 0.933, 1.0] to [0.8, 0.9, 1.0, 1.1]
- // to use 8-bit DPK QP table (0.933 == Photoshop JPEG 100)
- if(fltImageQuality > 0.8F && pixelInfo->bdBitDepth == BD_8 && wmiSCP->cfColorFormat != YUV_420 && wmiSCP->cfColorFormat != YUV_422) {
- fltImageQuality = 0.8F + (fltImageQuality - 0.8F) * 1.5F;
- }
-
- const int qi = (int) (10.0F * fltImageQuality);
- const float qf = 10.0F * fltImageQuality - (float)qi;
-
- const int *pQPs =
- (wmiSCP->cfColorFormat == YUV_420 || wmiSCP->cfColorFormat == YUV_422) ?
- DPK_QPS_420[qi] :
- (pixelInfo->bdBitDepth == BD_8 ? DPK_QPS_8[qi] :
- (pixelInfo->bdBitDepth == BD_16 ? DPK_QPS_16[qi] :
- (pixelInfo->bdBitDepth == BD_16F ? DPK_QPS_16f[qi] :
- DPK_QPS_32f[qi])));
-
- wmiSCP->uiDefaultQPIndex = (U8) (0.5F + (float) pQPs[0] * (1.0F - qf) + (float) (pQPs + 6)[0] * qf);
- wmiSCP->uiDefaultQPIndexU = (U8) (0.5F + (float) pQPs[1] * (1.0F - qf) + (float) (pQPs + 6)[1] * qf);
- wmiSCP->uiDefaultQPIndexV = (U8) (0.5F + (float) pQPs[2] * (1.0F - qf) + (float) (pQPs + 6)[2] * qf);
- wmiSCP->uiDefaultQPIndexYHP = (U8) (0.5F + (float) pQPs[3] * (1.0F - qf) + (float) (pQPs + 6)[3] * qf);
- wmiSCP->uiDefaultQPIndexUHP = (U8) (0.5F + (float) pQPs[4] * (1.0F - qf) + (float) (pQPs + 6)[4] * qf);
- wmiSCP->uiDefaultQPIndexVHP = (U8) (0.5F + (float) pQPs[5] * (1.0F - qf) + (float) (pQPs + 6)[5] * qf);
- }
- } // fltImageQuality < 1.0F
- else {
- // lossless mode
- wmiSCP->uiDefaultQPIndex = 1;
- }
-}
-
-/**
-Set encoder parameters
-@param wmiSCP Encoder parameters
-@param pixelInfo Image specifications
-@param flags FreeImage save flags
-@param bHasAlpha TRUE if an alpha layer is present
-*/
-static void
-SetEncoderParameters(CWMIStrCodecParam *wmiSCP, const PKPixelInfo *pixelInfo, int flags, BOOL bHasAlpha) {
- float fltImageQuality = 1.0F;
-
- // all values have been set to zero by the API
- // update default values for some attributes
- wmiSCP->cfColorFormat = YUV_444; // color format
- wmiSCP->bdBitDepth = BD_LONG; // internal bit depth
- wmiSCP->bfBitstreamFormat = SPATIAL; // compressed image data in spatial order
- wmiSCP->bProgressiveMode = FALSE; // sequential mode
- wmiSCP->olOverlap = OL_ONE; // single level overlap processing
- wmiSCP->cNumOfSliceMinus1H = 0; // # of horizontal slices
- wmiSCP->cNumOfSliceMinus1V = 0; // # of vertical slices
- wmiSCP->sbSubband = SB_ALL; // keep all subbands
- wmiSCP->uAlphaMode = 0; // 0:no alpha 1: alpha only else: something + alpha
- wmiSCP->uiDefaultQPIndex = 1; // quantization for grey or rgb layer(s), 1: lossless
- wmiSCP->uiDefaultQPIndexAlpha = 1; // quantization for alpha layer, 1: lossless
-
- // process the flags
- // -----------------
-
- // progressive mode
- if((flags & JXR_PROGRESSIVE) == JXR_PROGRESSIVE) {
- // turn on progressive mode (instead of sequential mode)
- wmiSCP->bProgressiveMode = TRUE;
- }
-
- // quality in [0.01 - 1.0), 1.0 means lossless - default is 0.80
- int quality = flags & 0x7F;
- if(quality == 0) {
- // defaut to 0.80
- fltImageQuality = 0.8F;
- } else if((flags & JXR_LOSSLESS) == JXR_LOSSLESS) {
- fltImageQuality = 1.0F;
- } else {
- quality = (quality >= 100) ? 100 : quality;
- fltImageQuality = quality / 100.0F;
- }
- SetCompression(wmiSCP, pixelInfo, fltImageQuality);
-
- // alpha compression
- if(bHasAlpha) {
- wmiSCP->uAlphaMode = 2; // encode with a planar alpha channel
- }
-}
-
-// --------------------------------------------------------------------------
-
-static BOOL DLL_CALLCONV
-Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
- BOOL bIsFlipped = FALSE; // FreeImage DIB are upside-down relative to usual graphic conventions
- PKPixelFormatGUID guid_format; // image format
- PKPixelInfo pixelInfo; // image specifications
- BOOL bHasAlpha = FALSE; // is alpha layer present ?
-
- PKImageEncode *pEncoder = NULL; // encoder interface
- ERR error_code = 0; // error code as returned by the interface
-
- // get the I/O stream wrapper
- WMPStream *pEncodeStream = (WMPStream*)data;
-
- if(!dib || !handle || !pEncodeStream) {
- return FALSE;
- }
-
- try {
- // get image dimensions
- unsigned width = FreeImage_GetWidth(dib);
- unsigned height = FreeImage_GetHeight(dib);
-
- // check JPEG-XR limits
- if((width < MB_WIDTH_PIXEL) || (height < MB_HEIGHT_PIXEL)) {
- FreeImage_OutputMessageProc(s_format_id, "Unsupported image size: width x height = %d x %d", width, height);
- throw (const char*)NULL;
- }
-
- // get output pixel format
- error_code = GetOutputPixelFormat(dib, &guid_format, &bHasAlpha);
- JXR_CHECK(error_code);
- pixelInfo.pGUIDPixFmt = &guid_format;
- error_code = PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD);
- JXR_CHECK(error_code);
-
- // create a JXR encoder interface and initialize function pointers with *_WMP functions
- error_code = PKImageEncode_Create_WMP(&pEncoder);
- JXR_CHECK(error_code);
-
- // attach the stream to the encoder and set all encoder parameters to zero ...
- error_code = pEncoder->Initialize(pEncoder, pEncodeStream, &pEncoder->WMP.wmiSCP, sizeof(CWMIStrCodecParam));
- JXR_CHECK(error_code);
-
- // ... then configure the encoder
- SetEncoderParameters(&pEncoder->WMP.wmiSCP, &pixelInfo, flags, bHasAlpha);
-
- // set pixel format
- pEncoder->SetPixelFormat(pEncoder, guid_format);
-
- // set image size
- pEncoder->SetSize(pEncoder, width, height);
-
- // set resolution (convert from universal units to English units)
- float resX = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterX(dib));
- float resY = (float)(unsigned)(0.5F + 0.0254F * FreeImage_GetDotsPerMeterY(dib));
- pEncoder->SetResolution(pEncoder, resX, resY);
-
- // set metadata
- WriteMetadata(pEncoder, dib);
-
- // write metadata & pixels
- // -----------------------
-
- // dib coordinates are upside-down relative to usual conventions
- bIsFlipped = FreeImage_FlipVertical(dib);
-
- // get a pointer to dst pixel data
- BYTE *dib_bits = FreeImage_GetBits(dib);
-
- // get dst pitch (count of BYTE for stride)
- const unsigned cbStride = FreeImage_GetPitch(dib);
-
- // write metadata + pixels on output
- error_code = pEncoder->WritePixels(pEncoder, height, dib_bits, cbStride);
- JXR_CHECK(error_code);
-
- // recover dib coordinates
- FreeImage_FlipVertical(dib);
-
- // free the encoder
- pEncoder->Release(&pEncoder);
- assert(pEncoder == NULL);
-
- return TRUE;
-
- } catch (const char *message) {
- if(bIsFlipped) {
- // recover dib coordinates
- FreeImage_FlipVertical(dib);
- }
- if(pEncoder) {
- // free the encoder
- pEncoder->Release(&pEncoder);
- assert(pEncoder == NULL);
- }
- if(NULL != message) {
- FreeImage_OutputMessageProc(s_format_id, message);
- }
- }
-
- return FALSE;
-}
-
-// ==========================================================
-// Init
-// ==========================================================
-
-void DLL_CALLCONV
-InitJXR(Plugin *plugin, int format_id) {
- s_format_id = format_id;
-
- plugin->format_proc = Format;
- plugin->description_proc = Description;
- plugin->extension_proc = Extension;
- plugin->regexpr_proc = RegExpr;
- plugin->open_proc = Open;
- plugin->close_proc = Close;
- plugin->pagecount_proc = NULL;
- plugin->pagecapability_proc = NULL;
- plugin->load_proc = Load;
- plugin->save_proc = Save;
- plugin->validate_proc = Validate;
- plugin->mime_proc = MimeType;
- plugin->supports_export_bpp_proc = SupportsExportDepth;
- plugin->supports_export_type_proc = SupportsExportType;
- plugin->supports_icc_profiles_proc = SupportsICCProfiles;
- plugin->supports_no_pixels_proc = SupportsNoPixels;
-}
-