//*@@@+++@@@@******************************************************************
//
// Copyright © Microsoft Corp.
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 
// • Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// • Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//*@@@---@@@@******************************************************************
#include <JXRTest.h>
#include <time.h>


//================================================================
static const size_t SKIPFLEXBITS = 0xff;

//================================================================
// Command line argument support
//================================================================
typedef struct tagWMPDECAPPARGS
{
    char* szInputFile;
    char* szOutputFile;

    Bool bVerbose;

    PKPixelFormatGUID guidPixFormat;
//    Bool bFlagRGB_BGR;

    // region decode
    size_t rLeftX;
    size_t rTopY;
    size_t rWidth;
    size_t rHeight;

    // thumbnail
    size_t tThumbnailFactor;

    // orientation
    ORIENTATION oOrientation;

    // post processing
    U8 cPostProcStrength;

    U8 uAlphaMode; // 0:no alpha 1: alpha only else: something + alpha 

    SUBBAND sbSubband;  // which subbands to keep (for transcoding)

    BITSTREAMFORMAT bfBitstreamFormat; // desired bitsream format (for transcoding)

    CWMIStrCodecParam wmiSCP;

    Bool bIgnoreOverlap;
} WMPDECAPPARGS;

//----------------------------------------------------------------
void WmpDecAppUsage(const char* szExe)
{
    printf(CRLF);
    printf("JPEG XR Decoder Utility" CRLF);
    printf("Copyright 2013 Microsoft Corporation - All Rights Reserved" CRLF); 
    printf(CRLF);
    printf("%s [options]..." CRLF, szExe);
    printf(CRLF);
    printf("  -i input.jxr/wdp             Input JPEG XR/HD Photo file name" CRLF);
    printf(CRLF);
    printf("  -o output.bmp/tif/jxr        Output image file name" CRLF);
    printf("                               bmp: <=8bpc, BGR" CRLF);
    printf("                               tif: >=8bpc, RGB" CRLF);
    printf("                               jxr: for compressed domain transcode" CRLF);
    printf(CRLF);

    printf("  -c format                    Specifies the uncompressed output format" CRLF);
    printf("                                0: 24bppBGR" CRLF);
    printf("                                1: 1bppBlackWhite" CRLF);
    printf("                                2: 8bppGray" CRLF);
    printf("                                3: 16bppGray" CRLF);
    printf("                                4: 16bppGrayFixedPoint" CRLF);
    printf("                                5: 16bppGrayHalf" CRLF);
//    printf("                               6: 32bppGray" CRLF);
    printf("                                7: 32bppGrayFixedPoint" CRLF);
    printf("                                8: 32bppGrayFloat" CRLF);

    printf("                                9: 24bppRGB" CRLF);
    printf("                               10: 48bppRGB" CRLF);
    printf("                               11: 48bppRGBFixedPoint" CRLF);
    printf("                               12: 48bppRGBHalf" CRLF);
//    printf("                               13: 96bppRGB" CRLF);
    printf("                               14: 96bppRGBFixedPoint" CRLF);
    printf("                               15: 128bppRGBFloat" CRLF);

    printf("                               16: 32bppRGBE" CRLF);

    printf("                               17: 32bppCMYK" CRLF);
    printf("                               18: 64bppCMYK" CRLF);

/*
    printf("                               19 - YUV 420" CRLF);
    printf("                               20 - YUV 422" CRLF);
    printf("                               21 - YUV 444" CRLF);
*/
    printf("                               22: 32bppBGRA" CRLF);
    printf("                               23: 64bppRGBA" CRLF);
    printf("                               24: 64bppRGBAFixedPoint" CRLF);
    printf("                               25: 64bppRGBAHalf" CRLF);
//    printf("                               26 - 128bpp RGBA" CRLF);
    printf("                               27: 128bppRGBAFixedPoint" CRLF);
    printf("                               28: 128bppRGBAFloat" CRLF);

    printf("                               29: 16bppBGR555" CRLF);
    printf("                               30: 16bppBGR565" CRLF);
    printf("                               31: 32bppBGR101010" CRLF);
    //printf("                               101..116 - 1..16 channel 8bpp" CRLF);
    printf("                               32: 40bppCMYKA" CRLF);
    printf("                               33: 80bppCMYKA" CRLF);

    printf("                               34: 32bppBGR" CRLF);
/*
    printf("                               35:  32bppPBGRA" CRLF);
    printf("                               36:  64bppPRGBA" CRLF);
    printf("                               37: 128bppPRGBA Float" CRLF);
*/
    printf(CRLF);

    printf("  -r top left height width     Specifies the rectangle for region decode" CRLF);
    printf(CRLF);
    printf("  -T m                         Reduced resolution (mipmap) decode" CRLF);
    printf("                                0: Full resolution (default)" CRLF);
    printf("                                1: 1/2 res (down-sampled from full res)" CRLF);
    printf("                                2: 1/4 res (native decode)" CRLF);
    printf("                                3: 1/8 res (down-sampled from 1/4 res)" CRLF);
    printf("                                4: 1/16 res (native decode)" CRLF);
    printf("                               >4: 1/(2^m) res (down-sampled from 1/16 res) " CRLF);
    printf(CRLF);

    printf("  -O orientation               0: No transformation (default)" CRLF);
    printf("                               1: Flip vertically" CRLF);
    printf("                               2: Flip horizontally" CRLF);
    printf("                               3: Flip vertically & horizontally" CRLF);
    printf("                               4: Rotate 90 degrees CW" CRLF);
    printf("                               5: Rotate 90 degrees CW & flip vertically" CRLF);
    printf("                               6: Rotate 90 degrees CW & flip horizontally" CRLF);
    printf("                               7: Rotate 90 degrees CW & flip vert & horiz" CRLF);
    printf(CRLF);

    printf("  -s skip subbands             Used for compressed domain transcoding" CRLF);    
    printf("                               0: All subbands included (default)" CRLF);    
    printf("                               1: Skip flexbits" CRLF);    
    printf("                               2: Skip highpass" CRLF);    
    printf("                               3: Skip highpass & lowpass (DC only)" CRLF);    
    printf(CRLF);

    printf("  -a alpha decode              0: Decode without alpha channel" CRLF);
    printf("                               1: Decode only alpha channel" CRLF);
    printf("                               2: Decode image & alpha (default)" CRLF);
    printf(CRLF);

    printf("  -p strength                  Post processing filter strength" CRLF);
    printf("                               0: None (default)" CRLF);
    printf("                               1: Light" CRLF);
    printf("                               2: Medium" CRLF);
    printf("                               3: Strong" CRLF);
    printf("                               4: Very strong" CRLF);
    printf(CRLF);

    printf("  -C                           Suppress overlapping boundary macro blocks" CRLF);
    printf("                               (Used for compressed domain tile extraction)" CRLF);
    printf(CRLF);

    printf("  -t                           Display timing information" CRLF);
    printf(CRLF);

    printf("  -v                           Display verbose decoder information" CRLF);
    printf(CRLF);
    printf("Eg: %s -i input.jxr -o output.bmp -c 0" CRLF, szExe);
}

