github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/jxr/jxrlib/jxrgluelib/JXRGlueJxr.c (about)

     1  
     2  //*@@@+++@@@@******************************************************************
     3  //
     4  // Copyright Microsoft Corp.
     5  // All rights reserved.
     6  // 
     7  // Redistribution and use in source and binary forms, with or without
     8  // modification, are permitted provided that the following conditions are met:
     9  // 
    10  // Redistributions of source code must retain the above copyright notice,
    11  //   this list of conditions and the following disclaimer.
    12  // Redistributions in binary form must reproduce the above copyright notice,
    13  //   this list of conditions and the following disclaimer in the documentation
    14  //   and/or other materials provided with the distribution.
    15  // 
    16  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  // POSSIBILITY OF SUCH DAMAGE.
    27  //
    28  //*@@@---@@@@******************************************************************
    29  #include <limits.h>
    30  #include <JXRGlue.h>
    31  
    32  
    33  static const char szHDPhotoFormat[] = "<dc:format>image/vnd.ms-photo</dc:format>";
    34  const U32 IFDEntryTypeSizes[] = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
    35  const U32 SizeofIFDEntry = sizeof(struct IFDEntry);
    36  
    37  
    38  void CalcMetadataSizeLPSTR(const DPKPROPVARIANT var,
    39                             U16 *pcInactiveMetadata,
    40                             U32 *pcbOffsetSize,
    41                             U32 *pcbCount)
    42  {
    43      if (DPKVT_EMPTY != var.vt)
    44      {
    45          U32 uiLenWithNull = (U32)strlen(var.VT.pszVal) + 1; // +1 for NULL;
    46          assert(DPKVT_LPSTR == var.vt);
    47  
    48          // We only use offset if size > 4
    49          if (uiLenWithNull > 4)
    50              *pcbOffsetSize += uiLenWithNull;
    51  
    52          if (pcbCount)
    53              *pcbCount = uiLenWithNull;
    54      }
    55      else
    56          *pcInactiveMetadata += 1;
    57  }
    58  
    59  void CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var,
    60                              U16 *pcInactiveMetadata,
    61                              U32 *pcbOffsetSize,
    62                              U32 *pcbCount)
    63  {
    64      if (DPKVT_EMPTY != var.vt)
    65      {
    66          U32 uiCBWithNull = sizeof(U16) * ((U32)wcslen((wchar_t *) var.VT.pwszVal) + 1); // +1 for NULL term;
    67          assert(DPKVT_LPWSTR == var.vt);
    68  
    69          // We only use offset if size > 4
    70          if (uiCBWithNull > 4)
    71              *pcbOffsetSize += uiCBWithNull;
    72  
    73          if (pcbCount)
    74              *pcbCount = uiCBWithNull;
    75      }
    76      else
    77          *pcInactiveMetadata += 1;
    78  }
    79  
    80  void CalcMetadataSizeUI2(const DPKPROPVARIANT var,
    81                           U16 *pcInactiveMetadata,
    82                           U32 *pcbMetadataSize)
    83  {
    84      UNREFERENCED_PARAMETER( pcbMetadataSize );
    85      if (DPKVT_EMPTY != var.vt)
    86      {
    87          assert(DPKVT_UI2 == var.vt);
    88          // This is a single UI2, so it will not be written via offset, but rather as value
    89      }
    90      else
    91          *pcInactiveMetadata += 1;
    92  }
    93  
    94  void CalcMetadataSizeUI4(const DPKPROPVARIANT var,
    95                           U16 *pcInactiveMetadata,
    96                           U32 *pcbContainer)
    97  {
    98      UNREFERENCED_PARAMETER( pcbContainer );
    99      if (DPKVT_EMPTY != var.vt)
   100      {
   101          assert(DPKVT_UI4 == var.vt);
   102          // This is a single UI4, so it will not be written via offset, but rather as value
   103      }
   104      else
   105          *pcInactiveMetadata += 1;
   106  }
   107  
   108  ERR CalcMetadataOffsetSize(PKImageEncode* pIE,
   109                             U16 *pcInactiveMetadata,
   110                             U32 *pcbMetadataSize)
   111  {
   112      ERR err = WMP_errSuccess;
   113  
   114      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarImageDescription, pcInactiveMetadata, pcbMetadataSize, NULL);
   115      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraMake, pcInactiveMetadata, pcbMetadataSize, NULL);
   116      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCameraModel, pcInactiveMetadata, pcbMetadataSize, NULL);
   117      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarSoftware, pcInactiveMetadata, pcbMetadataSize, NULL);
   118      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDateTime, pcInactiveMetadata, pcbMetadataSize, NULL);
   119      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarArtist, pcInactiveMetadata, pcbMetadataSize, NULL);
   120      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarCopyright, pcInactiveMetadata, pcbMetadataSize, NULL);
   121      CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingStars, pcInactiveMetadata, pcbMetadataSize);
   122      CalcMetadataSizeUI2(pIE->sDescMetadata.pvarRatingValue, pcInactiveMetadata, pcbMetadataSize);
   123      CalcMetadataSizeLPWSTR(pIE->sDescMetadata.pvarCaption, pcInactiveMetadata, pcbMetadataSize, NULL);
   124      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarDocumentName, pcInactiveMetadata, pcbMetadataSize, NULL);
   125      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarPageName, pcInactiveMetadata, pcbMetadataSize, NULL);
   126      CalcMetadataSizeUI4(pIE->sDescMetadata.pvarPageNumber, pcInactiveMetadata, pcbMetadataSize);
   127      CalcMetadataSizeLPSTR(pIE->sDescMetadata.pvarHostComputer, pcInactiveMetadata, pcbMetadataSize, NULL);
   128  
   129      return err;
   130  }
   131  
   132  
   133  ERR CopyDescMetadata(DPKPROPVARIANT *pvarDst,
   134                       const DPKPROPVARIANT varSrc)
   135  {
   136      ERR err = WMP_errSuccess;
   137      size_t  uiSize;
   138  
   139      pvarDst->vt = varSrc.vt;
   140      switch (varSrc.vt)
   141      {
   142          case DPKVT_LPSTR:
   143              pvarDst->vt = DPKVT_LPSTR;
   144              uiSize = strlen(varSrc.VT.pszVal) + 1;
   145              Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize));
   146              memcpy(pvarDst->VT.pszVal, varSrc.VT.pszVal, uiSize);
   147              break;
   148              
   149          case DPKVT_LPWSTR:
   150              pvarDst->vt = DPKVT_LPWSTR;
   151              uiSize = sizeof(U16) * (wcslen((wchar_t *) varSrc.VT.pwszVal) + 1); // +1 for NULL term
   152              Call(PKAlloc((void **) &pvarDst->VT.pszVal, uiSize));
   153              memcpy(pvarDst->VT.pwszVal, varSrc.VT.pwszVal, uiSize);
   154              break;
   155  
   156          case DPKVT_UI2:
   157              pvarDst->VT.uiVal = varSrc.VT.uiVal;
   158              break;
   159  
   160          case DPKVT_UI4:
   161              pvarDst->VT.ulVal = varSrc.VT.ulVal;
   162              break;
   163  
   164          default:
   165              assert(FALSE); // This case is not handled
   166              FailIf(TRUE, WMP_errNotYetImplemented);
   167  
   168              // *** FALL THROUGH ***
   169  
   170          case DPKVT_EMPTY:
   171              memset(pvarDst, 0, sizeof(*pvarDst));
   172              assert(DPKVT_EMPTY == pvarDst->vt);
   173              break;
   174      }
   175  
   176  Cleanup:
   177      return err;
   178  }
   179  
   180  
   181  void FreeDescMetadata(DPKPROPVARIANT *pvar)
   182  {
   183      switch (pvar->vt)
   184      {
   185          case DPKVT_LPSTR:
   186              PKFree((void **) &pvar->VT.pszVal);
   187              break;
   188  
   189          case DPKVT_LPWSTR:
   190              PKFree((void **) &pvar->VT.pwszVal);
   191              break;
   192  
   193          default:
   194              assert(FALSE); // This case is not handled
   195              break;
   196  
   197          case DPKVT_EMPTY:
   198          case DPKVT_UI2:
   199          case DPKVT_UI4:
   200              break;
   201      }
   202  }
   203  
   204  
   205  ERR WriteDescMetadata(PKImageEncode *pIE,
   206                        const DPKPROPVARIANT var,
   207                        WmpDE *pwmpDE,
   208                        U32 *puiCurrDescMetadataOffset,
   209                        size_t *poffPos)
   210  {
   211      ERR err = WMP_errSuccess;
   212      WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
   213      struct WMPStream* pWS = pIE->pStream;
   214      U32 uiMetadataOffsetSize = 0;
   215      U32 uiCount = 0;
   216      U32 uiDataWrittenToOffset = 0;
   217      U16 uiTemp = 0;
   218  
   219      if (0 == pDEMisc->uDescMetadataOffset || 0 == pDEMisc->uDescMetadataByteCount)
   220          goto Cleanup; // Nothing to do here
   221  
   222      // Sanity check before - can be equal due to remaining metadata being DPKVT_EMPTY
   223      assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount);
   224  
   225      switch (var.vt)
   226      {
   227          case DPKVT_EMPTY:
   228              break;
   229  
   230          case DPKVT_LPSTR:
   231              CalcMetadataSizeLPSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount);
   232              pwmpDE->uCount = uiCount;
   233              pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset;
   234              Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pszVal, &uiDataWrittenToOffset));
   235              break;
   236  
   237          case DPKVT_LPWSTR:
   238              CalcMetadataSizeLPWSTR(var, &uiTemp, &uiMetadataOffsetSize, &uiCount);
   239              pwmpDE->uCount = uiCount;
   240              pwmpDE->uValueOrOffset = pDEMisc->uDescMetadataOffset + *puiCurrDescMetadataOffset;
   241              Call(WriteWmpDE(pWS, poffPos, pwmpDE, (U8*)var.VT.pwszVal, &uiDataWrittenToOffset));
   242              break;
   243  
   244          case DPKVT_UI2:
   245              CalcMetadataSizeUI2(var, &uiTemp, &uiMetadataOffsetSize);
   246              pwmpDE->uCount = 1;
   247              pwmpDE->uValueOrOffset = var.VT.uiVal;
   248              Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL));
   249              break;
   250  
   251          case DPKVT_UI4:
   252              CalcMetadataSizeUI4(var, &uiTemp, &uiMetadataOffsetSize);
   253              pwmpDE->uCount = 1;
   254              pwmpDE->uValueOrOffset = var.VT.ulVal;
   255              Call(WriteWmpDE(pWS, poffPos, pwmpDE, NULL, NULL));
   256              break;
   257  
   258          default:
   259              assert(FALSE); // This case is not handled
   260              FailIf(TRUE, WMP_errNotYetImplemented);
   261              break;
   262      }
   263  
   264      *puiCurrDescMetadataOffset += uiDataWrittenToOffset;
   265  
   266      // Sanity check after
   267      assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); // Can be equal
   268  
   269  Cleanup:
   270      return err;
   271  }
   272  
   273  
   274  
   275  //================================================================
   276  // PKImageEncode_WMP
   277  //================================================================
   278  ERR WriteContainerPre(
   279      PKImageEncode* pIE)
   280  {
   281      ERR err = WMP_errSuccess;
   282      const U32 OFFSET_OF_PFD = 0x20;
   283      struct WMPStream* pWS = pIE->pStream;
   284      WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
   285      PKPixelInfo PI;
   286      size_t offPos = 0;
   287  
   288      U8 IIMM[2] = {'\x49', '\x49'};
   289      // const U32 cbWmpDEMisc = OFFSET_OF_PFD;
   290      U32 cbMetadataOffsetSize = 0;
   291      U16 cInactiveMetadata = 0;
   292      U32 uiCurrDescMetadataOffset = 0;
   293  
   294      static WmpDE wmpDEs[] =
   295      {
   296          {WMP_tagDocumentName, WMP_typASCII, 1, (U32) -1},     // Descriptive metadata
   297          {WMP_tagImageDescription, WMP_typASCII, 1, (U32) -1}, // Descriptive metadata
   298          {WMP_tagCameraMake, WMP_typASCII, 1, (U32) -1},       // Descriptive metadata
   299          {WMP_tagCameraModel, WMP_typASCII, 1, (U32) -1},      // Descriptive metadata
   300          {WMP_tagPageName, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
   301          {WMP_tagPageNumber, WMP_typSHORT, 2, (U32) -1},       // Descriptive metadata
   302          {WMP_tagSoftware, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
   303          {WMP_tagDateTime, WMP_typASCII, 1, (U32) -1},         // Descriptive metadata
   304          {WMP_tagArtist, WMP_typASCII, 1, (U32) -1},           // Descriptive metadata
   305          {WMP_tagHostComputer, WMP_typASCII, 1, (U32) -1},     // Descriptive metadata
   306          {WMP_tagRatingStars, WMP_typSHORT, 1, (U32) -1},      // Descriptive metadata
   307          {WMP_tagRatingValue, WMP_typSHORT, 1, (U32) -1},      // Descriptive metadata
   308          {WMP_tagCopyright, WMP_typASCII, 1, (U32) -1},        // Descriptive metadata
   309          {WMP_tagCaption, WMP_typBYTE, 1, (U32) -1},           // Descriptive metadata
   310  
   311          {WMP_tagXMPMetadata, WMP_typBYTE, 1, (U32) -1},
   312          {WMP_tagIPTCNAAMetadata, WMP_typBYTE, 1, (U32) -1},
   313          {WMP_tagPhotoshopMetadata, WMP_typBYTE, 1, (U32) -1},
   314          {WMP_tagEXIFMetadata, WMP_typLONG, 1, (U32) -1},
   315          {WMP_tagIccProfile, WMP_typUNDEFINED, 1, (U32) -1},
   316          {WMP_tagGPSInfoMetadata, WMP_typLONG, 1, (U32) -1},
   317  
   318          {WMP_tagPixelFormat, WMP_typBYTE, 16, (U32) -1},
   319          {WMP_tagTransformation, WMP_typLONG, 1, (U32) -1},
   320          {WMP_tagImageWidth, WMP_typLONG, 1, (U32) -1},
   321          {WMP_tagImageHeight, WMP_typLONG, 1, (U32) -1},
   322          {WMP_tagWidthResolution, WMP_typFLOAT, 1, (U32) -1},
   323          {WMP_tagHeightResolution, WMP_typFLOAT, 1, (U32) -1},
   324          {WMP_tagImageOffset, WMP_typLONG, 1, (U32) -1},
   325          {WMP_tagImageByteCount, WMP_typLONG, 1, (U32) -1},
   326          {WMP_tagAlphaOffset, WMP_typLONG, 1, (U32) -1},
   327          {WMP_tagAlphaByteCount, WMP_typLONG, 1, (U32) -1},
   328      };
   329      U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]);
   330      WmpDE wmpDE = {0};
   331      size_t i = 0;
   332  
   333      U8* pbEXIFMetadata = NULL;
   334      U8* pbGPSInfoMetadata = NULL;
   335  
   336      // const unsigned char Zero[0x20] = { 0 };
   337      const unsigned char Zero[sizeof(struct IFDEntry) * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32)] = { 0 };
   338      assert(SizeofIFDEntry * sizeof(wmpDEs) / sizeof(wmpDEs[0]) + sizeof(U32) > 0x20);
   339  
   340      //================
   341      Call(pWS->GetPos(pWS, &offPos));
   342      FailIf(0 != offPos, WMP_errUnsupportedFormat);
   343  
   344      //================
   345      // Header (8 bytes)
   346      Call(pWS->Write(pWS, IIMM, sizeof(IIMM))); offPos += 2;
   347      Call(PutUShort(pWS, offPos, 0x01bc)); offPos += 2;
   348      Call(PutULong(pWS, offPos, (U32)OFFSET_OF_PFD)); offPos += 4;
   349  
   350      //================
   351      // Write overflow area
   352      pDEMisc->uOffPixelFormat = (U32)offPos;
   353      PI.pGUIDPixFmt = &pIE->guidPixFormat;
   354      PixelFormatLookup(&PI, LOOKUP_FORWARD);
   355  
   356      //Call(pWS->Write(pWS, PI.pGUIDPixFmt, sizeof(*PI.pGUIDPixFmt))); offPos += 16;
   357      /** following code is endian-agnostic **/
   358      {
   359          unsigned char *pGuid = (unsigned char *) &pIE->guidPixFormat;
   360          Call(PutULong(pWS, offPos, ((U32 *)pGuid)[0]));
   361          Call(PutUShort(pWS, offPos + 4, ((U16 *)(pGuid + 4))[0]));
   362          Call(PutUShort(pWS, offPos + 6, ((U16 *)(pGuid + 6))[0]));
   363          Call(pWS->Write(pWS, pGuid + 8, 8));
   364          offPos += 16;
   365      }
   366  
   367      //================
   368      // Tally up space required for descriptive metadata 
   369      Call(CalcMetadataOffsetSize(pIE, &cInactiveMetadata, &cbMetadataOffsetSize));
   370      cWmpDEs -= cInactiveMetadata;
   371  
   372      //================
   373      // PFD
   374      assert (offPos <= OFFSET_OF_PFD); // otherwise stuff is overwritten
   375      if (offPos < OFFSET_OF_PFD)
   376          Call(pWS->Write(pWS, Zero, OFFSET_OF_PFD - offPos));
   377      offPos = (size_t)OFFSET_OF_PFD;
   378  
   379      if (!pIE->WMP.bHasAlpha || pIE->WMP.wmiSCP.uAlphaMode != 2) //no planar alpha
   380          cWmpDEs -= 2;
   381  
   382      if (0 == pIE->cbXMPMetadataByteCount)
   383          cWmpDEs -= 1; // No XMP metadata
   384  
   385      if (0 == pIE->cbIPTCNAAMetadataByteCount)
   386          cWmpDEs -= 1; // No IPTCNAA metadata
   387  
   388      if (0 == pIE->cbPhotoshopMetadataByteCount)
   389          cWmpDEs -= 1; // No Photoshop metadata
   390  
   391      if (0 == pIE->cbEXIFMetadataByteCount)
   392          cWmpDEs -= 1; // No EXIF metadata
   393  
   394      if (0 == pIE->cbColorContext)
   395          cWmpDEs -= 1; // No color context
   396  
   397      if (0 == pIE->cbGPSInfoMetadataByteCount)
   398          cWmpDEs -= 1; // No GPSInfo metadata
   399  
   400      pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + SizeofIFDEntry * cWmpDEs + sizeof(U32));
   401      
   402      if (cbMetadataOffsetSize > 0)
   403      {
   404          pDEMisc->uDescMetadataByteCount = cbMetadataOffsetSize;
   405          pDEMisc->uDescMetadataOffset = pDEMisc->uImageOffset;
   406          pDEMisc->uImageOffset += cbMetadataOffsetSize;
   407      }
   408  
   409      if (pIE->cbXMPMetadataByteCount > 0)
   410      {
   411          pDEMisc->uXMPMetadataOffset = pDEMisc->uImageOffset;
   412          pDEMisc->uImageOffset += pIE->cbXMPMetadataByteCount;
   413      }
   414  
   415      if (pIE->cbIPTCNAAMetadataByteCount > 0)
   416      {
   417          pDEMisc->uIPTCNAAMetadataOffset = pDEMisc->uImageOffset;
   418          pDEMisc->uImageOffset += pIE->cbIPTCNAAMetadataByteCount;
   419      }
   420  
   421      if (pIE->cbPhotoshopMetadataByteCount > 0)
   422      {
   423          pDEMisc->uPhotoshopMetadataOffset = pDEMisc->uImageOffset;
   424          pDEMisc->uImageOffset += pIE->cbPhotoshopMetadataByteCount;
   425      }
   426  
   427      if (pIE->cbEXIFMetadataByteCount > 0)
   428      {
   429          pDEMisc->uEXIFMetadataOffset = pDEMisc->uImageOffset;
   430          pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
   431          pDEMisc->uImageOffset += pIE->cbEXIFMetadataByteCount;
   432      }
   433  
   434      if (pIE->cbColorContext > 0)
   435      {
   436          pDEMisc->uColorProfileOffset = pDEMisc->uImageOffset;
   437          pDEMisc->uImageOffset += pIE->cbColorContext;
   438      }
   439  
   440      if (pIE->cbGPSInfoMetadataByteCount > 0)
   441      {
   442          pDEMisc->uGPSInfoMetadataOffset = pDEMisc->uImageOffset;
   443          pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
   444          pDEMisc->uImageOffset += pIE->cbGPSInfoMetadataByteCount;
   445      }
   446  
   447      Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2;
   448      Call(pWS->Write(pWS, Zero, SizeofIFDEntry * cWmpDEs + sizeof(U32)));
   449  
   450      //================
   451      wmpDE = wmpDEs[i++];
   452      assert(WMP_tagDocumentName == wmpDE.uTag);
   453      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDocumentName, &wmpDE,
   454          &uiCurrDescMetadataOffset, &offPos));
   455  
   456      wmpDE = wmpDEs[i++];
   457      assert(WMP_tagImageDescription == wmpDE.uTag);
   458      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarImageDescription, &wmpDE,
   459          &uiCurrDescMetadataOffset, &offPos));
   460  
   461      wmpDE = wmpDEs[i++];
   462      assert(WMP_tagCameraMake == wmpDE.uTag);
   463      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraMake, &wmpDE,
   464          &uiCurrDescMetadataOffset, &offPos));
   465  
   466      wmpDE = wmpDEs[i++];
   467      assert(WMP_tagCameraModel == wmpDE.uTag);
   468      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraModel, &wmpDE,
   469          &uiCurrDescMetadataOffset, &offPos));
   470  
   471      wmpDE = wmpDEs[i++];
   472      assert(WMP_tagPageName == wmpDE.uTag);
   473      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageName, &wmpDE,
   474          &uiCurrDescMetadataOffset, &offPos));
   475  
   476      wmpDE = wmpDEs[i++];
   477      assert(WMP_tagPageNumber == wmpDE.uTag);
   478      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageNumber, &wmpDE,
   479          &uiCurrDescMetadataOffset, &offPos));
   480  
   481      wmpDE = wmpDEs[i++];
   482      assert(WMP_tagSoftware == wmpDE.uTag);
   483      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarSoftware, &wmpDE,
   484          &uiCurrDescMetadataOffset, &offPos));
   485  
   486      wmpDE = wmpDEs[i++];
   487      assert(WMP_tagDateTime == wmpDE.uTag);
   488      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDateTime, &wmpDE,
   489          &uiCurrDescMetadataOffset, &offPos));
   490  
   491      wmpDE = wmpDEs[i++];
   492      assert(WMP_tagArtist == wmpDE.uTag);
   493      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarArtist, &wmpDE,
   494          &uiCurrDescMetadataOffset, &offPos));
   495  
   496      wmpDE = wmpDEs[i++];
   497      assert(WMP_tagHostComputer == wmpDE.uTag);
   498      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarHostComputer, &wmpDE,
   499          &uiCurrDescMetadataOffset, &offPos));
   500  
   501      wmpDE = wmpDEs[i++];
   502      assert(WMP_tagRatingStars == wmpDE.uTag);
   503      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingStars, &wmpDE,
   504          &uiCurrDescMetadataOffset, &offPos));
   505  
   506      wmpDE = wmpDEs[i++];
   507      assert(WMP_tagRatingValue == wmpDE.uTag);
   508      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingValue, &wmpDE,
   509          &uiCurrDescMetadataOffset, &offPos));
   510  
   511      wmpDE = wmpDEs[i++];
   512      assert(WMP_tagCopyright == wmpDE.uTag);
   513      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCopyright, &wmpDE,
   514          &uiCurrDescMetadataOffset, &offPos));
   515  
   516      wmpDE = wmpDEs[i++];
   517      assert(WMP_tagCaption == wmpDE.uTag);
   518      Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCaption, &wmpDE,
   519          &uiCurrDescMetadataOffset, &offPos));
   520  
   521      // XMP Metadata
   522      wmpDE = wmpDEs[i++];
   523      assert(WMP_tagXMPMetadata == wmpDE.uTag);
   524      if (pIE->cbXMPMetadataByteCount > 0)
   525      {
   526          U32 uiTemp;
   527          wmpDE.uCount = pIE->cbXMPMetadataByteCount;
   528          wmpDE.uValueOrOffset = pDEMisc->uXMPMetadataOffset;
   529          Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbXMPMetadata, &uiTemp));
   530      }
   531  
   532      // IPTCNAA Metadata
   533      wmpDE = wmpDEs[i++];
   534      assert(WMP_tagIPTCNAAMetadata == wmpDE.uTag);
   535      if (pIE->cbIPTCNAAMetadataByteCount > 0)
   536      {
   537          U32 uiTemp;
   538          wmpDE.uCount = pIE->cbIPTCNAAMetadataByteCount;
   539          wmpDE.uValueOrOffset = pDEMisc->uIPTCNAAMetadataOffset;
   540          Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbIPTCNAAMetadata, &uiTemp));
   541      }
   542  
   543      // Photoshop Metadata
   544      wmpDE = wmpDEs[i++];
   545      assert(WMP_tagPhotoshopMetadata == wmpDE.uTag);
   546      if (pIE->cbPhotoshopMetadataByteCount > 0)
   547      {
   548          U32 uiTemp;
   549          wmpDE.uCount = pIE->cbPhotoshopMetadataByteCount;
   550          wmpDE.uValueOrOffset = pDEMisc->uPhotoshopMetadataOffset;
   551          Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbPhotoshopMetadata, &uiTemp));
   552      }
   553  
   554      // EXIF Metadata
   555      wmpDE = wmpDEs[i++];
   556      assert(WMP_tagEXIFMetadata == wmpDE.uTag);
   557      if (pIE->cbEXIFMetadataByteCount > 0)
   558      {
   559          U32 uiTemp;
   560          if ((pDEMisc->uEXIFMetadataOffset & 1) != 0)
   561          {
   562              Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset));
   563              Call(pWS->Write(pWS, Zero, 1));
   564          }
   565          pDEMisc->uEXIFMetadataOffset += (pDEMisc->uEXIFMetadataOffset & 1);
   566          wmpDE.uValueOrOffset = pDEMisc->uEXIFMetadataOffset;
   567          Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   568  
   569          Call(PKAlloc((void **) &pbEXIFMetadata, pIE->cbEXIFMetadataByteCount));
   570          uiTemp = pDEMisc->uEXIFMetadataOffset;
   571          Call(BufferCopyIFD(pIE->pbEXIFMetadata, pIE->cbEXIFMetadataByteCount, 0, WMP_INTEL_ENDIAN,
   572              pbEXIFMetadata - uiTemp, uiTemp + pIE->cbEXIFMetadataByteCount, &uiTemp));
   573          Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset));
   574          Call(pWS->Write(pWS, pbEXIFMetadata, pIE->cbEXIFMetadataByteCount));
   575      }
   576  
   577      // ICC Profile
   578      wmpDE = wmpDEs[i++];
   579      assert(WMP_tagIccProfile == wmpDE.uTag);
   580      if (pIE->cbColorContext > 0)
   581      {
   582          U32 uiTemp;
   583          wmpDE.uCount = pIE->cbColorContext;
   584          wmpDE.uValueOrOffset = pDEMisc->uColorProfileOffset;
   585          Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbColorContext, &uiTemp));
   586      }
   587  
   588      // GPSInfo Metadata
   589      wmpDE = wmpDEs[i++];
   590      assert(WMP_tagGPSInfoMetadata == wmpDE.uTag);
   591      if (pIE->cbGPSInfoMetadataByteCount > 0)
   592      {
   593          U32 uiTemp;
   594          if ((pDEMisc->uGPSInfoMetadataOffset & 1) != 0)
   595          {
   596              Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset));
   597              Call(pWS->Write(pWS, Zero, 1));
   598          }
   599          pDEMisc->uGPSInfoMetadataOffset += (pDEMisc->uGPSInfoMetadataOffset & 1);
   600          wmpDE.uValueOrOffset = pDEMisc->uGPSInfoMetadataOffset;
   601          Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   602  
   603          Call(PKAlloc((void **) &pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount));
   604          uiTemp = pDEMisc->uGPSInfoMetadataOffset;
   605          Call(BufferCopyIFD(pIE->pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount, 0, WMP_INTEL_ENDIAN,
   606              pbGPSInfoMetadata - uiTemp, uiTemp + pIE->cbGPSInfoMetadataByteCount, &uiTemp));
   607          Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset));
   608          Call(pWS->Write(pWS, pbGPSInfoMetadata, pIE->cbGPSInfoMetadataByteCount));
   609      }
   610  
   611      wmpDE = wmpDEs[i++];
   612      assert(WMP_tagPixelFormat == wmpDE.uTag);
   613      wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat;
   614      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   615  
   616      wmpDE = wmpDEs[i++];
   617      assert(WMP_tagTransformation == wmpDE.uTag);
   618      wmpDE.uValueOrOffset = pIE->WMP.oOrientation;
   619      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   620  
   621      wmpDE = wmpDEs[i++];
   622      assert(WMP_tagImageWidth == wmpDE.uTag);
   623      wmpDE.uValueOrOffset = pIE->uWidth;
   624      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   625  
   626      wmpDE = wmpDEs[i++];
   627      assert(WMP_tagImageHeight == wmpDE.uTag);
   628      wmpDE.uValueOrOffset = pIE->uHeight;
   629      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   630      
   631      wmpDE = wmpDEs[i++];
   632      assert(WMP_tagWidthResolution == wmpDE.uTag);
   633      *((float *) &wmpDE.uValueOrOffset) = pIE->fResX;
   634      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   635  
   636      wmpDE = wmpDEs[i++];
   637      assert(WMP_tagHeightResolution == wmpDE.uTag);
   638      *((float *) &wmpDE.uValueOrOffset) = pIE->fResY;
   639      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   640     
   641      wmpDE = wmpDEs[i++];
   642      assert(WMP_tagImageOffset == wmpDE.uTag);
   643      wmpDE.uValueOrOffset = pDEMisc->uImageOffset;
   644      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   645  
   646      // fix up in WriteContainerPost()
   647      wmpDE = wmpDEs[i++];
   648      assert(WMP_tagImageByteCount == wmpDE.uTag);
   649      pDEMisc->uOffImageByteCount = (U32)offPos;
   650      wmpDE.uValueOrOffset = 0;
   651      Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   652  
   653      if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
   654      {
   655          // fix up in WriteContainerPost()
   656          wmpDE = wmpDEs[i++];
   657          assert(WMP_tagAlphaOffset == wmpDE.uTag);
   658          pDEMisc->uOffAlphaOffset = (U32)offPos;
   659          wmpDE.uValueOrOffset = 0;
   660          Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   661  
   662          // fix up in WriteContainerPost()
   663          wmpDE = wmpDEs[i++];
   664          assert(WMP_tagAlphaByteCount == wmpDE.uTag);
   665          pDEMisc->uOffAlphaByteCount = (U32)offPos;
   666          wmpDE.uValueOrOffset = 0;
   667          Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
   668      }
   669  
   670      //================
   671      Call(PutULong(pWS, offPos, 0)); offPos += 4;
   672  
   673      assert(0 == (offPos & 1));
   674      if (pDEMisc->uColorProfileOffset > 0 || pDEMisc->uDescMetadataOffset > 0 ||
   675          pDEMisc->uXMPMetadataOffset > 0 || pDEMisc->uIPTCNAAMetadataOffset > 0 ||
   676          pDEMisc->uPhotoshopMetadataOffset > 0 || pDEMisc->uEXIFMetadataOffset > 0 ||
   677          pDEMisc->uGPSInfoMetadataOffset > 0)
   678      {
   679          assert(pDEMisc->uColorProfileOffset == offPos ||
   680                 pDEMisc->uDescMetadataOffset == offPos ||
   681                 pDEMisc->uXMPMetadataOffset == offPos ||
   682                 pDEMisc->uIPTCNAAMetadataOffset == offPos ||
   683                 pDEMisc->uPhotoshopMetadataOffset == offPos ||
   684                 pDEMisc->uEXIFMetadataOffset == offPos ||
   685                 pDEMisc->uGPSInfoMetadataOffset == offPos);
   686  
   687          // OK, now skip to image offset
   688          Call(pWS->SetPos(pWS, pDEMisc->uImageOffset));
   689          offPos = pDEMisc->uImageOffset;
   690      }
   691      assert(pDEMisc->uImageOffset == offPos);
   692  
   693  Cleanup:
   694      if (pbEXIFMetadata != NULL)
   695          PKFree((void **) &pbEXIFMetadata);
   696      if (pbGPSInfoMetadata != NULL)
   697          PKFree((void **) &pbGPSInfoMetadata);
   698      return err;
   699  }
   700  
   701  
   702  
   703  ERR WriteContainerPost(
   704      PKImageEncode* pIE)
   705  {
   706      ERR err = WMP_errSuccess;
   707  
   708      struct WMPStream* pWS = pIE->pStream;
   709      WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
   710      size_t offPos;
   711  
   712      WmpDE deImageByteCount = {WMP_tagImageByteCount, WMP_typLONG,  1, 0};
   713      WmpDE deAlphaOffset     = {WMP_tagAlphaOffset, WMP_typLONG,  1, 0};
   714      WmpDE deAlphaByteCount  = {WMP_tagAlphaByteCount, WMP_typLONG,  1, 0};
   715  
   716      deImageByteCount.uValueOrOffset = pIE->WMP.nCbImage;
   717      offPos = pDEMisc->uOffImageByteCount;
   718      Call(WriteWmpDE(pWS, &offPos, &deImageByteCount, NULL, NULL));
   719  
   720      //Alpha
   721      if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
   722      {                
   723          deAlphaOffset.uValueOrOffset = pIE->WMP.nOffAlpha;
   724          offPos = pDEMisc->uOffAlphaOffset;
   725          Call(WriteWmpDE(pWS, &offPos, &deAlphaOffset, NULL, NULL));
   726  
   727          deAlphaByteCount.uValueOrOffset = pIE->WMP.nCbAlpha + pIE->WMP.nOffAlpha;
   728          offPos = pDEMisc->uOffAlphaByteCount;
   729          Call(WriteWmpDE(pWS, &offPos, &deAlphaByteCount, NULL, NULL));
   730      }
   731  
   732  Cleanup:
   733      return err;
   734  }
   735  
   736  
   737  //================================================
   738  ERR PKImageEncode_Initialize_WMP(
   739      PKImageEncode* pIE,
   740      struct WMPStream* pStream,
   741      void* pvParam,
   742      size_t cbParam)
   743  {
   744      ERR err = WMP_errSuccess;
   745  
   746      FailIf(sizeof(pIE->WMP.wmiSCP) != cbParam, WMP_errInvalidArgument);
   747  
   748      pIE->WMP.wmiSCP = *(CWMIStrCodecParam*)pvParam;
   749      pIE->WMP.wmiSCP_Alpha = *(CWMIStrCodecParam*)pvParam;
   750      pIE->pStream = pStream;
   751  
   752      pIE->WMP.wmiSCP.pWStream = pIE->pStream;
   753      pIE->WMP.wmiSCP_Alpha.pWStream = pIE->pStream;
   754  
   755  Cleanup:
   756      return err;
   757  }
   758  
   759  ERR PKImageEncode_Terminate_WMP(
   760      PKImageEncode* pIE)
   761  {
   762      ERR err = WMP_errSuccess;
   763      UNREFERENCED_PARAMETER( pIE );
   764      return err;
   765  }
   766  
   767  
   768  ERR PKImageEncode_EncodeContent_Init(
   769      PKImageEncode* pIE, 
   770      PKPixelInfo PI,
   771      U32 cLine,
   772      U8* pbPixels,
   773      U32 cbStride)
   774  {
   775      ERR err = WMP_errSuccess;
   776  
   777      // init codec
   778      pIE->WMP.wmiI.cWidth = pIE->uWidth;
   779      pIE->WMP.wmiI.cHeight = pIE->uHeight;
   780      pIE->WMP.wmiI.bdBitDepth = PI.bdBitDepth;
   781      pIE->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
   782      pIE->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR);
   783      pIE->WMP.wmiI.cfColorFormat = PI.cfColorFormat;
   784      pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation;
   785      
   786      // Set the fPaddedUserBuffer if the following conditions are met
   787      if (0 == ((size_t)pbPixels % 128) &&        // Frame buffer is aligned to 128-byte boundary
   788          0 == (pIE->uWidth % 16) &&              // Horizontal resolution is multiple of 16
   789          0 == (cLine % 16) &&                    // Vertical resolution is multiple of 16
   790          0 == (cbStride % 128))                  // Stride is a multiple of 128 bytes
   791      {
   792          pIE->WMP.wmiI.fPaddedUserBuffer = TRUE;
   793          // Note that there are additional conditions in strenc_x86.c's strEncOpt
   794          // which could prevent optimization from being engaged
   795      }
   796  
   797      //if (pIE->WMP.bHasAlpha)
   798      //{
   799      //    pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;
   800      //    pIE->WMP.wmiI.cfColorFormat = PI.cfStripAlpha;
   801      //}
   802      //else
   803  
   804      if(PI.cfColorFormat == NCOMPONENT && (!(PI.grBit & PK_pixfmtHasAlpha)))//N-channel without Alpha
   805          pIE->WMP.wmiSCP.cChannel = PI.cChannel;
   806      else 
   807          pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;//other formats and (N-channel + Alpha)
   808  
   809      pIE->idxCurrentLine = 0;
   810      
   811      pIE->WMP.wmiSCP.fMeasurePerf = TRUE;
   812      FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI, &pIE->WMP.wmiSCP, &pIE->WMP.ctxSC), WMP_errFail);
   813  
   814  Cleanup:
   815      return err;
   816  }
   817  
   818  ERR PKImageEncode_EncodeContent_Encode(
   819      PKImageEncode* pIE, 
   820      U32 cLine,
   821      U8* pbPixels,
   822      U32 cbStride)
   823  {
   824      ERR err = WMP_errSuccess;
   825      U32 i = 0;
   826  
   827      //================================
   828      for (i = 0; i < cLine; i += 16)
   829      {
   830  		Bool f420 = ( pIE->WMP.wmiI.cfColorFormat == YUV_420 || 
   831  					  (pIE->WMP.wmiSCP.bYUVData && pIE->WMP.wmiSCP.cfColorFormat==YUV_420) );
   832          CWMImageBufferInfo wmiBI = { 0 };
   833          wmiBI.pv = pbPixels + cbStride * i / (f420 ? 2 : 1);
   834          wmiBI.cLine = min(16, cLine - i);
   835          wmiBI.cbStride = cbStride;
   836          FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC, &wmiBI), WMP_errFail);
   837      }
   838      pIE->idxCurrentLine += cLine;
   839  
   840  Cleanup:
   841      return err;
   842  }
   843  
   844  ERR PKImageEncode_EncodeContent_Term(PKImageEncode* pIE)
   845  {
   846      ERR err = WMP_errSuccess;
   847  
   848      FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC), WMP_errFail);
   849  
   850  Cleanup:
   851      return err;
   852  }
   853  
   854  ERR PKImageEncode_EncodeContent(
   855      PKImageEncode* pIE, 
   856      PKPixelInfo PI,
   857      U32 cLine,
   858      U8* pbPixels,
   859      U32 cbStride)
   860  {
   861      ERR err = WMP_errSuccess;
   862      size_t offPos = 0;
   863  
   864      Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
   865      pIE->WMP.nOffImage = (Long)offPos;
   866  
   867      Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride));
   868      Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride));
   869      Call(PKImageEncode_EncodeContent_Term(pIE));
   870  
   871      Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
   872      pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage;
   873  
   874  Cleanup:
   875      return err;
   876  }
   877  
   878  
   879  ERR PKImageEncode_EncodeAlpha_Init(
   880      PKImageEncode* pIE, 
   881      PKPixelInfo PI,
   882      U32 cLine,
   883      U8* pbPixels,
   884      U32 cbStride)
   885  {
   886      ERR err = WMP_errSuccess;
   887  
   888      UNREFERENCED_PARAMETER( cLine );
   889      UNREFERENCED_PARAMETER( pbPixels );
   890      UNREFERENCED_PARAMETER( cbStride );
   891  
   892      pIE->WMP.wmiI_Alpha = pIE->WMP.wmiI;
   893  
   894      pIE->WMP.wmiI_Alpha.cWidth = pIE->uWidth;
   895      pIE->WMP.wmiI_Alpha.cHeight = pIE->uHeight;
   896      pIE->WMP.wmiI_Alpha.bdBitDepth = PI.bdBitDepth;
   897      pIE->WMP.wmiI_Alpha.cBitsPerUnit = PI.cbitUnit;
   898      pIE->WMP.wmiI_Alpha.bRGB = !(PI.grBit & PK_pixfmtBGR);
   899      pIE->WMP.wmiI.oOrientation = pIE->WMP.oOrientation;
   900  //    pIE->WMP.wmiI_Alpha.cLeadingPadding += pIE->WMP.wmiSCP.cChannel;
   901  //    pIE->WMP.wmiI_Alpha.cLeadingPadding += PI.cChannel - 1;
   902  
   903      switch (pIE->WMP.wmiI.bdBitDepth)
   904      {
   905          case BD_8:
   906              pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) - 1;
   907              break;
   908          
   909          case BD_16:
   910          case BD_16S:
   911          case BD_16F:
   912              pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1;
   913              break;
   914          
   915          case BD_32:
   916          case BD_32S:
   917          case BD_32F:
   918              pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1;
   919              break;
   920          
   921          case BD_5:
   922          case BD_10:
   923          case BD_565:
   924          default:
   925              break;
   926      }
   927  
   928  //    pIE->WMP.wmiSCP_Alpha.uAlphaMode = 1;
   929  
   930  
   931      //assert(pIE->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
   932      pIE->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
   933      
   934      pIE->WMP.wmiSCP_Alpha.cfColorFormat = Y_ONLY;
   935  
   936      pIE->idxCurrentLine = 0;
   937      pIE->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE;
   938      FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI_Alpha, &pIE->WMP.wmiSCP_Alpha, &pIE->WMP.ctxSC_Alpha), WMP_errFail);
   939  
   940  Cleanup:
   941      return err;
   942  }
   943  
   944  ERR PKImageEncode_EncodeAlpha_Encode(
   945      PKImageEncode* pIE, 
   946      U32 cLine,
   947      U8* pbPixels,
   948      U32 cbStride)
   949  {
   950      ERR err = WMP_errSuccess;
   951      U32 i = 0;
   952  
   953      //================================
   954      for (i = 0; i < cLine; i += 16)
   955      {
   956          CWMImageBufferInfo wmiBI = { 0 };
   957          wmiBI.pv = pbPixels + cbStride * i;
   958          wmiBI.cLine = min(16, cLine - i);
   959          wmiBI.cbStride = cbStride;
   960          FailIf(ICERR_OK != ImageStrEncEncode(pIE->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail);
   961      }
   962      pIE->idxCurrentLine += cLine;
   963  
   964  Cleanup:
   965      return err;
   966  }
   967  
   968  ERR PKImageEncode_EncodeAlpha_Term(PKImageEncode* pIE)
   969  {
   970      ERR err = WMP_errSuccess;
   971  
   972      FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC_Alpha), WMP_errFail);
   973  
   974  Cleanup:
   975      return err;
   976  }
   977  
   978  ERR PKImageEncode_EncodeAlpha(
   979      PKImageEncode* pIE, 
   980      PKPixelInfo PI,
   981      U32 cLine,
   982      U8* pbPixels,
   983      U32 cbStride)
   984  {
   985      ERR err = WMP_errSuccess;
   986      size_t offPos = 0;
   987  
   988      Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
   989      if ((offPos & 1) != 0)
   990      {
   991          // Make the mark even if it is odd by inserting a pad byte
   992          char zero = 0;
   993          Call(pIE->pStream->Write(pIE->pStream, &zero, 1));
   994          offPos++;
   995      }
   996      pIE->WMP.nOffAlpha = (Long)offPos;
   997  
   998      Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride));
   999      Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride));
  1000      Call(PKImageEncode_EncodeAlpha_Term(pIE));
  1001  
  1002      Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
  1003      pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha;
  1004  
  1005  Cleanup:
  1006      return err;
  1007  }
  1008  
  1009  
  1010  
  1011  static ERR SetMetadata(PKImageEncode *pIE, const U8 *pbMetadata, U32 cbMetadata, U8** pbSet, U32* pcbSet)
  1012  {
  1013      ERR err = WMP_errSuccess;
  1014  
  1015      // Fail if the caller called us after we've already written the header out
  1016      if (pIE->fHeaderDone)
  1017      {
  1018          assert(FALSE); // Message to programmer
  1019          err = WMP_errOutOfSequence;
  1020          goto Cleanup;
  1021      }
  1022  
  1023      // Make a copy of the metadata
  1024      PKFree((void **) pbSet);
  1025      *pcbSet = 0;
  1026  
  1027      Call(PKAlloc((void **) pbSet, cbMetadata));
  1028      memcpy(*pbSet, pbMetadata, cbMetadata);
  1029      *pcbSet = cbMetadata;
  1030  
  1031  Cleanup:
  1032      return err;
  1033  }
  1034  
  1035  
  1036  
  1037  ERR PKImageEncode_SetColorContext_WMP(PKImageEncode *pIE,
  1038                                        const U8 *pbColorContext,
  1039                                        U32 cbColorContext)
  1040  {
  1041      return SetMetadata(pIE, pbColorContext, cbColorContext, &pIE->pbColorContext, &pIE->cbColorContext);
  1042  }
  1043  
  1044  
  1045  
  1046  ERR PKImageEncode_SetXMPMetadata_WMP(PKImageEncode *pIE, const U8 *pbXMPMetadata, U32 cbXMPMetadata)
  1047  {   // same as the other Set's, but make sure dc:format is <dc:format>image/vnd.ms-photo</dc:format>
  1048      ERR err = WMP_errSuccess;
  1049      char* pbTemp = 0;
  1050      U32 cbTemp;
  1051      char* pszFormatBegin;
  1052      // const char* pszXMPMetadata = (const char*)pbXMPMetadata;
  1053      size_t cbBuffer;
  1054  
  1055      // Fail if the caller called us after we've already written the header out
  1056      FailIf(pIE->fHeaderDone, WMP_errOutOfSequence);
  1057      
  1058      // Free any previously set XMP metadata
  1059      PKFree((void **) &pIE->pbXMPMetadata);
  1060      pIE->cbXMPMetadataByteCount = 0;
  1061  
  1062      // allocate a block big enough for data passed in plus added trailing null plus added HD Photo dc:format
  1063      // there may already be a trailing null (but ps doesn't seem to)
  1064      // there may already be a dc:format we will replace with HD Photo's
  1065      // but anyway this block will be large enough guaranteed
  1066      cbBuffer = cbXMPMetadata + 1 + sizeof("<dc:format>") - 1 + sizeof("</dc:format>") - 1 + sizeof(szHDPhotoFormat) - 1;
  1067      Call(PKAlloc((void **) &pbTemp, cbBuffer));
  1068      memcpy(pbTemp, pbXMPMetadata, cbXMPMetadata); // Make a copy of the metadata
  1069      pbTemp[cbXMPMetadata] = '\0';
  1070      cbXMPMetadata = (U32)strlen(pbTemp);
  1071      pszFormatBegin = strstr(pbTemp, "<dc:format>");
  1072      if ( pszFormatBegin != 0 )
  1073      {
  1074          char* pszFormatEnd;
  1075          const char* pszLessThan;
  1076  
  1077          pszFormatEnd = strstr(pszFormatBegin, "</dc:format>");
  1078          FailIf(pszFormatEnd == 0, WMP_errFail);
  1079          pszLessThan = strchr(pszFormatBegin + sizeof("<dc:format>") - 1, '<');
  1080          FailIf(pszLessThan != pszFormatEnd, WMP_errFail);
  1081          pszFormatEnd += sizeof("</dc:format>") - 1;
  1082  
  1083          // photoshop doesn't put a trailing null, so we don't either
  1084          // hd and tiff don't put a trailing null, so we don't either
  1085          cbTemp = cbXMPMetadata - (U32) ( pszFormatEnd - pszFormatBegin ) + sizeof(szHDPhotoFormat) - 1;
  1086          assert(cbTemp <= cbBuffer);
  1087          FailIf(0 != STRCPY_SAFE(pszFormatBegin,
  1088              cbBuffer - (pszFormatBegin - pbTemp),
  1089              szHDPhotoFormat),
  1090              WMP_errBufferOverflow);
  1091          memcpy(pszFormatBegin + sizeof(szHDPhotoFormat) - 1, pbXMPMetadata + ( pszFormatEnd - pbTemp ),
  1092              cbXMPMetadata - ( pszFormatEnd - pbTemp ));
  1093      }
  1094      else
  1095      {
  1096          cbTemp = cbXMPMetadata;
  1097      }
  1098  
  1099      pIE->pbXMPMetadata = (U8 *) pbTemp;
  1100      pIE->cbXMPMetadataByteCount = cbTemp;
  1101      return ( err );
  1102  
  1103  Cleanup:
  1104      PKFree((void **) &pbTemp);
  1105      pIE->cbXMPMetadataByteCount = 0;
  1106      return err;
  1107  }
  1108  
  1109  
  1110  
  1111  ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata)
  1112  {
  1113      return SetMetadata(pIE, pbEXIFMetadata, cbEXIFMetadata,
  1114          &pIE->pbEXIFMetadata, &pIE->cbEXIFMetadataByteCount);
  1115  }
  1116  
  1117  
  1118  
  1119  ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata)
  1120  {
  1121      return SetMetadata(pIE, pbGPSInfoMetadata, cbGPSInfoMetadata,
  1122          &pIE->pbGPSInfoMetadata, &pIE->cbGPSInfoMetadataByteCount);
  1123  }
  1124  
  1125  
  1126  
  1127  ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata)
  1128  {
  1129      return SetMetadata(pIE, pbIPTCNAAMetadata, cbIPTCNAAMetadata,
  1130          &pIE->pbIPTCNAAMetadata, &pIE->cbIPTCNAAMetadataByteCount);
  1131  }
  1132  
  1133  
  1134  
  1135  ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata)
  1136  {
  1137      return SetMetadata(pIE, pbPhotoshopMetadata, cbPhotoshopMetadata,
  1138          &pIE->pbPhotoshopMetadata, &pIE->cbPhotoshopMetadataByteCount);
  1139  }
  1140  
  1141  
  1142  
  1143  ERR PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pSrcMeta)
  1144  {
  1145      ERR                     err = WMP_errSuccess;
  1146      DESCRIPTIVEMETADATA    *pDstMeta = &pIE->sDescMetadata;
  1147  
  1148      // Fail if the caller called us after we've already written the header out
  1149      if (pIE->fHeaderDone)
  1150      {
  1151          assert(FALSE); // Message to programmer
  1152          FailIf(TRUE, WMP_errOutOfSequence);
  1153      }
  1154  
  1155      // Make a copy of the descriptive metadata
  1156      Call(CopyDescMetadata(&pDstMeta->pvarImageDescription, pSrcMeta->pvarImageDescription));
  1157      Call(CopyDescMetadata(&pDstMeta->pvarCameraMake, pSrcMeta->pvarCameraMake));
  1158      Call(CopyDescMetadata(&pDstMeta->pvarCameraModel, pSrcMeta->pvarCameraModel));
  1159      Call(CopyDescMetadata(&pDstMeta->pvarSoftware, pSrcMeta->pvarSoftware));
  1160      Call(CopyDescMetadata(&pDstMeta->pvarDateTime, pSrcMeta->pvarDateTime));
  1161      Call(CopyDescMetadata(&pDstMeta->pvarArtist, pSrcMeta->pvarArtist));
  1162      Call(CopyDescMetadata(&pDstMeta->pvarCopyright, pSrcMeta->pvarCopyright));
  1163      Call(CopyDescMetadata(&pDstMeta->pvarRatingStars, pSrcMeta->pvarRatingStars));
  1164      Call(CopyDescMetadata(&pDstMeta->pvarRatingValue, pSrcMeta->pvarRatingValue));
  1165      Call(CopyDescMetadata(&pDstMeta->pvarCaption, pSrcMeta->pvarCaption));
  1166      Call(CopyDescMetadata(&pDstMeta->pvarDocumentName, pSrcMeta->pvarDocumentName));
  1167      Call(CopyDescMetadata(&pDstMeta->pvarPageName, pSrcMeta->pvarPageName));
  1168      Call(CopyDescMetadata(&pDstMeta->pvarPageNumber, pSrcMeta->pvarPageNumber));
  1169      Call(CopyDescMetadata(&pDstMeta->pvarHostComputer, pSrcMeta->pvarHostComputer));
  1170  
  1171  Cleanup:
  1172      return err;
  1173  }
  1174  
  1175  
  1176  
  1177  ERR PKImageEncode_WritePixels_WMP(
  1178      PKImageEncode* pIE,
  1179      U32 cLine,
  1180      U8* pbPixels,
  1181      U32 cbStride)
  1182  {
  1183      ERR err = WMP_errSuccess;
  1184      // U32 i = 0;
  1185      PKPixelInfo PI;
  1186  
  1187      // Performing non-banded encode
  1188      assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState);
  1189      pIE->WMP.eBandedEncState = BANDEDENCSTATE_NONBANDEDENCODE;
  1190  
  1191      PI.pGUIDPixFmt = &pIE->guidPixFormat;
  1192      PixelFormatLookup(&PI, LOOKUP_FORWARD);
  1193      pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
  1194  
  1195      if (!pIE->fHeaderDone)
  1196      {
  1197          // write metadata
  1198          Call(WriteContainerPre(pIE));
  1199  
  1200          pIE->fHeaderDone = !FALSE;
  1201      }
  1202  
  1203  /*    if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){
  1204          pIE->WMP.wmiSCP_Alpha = pIE->WMP.wmiSCP;
  1205      }
  1206  */
  1207      Call(PKImageEncode_EncodeContent(pIE, PI, cLine, pbPixels, cbStride));
  1208      if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){//planar alpha
  1209          Call(PKImageEncode_EncodeAlpha(pIE, PI, cLine, pbPixels, cbStride));
  1210      }
  1211      
  1212      Call(WriteContainerPost(pIE));
  1213  
  1214  Cleanup:
  1215      return err;
  1216  }
  1217  
  1218  
  1219  ERR PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode* pIE, struct WMPStream *pPATempFile)
  1220  {
  1221      ERR err = WMP_errSuccess;
  1222  
  1223      // Just make sure that we are in the correct state to begin a banded decode
  1224      assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState);
  1225      pIE->WMP.eBandedEncState = BANDEDENCSTATE_INIT;
  1226  
  1227      // Save the planar alpha tempfile for future use
  1228      pIE->WMP.pPATempFile = pPATempFile;
  1229  
  1230  //Cleanup:
  1231      return err;
  1232  }
  1233  
  1234  ERR PKImageEncode_WritePixelsBanded_WMP(PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride, Bool fLastCall)
  1235  {
  1236      ERR err = WMP_errSuccess;
  1237      PKPixelInfo PI = {0};
  1238      Bool fPI = FALSE;
  1239      BANDEDENCSTATE eEncStateOrig = pIE->WMP.eBandedEncState;
  1240      struct WMPStream *pPATempFile = pIE->WMP.pPATempFile;
  1241  
  1242      // Unless this is the last call, reject inputs which are not multiples of 16
  1243      FailIf(!fLastCall && 0 != cLine % 16, WMP_errMustBeMultipleOf16LinesUntilLastCall);
  1244  
  1245      if (!pIE->fHeaderDone || BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
  1246      {
  1247          PI.pGUIDPixFmt = &pIE->guidPixFormat;
  1248          PixelFormatLookup(&PI, LOOKUP_FORWARD);
  1249          pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
  1250          fPI = TRUE;
  1251  
  1252          // Check if this is planar alpha: banded encode requires temp file
  1253          if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
  1254          {
  1255              FailIf(NULL == pPATempFile, WMP_errPlanarAlphaBandedEncRequiresTempFile);
  1256          }
  1257      }
  1258  
  1259      if (!pIE->fHeaderDone)
  1260      {
  1261          // write metadata
  1262          assert(fPI);
  1263          Call(WriteContainerPre(pIE));
  1264          pIE->fHeaderDone = !FALSE;
  1265      }
  1266  
  1267      if (BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
  1268      {
  1269          // Record start of main content for future call to WriteContainerPost
  1270          size_t offPos;
  1271          Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
  1272          pIE->WMP.nOffImage = (Long)offPos;
  1273  
  1274          assert(fPI);
  1275          Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride));
  1276          pIE->WMP.eBandedEncState = BANDEDENCSTATE_ENCODING;
  1277      }
  1278  
  1279      Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride));
  1280      if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
  1281      {
  1282          //planar alpha
  1283          if (BANDEDENCSTATE_INIT == eEncStateOrig)
  1284          {
  1285              size_t  offStart;
  1286  
  1287              // We assume the following which allows us to avoid saving state
  1288              Call(pPATempFile->GetPos(pPATempFile, &offStart));
  1289              assert(0 == offStart);
  1290              assert(pIE->WMP.wmiSCP_Alpha.pWStream == pIE->WMP.wmiSCP.pWStream);
  1291  
  1292              // For planar alpha, we write the file to a temp file
  1293              pIE->WMP.wmiSCP_Alpha.pWStream = pPATempFile;
  1294              Call(PKImageEncode_EncodeAlpha_Init(pIE, PI, cLine, pbPixels, cbStride));
  1295          }
  1296  
  1297          Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride));
  1298      }
  1299  
  1300  Cleanup:
  1301      return err;
  1302  }
  1303  
  1304  ERR PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode* pIE)
  1305  {
  1306      ERR err = WMP_errSuccess;
  1307      struct WMPStream *pMainStream = pIE->WMP.wmiSCP.pWStream;
  1308      size_t offAlpha;
  1309  
  1310      assert(BANDEDENCSTATE_ENCODING == pIE->WMP.eBandedEncState);
  1311  
  1312      // Finish off main content, update its length ptr for WriteContainerPost
  1313      Call(PKImageEncode_EncodeContent_Term(pIE));
  1314      Call(pMainStream->GetPos(pIE->pStream, &offAlpha));
  1315      pIE->WMP.nCbImage = (Long)offAlpha - pIE->WMP.nOffImage;
  1316  
  1317      if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
  1318      {
  1319          size_t cbAlpha;
  1320          size_t cbBytesCopied;
  1321          struct WMPStream *pAlphaStream = pIE->WMP.wmiSCP_Alpha.pWStream;
  1322  
  1323          assert(pAlphaStream != pMainStream); // Otherwise we didn't use a temp file
  1324  
  1325          // Close it up - this causes write to temp file
  1326          Call(PKImageEncode_EncodeAlpha_Term(pIE));
  1327  
  1328          // Calculate size of alpha bitstream and its new offset
  1329          Call(pAlphaStream->GetPos(pAlphaStream, &cbAlpha));
  1330  
  1331          // Copy alpha bitstream to end of main stream
  1332          cbBytesCopied = 0;
  1333          Call(pAlphaStream->SetPos(pAlphaStream, 0));
  1334          while (cbBytesCopied < cbAlpha)
  1335          {
  1336              char rgbBuf[TEMPFILE_COPYBUF_SIZE];
  1337              size_t cbCopy;
  1338  
  1339              cbCopy = min(sizeof(rgbBuf), cbAlpha - cbBytesCopied);
  1340              Call(pAlphaStream->Read(pAlphaStream, rgbBuf, cbCopy));
  1341              Call(pMainStream->Write(pMainStream, rgbBuf, cbCopy));
  1342  
  1343              cbBytesCopied += cbCopy;
  1344          }
  1345          assert(cbBytesCopied == cbAlpha);
  1346  
  1347          // Update alpha offset/length for WriteContainerPost
  1348          pIE->WMP.nOffAlpha = (Long)offAlpha;
  1349          pIE->WMP.nCbAlpha = (Long)cbAlpha;
  1350      }
  1351  
  1352      Call(WriteContainerPost(pIE));
  1353  
  1354  Cleanup:
  1355      return err;
  1356  }
  1357  
  1358  
  1359  ERR PKImageEncode_Transcode_WMP(
  1360      PKImageEncode* pIE,
  1361      PKImageDecode* pID,
  1362      CWMTranscodingParam* pParam)
  1363  {
  1364      ERR err = WMP_errSuccess;
  1365      Float fResX = 0, fResY = 0;
  1366      PKPixelFormatGUID pixGUID = {0};
  1367      CWMTranscodingParam tcParamAlpha;
  1368      size_t offPos = 0;
  1369      Bool fPlanarAlpha;
  1370      PKPixelInfo PI;
  1371  
  1372      struct WMPStream* pWSDec = NULL;
  1373      struct WMPStream* pWSEnc= pIE->pStream;
  1374  
  1375      // pass through metadata
  1376      Call(pID->GetPixelFormat(pID, &pixGUID));
  1377      Call(pIE->SetPixelFormat(pIE, pixGUID));
  1378  
  1379      Call(pIE->SetSize(pIE, (I32)pParam->cWidth, (I32)pParam->cHeight));
  1380  
  1381      Call(pID->GetResolution(pID, &fResX, &fResY));
  1382      Call(pIE->SetResolution(pIE, fResX, fResY));
  1383  
  1384      PI.pGUIDPixFmt = &pIE->guidPixFormat;
  1385      PixelFormatLookup(&PI, LOOKUP_FORWARD);
  1386      pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha) && (2 == pParam->uAlphaMode);
  1387      assert(0 == pIE->WMP.bHasAlpha || (pParam->uAlphaMode == 2)); // Decode alpha mode does not match encode alpha mode!
  1388  
  1389      // Check for any situations where transcoder is being asked to convert alpha - we can't do this
  1390      // NOTE: Decoder's bHasAlpha parameter really means, "has PLANAR alpha"
  1391      PI.pGUIDPixFmt = &pixGUID;
  1392      PixelFormatLookup(&PI, LOOKUP_FORWARD);
  1393      FailIf(0 == (PI.grBit & PK_pixfmtHasAlpha) && pParam->uAlphaMode != 0,
  1394          WMP_errAlphaModeCannotBeTranscoded); // Destination is planar/interleaved, src has no alpha
  1395      FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 2 == pParam->uAlphaMode &&
  1396          FALSE == pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded);  // Destination is planar, src is interleaved
  1397      FailIf(!!(PI.grBit & PK_pixfmtHasAlpha) && 3 == pParam->uAlphaMode &&
  1398          pID->WMP.bHasAlpha, WMP_errAlphaModeCannotBeTranscoded);  // Destination is interleaved, src is planar
  1399      assert(/*pParam->uAlphaMode >= 0 &&*/ pParam->uAlphaMode <= 3); // All the above statements make this assumption
  1400  
  1401      fPlanarAlpha = pIE->WMP.bHasAlpha && (2 == pParam->uAlphaMode);
  1402  
  1403      // write matadata
  1404      Call(WriteContainerPre(pIE));
  1405  
  1406      // Copy transcoding params for alpha (codec changes the struct)
  1407      if (fPlanarAlpha)
  1408          tcParamAlpha = *pParam;
  1409  
  1410      // write compressed bitstream
  1411      Call(pID->GetRawStream(pID, &pWSDec));
  1412  
  1413      FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, pParam), WMP_errFail);
  1414      Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
  1415      pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage;
  1416  
  1417      if (fPlanarAlpha)
  1418      {
  1419          pIE->WMP.nOffAlpha = (Long)offPos;
  1420  
  1421          // Cue the stream to alpha block
  1422          assert(pID->WMP.wmiDEMisc.uAlphaOffset > 0);
  1423          Call(pWSDec->SetPos(pWSDec, pID->WMP.wmiDEMisc.uAlphaOffset));
  1424  
  1425          FailIf(ICERR_OK != WMPhotoTranscode(pWSDec, pWSEnc, &tcParamAlpha), WMP_errFail);
  1426          Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
  1427          pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha;
  1428      }
  1429  
  1430      // fixup matadata
  1431      Call(WriteContainerPost(pIE));
  1432  
  1433  Cleanup:
  1434      return err;
  1435  }
  1436  
  1437  ERR PKImageEncode_CreateNewFrame_WMP(
  1438      PKImageEncode* pIE,
  1439      void* pvParam,
  1440      size_t cbParam)
  1441  {
  1442      ERR err = WMP_errSuccess;
  1443  
  1444      UNREFERENCED_PARAMETER( pIE );
  1445      UNREFERENCED_PARAMETER( pvParam );
  1446      UNREFERENCED_PARAMETER( cbParam );
  1447  
  1448      Call(WMP_errNotYetImplemented);
  1449      
  1450  Cleanup:
  1451      return err;
  1452  }
  1453  
  1454  ERR PKImageEncode_Release_WMP(
  1455      PKImageEncode** ppIE)
  1456  {
  1457      ERR err = WMP_errSuccess;
  1458  
  1459      PKImageEncode *pIE = *ppIE;
  1460      pIE->pStream->Close(&pIE->pStream);
  1461  
  1462      PKFree((void **) &pIE->pbColorContext);
  1463      pIE->cbColorContext = 0;
  1464      PKFree((void **) &pIE->pbXMPMetadata);
  1465      pIE->cbXMPMetadataByteCount = 0;
  1466      PKFree((void **) &pIE->pbEXIFMetadata);
  1467      pIE->cbEXIFMetadataByteCount = 0;
  1468      PKFree((void **) &pIE->pbGPSInfoMetadata);
  1469      pIE->cbGPSInfoMetadataByteCount = 0;
  1470      PKFree((void **) &pIE->pbIPTCNAAMetadata);
  1471      pIE->cbIPTCNAAMetadataByteCount = 0;
  1472      PKFree((void **) &pIE->pbPhotoshopMetadata);
  1473      pIE->cbPhotoshopMetadataByteCount = 0;
  1474  
  1475      // Free descriptive metadata
  1476      FreeDescMetadata(&pIE->sDescMetadata.pvarImageDescription);
  1477      FreeDescMetadata(&pIE->sDescMetadata.pvarCameraMake);
  1478      FreeDescMetadata(&pIE->sDescMetadata.pvarCameraModel);
  1479      FreeDescMetadata(&pIE->sDescMetadata.pvarSoftware);
  1480      FreeDescMetadata(&pIE->sDescMetadata.pvarDateTime);
  1481      FreeDescMetadata(&pIE->sDescMetadata.pvarArtist);
  1482      FreeDescMetadata(&pIE->sDescMetadata.pvarCopyright);
  1483      FreeDescMetadata(&pIE->sDescMetadata.pvarRatingStars);
  1484      FreeDescMetadata(&pIE->sDescMetadata.pvarRatingValue);
  1485      FreeDescMetadata(&pIE->sDescMetadata.pvarCaption);
  1486      FreeDescMetadata(&pIE->sDescMetadata.pvarDocumentName);
  1487      FreeDescMetadata(&pIE->sDescMetadata.pvarPageName);
  1488      FreeDescMetadata(&pIE->sDescMetadata.pvarPageNumber);
  1489      FreeDescMetadata(&pIE->sDescMetadata.pvarHostComputer);
  1490  
  1491      Call(PKFree((void **) ppIE));
  1492  
  1493  Cleanup:
  1494      return err;
  1495  }
  1496  
  1497  //----------------------------------------------------------------
  1498  ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE)
  1499  {
  1500      ERR err = WMP_errSuccess;
  1501  
  1502      PKImageEncode* pIE = NULL;
  1503  
  1504      Call(PKImageEncode_Create(ppIE));
  1505  
  1506      pIE = *ppIE;
  1507      pIE->Initialize = PKImageEncode_Initialize_WMP;
  1508      pIE->Terminate = PKImageEncode_Terminate_WMP;
  1509      pIE->SetColorContext = PKImageEncode_SetColorContext_WMP;
  1510      pIE->SetDescriptiveMetadata = PKImageEncode_SetDescriptiveMetadata_WMP;
  1511      pIE->WritePixels = PKImageEncode_WritePixels_WMP;
  1512  
  1513      pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin_WMP;
  1514      pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded_WMP;
  1515      pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd_WMP;
  1516  
  1517      pIE->Transcode = PKImageEncode_Transcode_WMP;
  1518      pIE->CreateNewFrame = PKImageEncode_CreateNewFrame_WMP;
  1519      pIE->Release = PKImageEncode_Release_WMP;
  1520  	pIE->bWMP = TRUE; 
  1521  
  1522  Cleanup:
  1523      return err;
  1524  }
  1525  
  1526  
  1527  //================================================================
  1528  // PKImageDecode_WMP
  1529  //================================================================
  1530  ERR ParsePFDEntry(
  1531      PKImageDecode* pID,
  1532      U16 uTag,
  1533      U16 uType,
  1534      U32 uCount,
  1535      U32 uValue)
  1536  {
  1537      ERR err = WMP_errSuccess;
  1538      ERR errTmp = WMP_errSuccess;
  1539      PKPixelInfo PI;
  1540      struct WMPStream* pWS = pID->pStream;
  1541      // size_t offPos = 0;
  1542  
  1543      union uf{
  1544          U32 uVal;
  1545          Float fVal;
  1546      }ufValue = {0};
  1547  
  1548      //================================
  1549      switch (uTag)
  1550      {
  1551          case WMP_tagPixelFormat:
  1552          {
  1553              unsigned char *pGuid = (unsigned char *) &pID->guidPixFormat;
  1554              /** following code is endian-agnostic **/
  1555              Call(GetULong(pWS, uValue, (U32 *)pGuid));
  1556              Call(GetUShort(pWS, uValue + 4, (unsigned short *)(pGuid + 4)));
  1557              Call(GetUShort(pWS, uValue + 6, (unsigned short *)(pGuid + 6)));
  1558              Call(pWS->Read(pWS, pGuid + 8, 8));
  1559                  
  1560              PI.pGUIDPixFmt = &pID->guidPixFormat;
  1561              PixelFormatLookup(&PI, LOOKUP_FORWARD);
  1562  
  1563              pID->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
  1564              pID->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
  1565              pID->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR);
  1566  
  1567              break;
  1568          }
  1569  
  1570          case WMP_tagTransformation:
  1571              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1572              assert(uValue < O_MAX);
  1573              pID->WMP.fOrientationFromContainer = TRUE;
  1574              pID->WMP.oOrientationFromContainer = uValue;
  1575              break;
  1576  
  1577          case WMP_tagImageWidth:
  1578              FailIf(0 == uValue, WMP_errUnsupportedFormat);
  1579              break;
  1580  
  1581          case WMP_tagImageHeight:
  1582              FailIf(0 == uValue, WMP_errUnsupportedFormat);
  1583              break;
  1584  
  1585          case WMP_tagImageOffset:
  1586              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1587              pID->WMP.wmiDEMisc.uImageOffset = uValue;
  1588              break;
  1589  
  1590          case WMP_tagImageByteCount:
  1591              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1592              pID->WMP.wmiDEMisc.uImageByteCount = uValue;
  1593              break;
  1594  
  1595          case WMP_tagAlphaOffset:
  1596              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1597              pID->WMP.wmiDEMisc.uAlphaOffset = uValue;
  1598              break;
  1599  
  1600          case WMP_tagAlphaByteCount:
  1601              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1602              pID->WMP.wmiDEMisc.uAlphaByteCount = uValue;
  1603              break;
  1604  
  1605          case WMP_tagWidthResolution:
  1606              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1607              ufValue.uVal = uValue; 
  1608              pID->fResX = ufValue.fVal;
  1609              break;
  1610  
  1611          case WMP_tagHeightResolution:
  1612              FailIf(1 != uCount, WMP_errUnsupportedFormat);
  1613              ufValue.uVal = uValue; 
  1614              pID->fResY = ufValue.fVal;
  1615              break;
  1616  
  1617          case WMP_tagIccProfile:
  1618              pID->WMP.wmiDEMisc.uColorProfileByteCount = uCount;
  1619              pID->WMP.wmiDEMisc.uColorProfileOffset = uValue;
  1620              break;
  1621  
  1622          case WMP_tagXMPMetadata:
  1623              pID->WMP.wmiDEMisc.uXMPMetadataByteCount = uCount;
  1624              pID->WMP.wmiDEMisc.uXMPMetadataOffset = uValue;
  1625              break;
  1626  
  1627          case WMP_tagEXIFMetadata:
  1628              pID->WMP.wmiDEMisc.uEXIFMetadataOffset = uValue;
  1629              CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uEXIFMetadataByteCount));
  1630              break;
  1631  
  1632          case WMP_tagGPSInfoMetadata:
  1633              pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset = uValue;
  1634              CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount));
  1635              break;
  1636  
  1637          case WMP_tagIPTCNAAMetadata:
  1638              pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount = uCount;
  1639              pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset = uValue;
  1640              break;
  1641  
  1642          case WMP_tagPhotoshopMetadata:
  1643              pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount = uCount;
  1644              pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset = uValue;
  1645              break;
  1646  
  1647          case WMP_tagCompression:
  1648          case WMP_tagImageType:
  1649          case WMP_tagImageDataDiscard:
  1650          case WMP_tagAlphaDataDiscard:
  1651              break;
  1652  
  1653          // Descriptive Metadata
  1654          case WMP_tagImageDescription:
  1655              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1656                  &pID->WMP.sDescMetadata.pvarImageDescription));
  1657              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarImageDescription.vt);
  1658              break;
  1659  
  1660          case WMP_tagCameraMake:
  1661              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1662                  &pID->WMP.sDescMetadata.pvarCameraMake));
  1663              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraMake.vt);
  1664              break;
  1665  
  1666          case WMP_tagCameraModel:
  1667              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1668                  &pID->WMP.sDescMetadata.pvarCameraModel));
  1669              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCameraModel.vt);
  1670              break;
  1671  
  1672          case WMP_tagSoftware:
  1673              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1674                  &pID->WMP.sDescMetadata.pvarSoftware));
  1675              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarSoftware.vt);
  1676              break;
  1677  
  1678          case WMP_tagDateTime:
  1679              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1680                  &pID->WMP.sDescMetadata.pvarDateTime));
  1681              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDateTime.vt);
  1682              break;
  1683  
  1684          case WMP_tagArtist:
  1685              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1686                  &pID->WMP.sDescMetadata.pvarArtist));
  1687              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarArtist.vt);
  1688              break;
  1689  
  1690          case WMP_tagCopyright:
  1691              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1692                  &pID->WMP.sDescMetadata.pvarCopyright));
  1693              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarCopyright.vt);
  1694              break;
  1695  
  1696          case WMP_tagRatingStars:
  1697              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1698                  &pID->WMP.sDescMetadata.pvarRatingStars));
  1699              assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingStars.vt);
  1700              break;
  1701  
  1702          case WMP_tagRatingValue:
  1703              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1704                  &pID->WMP.sDescMetadata.pvarRatingValue));
  1705              assert(DPKVT_UI2 == pID->WMP.sDescMetadata.pvarRatingValue.vt);
  1706              break;
  1707  
  1708          case WMP_tagCaption:
  1709              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1710                  &pID->WMP.sDescMetadata.pvarCaption));
  1711              assert((DPKVT_BYREF | DPKVT_UI1) == pID->WMP.sDescMetadata.pvarCaption.vt);
  1712  
  1713              // Change type from C-style byte array to LPWSTR
  1714              assert((U8*)pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal ==
  1715                  pID->WMP.sDescMetadata.pvarCaption.VT.pbVal);
  1716              assert(0 == pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16) - 1]); // Confirm null-term
  1717              //  make sure null term (ReadPropvar allocated enough space for this)
  1718              pID->WMP.sDescMetadata.pvarCaption.VT.pwszVal[uCount/sizeof(U16)] = 0;
  1719              pID->WMP.sDescMetadata.pvarCaption.vt = DPKVT_LPWSTR;
  1720              break;
  1721  
  1722          case WMP_tagDocumentName:
  1723              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1724                  &pID->WMP.sDescMetadata.pvarDocumentName));
  1725              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarDocumentName.vt);
  1726              break;
  1727  
  1728          case WMP_tagPageName:
  1729              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1730                  &pID->WMP.sDescMetadata.pvarPageName));
  1731              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarPageName.vt);
  1732              break;
  1733  
  1734          case WMP_tagPageNumber:
  1735              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1736                  &pID->WMP.sDescMetadata.pvarPageNumber));
  1737              assert(DPKVT_UI4 == pID->WMP.sDescMetadata.pvarPageNumber.vt);
  1738              break;
  1739  
  1740          case WMP_tagHostComputer:
  1741              CallIgnoreError(errTmp, ReadPropvar(pWS, uType, uCount, uValue,
  1742                  &pID->WMP.sDescMetadata.pvarHostComputer));
  1743              assert(DPKVT_LPSTR == pID->WMP.sDescMetadata.pvarHostComputer.vt);
  1744              break;
  1745  
  1746          default:
  1747              fprintf(stderr, "Unrecognized WMPTag: %d(%#x), %d, %d, %#x" CRLF,
  1748                  (int)uTag, (int)uTag, (int)uType, (int)uCount, (int)uValue);
  1749              break;
  1750      }
  1751  
  1752  Cleanup:
  1753      return err;
  1754  }
  1755  
  1756  ERR ParsePFD(
  1757      PKImageDecode* pID,
  1758      size_t offPos,
  1759      U16 cEntry)
  1760  {
  1761      ERR err = WMP_errSuccess;
  1762      struct WMPStream* pWS = pID->pStream;
  1763      U16 i = 0;
  1764  
  1765      for (i = 0; i < cEntry; ++i)
  1766      {
  1767          U16 uTag = 0;
  1768          U16 uType = 0;
  1769          U32 uCount = 0;
  1770          U32 uValue = 0;
  1771  
  1772          Call(GetUShort(pWS, offPos, &uTag)); offPos += 2;
  1773          Call(GetUShort(pWS, offPos, &uType)); offPos += 2;
  1774          Call(GetULong(pWS, offPos, &uCount)); offPos += 4;
  1775          Call(GetULong(pWS, offPos, &uValue)); offPos += 4;
  1776  
  1777          Call(ParsePFDEntry(pID, uTag, uType, uCount, uValue)); 
  1778      }
  1779  
  1780      pID->WMP.bHasAlpha = ((pID->WMP.bHasAlpha) && (pID->WMP.wmiDEMisc.uAlphaOffset != 0) && (pID->WMP.wmiDEMisc.uAlphaByteCount != 0));//has planar alpha
  1781  
  1782  Cleanup:
  1783      return err;
  1784  }
  1785  
  1786  ERR ReadContainer(
  1787      PKImageDecode* pID)
  1788  {
  1789      ERR err = WMP_errSuccess;
  1790  
  1791      struct WMPStream* pWS = pID->pStream;
  1792      size_t offPos = 0;
  1793  
  1794      char szSig[2] = {0};
  1795      U16 uWmpID = 0;
  1796      U32 offPFD = 0;
  1797      U16 cPFDEntry = 0;
  1798      U8 bVersion;
  1799      
  1800      //================================
  1801      Call(pWS->GetPos(pWS, &offPos));
  1802      FailIf(0 != offPos, WMP_errUnsupportedFormat);
  1803  
  1804      //================================
  1805      // Header
  1806      Call(pWS->Read(pWS, szSig, sizeof(szSig))); offPos += 2;
  1807      FailIf(szSig != strstr(szSig, "II"), WMP_errUnsupportedFormat);
  1808  
  1809      Call(GetUShort(pWS, offPos, &uWmpID)); offPos += 2;
  1810      FailIf(WMP_valWMPhotoID != (0x00FF & uWmpID), WMP_errUnsupportedFormat);
  1811  
  1812      // We accept version 00 and version 01 bitstreams - all others rejected
  1813      bVersion = (0xFF00 & uWmpID) >> 8;
  1814      FailIf(bVersion != 0 && bVersion != 1, WMP_errUnsupportedFormat);
  1815  
  1816      Call(GetULong(pWS, offPos, &offPFD)); offPos += 4;
  1817  
  1818      //================================
  1819      // PFD
  1820      offPos = (size_t)offPFD;
  1821      Call(GetUShort(pWS, offPos, &cPFDEntry)); offPos += 2;
  1822      FailIf(0 == cPFDEntry || USHRT_MAX == cPFDEntry, WMP_errUnsupportedFormat);
  1823      Call(ParsePFD(pID, offPos, cPFDEntry));
  1824  
  1825      //================================
  1826      Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
  1827  
  1828  Cleanup:
  1829      return err;
  1830  }
  1831  
  1832  
  1833  //================================================
  1834  ERR PKImageDecode_Initialize_WMP(
  1835      PKImageDecode* pID,
  1836      struct WMPStream* pWS)
  1837  {
  1838      ERR err = WMP_errSuccess;
  1839  
  1840      CWMImageInfo* pII = NULL;
  1841  
  1842      //================================
  1843      Call(PKImageDecode_Initialize(pID, pWS));
  1844  
  1845      //================================
  1846      Call(ReadContainer(pID));
  1847  
  1848      //================================
  1849      pID->WMP.wmiSCP.pWStream = pWS;
  1850      pID->WMP.DecoderCurrMBRow = 0;
  1851      pID->WMP.cLinesDecoded = 0;
  1852      pID->WMP.cLinesCropped = 0;
  1853      pID->WMP.fFirstNonZeroDecode = FALSE;
  1854  
  1855      FailIf(ICERR_OK != ImageStrDecGetInfo(&pID->WMP.wmiI, &pID->WMP.wmiSCP), WMP_errFail);
  1856      assert(Y_ONLY <= pID->WMP.wmiSCP.cfColorFormat && pID->WMP.wmiSCP.cfColorFormat < CFT_MAX);
  1857      assert(BD_SHORT == pID->WMP.wmiSCP.bdBitDepth || BD_LONG == pID->WMP.wmiSCP.bdBitDepth);
  1858  
  1859      // If HD Photo container provided an orientation, this should override bitstream orientation
  1860      // If container did NOT provide an orientation, force O_NONE. This is to be consistent with
  1861      // Vista behaviour, which is to ignore bitstream orientation (only looks at container).
  1862      if (pID->WMP.fOrientationFromContainer)
  1863      {
  1864          pID->WMP.wmiI.oOrientation = pID->WMP.oOrientationFromContainer;
  1865      }
  1866      else
  1867      {
  1868          // Force to O_NONE to match Vista decode behaviour
  1869          pID->WMP.wmiI.oOrientation = O_NONE;
  1870      }
  1871  
  1872      pII = &pID->WMP.wmiI;
  1873      pID->uWidth = (U32)pII->cWidth;
  1874      pID->uHeight = (U32)pII->cHeight;
  1875  
  1876  Cleanup:
  1877      return err;
  1878  }
  1879  
  1880  
  1881  ERR PKImageDecode_GetSize_WMP(
  1882      PKImageDecode* pID,
  1883      I32* piWidth,
  1884      I32* piHeight)
  1885  {
  1886      if (pID->WMP.wmiI.oOrientation >= O_RCW)
  1887      {
  1888          *piWidth = (I32)pID->uHeight;
  1889          *piHeight = (I32)pID->uWidth;
  1890      }
  1891      else
  1892      {
  1893          *piWidth = (I32)pID->uWidth;
  1894          *piHeight = (I32)pID->uHeight;
  1895      }
  1896      return WMP_errSuccess;
  1897  }
  1898  
  1899  
  1900  ERR PKImageDecode_GetRawStream_WMP(
  1901      PKImageDecode* pID,
  1902      struct WMPStream** ppWS)
  1903  {
  1904      ERR err = WMP_errSuccess;
  1905      struct WMPStream* pWS = pID->pStream;
  1906  
  1907      *ppWS = NULL;
  1908      Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
  1909      *ppWS = pWS;
  1910  
  1911  Cleanup:
  1912      return err;
  1913  }
  1914  
  1915  ERR PKImageDecode_Copy_WMP(
  1916      PKImageDecode* pID,
  1917      const PKRect* pRect,
  1918      U8* pb,
  1919      U32 cbStride)
  1920  {
  1921      ERR err = WMP_errSuccess;
  1922      U32 cThumbnailScale;
  1923      U32 linesperMBRow;
  1924      CWMImageBufferInfo wmiBI = { 0 };
  1925  #ifdef REENTRANT_MODE
  1926      U8 *pbLowMemAdj = NULL;
  1927      U32 i, cMBRow;
  1928      U32 cMBRowStart;
  1929  #endif // REENTRANT_MODE
  1930      struct WMPStream* pWS = pID->pStream;
  1931      U8 tempAlphaMode = 0;
  1932      wmiBI.pv = pb;
  1933      wmiBI.cLine = pRect->Height;
  1934      wmiBI.cbStride = cbStride;
  1935  #ifdef REENTRANT_MODE
  1936      // In REENTRANT_MODE, we allow rectangles with any top left corner (not just (0,0))
  1937  #else
  1938      FailIf(0 != pRect->X, WMP_errInvalidParameter);
  1939      FailIf(0 != pRect->Y, WMP_errInvalidParameter);
  1940  #endif // REENTRANT_MODE
  1941  
  1942      cThumbnailScale = 1;
  1943  	if (pID->WMP.wmiI.cThumbnailWidth > 0)
  1944  	{
  1945  		while(cThumbnailScale * pID->WMP.wmiI.cThumbnailWidth < pID->uWidth)
  1946  			cThumbnailScale <<= 1;
  1947  	}
  1948      // note the following implementation can't handle fractional linesperMBRow limiting
  1949      // us to >= 1/256 thumbnail which is unfortunate, but all the PS plugin needs is 1/256
  1950      // and I didn't care to get into floating point or a bunch of conditional tests or
  1951      // other rewrite for a case not needed nor tested by PS plugin.  sorry.
  1952      linesperMBRow = 16 / cThumbnailScale;
  1953  
  1954  #ifdef REENTRANT_MODE
  1955      if (0 == pID->WMP.DecoderCurrMBRow) 
  1956      {
  1957  #endif // REENTRANT_MODE
  1958      // Set the fPaddedUserBuffer if the following conditions are met
  1959      if (0 == ((size_t)pb % 128) &&    // Frame buffer is aligned to 128-byte boundary
  1960          0 == (pRect->Height % 16) &&        // Horizontal resolution is multiple of 16
  1961          0 == (pRect->Width % 16) &&        // Vertical resolution is multiple of 16
  1962          0 == (cbStride % 128))              // Stride is a multiple of 128 bytes
  1963      {
  1964          pID->WMP.wmiI.fPaddedUserBuffer = TRUE;
  1965          // Note that there are additional conditions in strdec_x86.c's strDecOpt
  1966          // which could prevent optimization from being engaged
  1967      }
  1968  #ifdef REENTRANT_MODE
  1969      }
  1970  #endif // REENTRANT_MODE
  1971      //if(pID->WMP.wmiSCP.uAlphaMode != 1)
  1972      if((!pID->WMP.bHasAlpha) || (pID->WMP.wmiSCP.uAlphaMode != 1))
  1973      {
  1974          if(pID->WMP.bHasAlpha)//planar alpha
  1975          {
  1976              tempAlphaMode = pID->WMP.wmiSCP.uAlphaMode;
  1977              pID->WMP.wmiSCP.uAlphaMode = 0;
  1978          }
  1979          pID->WMP.wmiSCP.fMeasurePerf = TRUE;
  1980  #ifdef REENTRANT_MODE
  1981          if (0 == pID->WMP.DecoderCurrMBRow) 
  1982          {
  1983              Call(pID->WMP.wmiSCP.pWStream->GetPos(pID->WMP.wmiSCP.pWStream, &(pID->WMP.cMarker)));
  1984              FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
  1985          }
  1986          cMBRow = ((U32) pID->WMP.wmiI.cROITopY + pRect->Y + pRect->Height + linesperMBRow - 1) / linesperMBRow + 1;
  1987          cMBRowStart = pRect->Y / linesperMBRow + 1;
  1988          // if current request starts before current state, then rewind.
  1989          if (cMBRowStart < pID->WMP.DecoderCurrMBRow) 
  1990          {
  1991              pID->WMP.DecoderCurrMBRow = 0;
  1992              pID->WMP.cLinesDecoded = 0;
  1993              pID->WMP.cLinesCropped = 0;
  1994              pID->WMP.fFirstNonZeroDecode = FALSE;
  1995              FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);   
  1996              Call(pID->WMP.wmiSCP.pWStream->SetPos(pID->WMP.wmiSCP.pWStream, pID->WMP.cMarker));
  1997              FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
  1998          }
  1999  
  2000          // In "Low Memory mode", we don't have full frame buffer. We therefore cannot rotate the image.
  2001          // We can flip H, V and HV, but no rotations.
  2002          FailIf(pID->WMP.wmiI.oOrientation >= O_RCW, WMP_errFail);
  2003  
  2004          // In low-memory mode, the full frame buffer is unavailable. This doesn't seem to
  2005          // matter in O_NONE and O_FLIPH, but for O_FLIPV and O_FLIPVH, outputMBRow tries to write to
  2006          // the bottom of full-frame buffer. Adjust the buffer pointer to compensate.
  2007          if (O_FLIPV == pID->WMP.wmiI.oOrientation || O_FLIPVH == pID->WMP.wmiI.oOrientation)
  2008          {
  2009              I32 iActualY2 = pRect->Y + pRect->Height;
  2010              pbLowMemAdj = pb - (pID->WMP.wmiI.cROIHeight - (iActualY2 - pID->WMP.cLinesCropped)) * cbStride;
  2011          }
  2012          else
  2013          {
  2014              pbLowMemAdj = pb - (pRect->Y - pID->WMP.cLinesCropped) * cbStride;
  2015          }
  2016          wmiBI.pv = pbLowMemAdj;
  2017  
  2018          for (i = (U32)pID->WMP.DecoderCurrMBRow; i < cMBRow; i++)
  2019          {
  2020              size_t cLinesDecoded;
  2021              wmiBI.uiFirstMBRow = i;
  2022              wmiBI.uiLastMBRow = i;
  2023              FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI, &cLinesDecoded), WMP_errFail);
  2024              pID->WMP.cLinesDecoded += cLinesDecoded;
  2025              if (FALSE == pID->WMP.fFirstNonZeroDecode && cLinesDecoded > 0)
  2026              {
  2027                  pID->WMP.cLinesCropped += (linesperMBRow - cLinesDecoded);
  2028                  pID->WMP.fFirstNonZeroDecode = TRUE;
  2029              }
  2030  
  2031              if (0 == cLinesDecoded && pRect->Y > 0)
  2032              {
  2033                  pID->WMP.cLinesCropped += linesperMBRow;
  2034              }
  2035          }
  2036          wmiBI.pv = pbLowMemAdj;
  2037  
  2038          // If we're past the top of the image, then we're done, so terminate.
  2039          if (linesperMBRow * (cMBRow - 1) >= pID->WMP.wmiI.cROIHeight) {
  2040              FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);        
  2041          }
  2042          pID->WMP.DecoderCurrMBRow = cMBRow; // Set to next possible MBRow that is decodable
  2043  
  2044  #else
  2045          FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
  2046          FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI), WMP_errFail);
  2047          FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
  2048  #endif //REENTRANT_MODE
  2049  
  2050          if(pID->WMP.bHasAlpha)//planar alpha
  2051          {
  2052              pID->WMP.wmiSCP.uAlphaMode = tempAlphaMode;
  2053          }
  2054      }
  2055  
  2056  //    if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode == 2)
  2057  //    if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 1)
  2058      if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 0)
  2059      {
  2060          pID->WMP.wmiI_Alpha = pID->WMP.wmiI;
  2061          pID->WMP.wmiSCP_Alpha = pID->WMP.wmiSCP;
  2062  
  2063  //        assert(pID->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
  2064          pID->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
  2065  
  2066          switch (pID->WMP.wmiI.bdBitDepth)
  2067          {
  2068              case BD_8:
  2069                  pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) - 1;
  2070                  break;
  2071              
  2072              case BD_16:
  2073              case BD_16S:
  2074              case BD_16F:
  2075                  pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1;
  2076                  break;
  2077              
  2078              case BD_32:
  2079              case BD_32S:
  2080              case BD_32F:
  2081                  pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1;
  2082                  break;
  2083              
  2084              case BD_5:
  2085              case BD_10:
  2086              case BD_565:
  2087              default:
  2088                  break;
  2089          }
  2090  
  2091          pID->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE;
  2092          Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uAlphaOffset));
  2093  #ifdef REENTRANT_MODE
  2094          if (0 == pID->WMP.DecoderCurrAlphaMBRow) // add this to WMP struct!
  2095          {
  2096              FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
  2097          }
  2098          
  2099          cMBRow = ((U32) pID->WMP.wmiI.cROITopY + pRect->Y + pRect->Height + linesperMBRow - 1) / linesperMBRow + 1;
  2100          cMBRowStart = pRect->Y / linesperMBRow + 1;
  2101          // if current request starts before current state, then rewind.
  2102          if (cMBRowStart < pID->WMP.DecoderCurrAlphaMBRow) 
  2103          {
  2104              pID->WMP.DecoderCurrAlphaMBRow = 0;
  2105              FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
  2106              FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
  2107          }
  2108  
  2109          for (i = (U32)pID->WMP.DecoderCurrAlphaMBRow; i < cMBRow; i++)
  2110          {
  2111              size_t cLinesDecoded;
  2112              wmiBI.uiFirstMBRow = i;
  2113              wmiBI.uiLastMBRow = i;
  2114              FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI, &cLinesDecoded), WMP_errFail);
  2115          }
  2116  
  2117          // If we're past the top of the image, then we're done, so terminate
  2118          if (linesperMBRow * (cMBRow - 1) >= pID->WMP.wmiI.cROIHeight) {
  2119              FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
  2120          }
  2121          pID->WMP.DecoderCurrAlphaMBRow = cMBRow; // Set to next possible MBRow that is decodable
  2122          wmiBI.pv = pb;
  2123  #else
  2124          FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
  2125          FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail);
  2126          FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
  2127  #endif //REENTRANT_MODE
  2128      }
  2129  
  2130      pID->idxCurrentLine += pRect->Height;
  2131  
  2132  Cleanup:
  2133      return err;
  2134  }
  2135  
  2136  
  2137  ERR PKImageDecode_GetMetadata_WMP(PKImageDecode *pID, U32 uOffset, U32 uByteCount, U8 *pbGot, U32 *pcbGot)
  2138  {
  2139      ERR err = WMP_errSuccess;
  2140  
  2141      if (pbGot && uOffset)
  2142      {
  2143          struct WMPStream* pWS = pID->pStream;
  2144          size_t iCurrPos;
  2145  
  2146          FailIf(*pcbGot < uByteCount, WMP_errBufferOverflow);
  2147          Call(pWS->GetPos(pWS, &iCurrPos));
  2148          Call(pWS->SetPos(pWS, uOffset));
  2149          Call(pWS->Read(pWS, pbGot, uByteCount));
  2150          Call(pWS->SetPos(pWS, iCurrPos));
  2151      }
  2152  
  2153  Cleanup:
  2154      if (Failed(err))
  2155          *pcbGot = 0;
  2156      else
  2157          *pcbGot = uByteCount;
  2158  
  2159      return err;
  2160  }
  2161  
  2162  
  2163  
  2164  ERR PKImageDecode_GetColorContext_WMP(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext)
  2165  {
  2166      return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uColorProfileOffset,
  2167          pID->WMP.wmiDEMisc.uColorProfileByteCount, pbColorContext, pcbColorContext);
  2168  }
  2169  
  2170  
  2171  
  2172  ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata)
  2173  {
  2174      ERR err = WMP_errSuccess;
  2175      *pDescMetadata = pID->WMP.sDescMetadata;
  2176      return err;
  2177  }
  2178  
  2179  
  2180  ERR PKImageDecode_Release_WMP(PKImageDecode** ppID)
  2181  {
  2182      ERR             err = WMP_errSuccess;
  2183      PKImageDecode  *pID;
  2184  
  2185      if (NULL == ppID)
  2186          goto Cleanup;
  2187  
  2188      pID = *ppID;
  2189  
  2190      // Free descriptive metadata
  2191      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarImageDescription);
  2192      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraMake);
  2193      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraModel);
  2194      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarSoftware);
  2195      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDateTime);
  2196      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarArtist);
  2197      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCopyright);
  2198      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingStars);
  2199      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingValue);
  2200      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCaption);
  2201      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDocumentName);
  2202      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageName);
  2203      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageNumber);
  2204      FreeDescMetadata(&pID->WMP.sDescMetadata.pvarHostComputer);
  2205  
  2206      // Release base class
  2207      Call(PKImageDecode_Release(ppID));
  2208  
  2209  Cleanup:
  2210      return err;
  2211  }
  2212  
  2213  
  2214  
  2215  ERR PKImageDecode_Create_WMP(PKImageDecode** ppID)
  2216  {
  2217      ERR err = WMP_errSuccess;
  2218      PKImageDecode* pID = NULL;
  2219  
  2220      Call(PKImageDecode_Create(ppID));
  2221  
  2222      pID = *ppID;
  2223      pID->Initialize = PKImageDecode_Initialize_WMP;
  2224      pID->GetSize = PKImageDecode_GetSize_WMP;
  2225      pID->GetRawStream = PKImageDecode_GetRawStream_WMP;
  2226      pID->Copy = PKImageDecode_Copy_WMP;
  2227      pID->GetColorContext = PKImageDecode_GetColorContext_WMP;
  2228      pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata_WMP;
  2229      pID->Release = PKImageDecode_Release_WMP;
  2230  
  2231  Cleanup:
  2232      return err;
  2233  }
  2234