Пример #1
0
  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.");
  }
Пример #2
0
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;
}
Пример #3
0
/**
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;
	}
}
Пример #4
0
//================================================================
// 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;
}
Пример #5
0
//================================================================
// 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;
}
Пример #6
0
//================================================================
// 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;
}
Пример #7
0
//================================================================
// 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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
/**
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;
	}
}