void WmpDecAppShowArgs(WMPDECAPPARGS* args)
{
	GUID guidPF = args->guidPixFormat;

    printf("================================" CRLF);
    printf("Input file:     %s" CRLF, args->szInputFile);
    printf("Output file:    %s" CRLF, args->szOutputFile);
    printf("Color format:   %08X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X" CRLF, 
        guidPF.Data1, guidPF.Data2, guidPF.Data3, guidPF.Data4[0], guidPF.Data4[1], guidPF.Data4[2],
        guidPF.Data4[3], guidPF.Data4[4], guidPF.Data4[5], guidPF.Data4[6], guidPF.Data4[7]);
    printf("Post processing strength: %d" CRLF, args->cPostProcStrength);
    printf("Thumbnail:      %d" CRLF, (int) args->tThumbnailFactor);
    printf("================================" CRLF);
}

//----------------------------------------------------------------
void WmpDecAppInitDefaultArgs(WMPDECAPPARGS* args)
{
    memset(args, 0, sizeof(*args));
    args->guidPixFormat = GUID_PKPixelFormatDontCare;
//    args->bFlagRGB_BGR = FALSE; //default BGR
    args->bVerbose = FALSE;
    args->tThumbnailFactor = 0;
    args->oOrientation = O_NONE;
    args->cPostProcStrength = 0;
    args->uAlphaMode = 255;
    args->sbSubband = SB_ALL;
}

