void ImageDecoder::initialize() { // set default color format pixelInfo.pGUIDPixFmt = &pDecoder->guidPixFormat; Call(PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD)); Call(PixelFormatLookup(&pixelInfo, LOOKUP_BACKWARD_TIF)); // color transcoding if (IsEqualGUID(*pixelInfo.pGUIDPixFmt, GUID_PKPixelFormat8bppGray) || IsEqualGUID(*pixelInfo.pGUIDPixFmt, GUID_PKPixelFormat16bppGray)) { // ** => Y transcoding pDecoder->guidPixFormat = *pixelInfo.pGUIDPixFmt; pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY; } else if (IsEqualGUID(*pixelInfo.pGUIDPixFmt, GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK) { // CMYK = > RGB pDecoder->WMP.wmiI.cfColorFormat = CF_RGB; pDecoder->guidPixFormat = *pixelInfo.pGUIDPixFmt; pDecoder->WMP.wmiI.bRGB = 1; // RGB } PixelFormatLookup(&pixelInfo, LOOKUP_FORWARD); // alpha if (!!(pixelInfo.grBit & PK_pixfmtHasAlpha)) { pDecoder->WMP.wmiSCP.uAlphaMode = 2; // default is image & alpha for formats with alpha } else { pDecoder->WMP.wmiSCP.uAlphaMode = 0; // otherwise, 0 } // copy properties from PixelInfo to Decoder pDecoder->WMP.wmiI.cfColorFormat = pixelInfo.cfColorFormat; pDecoder->WMP.wmiI.bdBitDepth = pixelInfo.bdBitDepth; pDecoder->WMP.wmiI.cBitsPerUnit = pixelInfo.cbitUnit; // skip thumbnails pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth; pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight; pDecoder->WMP.wmiI.bSkipFlexbits = FALSE; // no region decoding pDecoder->WMP.wmiI.cROILeftX = 0; pDecoder->WMP.wmiI.cROITopY = 0; pDecoder->WMP.wmiI.cROIWidth = pDecoder->WMP.wmiI.cWidth; pDecoder->WMP.wmiI.cROIHeight = pDecoder->WMP.wmiI.cHeight; // other default values pDecoder->WMP.wmiSCP.bfBitstreamFormat = SPATIAL; pDecoder->WMP.wmiSCP.sbSubband = SB_ALL; pDecoder->WMP.bIgnoreOverlap = FALSE; pDecoder->WMP.wmiI.oOrientation = O_NONE; pDecoder->WMP.wmiI.cPostProcStrength = 0; pDecoder->WMP.wmiSCP.bVerbose = FALSE; // finished initializing return; Cleanup: throw FormatError("ERROR: Unable to initialize decoder."); }
ERR PKImageEncode_WritePixels_WMP( PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride) { ERR err = WMP_errSuccess; U32 i = 0; PKPixelInfo PI; PI.pGUIDPixFmt = &pIE->guidPixFormat; PixelFormatLookup(&PI, LOOKUP_FORWARD); pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); if (!pIE->fHeaderDone) { // write metadata Call(WriteContainerPre(pIE)); pIE->fHeaderDone = !FALSE; } /* if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){ pIE->WMP.wmiSCP_Alpha = pIE->WMP.wmiSCP; } */ PKImageEncode_EncodeContent(pIE, PI, cLine, pbPixels, cbStride); if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){//planar alpha PKImageEncode_EncodeAlpha(pIE, PI, cLine, pbPixels, cbStride); } Cleanup: return err; }
/** 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; } }
//================================================================ // main function //================================================================ int #ifndef __ANSI__ __cdecl #endif // __ANSI__ main(int argc, char* argv[]) { ERR err = WMP_errSuccess; PKFactory* pFactory = NULL; PKCodecFactory* pCodecFactory = NULL; PKImageDecode* pDecoder = NULL; WMPDECAPPARGS args = {0}; char* pExt = NULL; U32 cFrame = 0; U32 i = 0; PKPixelInfo PI; // static size_t cChannels[CFT_MAX] = {1, 3, 3, 3, 4, 4, -1, 3, 3, -1}; //================================ // parse command line parameters if (1 == argc) { WmpDecAppUsage(argv[0]); return 0; } Call(WmpDecAppParseArgs(argc, argv, &args)); if (args.bVerbose) { WmpDecAppShowArgs(&args); } //================================ pExt = strrchr(args.szOutputFile, '.'); FailIf(NULL == pExt, WMP_errUnsupportedFormat); //================================ Call(PKCreateFactory(&pFactory, PK_SDK_VERSION)); Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); Call(pCodecFactory->CreateDecoderFromFile(args.szInputFile, &pDecoder)); //==== set default color format if(IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormatDontCare)) { // take deocder color format and try to look up better one // (e.g. 32bppBGR -> 24bppBGR etc.) PKPixelInfo newPI; newPI.pGUIDPixFmt = PI.pGUIDPixFmt = &pDecoder->guidPixFormat; Call(PixelFormatLookup(&newPI, LOOKUP_FORWARD)); Call(PixelFormatLookup(&newPI, LOOKUP_BACKWARD_TIF)); args.guidPixFormat = *newPI.pGUIDPixFmt; } else PI.pGUIDPixFmt = &args.guidPixFormat; // pDecoder->WMP.wmiI.bRGB = args.bFlagRGB_BGR; // == color transcoding, if(IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat16bppGray)){ // ** => Y transcoding pDecoder->guidPixFormat = args.guidPixFormat; pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY; } else if(IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK){ // CMYK = > RGB pDecoder->WMP.wmiI.cfColorFormat = CF_RGB; pDecoder->guidPixFormat = args.guidPixFormat; pDecoder->WMP.wmiI.bRGB = 1; //RGB } PixelFormatLookup(&PI, LOOKUP_FORWARD); if(255 == args.uAlphaMode)//user didn't set { if(!!(PI.grBit & PK_pixfmtHasAlpha)) args.uAlphaMode = 2;//default is image & alpha for formats with alpha else args.uAlphaMode = 0;//otherwise, 0 } pDecoder->WMP.wmiSCP.bfBitstreamFormat = args.bfBitstreamFormat; pDecoder->WMP.wmiSCP.uAlphaMode = args.uAlphaMode; pDecoder->WMP.wmiSCP.sbSubband = args.sbSubband; pDecoder->WMP.bIgnoreOverlap = args.bIgnoreOverlap; pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat; pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth; pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; //==== Validate thumbnail decode parameters ===== pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth; pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight; pDecoder->WMP.wmiI.bSkipFlexbits = FALSE; if(args.tThumbnailFactor > 0 && args.tThumbnailFactor != SKIPFLEXBITS){ size_t tSize = ((size_t)1 << args.tThumbnailFactor); pDecoder->WMP.wmiI.cThumbnailWidth = (pDecoder->WMP.wmiI.cWidth + tSize - 1) / tSize; pDecoder->WMP.wmiI.cThumbnailHeight = (pDecoder->WMP.wmiI.cHeight + tSize - 1) / tSize; if(pDecoder->WMP.wmiI.cfColorFormat == YUV_420 || pDecoder->WMP.wmiI.cfColorFormat == YUV_422){ // unsupported thumbnail format pDecoder->WMP.wmiI.cfColorFormat = YUV_444; } } else if (args.tThumbnailFactor == SKIPFLEXBITS) { pDecoder->WMP.wmiI.bSkipFlexbits = TRUE; } if(args.rWidth == 0 || args.rHeight == 0){ // no region decode args.rLeftX = args.rTopY = 0; args.rWidth = pDecoder->WMP.wmiI.cThumbnailWidth; args.rHeight = pDecoder->WMP.wmiI.cThumbnailHeight; } pDecoder->WMP.wmiI.cROILeftX = args.rLeftX; pDecoder->WMP.wmiI.cROITopY = args.rTopY; pDecoder->WMP.wmiI.cROIWidth = args.rWidth; pDecoder->WMP.wmiI.cROIHeight = args.rHeight; pDecoder->WMP.wmiI.oOrientation = args.oOrientation; pDecoder->WMP.wmiI.cPostProcStrength = args.cPostProcStrength; pDecoder->WMP.wmiSCP.bVerbose = args.bVerbose; Call(pDecoder->GetFrameCount(pDecoder, &cFrame)); //================================ for (i = 0; ; ++i) { struct WMPStream* pEncodeStream = NULL; PKImageEncode* pEncoder = NULL; PKFormatConverter* pConverter = NULL; Float rX = 0.0, rY = 0.0; PKRect rect = {0, 0, 0, 0}; //================================ Call(pCodecFactory->CreateFormatConverter(&pConverter)); Call(pConverter->Initialize(pConverter, pDecoder, pExt, args.guidPixFormat)); //================================ Call(pFactory->CreateStreamFromFilename(&pEncodeStream, args.szOutputFile, "wb")); Call(WmpDecAppCreateEncoderFromExt(pCodecFactory, pExt, &pEncoder)); if(pEncoder->bWMP) Call(pEncoder->Initialize(pEncoder, pEncodeStream, &args.wmiSCP, sizeof(args.wmiSCP))); else Call(pEncoder->Initialize(pEncoder, pEncodeStream, NULL, 0)); //================================ Call(pEncoder->SetPixelFormat(pEncoder, args.guidPixFormat)); pEncoder->WMP.wmiSCP.bBlackWhite = pDecoder->WMP.wmiSCP.bBlackWhite; //Call(pDecoder->GetSize(pDecoder, &rect.Width, &rect.Height)); rect.Width = (I32)(pDecoder->WMP.wmiI.cROIWidth); rect.Height = (I32)(pDecoder->WMP.wmiI.cROIHeight); if(args.oOrientation > O_FLIPVH){ // allocate memory for rotated image! I32 bah = rect.Width; rect.Width = rect.Height; rect.Height = bah; } Call(pEncoder->SetSize(pEncoder, rect.Width, rect.Height)); Call(pDecoder->GetResolution(pDecoder, &rX, &rY)); if(args.oOrientation > O_FLIPVH) Call(pEncoder->SetResolution(pEncoder, rY, rX)); else Call(pEncoder->SetResolution(pEncoder, rX, rY)); if(pEncoder->bWMP && args.tThumbnailFactor > 0){ printf("-T can not be used for compressed domain operation!\n"); return 0; } //================================ pEncoder->WriteSource = PKImageEncode_Transcode; Call(pEncoder->WriteSource(pEncoder, pConverter, &rect)); //================================ // Call(pEncoder->Terminate(pEncoder)); pEncoder->Release(&pEncoder); // multi-frame support NYI if (i + 1 == cFrame) { break; } Call(pDecoder->SelectFrame(pDecoder, i + 1)); } pDecoder->Release(&pDecoder); Cleanup: if (WMP_errUnsupportedFormat == err) { printf("*** ERROR: Unsupported format in JPEG XR ***\n"); } else if (WMP_errSuccess != err) { WmpDecAppUsage(argv[0]); } return (int)err; }
//================================================================ // PKImageDecode_WMP //================================================================ ERR ParsePFDEntry( PKImageDecode* pID, U16 uTag, U16 uType, U32 uCount, U32 uValue) { ERR err = WMP_errSuccess; PKPixelInfo PI; struct WMPStream* pWS = pID->pStream; size_t offPos = 0; union uf{ U32 uVal; Float fVal; }ufValue = {0}; //================================ switch (uTag) { case WMP_tagPixelFormat: { unsigned char *pGuid = (unsigned char *) &pID->guidPixFormat; /** following code is endian-agnostic **/ Call(GetULong(pWS, uValue, (unsigned long *)pGuid)); Call(GetUShort(pWS, uValue + 4, (unsigned short *)(pGuid + 4))); Call(GetUShort(pWS, uValue + 6, (unsigned short *)(pGuid + 6))); Call(pWS->Read(pWS, pGuid + 8, 8)); PI.pGUIDPixFmt = &pID->guidPixFormat; PixelFormatLookup(&PI, LOOKUP_FORWARD); pID->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); pID->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; pID->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR); break; } case WMP_tagImageWidth: FailIf(0 == uValue, WMP_errUnsupportedFormat); break; case WMP_tagImageHeight: FailIf(0 == uValue, WMP_errUnsupportedFormat); break; case WMP_tagImageOffset: FailIf(1 != uCount, WMP_errUnsupportedFormat); pID->WMP.wmiDEMisc.uImageOffset = uValue; break; case WMP_tagImageByteCount: FailIf(1 != uCount, WMP_errUnsupportedFormat); pID->WMP.wmiDEMisc.uImageByteCount = uValue; break; case WMP_tagAlphaOffset: FailIf(1 != uCount, WMP_errUnsupportedFormat); pID->WMP.wmiDEMisc.uAlphaOffset = uValue; break; case WMP_tagAlphaByteCount: FailIf(1 != uCount, WMP_errUnsupportedFormat); pID->WMP.wmiDEMisc.uAlphaByteCount = uValue; break; case WMP_tagWidthResolution: FailIf(1 != uCount, WMP_errUnsupportedFormat); ufValue.uVal = uValue; pID->fResX = ufValue.fVal; break; case WMP_tagHeightResolution: FailIf(1 != uCount, WMP_errUnsupportedFormat); ufValue.uVal = uValue; pID->fResY = ufValue.fVal; break; case WMP_tagXMPMetadata: case WMP_tagIccProfile: case WMP_tagEXIFMetadata: case WMP_tagTransformation: case WMP_tagCompression: case WMP_tagImageType: case WMP_tagImageDataDiscard: case WMP_tagAlphaDataDiscard: break; default: fprintf(stderr, "Unrecognized WMPTag: %d(%#x), %d, %d, %#x" CRLF, (int)uTag, (int)uTag, (int)uType, (int)uCount, (int)uValue); break; } Cleanup: return err; }
//================================================================ // PKImageEncode_WMP //================================================================ ERR WriteContainerPre( PKImageEncode* pIE) { ERR err = WMP_errSuccess; const U32 OFFSET_OF_PFD = 0x20; struct WMPStream* pWS = pIE->pStream; WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; PKPixelInfo PI; size_t offPos = 0; U8 IIMM[2] = {'\x49', '\x49'}; const U32 cbWmpDEMisc = OFFSET_OF_PFD; static WmpDE wmpDEs[] = { {WMP_tagPixelFormat, WMP_typBYTE, 16, -1}, {WMP_tagImageWidth, WMP_typLONG, 1, -1}, {WMP_tagImageHeight, WMP_typLONG, 1, -1}, {WMP_tagWidthResolution, WMP_typFLOAT, 1, -1}, {WMP_tagHeightResolution, WMP_typFLOAT, 1, -1}, {WMP_tagImageOffset, WMP_typLONG, 1, -1}, {WMP_tagImageByteCount, WMP_typLONG, 1, -1}, {WMP_tagAlphaOffset, WMP_typLONG, 1, -1}, {WMP_tagAlphaByteCount, WMP_typLONG, 1, -1}, }; U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]); WmpDE wmpDE = {0}; size_t i = 0; //================ Call(pWS->GetPos(pWS, &offPos)); FailIf(0 != offPos, WMP_errUnsupportedFormat); //================ // Header (8 bytes) Call(pWS->Write(pWS, IIMM, sizeof(IIMM))); offPos += 2; Call(PutUShort(pWS, offPos, 0x01bc)); offPos += 2; Call(PutULong(pWS, offPos, (U32)OFFSET_OF_PFD)); offPos += 4; //================ // Write overflow area pDEMisc->uOffPixelFormat = (U32)offPos; PI.pGUIDPixFmt = &pIE->guidPixFormat; PixelFormatLookup(&PI, LOOKUP_FORWARD); //Call(pWS->Write(pWS, PI.pGUIDPixFmt, sizeof(*PI.pGUIDPixFmt))); offPos += 16; /** following code is endian-agnostic **/ { unsigned char *pGuid = (unsigned char *) &pIE->guidPixFormat; Call(PutULong(pWS, offPos, ((U32 *)pGuid)[0])); Call(PutUShort(pWS, offPos + 4, ((U16 *)(pGuid + 4))[0])); Call(PutUShort(pWS, offPos + 6, ((U16 *)(pGuid + 6))[0])); Call(pWS->Write(pWS, pGuid + 8, 8)); offPos += 16; } //================ // PFD assert (offPos <= OFFSET_OF_PFD); // otherwise stuff is overwritten offPos = (size_t)OFFSET_OF_PFD; if(!pIE->WMP.bHasAlpha)//no alpha cWmpDEs -= 2; pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + 12 * cWmpDEs + sizeof(U32)); Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2; //================ wmpDE = wmpDEs[i++]; assert(WMP_tagPixelFormat == wmpDE.uTag); wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; wmpDE = wmpDEs[i++]; assert(WMP_tagImageWidth == wmpDE.uTag); wmpDE.uValueOrOffset = pIE->uWidth; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; wmpDE = wmpDEs[i++]; assert(WMP_tagImageHeight == wmpDE.uTag); wmpDE.uValueOrOffset = pIE->uHeight; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; wmpDE = wmpDEs[i++]; assert(WMP_tagWidthResolution == wmpDE.uTag); wmpDE.f32 = pIE->fResX; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; wmpDE = wmpDEs[i++]; assert(WMP_tagHeightResolution == wmpDE.uTag); wmpDE.f32 = pIE->fResY; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; wmpDE = wmpDEs[i++]; assert(WMP_tagImageOffset == wmpDE.uTag); wmpDE.uValueOrOffset = pDEMisc->uImageOffset; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; // fix up in WriteContainerPost() wmpDE = wmpDEs[i++]; assert(WMP_tagImageByteCount == wmpDE.uTag); pDEMisc->uOffImageByteCount = (U32)offPos; wmpDE.uValueOrOffset = 0; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; if(pIE->WMP.bHasAlpha) { // fix up in WriteContainerPost() wmpDE = wmpDEs[i++]; assert(WMP_tagAlphaOffset == wmpDE.uTag); pDEMisc->uOffAlphaOffset = (U32)offPos; wmpDE.uValueOrOffset = 0; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; // fix up in WriteContainerPost() wmpDE = wmpDEs[i++]; assert(WMP_tagAlphaByteCount == wmpDE.uTag); pDEMisc->uOffAlphaByteCount = (U32)offPos; wmpDE.uValueOrOffset = 0; Call(WriteWmpDE(pWS, offPos, &wmpDE)); offPos += 12; } //================ Call(PutULong(pWS, offPos, 0)); offPos += 4; assert(0 == (offPos & 1)); assert(pDEMisc->uImageOffset == offPos); Cleanup: return err; }
//================================================================ // main function //================================================================ int #ifndef __ANSI__ __cdecl #endif // __ANSI__ jxrlibDecodeMain(int argc, char *argv[]) { ERR err = WMP_errSuccess; PKFactory *pFactory = NULL; PKCodecFactory *pCodecFactory = NULL; PKImageDecode *pDecoder = NULL; WMPDECAPPARGS args = {0}; char *pExt = NULL; U32 cFrame = 0; U32 i = 0; PKPixelInfo PI; // static size_t cChannels[CFT_MAX] = {1, 3, 3, 3, 4, 4, -1, 3, 3, -1}; //================================ // parse command line parameters if (1 == argc) { WmpDecAppUsage(argv[0]); return 0; } Call(WmpDecAppParseArgs(argc, argv, &args)); if (args.bVerbose) { WmpDecAppShowArgs(&args); } //================================ pExt = strrchr(args.szOutputFile, '.'); FailIf(NULL == pExt, WMP_errUnsupportedFormat); //================================ Call(PKCreateFactory(&pFactory, PK_SDK_VERSION)); Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); #if 0 Call(pCodecFactory->CreateDecoderFromFile(args.szInputFile, &pDecoder)); #else Call(PKCodecFactory_CreateDecoderFromFile(args.szInputFile, &pDecoder)); #endif // Fix the wrong image plane byte count { long fileSize; FILE *pFile = pDecoder->pStream->state.file.pFile; fseek(pFile, 0, SEEK_END); fileSize = ftell(pFile); if (args.bVerbose) { printf("File size: %ld\n", fileSize); } fseek(pFile, 0, SEEK_SET); if ((U32)fileSize < pDecoder->WMP.wmiDEMisc.uImageOffset + pDecoder->WMP.wmiDEMisc.uImageByteCount) { size_t byteCount = fileSize - pDecoder->WMP.wmiDEMisc.uImageOffset; pDecoder->WMP.wmiDEMisc.uImageByteCount = byteCount; pDecoder->WMP.wmiI.uImageByteCount = byteCount; } // Circumvent the bug in JXELIB's JPEG-XR encoder that used to write wrong alpha plane byte count. // Adjust the alpha plane byte count if the value is wrong. if (pDecoder->WMP.wmiDEMisc.uAlphaOffset + pDecoder->WMP.wmiI_Alpha.uImageByteCount > (U32)fileSize) pDecoder->WMP.wmiI_Alpha.uImageByteCount = fileSize - pDecoder->WMP.wmiDEMisc.uAlphaOffset; } //////////////// Save color profile /////////////////// if (args.szColorProfileFile && pDecoder->WMP.wmiDEMisc.uColorProfileByteCount != 0) { size_t cb = pDecoder->WMP.wmiDEMisc.uColorProfileByteCount; void *buf = malloc(cb); if (buf) { U32 cbRead = cb; ERR err = PKImageDecode_GetColorContext_WMP(pDecoder, (U8 *)buf, &cbRead); if (WMP_errSuccess == err) { // Save color pfofile in a file FILE *pFile; #ifdef WIN32 FailIf(0 != fopen_s(&pFile, args.szColorProfileFile, "wb"), WMP_errFileIO); #else pFile = fopen(args.szColorProfileFile, "wb"); FailIf(NULL == pFile, WMP_errFileIO); #endif FailIf(1 != fwrite(buf, cb, 1, pFile), WMP_errFileIO); fclose(pFile); } free(buf); } } /////////////////////////////////////////////////////////////// //==== set default color format if (IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormatDontCare)) { // take deocder color format and try to look up better one // (e.g. 32bppBGR -> 24bppBGR etc.) PKPixelInfo newPI; newPI.pGUIDPixFmt = PI.pGUIDPixFmt = &pDecoder->guidPixFormat; Call(PixelFormatLookup(&newPI, LOOKUP_FORWARD)); Call(PixelFormatLookup(&newPI, LOOKUP_BACKWARD_TIF)); args.guidPixFormat = *newPI.pGUIDPixFmt; } else PI.pGUIDPixFmt = &args.guidPixFormat; // pDecoder->WMP.wmiI.bRGB = args.bFlagRGB_BGR; // == color transcoding, if (IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat16bppGray)) { // ** => Y transcoding pDecoder->guidPixFormat = args.guidPixFormat; pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY; } else if (IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK) {// CMYK = > RGB pDecoder->WMP.wmiI.cfColorFormat = CF_RGB; pDecoder->guidPixFormat = args.guidPixFormat; pDecoder->WMP.wmiI.bRGB = 1; //RGB } PixelFormatLookup(&PI, LOOKUP_FORWARD); if (255 == args.uAlphaMode) //user didn't set { if (!!(PI.grBit & PK_pixfmtHasAlpha)) args.uAlphaMode = 2; //default is image & alpha for formats with alpha else args.uAlphaMode = 0; //otherwise, 0 } pDecoder->WMP.wmiSCP.bfBitstreamFormat = args.bfBitstreamFormat; pDecoder->WMP.wmiSCP.uAlphaMode = args.uAlphaMode; pDecoder->WMP.wmiSCP.sbSubband = args.sbSubband; pDecoder->WMP.bIgnoreOverlap = args.bIgnoreOverlap; pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat; pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth; pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; //==== Validate thumbnail decode parameters ===== pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth; pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight; pDecoder->WMP.wmiI.bSkipFlexbits = FALSE; if (args.tThumbnailFactor > 0 && args.tThumbnailFactor != SKIPFLEXBITS) { size_t tSize = ((size_t)1 << args.tThumbnailFactor); pDecoder->WMP.wmiI.cThumbnailWidth = (pDecoder->WMP.wmiI.cWidth + tSize - 1) / tSize; pDecoder->WMP.wmiI.cThumbnailHeight = (pDecoder->WMP.wmiI.cHeight + tSize - 1) / tSize; if (pDecoder->WMP.wmiI.cfColorFormat == YUV_420 || pDecoder->WMP.wmiI.cfColorFormat == YUV_422) { // unsupported thumbnail format pDecoder->WMP.wmiI.cfColorFormat = YUV_444; } } else if (args.tThumbnailFactor == SKIPFLEXBITS) { pDecoder->WMP.wmiI.bSkipFlexbits = TRUE; } if (args.rWidth == 0 || args.rHeight == 0) { // no region decode args.rLeftX = args.rTopY = 0; args.rWidth = pDecoder->WMP.wmiI.cThumbnailWidth; args.rHeight = pDecoder->WMP.wmiI.cThumbnailHeight; } pDecoder->WMP.wmiI.cROILeftX = args.rLeftX; pDecoder->WMP.wmiI.cROITopY = args.rTopY; pDecoder->WMP.wmiI.cROIWidth = args.rWidth; pDecoder->WMP.wmiI.cROIHeight = args.rHeight; pDecoder->WMP.wmiI.oOrientation = args.oOrientation; pDecoder->WMP.wmiI.cPostProcStrength = args.cPostProcStrength; pDecoder->WMP.wmiSCP.bVerbose = args.bVerbose; Call(pDecoder->GetFrameCount(pDecoder, &cFrame)); //================================ for (i = 0; ; ++i) { struct WMPStream *pEncodeStream = NULL; PKImageEncode *pEncoder = NULL; PKFormatConverter *pConverter = NULL; Float rX = 0.0, rY = 0.0; PKRect rect = {0, 0, 0, 0}; //================================ #if 0 Call(pCodecFactory->CreateFormatConverter(&pConverter)); #else Call(PKCodecFactory_CreateFormatConverter(&pConverter)); #endif Call(pConverter->Initialize(pConverter, pDecoder, pExt, args.guidPixFormat)); //================================ Call(pFactory->CreateStreamFromFilename(&pEncodeStream, args.szOutputFile, "wb")); Call(WmpDecAppCreateEncoderFromExt(pCodecFactory, pExt, &pEncoder)); if (pEncoder->bWMP) Call(pEncoder->Initialize(pEncoder, pEncodeStream, &args.wmiSCP, sizeof(args.wmiSCP))); else Call(pEncoder->Initialize(pEncoder, pEncodeStream, NULL, 0)); //!!! Do it here instead of JXRGlueEnc.c in order to avoid dependence of purely encoding applications on JXRDecodeLib.lib!!! pEncoder->Transcode = PKImageEncode_Transcode_WMP; //================================ Call(pEncoder->SetPixelFormat(pEncoder, args.guidPixFormat)); pEncoder->WMP.wmiSCP.bBlackWhite = pDecoder->WMP.wmiSCP.bBlackWhite; //Call(pDecoder->GetSize(pDecoder, &rect.Width, &rect.Height)); rect.Width = (I32)(pDecoder->WMP.wmiI.cROIWidth); rect.Height = (I32)(pDecoder->WMP.wmiI.cROIHeight); if (args.oOrientation > O_FLIPVH) { // allocate memory for rotated image! I32 bah = rect.Width; rect.Width = rect.Height; rect.Height = bah; } Call(pEncoder->SetSize(pEncoder, rect.Width, rect.Height)); Call(pDecoder->GetResolution(pDecoder, &rX, &rY)); if (args.oOrientation > O_FLIPVH) Call(pEncoder->SetResolution(pEncoder, rY, rX)); else Call(pEncoder->SetResolution(pEncoder, rX, rY)); if (pEncoder->bWMP && args.tThumbnailFactor > 0) { printf("-T can not be used for compressed domain operation!\n"); return 0; } //================================ pEncoder->WriteSource = PKImageEncode_Transcode; Call(pEncoder->WriteSource(pEncoder, pConverter, &rect)); //================================ // Call(pEncoder->Terminate(pEncoder)); pEncoder->Release(&pEncoder); // multi-frame support NYI if (i + 1 == cFrame) break; Call(pDecoder->SelectFrame(pDecoder, i + 1)); } pDecoder->Release(&pDecoder); Cleanup: if (WMP_errUnsupportedFormat == err) { printf("*** ERROR: Unsupported format in JPEG XR ***\n"); } return (int)err; }
ILboolean iLoadWdpInternal(/*ILconst_string FileName*/) { ERR err = WMP_errSuccess; PKFactory* pFactory = NULL; PKCodecFactory* pCodecFactory = NULL; PKImageDecode* pDecoder = NULL; PKPixelInfo PI; PKPixelFormatGUID guidPixFormat; PKFormatConverter* pConverter = NULL; U32 cFrame = 0, i = 0; PKRect Rect; struct WMPStream* pEncodeStream = NULL; PKImageEncode* pEncoder = NULL; //Call(PKCreateFactory(&pFactory, PK_SDK_VERSION)); //Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); //Call(pCodecFactory->CreateDecoderFromFile(FileName, &pDecoder)); Call(ilPKCreateFactory(&pFactory, PK_SDK_VERSION)); Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); Call(ilPKCodecFactory_CreateDecoderFromFile(&pDecoder)); //guidPixFormat = GUID_PKPixelFormat24bppRGB; guidPixFormat = GUID_PKPixelFormat32bppBGRA; //guidPixFormat = GUID_PKPixelFormat8bppGray; //guidPixFormat = GUID_PKPixelFormat16bppGray; // Color transcoding if (IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat16bppGray)){ // ** => Y transcoding pDecoder->guidPixFormat = guidPixFormat; pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY; } else if(IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK){ // CMYK = > RGB pDecoder->WMP.wmiI.cfColorFormat = CF_RGB; pDecoder->guidPixFormat = guidPixFormat; pDecoder->WMP.wmiI.bRGB = 1; //RGB } PI.pGUIDPixFmt = &guidPixFormat; PixelFormatLookup(&PI, LOOKUP_FORWARD); pDecoder->WMP.wmiSCP.bfBitstreamFormat = 0; pDecoder->WMP.wmiSCP.uAlphaMode = 0; pDecoder->WMP.wmiSCP.sbSubband = SB_ALL; pDecoder->WMP.bIgnoreOverlap = FALSE; pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat; pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth; pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; //==== Validate thumbnail decode parameters ===== pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth; pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight; pDecoder->WMP.wmiI.bSkipFlexbits = FALSE; pCodecFactory->CreateFormatConverter(&pConverter); pConverter->Initialize(pConverter, pDecoder, NULL, guidPixFormat); // Right now, we are just assuming one frame. // @TODO: Deal with multiple frames. //pDecoder->GetFrameCount(pDecoder, &cFrame); //pDecoder->SelectFrame(pDecoder, 1); if (!ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL)) goto Cleanup; //ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, Data); pFactory->CreateStreamFromMemory(&pEncodeStream, iCurImage->Data, iCurImage->SizeOfData); iWmpDecAppCreateEncoderFromExt(pCodecFactory, ".wdp", &pEncoder); pEncoder->Initialize(pEncoder, pEncodeStream, ".wdp", 0); pEncoder->pStream->GetPos(pEncoder->pStream, &pEncoder->offStart); // Set the region that we want to be the whole image. Rect.X = 0; Rect.Y = 0; Rect.Height = pDecoder->uHeight; Rect.Width = pDecoder->uWidth; pEncoder->SetPixelFormat(pEncoder, guidPixFormat); pEncoder->SetSize(pEncoder, Rect.Width, Rect.Height); pEncoder->WriteSource = PKImageEncode_Transcode; pEncoder->WriteSource(pEncoder, pConverter, &Rect); Cleanup: // Release everything all at the end. PKImageDecode_Release(&pDecoder); if (pEncoder) PKImageEncode_Release(&pEncoder); PKCreateCodecFactory_Release(&pCodecFactory); PKCreateFactory_Release(&pFactory); PKFormatConverter_Release(&pConverter); if (err != WMP_errSuccess) return IL_FALSE; return IL_TRUE; }
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; }
/** 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; } }