diff -Naur jxrlib-0.2.4/image/sys/common.h jxrlib-0.2.4.new/image/sys/common.h --- jxrlib-0.2.4/image/sys/common.h 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/image/sys/common.h 2024-05-27 10:10:14.343852955 +0200 @@ -124,8 +124,8 @@ Void AdaptFixed (CAdaptiveHuffman *pAdHuff); Void AdaptDiscriminant (CAdaptiveHuffman *pAdHuff); -#ifndef _PREFAST_ -#pragma warning(disable:4068) -#endif +// #ifndef _PREFAST_ +// #pragma warning(disable:4068) +// #endif #endif // WMI_COMMON_H diff -Naur jxrlib-0.2.4/image/sys/strcodec.c jxrlib-0.2.4.new/image/sys/strcodec.c --- jxrlib-0.2.4/image/sys/strcodec.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/image/sys/strcodec.c 2024-05-27 10:10:14.407853373 +0200 @@ -668,9 +668,7 @@ // WinCE ARM and Desktop x86 #else // other platform -#ifdef _BIG__ENDIAN_ -#define _byteswap_ulong(x) (x) -#else // _BIG__ENDIAN_ +#ifndef _BIG__ENDIAN_ U32 _byteswap_ulong(U32 bits) { U32 r = (bits & 0xffu) << 24; diff -Naur jxrlib-0.2.4/image/sys/strcodec.h jxrlib-0.2.4.new/image/sys/strcodec.h --- jxrlib-0.2.4/image/sys/strcodec.h 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/image/sys/strcodec.h 2024-05-27 10:10:14.407853373 +0200 @@ -64,7 +64,7 @@ #ifndef UNREFERENCED_PARAMETER #define UNREFERENCED_PARAMETER(P) { (P) = (P); } -#endif UNREFERENCED_PARAMETER +#endif // UNREFERENCED_PARAMETER #ifdef UNDER_CE #define PLATFORM_WCE @@ -673,6 +673,16 @@ pIO->cBitsUsed &= 16 - 1;\ pIO->uiAccumulator = LOAD16(pIO->pbCurrent) << pIO->cBitsUsed;\ return 0; -// pIO->uiAccumulator = LOAD16(pIO->pbCurrent) & ((U32)(-1) >> pIO->cBitsUsed);\ void OutputPerfTimerReport(CWMImageStrCodec *pState); + +#if (defined(WIN32) && !defined(UNDER_CE)) || (defined(UNDER_CE) && defined(_ARM_)) +// WinCE ARM and Desktop x86 +#else +// other platform +#ifdef _BIG__ENDIAN_ +#define _byteswap_ulong(x) (x) +#else // _BIG__ENDIAN_ +U32 _byteswap_ulong(U32 bits); +#endif // _BIG__ENDIAN_ +#endif \ No newline at end of file diff -Naur jxrlib-0.2.4/jxrencoderdecoder/JxrDecApp.c jxrlib-0.2.4.new/jxrencoderdecoder/JxrDecApp.c --- jxrlib-0.2.4/jxrencoderdecoder/JxrDecApp.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrencoderdecoder/JxrDecApp.c 2024-05-27 10:23:16.329960792 +0200 @@ -427,7 +427,7 @@ Call(GetTestEncodeIID(szExt, &pIID)); // Create encoder - Call(PKTestFactory_CreateCodec(pIID, ppIE)); + Call(PKTestFactory_CreateCodec(pIID, (void**)ppIE)); Cleanup: return err; diff -Naur jxrlib-0.2.4/jxrencoderdecoder/JxrDecApp.c~ jxrlib-0.2.4.new/jxrencoderdecoder/JxrDecApp.c~ --- jxrlib-0.2.4/jxrencoderdecoder/JxrDecApp.c~ 1970-01-01 01:00:00.000000000 +0100 +++ jxrlib-0.2.4.new/jxrencoderdecoder/JxrDecApp.c~ 2024-05-27 10:10:05.550795509 +0200 @@ -0,0 +1,644 @@ +//*@@@+++@@@@****************************************************************** +// +// 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 +#include + + +//================================================================ +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; +} diff -Naur jxrlib-0.2.4/jxrencoderdecoder/JxrEncApp.c jxrlib-0.2.4.new/jxrencoderdecoder/JxrEncApp.c --- jxrlib-0.2.4/jxrencoderdecoder/JxrEncApp.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrencoderdecoder/JxrEncApp.c 2024-05-27 10:22:43.209744298 +0200 @@ -615,7 +615,7 @@ //================================ Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); - Call(pCodecFactory->CreateCodec(&IID_PKImageWmpEncode, &pEncoder)); + Call(pCodecFactory->CreateCodec(&IID_PKImageWmpEncode, (void**)&pEncoder)); //---------------------------------------------------------------- Call(PKCreateTestFactory(&pTestFactory, WMP_SDK_VERSION)); diff -Naur jxrlib-0.2.4/jxrencoderdecoder/JxrEncApp.c~ jxrlib-0.2.4.new/jxrencoderdecoder/JxrEncApp.c~ --- jxrlib-0.2.4/jxrencoderdecoder/JxrEncApp.c~ 1970-01-01 01:00:00.000000000 +0100 +++ jxrlib-0.2.4.new/jxrencoderdecoder/JxrEncApp.c~ 2024-05-27 10:10:05.550795509 +0200 @@ -0,0 +1,777 @@ +//*@@@+++@@@@****************************************************************** +// +// 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 +#include + + +//================================================================ +// Command line argument support +//================================================================ +typedef struct tagWMPENCAPPARGS +{ + char* szInputFile; + char* szOutputFile; + + PKPixelFormatGUID guidPixFormat; +// Bool bFlagRGB_BGR; + + CWMIStrCodecParam wmiSCP; + float fltImageQuality; + Bool bOverlapSet; + Bool bColorFormatSet; +} WMPENCAPPARGS; + +//---------------------------------------------------------------- +void WmpEncAppUsage(const char* szExe) +{ + printf(CRLF); + printf("JPEG XR Encoder Utility" CRLF); + printf("Copyright 2013 Microsoft Corporation - All Rights Reserved" CRLF); + printf(CRLF); + printf("%s [options]..." CRLF, szExe); + printf(CRLF); + printf(" -i input.bmp/tif/hdr Input image file name" CRLF); + printf(" bmp: <=8bpc, BGR" CRLF); + printf(" tif: >=8bpc, RGB" CRLF); + printf(" hdr: 32bppRGBE only" CRLF); + printf(CRLF); + + printf(" -o output.jxr Output JPEG XR file name" CRLF); + printf(CRLF); + + printf(" -q quality [0.0 - 1.0) Default = 1.0, lossless" CRLF); + printf(" or quantization [1 - 255] Default = 1, lossless" CRLF); + printf(CRLF); + + printf(" -c format Required to define uncompressed source pixel 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(" -d chroma sub-sampling 0: Y-only" CRLF); + printf(" 1: YCoCg 4:2:0" CRLF); + printf(" 2: YCoCg 4:2:2" CRLF); + printf(" 3: YCoCg 4:4:4 (default)" CRLF); + printf(" (if not set is 4:4:4 for quality >= 0.5 or 4:2:0 for quality < 0.5)" CRLF); + printf(CRLF); + + printf(" -l overlapping 0: No overlapping" CRLF); + printf(" 1: One level overlapping (default)" CRLF); + printf(" 2: Two level overlapping" CRLF); + printf(" (if not set is One for quality >= 0.5 or Two for quality < 0.5)" CRLF); + printf(CRLF); + + printf(" -f Turn off frequency order bit stream (to spatial)" CRLF); + printf(CRLF); + printf(" -p Turn off progressive mode (to sequential)" CRLF); + printf(CRLF); + printf(" -t Display timing information" CRLF); + printf(CRLF); + printf(" -v Display verbose encoder information" CRLF); + printf(CRLF); + printf(" -V tile_wd0 [tile_wd1 ... ] Macro block columns per tile " CRLF); + printf(CRLF); + printf(" -H tile_ht0 [tile_ht1 ... ] Macro block rows per tile" CRLF); + printf(CRLF); + printf(" -U num_v_tiles num_h_tiles Vertical & horizontal tile count for uniform tiling" CRLF); + printf(CRLF); + + printf(" -b Black/White Applies to 1bpp black/white images" CRLF); + printf(" 0: 0 = black (default)" CRLF); + printf(" 1: 0 = white" CRLF); + printf(CRLF); + + printf(" -a alpha channel format Required for any pixel format with an alpha channel" CRLF); + printf(" 2: Planar alpha (default)" CRLF); + printf(" 3: Interleaved alpha" CRLF); + printf(" Other: Reserved, do not use" CRLF); + printf(CRLF); + + printf(" -Q quantization for alpha [1 - 255] Default = 1, lossless" CRLF); + printf(CRLF); + + printf(" -F trimmed flexbits [0 - 15] 0: no trimming (default)" CRLF); + printf(" 15: trim all" CRLF); + printf(CRLF); + printf(" -s skip subbands 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("Eg: %s -i input.bmp -o output.jxr -q 0.9" CRLF, szExe); +} + +void WmpEncAppShowArgs(WMPENCAPPARGS* args) +{ + const char *szCF[] = {"Y_ONLY", "YUV_420", "YUV_422", "YUV_444", "CMYK"}; + + 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("Internal cf: %s" CRLF, szCF[args->wmiSCP.cfColorFormat]); + printf("Overlap: %s" CRLF, 0 < args->wmiSCP.olOverlap ? "yes" : "no"); + printf("DCOverlap: %s" CRLF, 1 < args->wmiSCP.olOverlap ? "yes" : "no"); + printf("Alpha: %s" CRLF, 1 < args->wmiSCP.uAlphaMode ? "yes" : "no"); + printf("================================" CRLF); +} + +//---------------------------------------------------------------- +void WmpEncAppInitDefaultArgs(WMPENCAPPARGS* args) +{ + memset(args, 0, sizeof(*args)); + + args->guidPixFormat = GUID_PKPixelFormatDontCare; + + args->wmiSCP.bVerbose = FALSE; + args->wmiSCP.cfColorFormat = YUV_444; +// args->bFlagRGB_BGR = FALSE; //default BGR + args->wmiSCP.bdBitDepth = BD_LONG; + args->wmiSCP.bfBitstreamFormat = FREQUENCY; + args->wmiSCP.bProgressiveMode = TRUE; + args->wmiSCP.olOverlap = OL_ONE; + args->wmiSCP.cNumOfSliceMinus1H = args->wmiSCP.cNumOfSliceMinus1V = 0; + args->wmiSCP.sbSubband = SB_ALL; + args->wmiSCP.uAlphaMode = 0; + args->wmiSCP.uiDefaultQPIndex = 1; + args->wmiSCP.uiDefaultQPIndexAlpha = 1; + + args->fltImageQuality = 1.f; + args->bOverlapSet = 0; + args->bColorFormatSet = 0; +} + +ERR WmpEncAppValidateArgs(WMPENCAPPARGS* args) +{ + ERR err = WMP_errSuccess; + + Test(NULL != args->szInputFile, WMP_errInvalidParameter); + Test(NULL != args->szOutputFile, WMP_errInvalidParameter); + +Cleanup: + return err; +} + +ERR WmpEncAppParseArgs(int argc, char* argv[], WMPENCAPPARGS* args) +{ + ERR err = WMP_errSuccess; + + static const PKPixelFormatGUID* pixelFormat[] = + { + &GUID_PKPixelFormat24bppBGR, + + &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_PKPixelFormat32bppPBGRA + &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}; + size_t AlphaPF[8] = {22, 23, 24, 25, 27, 28, 32, 33}; + + int i = 1, j = 0, k; + char c; + int idxPF = -1; + + WmpEncAppInitDefaultArgs(args); + + while (i < argc && argv[i][0] == '-') + { + switch ((c = argv[i][1])) { + /* the no-argument switches */ + case 't': + // NOOP - now we always print timing info + break; + + case 'v': + args->wmiSCP.bVerbose = !FALSE; + break; + + /* simple flag argument */ + case 'f': + args->wmiSCP.bfBitstreamFormat = SPATIAL; + break; + + case 'p': + args->wmiSCP.bProgressiveMode = FALSE; + break; + + case 'u': + args->wmiSCP.bUnscaledArith = TRUE; + 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 'q': + { + args->fltImageQuality = (float) atof(argv[i]); + if (args->fltImageQuality < 0.f || args->fltImageQuality > 255.f) + Call(WMP_errInvalidArgument); + } + break; + + case 'Q': + args->wmiSCP.uiDefaultQPIndexAlpha = (U8)(atoi(argv[i])); + break; + + case 's': + args->wmiSCP.sbSubband = (SUBBAND)(atoi(argv[i])); + break; + + case 'c': + idxPF = (size_t)atol(argv[i]); + for (k = 0; k < 9; k++) + { + if (InvalidPF[k] == (size_t) idxPF) + { + printf("*** Unsupported format in JPEG XR ***\n"); + Call(WMP_errInvalidArgument); + } + } + break; + + case 'a': + args->wmiSCP.uAlphaMode = (U8)atoi(argv[i]); + break; + +/* case 'R': + args->bFlagRGB_BGR = (Bool)atoi(argv[i]); + break; +*/ + case 'l': + args->wmiSCP.olOverlap = (OVERLAP)atoi(argv[i]); + args->bOverlapSet = 1; + break; + + case 'd': + args->wmiSCP.cfColorFormat = (COLORFORMAT)atoi(argv[i]); + args->bColorFormatSet = 1; + break; + + case 'H': // horizontal tiling + for(j = 0;;i ++, j ++){ + args->wmiSCP.uiTileY[j] = atoi(argv[i]); + if(i + 1 == argc || argv[i + 1][0] == '-' || j >= MAX_TILES-1) + break; + } + args->wmiSCP.cNumOfSliceMinus1H = (U8)j; + break; + + case 'V': // vertical tiling + for(j = 0;;i ++, j ++){ + args->wmiSCP.uiTileX[j] = atoi(argv[i]); + if(i + 1 == argc || argv[i + 1][0] == '-' || j >= MAX_TILES-1) + break; + } + args->wmiSCP.cNumOfSliceMinus1V = (U8)j; + break; + + case 'U': // uniform tiling + if(i + 1 < argc && argv[i + 1][0] != '-'){ + if(atoi(argv[i]) > 0 && atoi(argv[i + 1]) > 0){ + args->wmiSCP.cNumOfSliceMinus1H = atoi(argv[i]) - 1; + args->wmiSCP.cNumOfSliceMinus1V = atoi(argv[i + 1]) - 1; + } + i ++; + } + break; + + case 'm': + args->wmiSCP.nLenMantissaOrShift = (U8)atoi(argv[i]); + break; + + case 'C': + args->wmiSCP.nExpBias = (I8) atoi(argv[i]) + 128; // rollover arithmetic + break; + + case 'b': + args->wmiSCP.bBlackWhite = (Bool)atoi(argv[i]); + break; + + case 'F': + args->wmiSCP.uiTrimFlexBits = (U8)atoi(argv[i]); + if (args->wmiSCP.uiTrimFlexBits > 15) + args->wmiSCP.uiTrimFlexBits = 15; + break; + + default: + Call(WMP_errInvalidArgument); + } + } + + i ++; + } + + FailIf((int) sizeof2(pixelFormat) <= idxPF, WMP_errUnsupportedFormat); + if (idxPF >= 0) + args->guidPixFormat = *pixelFormat[idxPF]; + + if ((idxPF >= 1) && (idxPF <= 8)) + args->wmiSCP.cfColorFormat = Y_ONLY; + else if ((idxPF == 17) || (idxPF == 18) || (idxPF == 32) || (idxPF == 33)) + args->wmiSCP.cfColorFormat = CMYK; + + for (k = 0; k < 8; k++) + { + if (AlphaPF[k] == (size_t) idxPF) + { + if(0 == args->wmiSCP.uAlphaMode)//with Alpha and no default, set default as Planar + { + args->wmiSCP.uAlphaMode = 2; + } + break; + } + } + + //================================ + Call(WmpEncAppValidateArgs(args)); + +Cleanup: + if (WMP_errSuccess != err) + { + WmpEncAppUsage(argv[0]); + } + return err; +} + + +// Y, U, V, YHP, UHP, VHP +#if 1 +// optimized for PSNR +int DPK_QPS_420[11][6] = { // for 8 bit only + { 66, 65, 70, 72, 72, 77 }, + { 59, 58, 63, 64, 63, 68 }, + { 52, 51, 57, 56, 56, 61 }, + { 48, 48, 54, 51, 50, 55 }, + { 43, 44, 48, 46, 46, 49 }, + { 37, 37, 42, 38, 38, 43 }, + { 26, 28, 31, 27, 28, 31 }, + { 16, 17, 22, 16, 17, 21 }, + { 10, 11, 13, 10, 10, 13 }, + { 5, 5, 6, 5, 5, 6 }, + { 2, 2, 3, 2, 2, 2 } +}; + +int DPK_QPS_8[12][6] = { + { 67, 79, 86, 72, 90, 98 }, + { 59, 74, 80, 64, 83, 89 }, + { 53, 68, 75, 57, 76, 83 }, + { 49, 64, 71, 53, 70, 77 }, + { 45, 60, 67, 48, 67, 74 }, + { 40, 56, 62, 42, 59, 66 }, + { 33, 49, 55, 35, 51, 58 }, + { 27, 44, 49, 28, 45, 50 }, + { 20, 36, 42, 20, 38, 44 }, + { 13, 27, 34, 13, 28, 34 }, + { 7, 17, 21, 8, 17, 21 }, // Photoshop 100% + { 2, 5, 6, 2, 5, 6 } +}; +#else +// optimized for SSIM +int DPK_QPS_420[11][6] = { // for 8 bit only + { 67, 77, 80, 75, 82, 86 }, + { 58, 67, 71, 63, 74, 78 }, + { 50, 60, 64, 54, 66, 69 }, + { 46, 55, 59, 49, 60, 63 }, + { 41, 48, 53, 43, 52, 56 }, + { 35, 43, 48, 36, 44, 49 }, + { 29, 37, 41, 30, 38, 41 }, + { 22, 29, 33, 22, 29, 33 }, + { 15, 20, 26, 14, 20, 25 }, + { 9, 14, 18, 8, 14, 17 }, + { 4, 6, 7, 3, 5, 5 } +}; + +int DPK_QPS_8[12][6] = { + { 67, 93, 98, 71, 98, 104 }, + { 59, 83, 88, 61, 89, 95 }, + { 50, 76, 81, 53, 85, 90 }, + { 46, 71, 77, 47, 79, 85 }, + { 41, 67, 71, 42, 75, 78 }, + { 34, 59, 65, 35, 66, 72 }, + { 30, 54, 60, 29, 60, 66 }, + { 24, 48, 53, 22, 53, 58 }, + { 18, 39, 45, 17, 43, 48 }, + { 13, 34, 38, 11, 35, 38 }, + { 8, 20, 24, 7, 22, 25 }, // Photoshop 100% + { 2, 5, 6, 2, 5, 6 } +}; +#endif + +int DPK_QPS_16[11][6] = { + { 197, 203, 210, 202, 207, 213 }, + { 174, 188, 193, 180, 189, 196 }, + { 152, 167, 173, 156, 169, 174 }, + { 135, 152, 157, 137, 153, 158 }, + { 119, 137, 141, 119, 138, 142 }, + { 102, 120, 125, 100, 120, 124 }, + { 82, 98, 104, 79, 98, 103 }, + { 60, 76, 81, 58, 76, 81 }, + { 39, 52, 58, 36, 52, 58 }, + { 16, 27, 33, 14, 27, 33 }, + { 5, 8, 9, 4, 7, 8 } +}; + +int DPK_QPS_16f[11][6] = { + { 148, 177, 171, 165, 187, 191 }, + { 133, 155, 153, 147, 172, 181 }, + { 114, 133, 138, 130, 157, 167 }, + { 97, 118, 120, 109, 137, 144 }, + { 76, 98, 103, 85, 115, 121 }, + { 63, 86, 91, 62, 96, 99 }, + { 46, 68, 71, 43, 73, 75 }, + { 29, 48, 52, 27, 48, 51 }, + { 16, 30, 35, 14, 29, 34 }, + { 8, 14, 17, 7, 13, 17 }, + { 3, 5, 7, 3, 5, 6 } +}; + +int DPK_QPS_32f[11][6] = { + { 194, 206, 209, 204, 211, 217 }, + { 175, 187, 196, 186, 193, 205 }, + { 157, 170, 177, 167, 180, 190 }, + { 133, 152, 156, 144, 163, 168 }, + { 116, 138, 142, 117, 143, 148 }, + { 98, 120, 123, 96, 123, 126 }, + { 80, 99, 102, 78, 99, 102 }, + { 65, 79, 84, 63, 79, 84 }, + { 48, 61, 67, 45, 60, 66 }, + { 27, 41, 46, 24, 40, 45 }, + { 3, 22, 24, 2, 21, 22 } +}; + +//================================================================ +// main function +//================================================================ +int +#ifndef __ANSI__ +__cdecl +#endif // __ANSI__ +main(int argc, char* argv[]) +{ + ERR err = WMP_errSuccess; + + PKFactory* pFactory = NULL; + struct WMPStream* pEncodeStream = NULL; + PKCodecFactory* pCodecFactory = NULL; + PKCodecFactory* pTestFactory = NULL; + PKImageEncode* pEncoder = NULL; + + // clock_t start = 0, finish = 0; + WMPENCAPPARGS args; + char* pExt = NULL; + + //================================ + // parse command line parameters + if (1 == argc) + { + WmpEncAppUsage(argv[0]); + return 0; + } + + Call(WmpEncAppParseArgs(argc, argv, &args)); + if (args.wmiSCP.bVerbose) + { + WmpEncAppShowArgs(&args); + } + + //================================ + pExt = strrchr(args.szInputFile, '.'); + FailIf(NULL == pExt, WMP_errUnsupportedFormat); + + //================================ + Call(PKCreateFactory(&pFactory, PK_SDK_VERSION)); + Call(pFactory->CreateStreamFromFilename(&pEncodeStream, args.szOutputFile, "wb")); + + //================================ + Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION)); + Call(pCodecFactory->CreateCodec(&IID_PKImageWmpEncode, &pEncoder)); + + //---------------------------------------------------------------- + Call(PKCreateTestFactory(&pTestFactory, WMP_SDK_VERSION)); + + // + // go through each image + // + //for (i = 0; ; ++i) + { + PKImageDecode* pDecoder = NULL; + PKFormatConverter* pConverter = NULL; + PKPixelInfo PI; + + Float rX = 0.0, rY = 0.0; + PKRect rect = {0, 0, 0, 0}; + + //================================ + Call(pTestFactory->CreateDecoderFromFile(args.szInputFile, &pDecoder)); + if (IsEqualGUID(&args.guidPixFormat, &GUID_PKPixelFormatDontCare)) + Call(pDecoder->GetPixelFormat(pDecoder, &args.guidPixFormat)); + + PI.pGUIDPixFmt = &args.guidPixFormat; + Call(PixelFormatLookup(&PI, LOOKUP_FORWARD)); + if ((PI.grBit & PK_pixfmtHasAlpha) && args.wmiSCP.uAlphaMode == 0) + args.wmiSCP.uAlphaMode = 2; // with Alpha and no default, set default as Planar + + FailIf(PI.uSamplePerPixel > 1 && PI.uBitsPerSample > 8 && args.wmiSCP.cfColorFormat != YUV_444, + WMP_errInvalidArgument); + + //================================ + Call(pCodecFactory->CreateFormatConverter(&pConverter)); + Call(pConverter->Initialize(pConverter, pDecoder, pExt, args.guidPixFormat)); + + //================================ + Call(pDecoder->GetSize(pDecoder, &rect.Width, &rect.Height)); + + if (args.wmiSCP.cNumOfSliceMinus1H == 0 && args.wmiSCP.uiTileY[0] > 0) + { + // # of horizontal slices, rounded down by half tile size. + U32 uTileY = args.wmiSCP.uiTileY[0] * MB_HEIGHT_PIXEL; + args.wmiSCP.cNumOfSliceMinus1H = (U32) rect.Height < (uTileY >> 1) ? 0 : + (rect.Height + (uTileY >> 1)) / uTileY - 1; + } + if (args.wmiSCP.cNumOfSliceMinus1V == 0 && args.wmiSCP.uiTileX[0] > 0) + { + // # of vertical slices, rounded down by half tile size. + U32 uTileX = args.wmiSCP.uiTileX[0] * MB_HEIGHT_PIXEL; + args.wmiSCP.cNumOfSliceMinus1V = (U32) rect.Width < (uTileX >> 1) ? 0 : + (rect.Width + (uTileX >> 1)) / uTileX - 1; + } + + Call(pEncoder->Initialize(pEncoder, pEncodeStream, &args.wmiSCP, sizeof(args.wmiSCP))); + + //ImageQuality Q (BD==1) Q (BD==8) Q (BD==16) Q (BD==32F) Subsample Overlap + //[0.0, 0.5) 8-IQ*5 (see table) (see table) (see table) 4:2:0 2 + //[0.5, 1.0) 8-IQ*5 (see table) (see table) (see table) 4:4:4 1 + //[1.0, 1.0] 1 1 1 1 4:4:4 0 + + if (args.fltImageQuality < 1.0F) + { + if (!args.bOverlapSet) + { + // Image width must be at least 2 MB wide for subsampled chroma and two levels of overlap! + if (args.fltImageQuality >= 0.5F || rect.Width < 2 * MB_WIDTH_PIXEL) + pEncoder->WMP.wmiSCP.olOverlap = OL_ONE; + else + pEncoder->WMP.wmiSCP.olOverlap = OL_TWO; + } + + if (!args.bColorFormatSet) + { + if (args.fltImageQuality >= 0.5F || PI.uBitsPerSample > 8) + pEncoder->WMP.wmiSCP.cfColorFormat = YUV_444; + else + pEncoder->WMP.wmiSCP.cfColorFormat = YUV_420; + } + + if (PI.bdBitDepth == BD_1) + { + pEncoder->WMP.wmiSCP.uiDefaultQPIndex = (U8)(8 - 5.0F * + args.fltImageQuality + 0.5F); + } + else + { + // remap [0.8, 0.866, 0.933, 1.0] to [0.8, 0.9, 1.0, 1.1] + // to use 8-bit DPK QP table (0.933 == Photoshop JPEG 100) + int qi; + float qf; + int* pQPs; + if (args.fltImageQuality > 0.8f && PI.bdBitDepth == BD_8 && + pEncoder->WMP.wmiSCP.cfColorFormat != YUV_420 && + pEncoder->WMP.wmiSCP.cfColorFormat != YUV_422) + args.fltImageQuality = 0.8f + (args.fltImageQuality - 0.8f) * 1.5f; + + qi = (int) (10.f * args.fltImageQuality); + qf = 10.f * args.fltImageQuality - (float) qi; + + pQPs = + (pEncoder->WMP.wmiSCP.cfColorFormat == YUV_420 || + pEncoder->WMP.wmiSCP.cfColorFormat == YUV_422) ? + DPK_QPS_420[qi] : + (PI.bdBitDepth == BD_8 ? DPK_QPS_8[qi] : + (PI.bdBitDepth == BD_16 ? DPK_QPS_16[qi] : + (PI.bdBitDepth == BD_16F ? DPK_QPS_16f[qi] : + DPK_QPS_32f[qi]))); + + pEncoder->WMP.wmiSCP.uiDefaultQPIndex = (U8) (0.5f + + (float) pQPs[0] * (1.f - qf) + (float) (pQPs + 6)[0] * qf); + pEncoder->WMP.wmiSCP.uiDefaultQPIndexU = (U8) (0.5f + + (float) pQPs[1] * (1.f - qf) + (float) (pQPs + 6)[1] * qf); + pEncoder->WMP.wmiSCP.uiDefaultQPIndexV = (U8) (0.5f + + (float) pQPs[2] * (1.f - qf) + (float) (pQPs + 6)[2] * qf); + pEncoder->WMP.wmiSCP.uiDefaultQPIndexYHP = (U8) (0.5f + + (float) pQPs[3] * (1.f - qf) + (float) (pQPs + 6)[3] * qf); + pEncoder->WMP.wmiSCP.uiDefaultQPIndexUHP = (U8) (0.5f + + (float) pQPs[4] * (1.f - qf) + (float) (pQPs + 6)[4] * qf); + pEncoder->WMP.wmiSCP.uiDefaultQPIndexVHP = (U8) (0.5f + + (float) pQPs[5] * (1.f - qf) + (float) (pQPs + 6)[5] * qf); + } + } + else + { + pEncoder->WMP.wmiSCP.uiDefaultQPIndex = (U8) args.fltImageQuality; + } + + if(pEncoder->WMP.wmiSCP.uAlphaMode == 2) + pEncoder->WMP.wmiSCP_Alpha.uiDefaultQPIndex = args.wmiSCP.uiDefaultQPIndexAlpha; + + Call(pEncoder->SetPixelFormat(pEncoder, args.guidPixFormat)); + + Call(pEncoder->SetSize(pEncoder, rect.Width, rect.Height)); + + Call(pDecoder->GetResolution(pDecoder, &rX, &rY)); + Call(pEncoder->SetResolution(pEncoder, rX, rY)); + + //================================ + // re-encode the input source to the output + // + pEncoder->WriteSource = PKImageEncode_WriteSource; + Call(pEncoder->WriteSource(pEncoder, pConverter, &rect)); + + pConverter->Release(&pConverter); + pDecoder->Release(&pDecoder); + + //if (i + 1 == 5) + //{ + // break; + //} + + // multi-frame support NYI + //Call(pEncoder->CreateNewFrame(pEncoder, &wmiSCP, sizeof(wmiSCP))); + } + +// Call(pEncoder->Terminate(pEncoder)); + pEncoder->Release(&pEncoder); + +Cleanup: + return (int)err; +} diff -Naur jxrlib-0.2.4/jxrgluelib/JXRGlueJxr.c jxrlib-0.2.4.new/jxrgluelib/JXRGlueJxr.c --- jxrlib-0.2.4/jxrgluelib/JXRGlueJxr.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrgluelib/JXRGlueJxr.c 2024-05-27 10:18:24.262052894 +0200 @@ -28,6 +28,7 @@ //*@@@---@@@@****************************************************************** #include #include +#include static const char szHDPhotoFormat[] = "image/vnd.ms-photo"; diff -Naur jxrlib-0.2.4/jxrgluelib/JXRGlueJxr.c~ jxrlib-0.2.4.new/jxrgluelib/JXRGlueJxr.c~ --- jxrlib-0.2.4/jxrgluelib/JXRGlueJxr.c~ 1970-01-01 01:00:00.000000000 +0100 +++ jxrlib-0.2.4.new/jxrgluelib/JXRGlueJxr.c~ 2024-05-27 10:10:05.550795509 +0200 @@ -0,0 +1,2280 @@ + +//*@@@+++@@@@****************************************************************** +// +// 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 +#include + + +static const char szHDPhotoFormat[] = "image/vnd.ms-photo"; +const U32 IFDEntryTypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 }; +const U32 SizeofIFDEntry = sizeof(struct IFDEntry); + + +void CalcMetadataSizeLPSTR(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbOffsetSize, + U32 *pcbCount) +{ + if (DPKVT_EMPTY != var.vt) + { + U32 uiLenWithNull = (U32)strlen(var.VT.pszVal) + 1; // +1 for NULL; + assert(DPKVT_LPSTR == var.vt); + + // We only use offset if size > 4 + if (uiLenWithNull > 4) + *pcbOffsetSize += uiLenWithNull; + + if (pcbCount) + *pcbCount = uiLenWithNull; + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbOffsetSize, + U32 *pcbCount) +{ + if (DPKVT_EMPTY != var.vt) + { + U32 uiCBWithNull = sizeof(U16) * ((U32)wcslen((wchar_t *) var.VT.pwszVal) + 1); // +1 for NULL term; + assert(DPKVT_LPWSTR == var.vt); + + // We only use offset if size > 4 + if (uiCBWithNull > 4) + *pcbOffsetSize += uiCBWithNull; + + if (pcbCount) + *pcbCount = uiCBWithNull; + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeUI2(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbMetadataSize) +{ + UNREFERENCED_PARAMETER( pcbMetadataSize ); + if (DPKVT_EMPTY != var.vt) + { + assert(DPKVT_UI2 == var.vt); + // This is a single UI2, so it will not be written via offset, but rather as value + } + else + *pcInactiveMetadata += 1; +} + +void CalcMetadataSizeUI4(const DPKPROPVARIANT var, + U16 *pcInactiveMetadata, + U32 *pcbContainer) +{ + UNREFERENCED_PARAMETER( pcbContainer ); + if (DPKVT_EMPTY != var.vt) + { + assert(DPKVT_UI4 == var.vt); + // This is a single UI4, so it will not be written via offset, but rather as value + } + else + *pcInactiveMetadata += 1; +} + +ERR CalcMetadataOffsetSize(PKImageEncode* pIE, + U16 *pcInactiveMetadata, + U32 *pcbMetadataSize) +{ + ERR err = WMP_errSuccess; + + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarImageDescription, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraMake, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraModel, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarSoftware, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDateTime, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarArtist, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCopyright, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingStars, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingValue, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeLPWSTR(pIE->sDescMetadata.pvarCaption, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDocumentName, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarPageName, pcInactiveMetadata, pcbMetadataSize, NULL); + CalcMetadataSizeUI4(pIE->sDescMetadata.pvarPageNumber, pcInactiveMetadata, pcbMetadataSize); + CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarHostComputer, pcInactiveMetadata, pcbMetadataSize, NULL); + + return err; +} + + +ERR CopyDescMetadata(DPKPROPVARIANT *pvarDst, + const DPKPROPVARIANT varSrc) +{ + ERR err = WMP_errSuccess; + size_t uiSize; + + pvarDst->vt = varSrc.vt; + switch (varSrc.vt) + { + case DPKVT_LPSTR: + pvarDst->vt = DPKVT_LPSTR; + uiSize = strlen(varSrc.VT.pszVal) + 1; + Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize)); + memmove(pvarDst->VT.pszVal, varSrc.VT.pszVal, uiSize); + break; + + case DPKVT_LPWSTR: + pvarDst->vt = DPKVT_LPWSTR; + uiSize = sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1); // +1 for NULL term + Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize)); + memmove(pvarDst->VT.pwszVal, varSrc.VT.pwszVal, uiSize); + break; + + case DPKVT_UI2: + pvarDst->VT.uiVal = varSrc.VT.uiVal; + break; + + case DPKVT_UI4: + pvarDst->VT.ulVal = varSrc.VT.ulVal; + break; + + default: + assert(FALSE); // This case is not handled + FailIf(TRUE, WMP_errNotYetImplemented); + + // *** FALL THROUGH *** + + case DPKVT_EMPTY: + memset(pvarDst, 0, sizeof(*pvarDst)); + assert(DPKVT_EMPTY == pvarDst->vt); + break; + } + +Cleanup: + return err; +} + + +void FreeDescMetadata(DPKPROPVARIANT *pvar) +{ + switch (pvar->vt) + { + case DPKVT_LPSTR: + PKFree((void **) &pvar->VT.pszVal); + break; + + case DPKVT_LPWSTR: + PKFree((void **) &pvar->VT.pwszVal); + break; + + default: + assert(FALSE); // This case is not handled + break; + + case DPKVT_EMPTY: + case DPKVT_UI2: + case DPKVT_UI4: + break; + } +} + + +ERR WriteDescMetadata(PKImageEncode *pIE, + const DPKPROPVARIANT var, + WmpDE *pwmpDE, + U32 *puiCurrDescMetadataOffset, + size_t *poffPos) +{ + ERR err = WMP_errSuccess; + WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; + struct WMPStream* pWS = pIE->pStream; + U32 uiMetadataOffsetSize = 0; + U32 uiCount = 0; + U32 uiDataWrittenToOffset = 0; + U16 uiTemp = 0; + + if (0 == pDEMisc->uDescMetadataOffset || 0 == pDEMisc->uDescMetadataByteCount) + goto Cleanup; // Nothing to do here + + // Sanity check before - can be equal due to remaining metadata being DPKVT_EMPTY + assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); + + switch (var.vt) + { + case DPKVT_EMPTY: + break; + + case DPKVT_LPSTR: + CalcMetadataSizeLPSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount); + pwmpDE->uCount = uiCount; + pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pszVal, &uiDataWrittenToOffset)); + break; + + case DPKVT_LPWSTR: + CalcMetadataSizeLPWSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount); + pwmpDE->uCount = uiCount; + pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pwszVal, &uiDataWrittenToOffset)); + break; + + case DPKVT_UI2: + CalcMetadataSizeUI2(var, &uiTemp, &uiMetadataOffsetSize); + pwmpDE->uCount = 1; + pwmpDE->uValueOrOffset = var.VT.uiVal; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL)); + break; + + case DPKVT_UI4: + CalcMetadataSizeUI4(var, &uiTemp, &uiMetadataOffsetSize); + pwmpDE->uCount = 1; + pwmpDE->uValueOrOffset = var.VT.ulVal; + Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL)); + break; + + default: + assert(FALSE); // This case is not handled + FailIf(TRUE, WMP_errNotYetImplemented); + break; + } + + *puiCurrDescMetadataOffset += uiDataWrittenToOffset; + + // Sanity check after + assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); // Can be equal + +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; + U32 cbMetadataOffsetSize = 0; + U16 cInactiveMetadata = 0; + U32 uiCurrDescMetadataOffset = 0; + + static WmpDE wmpDEs[] = + { + {WMP_tagDocumentName, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagImageDescription, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCameraMake, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCameraModel, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagPageName, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagPageNumber, WMP_typSHORT, 2, (U32) -1}, // Descriptive metadata + {WMP_tagSoftware, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagDateTime, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagArtist, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagHostComputer, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagRatingStars, WMP_typSHORT, 1, (U32) -1}, // Descriptive metadata + {WMP_tagRatingValue, WMP_typSHORT, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCopyright, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata + {WMP_tagCaption, WMP_typBYTE, 1, (U32) -1}, // Descriptive metadata + + {WMP_tagXMPMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagIPTCNAAMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagPhotoshopMetadata, WMP_typBYTE, 1, (U32) -1}, + {WMP_tagEXIFMetadata, WMP_typLONG, 1, (U32) -1}, + {WMP_tagIccProfile, WMP_typUNDEFINED, 1, (U32) -1}, + {WMP_tagGPSInfoMetadata, WMP_typLONG, 1, (U32) -1}, + + {WMP_tagPixelFormat, WMP_typBYTE, 16, (U32) -1}, + {WMP_tagTransformation, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageWidth, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageHeight, WMP_typLONG, 1, (U32) -1}, + {WMP_tagWidthResolution, WMP_typFLOAT, 1, (U32) -1}, + {WMP_tagHeightResolution, WMP_typFLOAT, 1, (U32) -1}, + {WMP_tagImageOffset, WMP_typLONG, 1, (U32) -1}, + {WMP_tagImageByteCount, WMP_typLONG, 1, (U32) -1}, + {WMP_tagAlphaOffset, WMP_typLONG, 1, (U32) -1}, + {WMP_tagAlphaByteCount, WMP_typLONG, 1, (U32) -1}, + }; + U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]); + WmpDE wmpDE = {0}; + size_t i = 0; + + U8* pbEXIFMetadata = NULL; + U8* pbGPSInfoMetadata = NULL; + + // const unsigned char Zero[0x20] = { 0 }; + const unsigned char Zero[sizeof(struct IFDEntry) * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32)] = { 0 }; + assert(SizeofIFDEntry * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32) > 0x20); + + //================ + 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; + } + + //================ + // Tally up space required for descriptive metadata + Call(CalcMetadataOffsetSize(pIE, &cInactiveMetadata, &cbMetadataOffsetSize)); + cWmpDEs -= cInactiveMetadata; + + //================ + // PFD + assert (offPos <= OFFSET_OF_PFD); // otherwise stuff is overwritten + if (offPos < OFFSET_OF_PFD) + Call(pWS->Write(pWS, Zero, OFFSET_OF_PFD - offPos)); + offPos = (size_t)OFFSET_OF_PFD; + + if (!pIE->WMP.bHasAlpha || pIE->WMP.wmiSCP.uAlphaMode != 2) //no planar alpha + cWmpDEs -= 2; + + if (0 == pIE->cbXMPMetadataByteCount) + cWmpDEs -= 1; // No XMP metadata + + if (0 == pIE->cbIPTCNAAMetadataByteCount) + cWmpDEs -= 1; // No IPTCNAA metadata + + if (0 == pIE->cbPhotoshopMetadataByteCount) + cWmpDEs -= 1; // No Photoshop metadata + + if (0 == pIE->cbEXIFMetadataByteCount) + cWmpDEs -= 1; // No EXIF metadata + + if (0 == pIE->cbColorContext) + cWmpDEs -= 1; // No color context + + if (0 == pIE->cbGPSInfoMetadataByteCount) + cWmpDEs -= 1; // No GPSInfo metadata + + pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + SizeofIFDEntry * cWmpDEs + sizeof(U32)); + + if (cbMetadataOffsetSize > 0) + { + pDEMisc->uDescMetadataByteCount = cbMetadataOffsetSize; + pDEMisc->uDescMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += cbMetadataOffsetSize; + } + + if (pIE->cbXMPMetadataByteCount > 0) + { + pDEMisc->uXMPMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbXMPMetadataByteCount; + } + + if (pIE->cbIPTCNAAMetadataByteCount > 0) + { + pDEMisc->uIPTCNAAMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbIPTCNAAMetadataByteCount; + } + + if (pIE->cbPhotoshopMetadataByteCount > 0) + { + pDEMisc->uPhotoshopMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbPhotoshopMetadataByteCount; + } + + if (pIE->cbEXIFMetadataByteCount > 0) + { + pDEMisc->uEXIFMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1); + pDEMisc->uImageOffset += pIE->cbEXIFMetadataByteCount; + } + + if (pIE->cbColorContext > 0) + { + pDEMisc->uColorProfileOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += pIE->cbColorContext; + } + + if (pIE->cbGPSInfoMetadataByteCount > 0) + { + pDEMisc->uGPSInfoMetadataOffset = pDEMisc->uImageOffset; + pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1); + pDEMisc->uImageOffset += pIE->cbGPSInfoMetadataByteCount; + } + + Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2; + Call(pWS->Write(pWS, Zero, SizeofIFDEntry * cWmpDEs + sizeof(U32))); + + //================ + wmpDE = wmpDEs[i++]; + assert(WMP_tagDocumentName == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDocumentName, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageDescription == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarImageDescription, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCameraMake == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraMake, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCameraModel == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraModel, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPageName == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageName, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPageNumber == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageNumber, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagSoftware == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarSoftware, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagDateTime == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDateTime, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagArtist == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarArtist, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagHostComputer == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarHostComputer, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagRatingStars == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingStars, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagRatingValue == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingValue, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCopyright == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCopyright, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagCaption == wmpDE.uTag); + Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCaption, &wmpDE, + &uiCurrDescMetadataOffset, &offPos)); + + // XMP Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagXMPMetadata == wmpDE.uTag); + if (pIE->cbXMPMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbXMPMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uXMPMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbXMPMetadata, &uiTemp)); + } + + // IPTCNAA Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagIPTCNAAMetadata == wmpDE.uTag); + if (pIE->cbIPTCNAAMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbIPTCNAAMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uIPTCNAAMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbIPTCNAAMetadata, &uiTemp)); + } + + // Photoshop Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagPhotoshopMetadata == wmpDE.uTag); + if (pIE->cbPhotoshopMetadataByteCount > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbPhotoshopMetadataByteCount; + wmpDE.uValueOrOffset = pDEMisc->uPhotoshopMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbPhotoshopMetadata, &uiTemp)); + } + + // EXIF Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagEXIFMetadata == wmpDE.uTag); + if (pIE->cbEXIFMetadataByteCount > 0) + { + U32 uiTemp; + if ((pDEMisc->uEXIFMetadataOffset & 1) != 0) + { + Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset)); + Call(pWS->Write(pWS, Zero, 1)); + } + pDEMisc->uEXIFMetadataOffset += (pDEMisc->uEXIFMetadataOffset & 1); + wmpDE.uValueOrOffset = pDEMisc->uEXIFMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + Call(PKAlloc((void **) &pbEXIFMetadata, pIE->cbEXIFMetadataByteCount)); + uiTemp = pDEMisc->uEXIFMetadataOffset; + Call(BufferCopyIFD(pIE->pbEXIFMetadata, pIE->cbEXIFMetadataByteCount, 0, WMP_INTEL_ENDIAN, + pbEXIFMetadata - uiTemp, uiTemp + pIE->cbEXIFMetadataByteCount, &uiTemp)); + Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset)); + Call(pWS->Write(pWS, pbEXIFMetadata, pIE->cbEXIFMetadataByteCount)); + } + + // ICC Profile + wmpDE = wmpDEs[i++]; + assert(WMP_tagIccProfile == wmpDE.uTag); + if (pIE->cbColorContext > 0) + { + U32 uiTemp; + wmpDE.uCount = pIE->cbColorContext; + wmpDE.uValueOrOffset = pDEMisc->uColorProfileOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbColorContext, &uiTemp)); + } + + // GPSInfo Metadata + wmpDE = wmpDEs[i++]; + assert(WMP_tagGPSInfoMetadata == wmpDE.uTag); + if (pIE->cbGPSInfoMetadataByteCount > 0) + { + U32 uiTemp; + if ((pDEMisc->uGPSInfoMetadataOffset & 1) != 0) + { + Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset)); + Call(pWS->Write(pWS, Zero, 1)); + } + pDEMisc->uGPSInfoMetadataOffset += (pDEMisc->uGPSInfoMetadataOffset & 1); + wmpDE.uValueOrOffset = pDEMisc->uGPSInfoMetadataOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + Call(PKAlloc((void **) &pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount)); + uiTemp = pDEMisc->uGPSInfoMetadataOffset; + Call(BufferCopyIFD(pIE->pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount, 0, WMP_INTEL_ENDIAN, + pbGPSInfoMetadata - uiTemp, uiTemp + pIE->cbGPSInfoMetadataByteCount, &uiTemp)); + Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset)); + Call(pWS->Write(pWS, pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount)); + } + + wmpDE = wmpDEs[i++]; + assert(WMP_tagPixelFormat == wmpDE.uTag); + wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagTransformation == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->WMP.oOrientation; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageWidth == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->uWidth; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageHeight == wmpDE.uTag); + wmpDE.uValueOrOffset = pIE->uHeight; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagWidthResolution == wmpDE.uTag); + *((float *) &wmpDE.uValueOrOffset) = pIE->fResX; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagHeightResolution == wmpDE.uTag); + *((float *) &wmpDE.uValueOrOffset) = pIE->fResY; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageOffset == wmpDE.uTag); + wmpDE.uValueOrOffset = pDEMisc->uImageOffset; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagImageByteCount == wmpDE.uTag); + pDEMisc->uOffImageByteCount = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagAlphaOffset == wmpDE.uTag); + pDEMisc->uOffAlphaOffset = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + + // fix up in WriteContainerPost() + wmpDE = wmpDEs[i++]; + assert(WMP_tagAlphaByteCount == wmpDE.uTag); + pDEMisc->uOffAlphaByteCount = (U32)offPos; + wmpDE.uValueOrOffset = 0; + Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL)); + } + + //================ + Call(PutULong(pWS, offPos, 0)); offPos += 4; + + assert(0 == (offPos & 1)); + if (pDEMisc->uColorProfileOffset > 0 || pDEMisc->uDescMetadataOffset > 0 || + pDEMisc->uXMPMetadataOffset > 0 || pDEMisc->uIPTCNAAMetadataOffset > 0 || + pDEMisc->uPhotoshopMetadataOffset > 0 || pDEMisc->uEXIFMetadataOffset > 0 || + pDEMisc->uGPSInfoMetadataOffset > 0) + { + assert(pDEMisc->uColorProfileOffset == offPos || + pDEMisc->uDescMetadataOffset == offPos || + pDEMisc->uXMPMetadataOffset == offPos || + pDEMisc->uIPTCNAAMetadataOffset == offPos || + pDEMisc->uPhotoshopMetadataOffset == offPos || + pDEMisc->uEXIFMetadataOffset == offPos || + pDEMisc->uGPSInfoMetadataOffset == offPos); + + // OK, now skip to image offset + Call(pWS->SetPos(pWS, pDEMisc->uImageOffset)); + offPos = pDEMisc->uImageOffset; + } + assert(pDEMisc->uImageOffset == offPos); + +Cleanup: + if (pbEXIFMetadata != NULL) + PKFree((void **) &pbEXIFMetadata); + if (pbGPSInfoMetadata != NULL) + PKFree((void **) &pbGPSInfoMetadata); + return err; +} + + + +ERR WriteContainerPost( + PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + struct WMPStream* pWS = pIE->pStream; + WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc; + size_t offPos; + + WmpDE deImageByteCount = {WMP_tagImageByteCount, WMP_typLONG, 1, 0}; + WmpDE deAlphaOffset = {WMP_tagAlphaOffset, WMP_typLONG, 1, 0}; + WmpDE deAlphaByteCount = {WMP_tagAlphaByteCount, WMP_typLONG, 1, 0}; + + deImageByteCount.uValueOrOffset = pIE->WMP.nCbImage; + offPos = pDEMisc->uOffImageByteCount; + Call(WriteWmpDE(pWS, &offPos, &deImageByteCount, NULL, NULL)); + + //Alpha + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + deAlphaOffset.uValueOrOffset = pIE->WMP.nOffAlpha; + offPos = pDEMisc->uOffAlphaOffset; + Call(WriteWmpDE(pWS, &offPos, &deAlphaOffset, NULL, NULL)); + + deAlphaByteCount.uValueOrOffset = pIE->WMP.nCbAlpha + pIE->WMP.nOffAlpha; + offPos = pDEMisc->uOffAlphaByteCount; + Call(WriteWmpDE(pWS, &offPos, &deAlphaByteCount, NULL, NULL)); + } + +Cleanup: + return err; +} + + +//================================================ +ERR PKImageEncode_Initialize_WMP( + PKImageEncode* pIE, + struct WMPStream* pStream, + void* pvParam, + size_t cbParam) +{ + ERR err = WMP_errSuccess; + + FailIf(sizeof(pIE->WMP.wmiSCP) != cbParam, WMP_errInvalidArgument); + + pIE->WMP.wmiSCP = *(CWMIStrCodecParam*)pvParam; + pIE->WMP.wmiSCP_Alpha = *(CWMIStrCodecParam*)pvParam; + pIE->pStream = pStream; + + pIE->WMP.wmiSCP.pWStream = pIE->pStream; + pIE->WMP.wmiSCP_Alpha.pWStream = pIE->pStream; + +Cleanup: + return err; +} + +ERR PKImageEncode_Terminate_WMP( + PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + UNREFERENCED_PARAMETER( pIE ); + return err; +} + + +ERR PKImageEncode_EncodeContent_Init( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + + // init codec + pIE->WMP.wmiI.cWidth = pIE->uWidth; + pIE->WMP.wmiI.cHeight = pIE->uHeight; + pIE->WMP.wmiI.bdBitDepth = PI.bdBitDepth; + pIE->WMP.wmiI.cBitsPerUnit = PI.cbitUnit; + pIE->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR); + pIE->WMP.wmiI.cfColorFormat = PI.cfColorFormat; + pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation; + + // Set the fPaddedUserBuffer if the following conditions are met + if (0 == ((size_t)pbPixels % 128) && // Frame buffer is aligned to 128-byte boundary + 0 == (pIE->uWidth % 16) && // Horizontal resolution is multiple of 16 + 0 == (cLine % 16) && // Vertical resolution is multiple of 16 + 0 == (cbStride % 128)) // Stride is a multiple of 128 bytes + { + pIE->WMP.wmiI.fPaddedUserBuffer = TRUE; + // Note that there are additional conditions in strenc_x86.c's strEncOpt + // which could prevent optimization from being engaged + } + + //if (pIE->WMP.bHasAlpha) + //{ + // pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1; + // pIE->WMP.wmiI.cfColorFormat = PI.cfStripAlpha; + //} + //else + + if(PI.cfColorFormat == NCOMPONENT && (!(PI.grBit & PK_pixfmtHasAlpha)))//N-channel without Alpha + pIE->WMP.wmiSCP.cChannel = PI.cChannel; + else + pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;//other formats and (N-channel + Alpha) + + pIE->idxCurrentLine = 0; + + pIE->WMP.wmiSCP.fMeasurePerf = TRUE; + FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI, &pIE->WMP.wmiSCP, &pIE->WMP.ctxSC), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent_Encode( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 i = 0; + + //================================ + for (i = 0; i < cLine; i += 16) + { + Bool f420 = ( pIE->WMP.wmiI.cfColorFormat == YUV_420 || + (pIE->WMP.wmiSCP.bYUVData && pIE->WMP.wmiSCP.cfColorFormat==YUV_420) ); + CWMImageBufferInfo wmiBI = { 0 }; + wmiBI.pv = pbPixels + cbStride * i / (f420 ? 2 : 1); + wmiBI.cLine = min(16, cLine - i); + wmiBI.cbStride = cbStride; + FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC, &wmiBI), WMP_errFail); + } + pIE->idxCurrentLine += cLine; + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent_Term(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeContent( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + size_t offPos = 0; + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nOffImage = (Long)offPos; + + Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeContent_Term(pIE)); + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage; + +Cleanup: + return err; +} + + +ERR PKImageEncode_EncodeAlpha_Init( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( cLine ); + UNREFERENCED_PARAMETER( pbPixels ); + UNREFERENCED_PARAMETER( cbStride ); + + pIE->WMP.wmiI_Alpha = pIE->WMP.wmiI; + + pIE->WMP.wmiI_Alpha.cWidth = pIE->uWidth; + pIE->WMP.wmiI_Alpha.cHeight = pIE->uHeight; + pIE->WMP.wmiI_Alpha.bdBitDepth = PI.bdBitDepth; + pIE->WMP.wmiI_Alpha.cBitsPerUnit = PI.cbitUnit; + pIE->WMP.wmiI_Alpha.bRGB = !(PI.grBit & PK_pixfmtBGR); + pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation; +// pIE->WMP.wmiI_Alpha.cLeadingPadding += pIE->WMP.wmiSCP.cChannel; +// pIE->WMP.wmiI_Alpha.cLeadingPadding += PI.cChannel - 1; + + switch (pIE->WMP.wmiI.bdBitDepth) + { + case BD_8: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) - 1; + break; + + case BD_16: + case BD_16S: + case BD_16F: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1; + break; + + case BD_32: + case BD_32S: + case BD_32F: + pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1; + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + +// pIE->WMP.wmiSCP_Alpha.uAlphaMode = 1; + + + //assert(pIE->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now! + pIE->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY; + + pIE->WMP.wmiSCP_Alpha.cfColorFormat = Y_ONLY; + + pIE->idxCurrentLine = 0; + pIE->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE; + FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI_Alpha, &pIE->WMP.wmiSCP_Alpha, &pIE->WMP.ctxSC_Alpha), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha_Encode( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 i = 0; + + //================================ + for (i = 0; i < cLine; i += 16) + { + CWMImageBufferInfo wmiBI = { 0 }; + wmiBI.pv = pbPixels + cbStride * i; + wmiBI.cLine = min(16, cLine - i); + wmiBI.cbStride = cbStride; + FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail); + } + pIE->idxCurrentLine += cLine; + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha_Term(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + + FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC_Alpha), WMP_errFail); + +Cleanup: + return err; +} + +ERR PKImageEncode_EncodeAlpha( + PKImageEncode* pIE, + PKPixelInfo PI, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + size_t offPos = 0; + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + if ((offPos & 1) != 0) + { + // Make the mark even if it is odd by inserting a pad byte + char zero = 0; + Call(pIE->pStream->Write(pIE->pStream, &zero, 1)); + offPos++; + } + pIE->WMP.nOffAlpha = (Long)offPos; + + Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride)); + Call(PKImageEncode_EncodeAlpha_Term(pIE)); + + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha; + +Cleanup: + return err; +} + + + +static ERR SetMetadata(PKImageEncode *pIE, const U8 *pbMetadata, U32 cbMetadata, U8** pbSet, U32* pcbSet) +{ + ERR err = WMP_errSuccess; + + // Fail if the caller called us after we've already written the header out + if (pIE->fHeaderDone) + { + assert(FALSE); // Message to programmer + err = WMP_errOutOfSequence; + goto Cleanup; + } + + // Make a copy of the metadata + PKFree((void **) pbSet); + *pcbSet = 0; + + Call(PKAlloc((void **) pbSet, cbMetadata)); + memmove(*pbSet, pbMetadata, cbMetadata); + *pcbSet = cbMetadata; + +Cleanup: + return err; +} + + + +ERR PKImageEncode_SetColorContext_WMP(PKImageEncode *pIE, + const U8 *pbColorContext, + U32 cbColorContext) +{ + return SetMetadata(pIE, pbColorContext, cbColorContext, &pIE->pbColorContext, &pIE->cbColorContext); +} + + + +ERR PKImageEncode_SetXMPMetadata_WMP(PKImageEncode *pIE, const U8 *pbXMPMetadata, U32 cbXMPMetadata) +{ // same as the other Set's, but make sure dc:format is image/vnd.ms-photo + ERR err = WMP_errSuccess; + char* pbTemp = 0; + U32 cbTemp; + char* pszFormatBegin; + // const char* pszXMPMetadata = (const char*)pbXMPMetadata; + size_t cbBuffer; + + // Fail if the caller called us after we've already written the header out + FailIf(pIE->fHeaderDone, WMP_errOutOfSequence); + + // Free any previously set XMP metadata + PKFree((void **) &pIE->pbXMPMetadata); + pIE->cbXMPMetadataByteCount = 0; + + // allocate a block big enough for data passed in plus added trailing null plus added HD Photo dc:format + // there may already be a trailing null (but ps doesn't seem to) + // there may already be a dc:format we will replace with HD Photo's + // but anyway this block will be large enough guaranteed + cbBuffer = cbXMPMetadata + 1 + sizeof("") - 1 + sizeof("") - 1 + sizeof(szHDPhotoFormat) - 1; + Call(PKAlloc((void **) &pbTemp, cbBuffer)); + memmove(pbTemp, pbXMPMetadata, cbXMPMetadata); // Make a copy of the metadata + pbTemp[cbXMPMetadata] = '\0'; + cbXMPMetadata = (U32)strlen(pbTemp); + pszFormatBegin = strstr(pbTemp, ""); + if ( pszFormatBegin != 0 ) + { + char* pszFormatEnd; + const char* pszLessThan; + + pszFormatEnd = strstr(pszFormatBegin, ""); + FailIf(pszFormatEnd == 0, WMP_errFail); + pszLessThan = strchr(pszFormatBegin + sizeof("") - 1, '<'); + FailIf(pszLessThan != pszFormatEnd, WMP_errFail); + pszFormatEnd += sizeof("") - 1; + + // photoshop doesn't put a trailing null, so we don't either + // hd and tiff don't put a trailing null, so we don't either + cbTemp = cbXMPMetadata - (U32) ( pszFormatEnd - pszFormatBegin ) + sizeof(szHDPhotoFormat) - 1; + assert(cbTemp <= cbBuffer); + FailIf(0 != STRCPY_SAFE(pszFormatBegin, + cbBuffer - (pszFormatBegin - pbTemp), + szHDPhotoFormat), + WMP_errBufferOverflow); + memmove(pszFormatBegin + sizeof(szHDPhotoFormat) - 1, pbXMPMetadata + ( pszFormatEnd - pbTemp ), + cbXMPMetadata - ( pszFormatEnd - pbTemp )); + } + else + { + cbTemp = cbXMPMetadata; + } + + pIE->pbXMPMetadata = (U8 *) pbTemp; + pIE->cbXMPMetadataByteCount = cbTemp; + return ( err ); + +Cleanup: + PKFree((void **) &pbTemp); + pIE->cbXMPMetadataByteCount = 0; + return err; +} + + + +ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata) +{ + return SetMetadata(pIE, pbEXIFMetadata, cbEXIFMetadata, + &pIE->pbEXIFMetadata, &pIE->cbEXIFMetadataByteCount); +} + + + +ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata) +{ + return SetMetadata(pIE, pbGPSInfoMetadata, cbGPSInfoMetadata, + &pIE->pbGPSInfoMetadata, &pIE->cbGPSInfoMetadataByteCount); +} + + + +ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata) +{ + return SetMetadata(pIE, pbIPTCNAAMetadata, cbIPTCNAAMetadata, + &pIE->pbIPTCNAAMetadata, &pIE->cbIPTCNAAMetadataByteCount); +} + + + +ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata) +{ + return SetMetadata(pIE, pbPhotoshopMetadata, cbPhotoshopMetadata, + &pIE->pbPhotoshopMetadata, &pIE->cbPhotoshopMetadataByteCount); +} + + + +ERR PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pSrcMeta) +{ + ERR err = WMP_errSuccess; + DESCRIPTIVEMETADATA *pDstMeta = &pIE->sDescMetadata; + + // Fail if the caller called us after we've already written the header out + if (pIE->fHeaderDone) + { + assert(FALSE); // Message to programmer + FailIf(TRUE, WMP_errOutOfSequence); + } + + // Make a copy of the descriptive metadata + Call(CopyDescMetadata(&pDstMeta->pvarImageDescription, pSrcMeta->pvarImageDescription)); + Call(CopyDescMetadata(&pDstMeta->pvarCameraMake, pSrcMeta->pvarCameraMake)); + Call(CopyDescMetadata(&pDstMeta->pvarCameraModel, pSrcMeta->pvarCameraModel)); + Call(CopyDescMetadata(&pDstMeta->pvarSoftware, pSrcMeta->pvarSoftware)); + Call(CopyDescMetadata(&pDstMeta->pvarDateTime, pSrcMeta->pvarDateTime)); + Call(CopyDescMetadata(&pDstMeta->pvarArtist, pSrcMeta->pvarArtist)); + Call(CopyDescMetadata(&pDstMeta->pvarCopyright, pSrcMeta->pvarCopyright)); + Call(CopyDescMetadata(&pDstMeta->pvarRatingStars, pSrcMeta->pvarRatingStars)); + Call(CopyDescMetadata(&pDstMeta->pvarRatingValue, pSrcMeta->pvarRatingValue)); + Call(CopyDescMetadata(&pDstMeta->pvarCaption, pSrcMeta->pvarCaption)); + Call(CopyDescMetadata(&pDstMeta->pvarDocumentName, pSrcMeta->pvarDocumentName)); + Call(CopyDescMetadata(&pDstMeta->pvarPageName, pSrcMeta->pvarPageName)); + Call(CopyDescMetadata(&pDstMeta->pvarPageNumber, pSrcMeta->pvarPageNumber)); + Call(CopyDescMetadata(&pDstMeta->pvarHostComputer, pSrcMeta->pvarHostComputer)); + +Cleanup: + return err; +} + + + +ERR PKImageEncode_WritePixels_WMP( + PKImageEncode* pIE, + U32 cLine, + U8* pbPixels, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + // U32 i = 0; + PKPixelInfo PI; + + // Performing non-banded encode + assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_NONBANDEDENCODE; + + 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; + } +*/ + Call(PKImageEncode_EncodeContent(pIE, PI, cLine, pbPixels, cbStride)); + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){//planar alpha + Call(PKImageEncode_EncodeAlpha(pIE, PI, cLine, pbPixels, cbStride)); + } + + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + + +ERR PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode* pIE, struct WMPStream *pPATempFile) +{ + ERR err = WMP_errSuccess; + + // Just make sure that we are in the correct state to begin a banded decode + assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_INIT; + + // Save the planar alpha tempfile for future use + pIE->WMP.pPATempFile = pPATempFile; + +//Cleanup: + return err; +} + +ERR PKImageEncode_WritePixelsBanded_WMP(PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride, Bool fLastCall) +{ + ERR err = WMP_errSuccess; + PKPixelInfo PI = {0}; + Bool fPI = FALSE; + BANDEDENCSTATE eEncStateOrig = pIE->WMP.eBandedEncState; + struct WMPStream *pPATempFile = pIE->WMP.pPATempFile; + + // Unless this is the last call, reject inputs which are not multiples of 16 + FailIf(!fLastCall && 0 != cLine % 16, WMP_errMustBeMultipleOf16LinesUntilLastCall); + + if (!pIE->fHeaderDone || BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState) + { + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha); + fPI = TRUE; + + // Check if this is planar alpha: banded encode requires temp file + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + FailIf(NULL == pPATempFile, WMP_errPlanarAlphaBandedEncRequiresTempFile); + } + } + + if (!pIE->fHeaderDone) + { + // write metadata + assert(fPI); + Call(WriteContainerPre(pIE)); + pIE->fHeaderDone = !FALSE; + } + + if (BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState) + { + // Record start of main content for future call to WriteContainerPost + size_t offPos; + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nOffImage = (Long)offPos; + + assert(fPI); + Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride)); + pIE->WMP.eBandedEncState = BANDEDENCSTATE_ENCODING; + } + + Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride)); + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + //planar alpha + if (BANDEDENCSTATE_INIT == eEncStateOrig) + { + size_t offStart; + + // We assume the following which allows us to avoid saving state + Call(pPATempFile->GetPos(pPATempFile, &offStart)); + assert(0 == offStart); + assert(pIE->WMP.wmiSCP_Alpha.pWStream == pIE->WMP.wmiSCP.pWStream); + + // For planar alpha, we write the file to a temp file + pIE->WMP.wmiSCP_Alpha.pWStream = pPATempFile; + Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride)); + } + + Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride)); + } + +Cleanup: + return err; +} + +ERR PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode* pIE) +{ + ERR err = WMP_errSuccess; + struct WMPStream *pMainStream = pIE->WMP.wmiSCP.pWStream; + size_t offAlpha; + + assert(BANDEDENCSTATE_ENCODING == pIE->WMP.eBandedEncState); + + // Finish off main content, update its length ptr for WriteContainerPost + Call(PKImageEncode_EncodeContent_Term(pIE)); + Call(pMainStream->GetPos(pIE->pStream, &offAlpha)); + pIE->WMP.nCbImage = (Long)offAlpha - pIE->WMP.nOffImage; + + if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2) + { + size_t cbAlpha; + size_t cbBytesCopied; + struct WMPStream *pAlphaStream = pIE->WMP.wmiSCP_Alpha.pWStream; + + assert(pAlphaStream != pMainStream); // Otherwise we didn't use a temp file + + // Close it up - this causes write to temp file + Call(PKImageEncode_EncodeAlpha_Term(pIE)); + + // Calculate size of alpha bitstream and its new offset + Call(pAlphaStream->GetPos(pAlphaStream, &cbAlpha)); + + // Copy alpha bitstream to end of main stream + cbBytesCopied = 0; + Call(pAlphaStream->SetPos(pAlphaStream, 0)); + while (cbBytesCopied < cbAlpha) + { + char rgbBuf[TEMPFILE_COPYBUF_SIZE]; + size_t cbCopy; + + cbCopy = min(sizeof(rgbBuf), cbAlpha - cbBytesCopied); + Call(pAlphaStream->Read(pAlphaStream, rgbBuf, cbCopy)); + Call(pMainStream->Write(pMainStream, rgbBuf, cbCopy)); + + cbBytesCopied += cbCopy; + } + assert(cbBytesCopied == cbAlpha); + + // Update alpha offset/length for WriteContainerPost + pIE->WMP.nOffAlpha = (Long)offAlpha; + pIE->WMP.nCbAlpha = (Long)cbAlpha; + } + + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + + +ERR PKImageEncode_Transcode_WMP( + PKImageEncode* pIE, + PKImageDecode* pID, + CWMTranscodingParam* pParam) +{ + ERR err = WMP_errSuccess; + Float fResX = 0, fResY = 0; + PKPixelFormatGUID pixGUID = {0}; + CWMTranscodingParam tcParamAlpha; + size_t offPos = 0; + Bool fPlanarAlpha; + PKPixelInfo PI; + + struct WMPStream* pWSDec = NULL; + struct WMPStream* pWSEnc= pIE->pStream; + + // pass through metadata + Call(pID->GetPixelFormat(pID, &pixGUID)); + Call(pIE->SetPixelFormat(pIE, pixGUID)); + + Call(pIE->SetSize(pIE, (I32)pParam->cWidth, (I32)pParam->cHeight)); + + Call(pID->GetResolution(pID, &fResX, &fResY)); + Call(pIE->SetResolution(pIE, fResX, fResY)); + + PI.pGUIDPixFmt = &pIE->guidPixFormat; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha) && (2 == pParam->uAlphaMode); + assert(0 == pIE->WMP.bHasAlpha || (pParam->uAlphaMode == 2)); // Decode alpha mode does not match encode alpha mode! + + // Check for any situations where transcoder is being asked to convert alpha - we can't do this + // NOTE: Decoder's bHasAlpha parameter really means, "has PLANAR alpha" + PI.pGUIDPixFmt = &pixGUID; + PixelFormatLookup(&PI, LOOKUP_FORWARD); + FailIf(0 == (PI.grBit & PK_pixfmtHasAlpha) && pParam->uAlphaMode != 0, + WMP_errAlphaModeCannotBeTranscoded); // Destination is planar/interleaved, src has no alpha + FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 2 == pParam->uAlphaMode && + FALSE == pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded); // Destination is planar, src is interleaved + FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 3 == pParam->uAlphaMode && + pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded); // Destination is interleaved, src is planar + assert(/*pParam->uAlphaMode >= 0 &&*/ pParam->uAlphaMode <= 3); // All the above statements make this assumption + + fPlanarAlpha = pIE->WMP.bHasAlpha && (2 == pParam->uAlphaMode); + + // write matadata + Call(WriteContainerPre(pIE)); + + // Copy transcoding params for alpha (codec changes the struct) + if (fPlanarAlpha) + tcParamAlpha = *pParam; + + // write compressed bitstream + Call(pID->GetRawStream(pID, &pWSDec)); + + FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, pParam), WMP_errFail); + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage; + + if (fPlanarAlpha) + { + pIE->WMP.nOffAlpha = (Long)offPos; + + // Cue the stream to alpha block + assert(pID->WMP.wmiDEMisc.uAlphaOffset > 0); + Call(pWSDec->SetPos(pWSDec, pID->WMP.wmiDEMisc.uAlphaOffset)); + + FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, &tcParamAlpha), WMP_errFail); + Call(pIE->pStream->GetPos(pIE->pStream, &offPos)); + pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha; + } + + // fixup matadata + Call(WriteContainerPost(pIE)); + +Cleanup: + return err; +} + +ERR PKImageEncode_CreateNewFrame_WMP( + PKImageEncode* pIE, + void* pvParam, + size_t cbParam) +{ + ERR err = WMP_errSuccess; + + UNREFERENCED_PARAMETER( pIE ); + UNREFERENCED_PARAMETER( pvParam ); + UNREFERENCED_PARAMETER( cbParam ); + + Call(WMP_errNotYetImplemented); + +Cleanup: + return err; +} + +ERR PKImageEncode_Release_WMP( + PKImageEncode** ppIE) +{ + ERR err = WMP_errSuccess; + + PKImageEncode *pIE = *ppIE; + pIE->pStream->Close(&pIE->pStream); + + PKFree((void **) &pIE->pbColorContext); + pIE->cbColorContext = 0; + PKFree((void **) &pIE->pbXMPMetadata); + pIE->cbXMPMetadataByteCount = 0; + PKFree((void **) &pIE->pbEXIFMetadata); + pIE->cbEXIFMetadataByteCount = 0; + PKFree((void **) &pIE->pbGPSInfoMetadata); + pIE->cbGPSInfoMetadataByteCount = 0; + PKFree((void **) &pIE->pbIPTCNAAMetadata); + pIE->cbIPTCNAAMetadataByteCount = 0; + PKFree((void **) &pIE->pbPhotoshopMetadata); + pIE->cbPhotoshopMetadataByteCount = 0; + + // Free descriptive metadata + FreeDescMetadata(&pIE->sDescMetadata.pvarImageDescription); + FreeDescMetadata(&pIE->sDescMetadata.pvarCameraMake); + FreeDescMetadata(&pIE->sDescMetadata.pvarCameraModel); + FreeDescMetadata(&pIE->sDescMetadata.pvarSoftware); + FreeDescMetadata(&pIE->sDescMetadata.pvarDateTime); + FreeDescMetadata(&pIE->sDescMetadata.pvarArtist); + FreeDescMetadata(&pIE->sDescMetadata.pvarCopyright); + FreeDescMetadata(&pIE->sDescMetadata.pvarRatingStars); + FreeDescMetadata(&pIE->sDescMetadata.pvarRatingValue); + FreeDescMetadata(&pIE->sDescMetadata.pvarCaption); + FreeDescMetadata(&pIE->sDescMetadata.pvarDocumentName); + FreeDescMetadata(&pIE->sDescMetadata.pvarPageName); + FreeDescMetadata(&pIE->sDescMetadata.pvarPageNumber); + FreeDescMetadata(&pIE->sDescMetadata.pvarHostComputer); + + Call(PKFree((void **) ppIE)); + +Cleanup: + return err; +} + +//---------------------------------------------------------------- +ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE) +{ + ERR err = WMP_errSuccess; + + PKImageEncode* pIE = NULL; + + Call(PKImageEncode_Create(ppIE)); + + pIE = *ppIE; + pIE->Initialize = PKImageEncode_Initialize_WMP; + pIE->Terminate = PKImageEncode_Terminate_WMP; + pIE->SetColorContext = PKImageEncode_SetColorContext_WMP; + pIE->SetDescriptiveMetadata = PKImageEncode_SetDescriptiveMetadata_WMP; + pIE->WritePixels = PKImageEncode_WritePixels_WMP; + + pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin_WMP; + pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded_WMP; + pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd_WMP; + + pIE->Transcode = PKImageEncode_Transcode_WMP; + pIE->CreateNewFrame = PKImageEncode_CreateNewFrame_WMP; + pIE->Release = PKImageEncode_Release_WMP; + pIE->bWMP = TRUE; + +Cleanup: + return err; +} + + +//================================================================ +// PKImageDecode_WMP +//================================================================ +ERR ParsePFDEntry( + PKImageDecode* pID, + U16 uTag, + U16 uType, + U32 uCount, + U32 uValue) +{ + ERR err = WMP_errSuccess; + ERR errTmp = 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, (U32 *)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_tagTransformation: + FailIf(1 != uCount, WMP_errUnsupportedFormat); + assert(uValue < O_MAX); + pID->WMP.fOrientationFromContainer = TRUE; + pID->WMP.oOrientationFromContainer = uValue; + 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_tagIccProfile: + pID->WMP.wmiDEMisc.uColorProfileByteCount = uCount; + pID->WMP.wmiDEMisc.uColorProfileOffset = uValue; + break; + + case WMP_tagXMPMetadata: + pID->WMP.wmiDEMisc.uXMPMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uXMPMetadataOffset = uValue; + break; + + case WMP_tagEXIFMetadata: + pID->WMP.wmiDEMisc.uEXIFMetadataOffset = uValue; + CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uEXIFMetadataByteCount)); + break; + + case WMP_tagGPSInfoMetadata: + pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset = uValue; + CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount)); + break; + + case WMP_tagIPTCNAAMetadata: + pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset = uValue; + break; + + case WMP_tagPhotoshopMetadata: + pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount = uCount; + pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset = uValue; + break; + + case WMP_tagCompression: + case WMP_tagImageType: + case WMP_tagImageDataDiscard: + case WMP_tagAlphaDataDiscard: + break; + + // Descriptive Metadata + case WMP_tagImageDescription: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarImageDescription)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarImageDescription.vt); + break; + + case WMP_tagCameraMake: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCameraMake)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraMake.vt); + break; + + case WMP_tagCameraModel: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCameraModel)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraModel.vt); + break; + + case WMP_tagSoftware: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarSoftware)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarSoftware.vt); + break; + + case WMP_tagDateTime: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarDateTime)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDateTime.vt); + break; + + case WMP_tagArtist: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarArtist)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarArtist.vt); + break; + + case WMP_tagCopyright: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCopyright)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCopyright.vt); + break; + + case WMP_tagRatingStars: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarRatingStars)); + assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingStars.vt); + break; + + case WMP_tagRatingValue: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarRatingValue)); + assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingValue.vt); + break; + + case WMP_tagCaption: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarCaption)); + assert((DPKVT_BYREF | DPKVT_UI1) == pID->WMP.sDescMetadata.pvarCaption.vt); + + // Change type from C-style byte array to LPWSTR + assert((U8*)pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal == + pID->WMP.sDescMetadata.pvarCaption.VT.pbVal); + assert(0 == pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16) - 1]); // Confirm null-term + // make sure null term (ReadPropvar allocated enough space for this) + pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16)] = 0; + pID->WMP.sDescMetadata.pvarCaption.vt = DPKVT_LPWSTR; + break; + + case WMP_tagDocumentName: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarDocumentName)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDocumentName.vt); + break; + + case WMP_tagPageName: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarPageName)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarPageName.vt); + break; + + case WMP_tagPageNumber: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarPageNumber)); + assert(DPKVT_UI4 == pID->WMP.sDescMetadata.pvarPageNumber.vt); + break; + + case WMP_tagHostComputer: + CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue, + &pID->WMP.sDescMetadata.pvarHostComputer)); + assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarHostComputer.vt); + 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; +} + +ERR ParsePFD( + PKImageDecode* pID, + size_t offPos, + U16 cEntry) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = pID->pStream; + U16 i = 0; + + for (i = 0; i < cEntry; ++i) + { + U16 uTag = 0; + U16 uType = 0; + U32 uCount = 0; + U32 uValue = 0; + + Call(GetUShort(pWS, offPos, &uTag)); offPos += 2; + Call(GetUShort(pWS, offPos, &uType)); offPos += 2; + Call(GetULong(pWS, offPos, &uCount)); offPos += 4; + Call(GetULong(pWS, offPos, &uValue)); offPos += 4; + + Call(ParsePFDEntry(pID, uTag, uType, uCount, uValue)); + } + + pID->WMP.bHasAlpha = ((pID->WMP.bHasAlpha) && (pID->WMP.wmiDEMisc.uAlphaOffset != 0) && (pID->WMP.wmiDEMisc.uAlphaByteCount != 0));//has planar alpha + +Cleanup: + return err; +} + +ERR ReadContainer( + PKImageDecode* pID) +{ + ERR err = WMP_errSuccess; + + struct WMPStream* pWS = pID->pStream; + size_t offPos = 0; + + char szSig[2] = {0}; + U16 uWmpID = 0; + U32 offPFD = 0; + U16 cPFDEntry = 0; + U8 bVersion; + + //================================ + Call(pWS->GetPos(pWS, &offPos)); + FailIf(0 != offPos, WMP_errUnsupportedFormat); + + //================================ + // Header + Call(pWS->Read(pWS, szSig, sizeof(szSig))); offPos += 2; + FailIf(szSig != strstr(szSig, "II"), WMP_errUnsupportedFormat); + + Call(GetUShort(pWS, offPos, &uWmpID)); offPos += 2; + FailIf(WMP_valWMPhotoID != (0x00FF & uWmpID), WMP_errUnsupportedFormat); + + // We accept version 00 and version 01 bitstreams - all others rejected + bVersion = (0xFF00 & uWmpID) >> 8; + FailIf(bVersion != 0 && bVersion != 1, WMP_errUnsupportedFormat); + + Call(GetULong(pWS, offPos, &offPFD)); offPos += 4; + + //================================ + // PFD + offPos = (size_t)offPFD; + Call(GetUShort(pWS, offPos, &cPFDEntry)); offPos += 2; + FailIf(0 == cPFDEntry || USHRT_MAX == cPFDEntry, WMP_errUnsupportedFormat); + Call(ParsePFD(pID, offPos, cPFDEntry)); + + //================================ + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset)); + +Cleanup: + return err; +} + + +//================================================ +ERR PKImageDecode_Initialize_WMP( + PKImageDecode* pID, + struct WMPStream* pWS) +{ + ERR err = WMP_errSuccess; + + CWMImageInfo* pII = NULL; + + //================================ + Call(PKImageDecode_Initialize(pID, pWS)); + + //================================ + Call(ReadContainer(pID)); + + //================================ + pID->WMP.wmiSCP.pWStream = pWS; + pID->WMP.DecoderCurrMBRow = 0; + pID->WMP.cLinesDecoded = 0; + pID->WMP.cLinesCropped = 0; + pID->WMP.fFirstNonZeroDecode = FALSE; + + FailIf(ICERR_OK != ImageStrDecGetInfo(&pID->WMP.wmiI, &pID->WMP.wmiSCP), WMP_errFail); + assert(Y_ONLY <= pID->WMP.wmiSCP.cfColorFormat && pID->WMP.wmiSCP.cfColorFormat < CFT_MAX); + assert(BD_SHORT == pID->WMP.wmiSCP.bdBitDepth || BD_LONG == pID->WMP.wmiSCP.bdBitDepth); + + // If HD Photo container provided an orientation, this should override bitstream orientation + // If container did NOT provide an orientation, force O_NONE. This is to be consistent with + // Vista behaviour, which is to ignore bitstream orientation (only looks at container). + if (pID->WMP.fOrientationFromContainer) + { + pID->WMP.wmiI.oOrientation = pID->WMP.oOrientationFromContainer; + } + else + { + // Force to O_NONE to match Vista decode behaviour + pID->WMP.wmiI.oOrientation = O_NONE; + } + + pII = &pID->WMP.wmiI; + pID->uWidth = (U32)pII->cWidth; + pID->uHeight = (U32)pII->cHeight; + +Cleanup: + return err; +} + + +ERR PKImageDecode_GetSize_WMP( + PKImageDecode* pID, + I32* piWidth, + I32* piHeight) +{ + if (pID->WMP.wmiI.oOrientation >= O_RCW) + { + *piWidth = (I32)pID->uHeight; + *piHeight = (I32)pID->uWidth; + } + else + { + *piWidth = (I32)pID->uWidth; + *piHeight = (I32)pID->uHeight; + } + return WMP_errSuccess; +} + + +ERR PKImageDecode_GetRawStream_WMP( + PKImageDecode* pID, + struct WMPStream** ppWS) +{ + ERR err = WMP_errSuccess; + struct WMPStream* pWS = pID->pStream; + + *ppWS = NULL; + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset)); + *ppWS = pWS; + +Cleanup: + return err; +} + +ERR PKImageDecode_Copy_WMP( + PKImageDecode* pID, + const PKRect* pRect, + U8* pb, + U32 cbStride) +{ + ERR err = WMP_errSuccess; + U32 cThumbnailScale; + U32 linesperMBRow; + CWMImageBufferInfo wmiBI = { 0 }; +#ifdef REENTRANT_MODE + U8 *pbLowMemAdj = NULL; + U32 i, cMBRow; + U32 cMBRowStart; +#endif // REENTRANT_MODE + struct WMPStream* pWS = pID->pStream; + U8 tempAlphaMode = 0; + wmiBI.pv = pb; + wmiBI.cLine = pRect->Height; + wmiBI.cbStride = cbStride; +#ifdef REENTRANT_MODE + // In REENTRANT_MODE, we allow rectangles with any top left corner (not just (0,0)) +#else + FailIf(0 != pRect->X, WMP_errInvalidParameter); + FailIf(0 != pRect->Y, WMP_errInvalidParameter); +#endif // REENTRANT_MODE + + cThumbnailScale = 1; + if (pID->WMP.wmiI.cThumbnailWidth > 0) + { + while(cThumbnailScale * pID->WMP.wmiI.cThumbnailWidth < pID->uWidth) + cThumbnailScale <<= 1; + } + // note the following implementation can't handle fractional linesperMBRow limiting + // us to >= 1/256 thumbnail which is unfortunate, but all the PS plugin needs is 1/256 + // and I didn't care to get into floating point or a bunch of conditional tests or + // other rewrite for a case not needed nor tested by PS plugin. sorry. + linesperMBRow = 16 / cThumbnailScale; + +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrMBRow) + { +#endif // REENTRANT_MODE + // Set the fPaddedUserBuffer if the following conditions are met + if (0 == ((size_t)pb % 128) && // Frame buffer is aligned to 128-byte boundary + 0 == (pRect->Height % 16) && // Horizontal resolution is multiple of 16 + 0 == (pRect->Width % 16) && // Vertical resolution is multiple of 16 + 0 == (cbStride % 128)) // Stride is a multiple of 128 bytes + { + pID->WMP.wmiI.fPaddedUserBuffer = TRUE; + // Note that there are additional conditions in strdec_x86.c's strDecOpt + // which could prevent optimization from being engaged + } +#ifdef REENTRANT_MODE + } +#endif // REENTRANT_MODE + //if(pID->WMP.wmiSCP.uAlphaMode != 1) + if((!pID->WMP.bHasAlpha) || (pID->WMP.wmiSCP.uAlphaMode != 1)) + { + if(pID->WMP.bHasAlpha)//planar alpha + { + tempAlphaMode = pID->WMP.wmiSCP.uAlphaMode; + pID->WMP.wmiSCP.uAlphaMode = 0; + } + pID->WMP.wmiSCP.fMeasurePerf = TRUE; +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrMBRow) + { + Call(pID->WMP.wmiSCP.pWStream->GetPos(pID->WMP.wmiSCP.pWStream, &(pID->WMP.cMarker))); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + } + // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1; + // if current request starts before current state, then rewind. + if (cMBRowStart < pID->WMP.DecoderCurrMBRow) + { + pID->WMP.DecoderCurrMBRow = 0; + pID->WMP.cLinesDecoded = 0; + pID->WMP.cLinesCropped = 0; + pID->WMP.fFirstNonZeroDecode = FALSE; + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); + Call(pID->WMP.wmiSCP.pWStream->SetPos(pID->WMP.wmiSCP.pWStream, pID->WMP.cMarker)); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + } + + // In "Low Memory mode", we don't have full frame buffer. We therefore cannot rotate the image. + // We can flip H, V and HV, but no rotations. + FailIf(pID->WMP.wmiI.oOrientation >= O_RCW, WMP_errFail); + + // In low-memory mode, the full frame buffer is unavailable. This doesn't seem to + // matter in O_NONE and O_FLIPH, but for O_FLIPV and O_FLIPVH, outputMBRow tries to write to + // the bottom of full-frame buffer. Adjust the buffer pointer to compensate. + if (O_FLIPV == pID->WMP.wmiI.oOrientation || O_FLIPVH == pID->WMP.wmiI.oOrientation) + { + I32 iActualY2 = pRect->Y + pRect->Height; + pbLowMemAdj = pb - (pID->WMP.wmiI.cROIHeight - (iActualY2 - pID->WMP.cLinesCropped)) * cbStride; + } + else + { + pbLowMemAdj = pb - pRect->Y * cbStride; + } + wmiBI.pv = pbLowMemAdj; + + for (i = (U32)pID->WMP.DecoderCurrMBRow; i < cMBRow; i++) + { + size_t cLinesDecoded; + wmiBI.uiFirstMBRow = i; + wmiBI.uiLastMBRow = i; + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI, &cLinesDecoded), WMP_errFail); + pID->WMP.cLinesDecoded = cLinesDecoded; + if (FALSE == pID->WMP.fFirstNonZeroDecode && cLinesDecoded > 0) + { + pID->WMP.cLinesCropped += (linesperMBRow - cLinesDecoded); + pID->WMP.fFirstNonZeroDecode = TRUE; + // update cMBRow if partial MB row cropped + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + } + + if (0 == cLinesDecoded && i > 0) + { + pID->WMP.cLinesCropped += linesperMBRow; + // update cMBRow if whole MB row cropped + cMBRow++; + } + } + wmiBI.pv = pbLowMemAdj; + + // If we're past the top of the image, then we're done, so terminate. + if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) { + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); + } + pID->WMP.DecoderCurrMBRow = cMBRow; // Set to next possible MBRow that is decodable + +#else + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail); +#endif //REENTRANT_MODE + + if(pID->WMP.bHasAlpha)//planar alpha + { + pID->WMP.wmiSCP.uAlphaMode = tempAlphaMode; + } + } + +// if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode == 2) +// if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 1) + if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 0) + { + pID->WMP.wmiI_Alpha = pID->WMP.wmiI; + pID->WMP.wmiSCP_Alpha = pID->WMP.wmiSCP; + +// assert(pID->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now! + pID->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY; + + switch (pID->WMP.wmiI.bdBitDepth) + { + case BD_8: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) - 1; + break; + + case BD_16: + case BD_16S: + case BD_16F: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1; + break; + + case BD_32: + case BD_32S: + case BD_32F: + pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1; + break; + + case BD_5: + case BD_10: + case BD_565: + default: + break; + } + + pID->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE; + Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uAlphaOffset)); +#ifdef REENTRANT_MODE + if (0 == pID->WMP.DecoderCurrAlphaMBRow) // add this to WMP struct! + { + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + } + + // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR + cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height + + (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR + linesperMBRow + 1; + cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1; + // if current request starts before current state, then rewind. + if (cMBRowStart < pID->WMP.DecoderCurrAlphaMBRow) + { + pID->WMP.DecoderCurrAlphaMBRow = 0; + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + } + + for (i = (U32)pID->WMP.DecoderCurrAlphaMBRow; i < cMBRow; i++) + { + size_t cLinesDecoded; + wmiBI.uiFirstMBRow = i; + wmiBI.uiLastMBRow = i; + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI, &cLinesDecoded), WMP_errFail); + } + + // If we're past the top of the image, then we're done, so terminate + if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) { + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); + } + pID->WMP.DecoderCurrAlphaMBRow = cMBRow; // Set to next possible MBRow that is decodable + wmiBI.pv = pb; +#else + FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail); + FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail); +#endif //REENTRANT_MODE + } + + pID->idxCurrentLine += pRect->Height; + +Cleanup: + return err; +} + + +ERR PKImageDecode_GetMetadata_WMP(PKImageDecode *pID, U32 uOffset, U32 uByteCount, U8 *pbGot, U32 *pcbGot) +{ + ERR err = WMP_errSuccess; + + if (pbGot && uOffset) + { + struct WMPStream* pWS = pID->pStream; + size_t iCurrPos; + + FailIf(*pcbGot < uByteCount, WMP_errBufferOverflow); + Call(pWS->GetPos(pWS, &iCurrPos)); + Call(pWS->SetPos(pWS, uOffset)); + Call(pWS->Read(pWS, pbGot, uByteCount)); + Call(pWS->SetPos(pWS, iCurrPos)); + } + +Cleanup: + if (Failed(err)) + *pcbGot = 0; + else + *pcbGot = uByteCount; + + return err; +} + + + +ERR PKImageDecode_GetColorContext_WMP(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uColorProfileOffset, + pID->WMP.wmiDEMisc.uColorProfileByteCount, pbColorContext, pcbColorContext); +} + + +ERR PKImageDecode_GetXMPMetadata_WMP(PKImageDecode *pID, U8 *pbXMPMetadata, U32 *pcbXMPMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uXMPMetadataOffset, + pID->WMP.wmiDEMisc.uXMPMetadataByteCount, pbXMPMetadata, pcbXMPMetadata); +} + + +ERR PKImageDecode_GetEXIFMetadata_WMP(PKImageDecode *pID, U8 *pbEXIFMetadata, U32 *pcbEXIFMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uEXIFMetadataOffset, + pID->WMP.wmiDEMisc.uEXIFMetadataByteCount, pbEXIFMetadata, pcbEXIFMetadata); +} + + +ERR PKImageDecode_GetGPSInfoMetadata_WMP(PKImageDecode *pID, U8 *pbGPSInfoMetadata, U32 *pcbGPSInfoMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset, + pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount, pbGPSInfoMetadata, pcbGPSInfoMetadata); +} + + +ERR PKImageDecode_GetIPTCNAAMetadata_WMP(PKImageDecode *pID, U8 *pbIPTCNAAMetadata, U32 *pcbIPTCNAAMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset, + pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount, pbIPTCNAAMetadata, pcbIPTCNAAMetadata); +} + + +ERR PKImageDecode_GetPhotoshopMetadata_WMP(PKImageDecode *pID, U8 *pbPhotoshopMetadata, U32 *pcbPhotoshopMetadata) +{ + return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset, + pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount, pbPhotoshopMetadata, pcbPhotoshopMetadata); +} + + +ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata) +{ + ERR err = WMP_errSuccess; + *pDescMetadata = pID->WMP.sDescMetadata; + return err; +} + + +ERR PKImageDecode_Release_WMP(PKImageDecode** ppID) +{ + ERR err = WMP_errSuccess; + PKImageDecode *pID; + + if (NULL == ppID) + goto Cleanup; + + pID = *ppID; + + // Free descriptive metadata + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarImageDescription); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraMake); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraModel); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarSoftware); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDateTime); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarArtist); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCopyright); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingStars); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingValue); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCaption); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDocumentName); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageName); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageNumber); + FreeDescMetadata(&pID->WMP.sDescMetadata.pvarHostComputer); + + // Release base class + Call(PKImageDecode_Release(ppID)); + +Cleanup: + return err; +} + + + +ERR PKImageDecode_Create_WMP(PKImageDecode** ppID) +{ + ERR err = WMP_errSuccess; + PKImageDecode* pID = NULL; + + Call(PKImageDecode_Create(ppID)); + + pID = *ppID; + pID->Initialize = PKImageDecode_Initialize_WMP; + pID->GetSize = PKImageDecode_GetSize_WMP; + pID->GetRawStream = PKImageDecode_GetRawStream_WMP; + pID->Copy = PKImageDecode_Copy_WMP; + pID->GetColorContext = PKImageDecode_GetColorContext_WMP; + pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata_WMP; + pID->Release = PKImageDecode_Release_WMP; + +Cleanup: + return err; +} + diff -Naur jxrlib-0.2.4/jxrtestlib/JXRTest.c jxrlib-0.2.4.new/jxrtestlib/JXRTest.c --- jxrlib-0.2.4/jxrtestlib/JXRTest.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrtestlib/JXRTest.c 2024-05-27 10:10:14.412853405 +0200 @@ -198,7 +198,7 @@ ERR err = WMP_errSuccess; char *pExt = NULL; - PKIID* pIID = NULL; + const PKIID* pIID = NULL; struct WMPStream* pStream = NULL; PKImageDecode* pDecoder = NULL; @@ -214,7 +214,7 @@ Call(CreateWS_File(&pStream, szFilename, "rb")); // Create decoder - Call(PKTestFactory_CreateCodec(pIID, ppDecoder)); + Call(PKTestFactory_CreateCodec(pIID, (void**)ppDecoder)); pDecoder = *ppDecoder; // attach stream to decoder @@ -232,7 +232,7 @@ UNREFERENCED_PARAMETER( uVersion ); - Call(PKAlloc(ppCFactory, sizeof(**ppCFactory))); + Call(PKAlloc((void**)ppCFactory, sizeof(**ppCFactory))); pCFactory = *ppCFactory; pCFactory->CreateCodec = PKTestFactory_CreateCodec; @@ -287,7 +287,7 @@ pID->fStreamOwner && pID->pStream->Close(&pID->pStream); - return PKFree(ppID); + return PKFree((void**)ppID); } ERR PKTestDecode_Create( @@ -296,7 +296,7 @@ ERR err = WMP_errSuccess; PKTestDecode* pID = NULL; - Call(PKAlloc(ppID, sizeof(**ppID))); + Call(PKAlloc((void**)ppID, sizeof(**ppID))); pID = *ppID; pID->Initialize = PKTestDecode_Initialize; diff -Naur jxrlib-0.2.4/jxrtestlib/JXRTestHdr.c jxrlib-0.2.4.new/jxrtestlib/JXRTestHdr.c --- jxrlib-0.2.4/jxrtestlib/JXRTestHdr.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrtestlib/JXRTestHdr.c 2024-05-27 10:10:14.412853405 +0200 @@ -27,7 +27,7 @@ //*@@@---@@@@****************************************************************** #ifndef ANSI #define _CRT_SECURE_NO_WARNINGS -#endif ANSI +#endif // ANSI #include #include diff -Naur jxrlib-0.2.4/jxrtestlib/JXRTestPnm.c jxrlib-0.2.4.new/jxrtestlib/JXRTestPnm.c --- jxrlib-0.2.4/jxrtestlib/JXRTestPnm.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrtestlib/JXRTestPnm.c 2024-05-27 10:10:14.412853405 +0200 @@ -27,7 +27,7 @@ //*@@@---@@@@****************************************************************** #ifndef ANSI #define _CRT_SECURE_NO_WARNINGS -#endif ANSI +#endif // ANSI #include diff -Naur jxrlib-0.2.4/jxrtestlib/JXRTestTif.c jxrlib-0.2.4.new/jxrtestlib/JXRTestTif.c --- jxrlib-0.2.4/jxrtestlib/JXRTestTif.c 2020-05-11 11:07:07.000000000 +0200 +++ jxrlib-0.2.4.new/jxrtestlib/JXRTestTif.c 2024-05-27 10:10:14.412853405 +0200 @@ -909,8 +909,8 @@ PKTestDecode *pID = *ppID; - Call(WMPFree(&pID->EXT.TIF.uStripOffsets)); - Call(WMPFree(&pID->EXT.TIF.uStripByteCounts)); + Call(WMPFree((void**)&pID->EXT.TIF.uStripOffsets)); + Call(WMPFree((void**)&pID->EXT.TIF.uStripByteCounts)); Call(PKTestDecode_Release(ppID));