ERR WmpDecAppValidateArgs(WMPDECAPPARGS* args)
{
    ERR err = WMP_errSuccess;

    Test(NULL != args->szInputFile, WMP_errInvalidParameter);
    Test(NULL != args->szOutputFile, WMP_errInvalidParameter);
    //Test(GUID_PKPixelFormatDontCare != args->enPixelFormat, WMP_errInvalidParameter);

Cleanup:
    return err;
}

ERR WmpDecAppParseArgs(int argc, char* argv[], WMPDECAPPARGS* args)
{
    ERR err = WMP_errSuccess;

    int c = 0, i = 1;
    // char* arg = NULL;

    static const PKPixelFormatGUID* pixelFormat[] =
    {
        &GUID_PKPixelFormat24bppRGB,

        &GUID_PKPixelFormatBlackWhite,

        &GUID_PKPixelFormat8bppGray,
        &GUID_PKPixelFormat16bppGray,
        &GUID_PKPixelFormat16bppGrayFixedPoint,
        &GUID_PKPixelFormat16bppGrayHalf,
        &GUID_PKPixelFormatDontCare, // &GUID_PKPixelFormat32bppGray,
        &GUID_PKPixelFormat32bppGrayFixedPoint,
        &GUID_PKPixelFormat32bppGrayFloat,

        &GUID_PKPixelFormat24bppRGB,
        &GUID_PKPixelFormat48bppRGB,
        &GUID_PKPixelFormat48bppRGBFixedPoint,
        &GUID_PKPixelFormat48bppRGBHalf,
        &GUID_PKPixelFormatDontCare, // &GUID_PKPixelFormat96bppRGB,
        &GUID_PKPixelFormat96bppRGBFixedPoint,
        &GUID_PKPixelFormat128bppRGBFloat,

        &GUID_PKPixelFormat32bppRGBE,
        &GUID_PKPixelFormat32bppCMYK,
        &GUID_PKPixelFormat64bppCMYK,

        &GUID_PKPixelFormat12bppYUV420, 
        &GUID_PKPixelFormat16bppYUV422,
        &GUID_PKPixelFormat24bppYUV444,

//        &GUID_PKPixelFormat32bppRGBA,
        &GUID_PKPixelFormat32bppBGRA,
        &GUID_PKPixelFormat64bppRGBA,
        &GUID_PKPixelFormat64bppRGBAFixedPoint,
        &GUID_PKPixelFormat64bppRGBAHalf,
        &GUID_PKPixelFormatDontCare, // &GUID_PKPixelFormat128bppRGBA,
        &GUID_PKPixelFormat128bppRGBAFixedPoint,
        &GUID_PKPixelFormat128bppRGBAFloat,
        &GUID_PKPixelFormat16bppRGB555,
        &GUID_PKPixelFormat16bppRGB565,
        &GUID_PKPixelFormat32bppRGB101010,
        &GUID_PKPixelFormat40bppCMYKAlpha,
        &GUID_PKPixelFormat80bppCMYKAlpha,
        &GUID_PKPixelFormat32bppBGR,
        &GUID_PKPixelFormat32bppPBGRA,
        &GUID_PKPixelFormat64bppPRGBA,
        &GUID_PKPixelFormat128bppPRGBAFloat,
    };

    size_t InvalidPF[9] = {6, 13, 19, 20, 21, 26, 35, 36, 37};
    int k;

    WmpDecAppInitDefaultArgs(args);

    while(i < argc && argv[i][0] == '-')
//    while (EOF != (c = argit(argc, argv, "i:o:c:ptv", &arg)))
    {
         /* separate out the no-argument switches */
        switch ((c = argv[i][1])) {
            case 't':
                // NOOP - now we always print timing info
                break;

            case 'v':
                args->bVerbose = !FALSE;
                break;

            case 'C':
                args->bIgnoreOverlap = TRUE;
                break;
            
            case 'f': 
                args->bfBitstreamFormat = FREQUENCY;
                break;

            default:
                i ++;
                if (i == argc || argv[i][0] == '-') // need more info
                    Call(WMP_errInvalidArgument);
                
                switch (c)
                {
                case 'i':
                    args->szInputFile= argv[i];
                    break;

                case 'o':
                    args->szOutputFile = argv[i];
                    break;
                
                case 'p':
                    args->cPostProcStrength = (U8)atoi(argv[i]);
                    break;

                case 'c':
                {
                    size_t idxPF = (size_t)atol(argv[i]);

                    FailIf(sizeof2(pixelFormat) <= idxPF, WMP_errUnsupportedFormat);

                    for (k = 0; k < 9; k++)
                    {
                        if (InvalidPF[k] == idxPF)
                        {
                            printf("*** ERROR: Unsupported format in JPEG XR ***\n");
                            Call(WMP_errInvalidArgument);
                        }
                    }

                    args->guidPixFormat = *pixelFormat[idxPF];

                    break;
                }

/*                case 'R': 
                    args->bFlagRGB_BGR = (Bool)atoi(argv[i]);
                    break;
*/
                case 'a': 
                    args->uAlphaMode = (U8)atoi(argv[i]);
                    break;

                case 's': 
                    args->sbSubband = (SUBBAND)atoi(argv[i]);
                    break;

                case 'r': // Region decode
                    if(i + 3 >= argc || argv[i + 1][0] == '-' || argv[i + 2][0] == '-' || argv[i + 3][0] == '-') // not a valid region
                        Call(WMP_errInvalidArgument);

                    args->rTopY = (size_t)atoi(argv[i]);
                    args->rLeftX = (size_t)atoi(argv[i + 1]);
                    args->rHeight = (size_t)atoi(argv[i + 2]);
                    args->rWidth = (size_t)atoi(argv[i + 3]);
                    i += 3;

                    break;

                case 'T': // thumnail decode
                    args->tThumbnailFactor = (size_t)atoi(argv[i]);
                    if (args->tThumbnailFactor == 0) {  // skip flexbits
                        args->tThumbnailFactor = SKIPFLEXBITS;
                    }
                    break;

                case 'O': // orientation
                    args->oOrientation = (atoi(argv[i]) < 8 ? atoi(argv[i]) : O_NONE);
                    break;

                default:
                    Call(WMP_errInvalidArgument);
                    break;
            }
        }

        i ++;
    }

    Call(WmpDecAppValidateArgs(args));

Cleanup:
    if (WMP_errSuccess != err)
    {
        WmpDecAppUsage(argv[0]);
    }
    return err;
}


//================================================================
// Encoder factory on file extension
//================================================================
ERR WmpDecAppCreateEncoderFromExt(
    PKCodecFactory* pCFactory,
    const char* szExt,
    PKImageEncode** ppIE)
{
    ERR err = WMP_errSuccess;
    const PKIID* pIID = NULL;

    UNREFERENCED_PARAMETER( pCFactory );

    // get encod PKIID
    Call(GetTestEncodeIID(szExt, &pIID));

    // Create encoder
    Call(PKTestFactory_CreateCodec(pIID, ppIE));

Cleanup:
    return err;
}


//================================================================
// 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");
    }
    
    return (int)err;
}
