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

     1  //*@@@+++@@@@******************************************************************
     2  //
     3  // Copyright Microsoft Corp.
     4  // All rights reserved.
     5  // 
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are met:
     8  // 
     9  // Redistributions of source code must retain the above copyright notice,
    10  //   this list of conditions and the following disclaimer.
    11  // Redistributions in binary form must reproduce the above copyright notice,
    12  //   this list of conditions and the following disclaimer in the documentation
    13  //   and/or other materials provided with the distribution.
    14  // 
    15  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    16  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    17  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    18  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    19  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    20  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    21  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    22  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    23  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    24  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    25  // POSSIBILITY OF SUCH DAMAGE.
    26  //
    27  //*@@@---@@@@******************************************************************
    28  #include <stdlib.h>
    29  #include <string.h>
    30  
    31  #include <strcodec.h>
    32  #include <JXRTest.h>
    33  
    34  //================================================================
    35  #define TIF_tagNull 0
    36  #define TIF_tagSubfileType 0xff
    37  #define TIF_tagNewSubfileType 0xfe
    38  #define TIF_tagImageWidth 0x100
    39  #define TIF_tagImageLength 0x101
    40  #define TIF_tagBitsPerSample 0x102
    41  #define TIF_tagCompression 0x103
    42  #define TIF_tagPhotometricInterpretation 0x106
    43  #define TIF_tagStripOffsets 0x111
    44  #define TIF_tagOrientation 0x112
    45  #define TIF_tagSamplesPerPixel 0x115
    46  #define TIF_tagRowsPerStrip 0x116
    47  #define TIF_tagStripByteCounts 0x117
    48  #define TIF_tagXResolution 0x11a
    49  #define TIF_tagYResolution 0x11b
    50  #define TIF_tagPlanarConfiguration 0x11c
    51  #define TIF_tagResolutionUnit 0x128
    52  #define TIF_tagSoftware 0x131
    53  #define TIF_tagColorMap 0x140
    54  #define TIF_tagPredictor 0x13d
    55  #define TIF_tagInkSet 0x14c
    56  #define TIF_tagExtraSamples 0x152
    57  #define TIF_tagSampleFormat 0x153
    58  
    59  #define TIF_typBYTE 1
    60  #define TIF_typASCII 2
    61  #define TIF_typSHORT 3
    62  #define TIF_typLONG 4
    63  #define TIF_typRATIOAL 5
    64  #define TIF_typSBYTE 6
    65  #define TIF_typUNDEFINED 7
    66  #define TIF_typSSHORT 8
    67  #define TIF_typSLONG 9
    68  #define TIF_typSRATIONAL 10
    69  #define TIF_typFLOAT 11
    70  #define TIF_typDOUBLE 12
    71  
    72  
    73  //================================================================
    74  typedef float FLOAT;
    75  typedef double DOUBLE;
    76  
    77  
    78  //================================================================
    79  // PKImageEncode_TIF helpers
    80  //================================================================
    81  typedef struct tagTifDE
    82  {
    83      U16 uTag;
    84      U16 uType;
    85      U32 uCount;
    86      U32 uValueOrOffset;
    87  } TifDE;
    88  
    89  typedef struct tagTifDEMisc
    90  {
    91      U32 offBitsPerSample;
    92      U32 offSampleFormat;
    93      U32 bps, spp, sf;
    94      U32 iPhotometricInterpretation;
    95  
    96      U32 offXResolution;
    97      U32 resXF, resXD;
    98  
    99      U32 offYResolution;
   100      U32 resYF, resYD;
   101  } TifDEMisc;
   102  
   103  ERR PutTifUShort(
   104      struct WMPStream* pS,
   105      size_t offPos,
   106      U16 uValue)
   107  {
   108      ERR err = WMP_errSuccess;
   109  
   110      Call(pS->SetPos(pS, offPos));
   111      Call(pS->Write(pS, &uValue, sizeof(uValue)));
   112  
   113  Cleanup:
   114      return err;
   115  }
   116  
   117  ERR PutTifULong(
   118      struct WMPStream* pS,
   119      size_t offPos,
   120      U32 uValue)
   121  {
   122      ERR err = WMP_errSuccess;
   123  
   124      Call(pS->SetPos(pS, offPos));
   125      Call(pS->Write(pS, &uValue, sizeof(uValue)));
   126  
   127  Cleanup:
   128      return err;
   129  }
   130  
   131  ERR WriteTifDE(
   132      struct WMPStream* pS,
   133      size_t offPos,
   134      TifDE* pDE)
   135  {
   136      ERR err = WMP_errSuccess;
   137  
   138      assert(-1 != pDE->uCount);
   139      assert(-1 != pDE->uValueOrOffset);
   140  
   141      Call(PutTifUShort(pS, offPos, pDE->uTag)); offPos += 2;
   142      Call(PutTifUShort(pS, offPos, pDE->uType)); offPos += 2;
   143      Call(PutTifULong(pS, offPos, pDE->uCount)); offPos += 4;
   144  
   145      switch (pDE->uType)
   146      {
   147          case TIF_typSHORT:
   148              if (1 == pDE->uCount)
   149              {
   150                  Call(PutTifUShort(pS, offPos, (U16)pDE->uValueOrOffset)); offPos += 2;
   151                  Call(PutTifUShort(pS, offPos, 0)); offPos += 2;
   152                  break;
   153              }
   154              
   155          case TIF_typLONG:
   156          case TIF_typRATIOAL:
   157              Call(PutTifULong(pS, offPos, pDE->uValueOrOffset)); offPos += 4;
   158              break;
   159  
   160          default:
   161              Call(WMP_errInvalidParameter);
   162              break;
   163      }
   164  
   165  Cleanup:
   166      return err;
   167  }
   168  
   169  ERR WriteTifHeader(
   170      PKImageEncode* pIE)
   171  {
   172      ERR err = WMP_errSuccess;
   173      struct WMPStream* pS = pIE->pStream;
   174      size_t offPos = 0;
   175  
   176  #ifdef _BIG__ENDIAN_
   177      U8 IIMM[3] = "MM";
   178  #else // _BIG__ENDIAN_
   179      U8 IIMM[3] = "II";
   180  #endif // _BIG__ENDIAN_
   181  
   182      TifDEMisc tifDEMisc = {
   183          (U32) -1, (U32) -1, (U32) -1, (U32) -1, (U32) -1, 
   184          2, // photometric interpretation
   185          (U32) -1, 10000, 10000,
   186          (U32) -1, 10000, 10000,
   187      };
   188      // const U32 cbTifDEMisc = sizeof(U16) * 10 + sizeof(U32) * 2 * 2;
   189  
   190      const static TifDE tifDEs[] =
   191      {
   192          {0x100, 4,  1, (U32) -1}, // TIF_tagImageWidth
   193          {0x101, 4,  1, (U32) -1}, // TIF_tagImageLength
   194          {0x102, 3, (U32) -1, (U32) -1}, // TIF_tagBitsPerSample
   195          {0x103, 3,  1,  1}, // TIF_tagCompression
   196          {0x106, 3,  1, (U32) -1}, // TIF_tagPhotometricInterpretation
   197          {0x111, 4,  1, (U32) -1}, // TIF_tagStripOffsets
   198          {0x112, 3,  1,  1}, // TIF_tagOrientation
   199          {0x115, 3,  1, (U32) -1}, // TIF_tagSamplesPerPixel
   200          {0x116, 4,  1, (U32) -1}, // TIF_tagRowsPerStrip
   201          {0x117, 4,  1, (U32) -1}, // TIF_tagStripByteCounts
   202          {0x11a, 5,  1, (U32) -1}, // TIF_tagXResolution
   203          {0x11b, 5,  1, (U32) -1}, // TIF_tagYResolution
   204          {0x11c, 3,  1,  1}, // TIF_tagPlanarConfiguration
   205          {0x128, 3,  1,  2}, // TIF_tagResolutionUnit
   206          {0x153, 3, (U32) -1, (U32) -1}, // TIF_tagSampleFormat 
   207  //        {0x131, 2,  -1, -1}, // TIF_tagSoftware
   208  //        {0x140, 3,  -1, -1}, // TIF_tagColorMap
   209      };
   210      U16 cTifDEs = sizeof2(tifDEs);
   211      TifDE tifDE = {0};
   212      PKPixelInfo PI;
   213      size_t cbLine = 0;
   214  
   215      size_t i = 0;
   216      size_t j;
   217  
   218      tifDEMisc.resXF = (U32)(pIE->fResX * 10000);
   219      tifDEMisc.resYF = (U32)(pIE->fResY * 10000);
   220  
   221      Call(pS->GetPos(pS, &offPos));
   222      FailIf(0 != offPos, WMP_errUnsupportedFormat);
   223  
   224      //================
   225      // TifHeader
   226      Call(pS->Write(pS, IIMM, 2)); offPos += 2;
   227      Call(PutTifUShort(pS, offPos, 42)); offPos += 2;
   228      Call(PutTifULong(pS, offPos, (U32)(offPos + 4))); offPos += 4;
   229  
   230      //================
   231      // TifDEMisc
   232      PI.pGUIDPixFmt = &pIE->guidPixFormat;
   233      PixelFormatLookup(&PI, LOOKUP_FORWARD);
   234  
   235      tifDEMisc.iPhotometricInterpretation =
   236          //the N channel TIF by PS has PhotometricInterpretation of PK_PI_RGB
   237          PI.uInterpretation == PK_PI_NCH || PI.uInterpretation == PK_PI_RGBE ? PK_PI_RGB :
   238          (PI.uInterpretation == PK_PI_B0 && pIE->WMP.wmiSCP.bBlackWhite ? PK_PI_W0 : PI.uInterpretation);
   239      tifDEMisc.spp = PI.uSamplePerPixel;
   240      tifDEMisc.bps = PI.uBitsPerSample;
   241      tifDEMisc.sf = PI.uSampleFormat;
   242  
   243      if (tifDEMisc.iPhotometricInterpretation == PK_PI_CMYK)
   244          cTifDEs++;
   245      if (PI.grBit & PK_pixfmtHasAlpha)
   246          cTifDEs++;
   247      tifDEMisc.offBitsPerSample = (U32)offPos + sizeof(U16) + 12 * cTifDEs + sizeof(U32);
   248      tifDEMisc.offSampleFormat = tifDEMisc.offBitsPerSample + (tifDEMisc.spp == 1 ? 0 : tifDEMisc.spp * 2);
   249      tifDEMisc.offXResolution = tifDEMisc.offSampleFormat + (tifDEMisc.spp == 1 ? 0 : tifDEMisc.spp * 2);
   250      tifDEMisc.offYResolution = tifDEMisc.offXResolution + 8;
   251  
   252      //================
   253      // TifIFD
   254      pIE->offPixel = tifDEMisc.offYResolution + 8;
   255      Call(PutTifUShort(pS, offPos, cTifDEs)); offPos += 2;
   256  
   257      //================
   258      tifDE = tifDEs[i++];
   259      assert(TIF_tagImageWidth == tifDE.uTag);
   260      tifDE.uValueOrOffset = pIE->uWidth;
   261      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   262  
   263      tifDE = tifDEs[i++];
   264      assert(TIF_tagImageLength == tifDE.uTag);
   265      tifDE.uValueOrOffset = pIE->uHeight;
   266      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   267      
   268      tifDE = tifDEs[i++];
   269      assert(TIF_tagBitsPerSample == tifDE.uTag);
   270      tifDE.uCount = tifDEMisc.spp;
   271      tifDE.uValueOrOffset = 1 == tifDE.uCount ? tifDEMisc.bps : tifDEMisc.offBitsPerSample;
   272      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   273  
   274      tifDE = tifDEs[i++];
   275      assert(TIF_tagCompression == tifDE.uTag);
   276      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   277  
   278      tifDE = tifDEs[i++];
   279      assert(TIF_tagPhotometricInterpretation == tifDE.uTag);
   280      tifDE.uValueOrOffset = tifDEMisc.iPhotometricInterpretation;
   281      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   282  
   283      tifDE = tifDEs[i++];
   284      assert(TIF_tagStripOffsets == tifDE.uTag);
   285      tifDE.uValueOrOffset = (U32)pIE->offPixel;
   286      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   287  
   288      tifDE = tifDEs[i++];
   289      assert(TIF_tagOrientation == tifDE.uTag);
   290      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   291  
   292      tifDE = tifDEs[i++];
   293      assert(TIF_tagSamplesPerPixel == tifDE.uTag);
   294      tifDE.uValueOrOffset = tifDEMisc.spp;
   295      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   296  
   297      tifDE = tifDEs[i++];
   298      assert(TIF_tagRowsPerStrip == tifDE.uTag);
   299      tifDE.uValueOrOffset = pIE->uHeight;
   300      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   301  
   302      tifDE = tifDEs[i++];
   303      assert(TIF_tagStripByteCounts == tifDE.uTag);
   304      cbLine = (BD_1 == PI.bdBitDepth ? ((PI.cbitUnit * pIE->uWidth + 7) >> 3) : (((PI.cbitUnit + 7) >> 3) * pIE->uWidth)); 
   305      tifDE.uValueOrOffset = (U32)(cbLine * pIE->uHeight);
   306      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   307  
   308      tifDE = tifDEs[i++];
   309      assert(TIF_tagXResolution == tifDE.uTag);
   310      tifDE.uValueOrOffset = tifDEMisc.offXResolution;
   311      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   312  
   313      tifDE = tifDEs[i++];
   314      assert(TIF_tagYResolution == tifDE.uTag);
   315      tifDE.uValueOrOffset = tifDEMisc.offYResolution;
   316      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   317     
   318      tifDE = tifDEs[i++];
   319      assert(TIF_tagPlanarConfiguration == tifDE.uTag);
   320      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   321  
   322      tifDE = tifDEs[i++];
   323      assert(TIF_tagResolutionUnit == tifDE.uTag);
   324      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   325  
   326      if (tifDEMisc.iPhotometricInterpretation == PK_PI_CMYK)
   327      {
   328          TifDE tifDE = {TIF_tagInkSet, 3, 1, 1};
   329          Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   330      }
   331  
   332      if (PI.grBit & PK_pixfmtHasAlpha)
   333      {
   334          TifDE tifDE = {TIF_tagExtraSamples, 3, 1, 1};
   335          if (!(PI.grBit & PK_pixfmtPreMul))
   336              tifDE.uValueOrOffset++;
   337          Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   338      }
   339  
   340      tifDE = tifDEs[i++];
   341      assert(TIF_tagSampleFormat == tifDE.uTag);
   342      tifDE.uCount = tifDEMisc.spp;
   343      tifDE.uValueOrOffset = 1 == tifDE.uCount ? tifDEMisc.sf : tifDEMisc.offSampleFormat;
   344      Call(WriteTifDE(pS, offPos, &tifDE)); offPos += 12;
   345  
   346      //================
   347      Call(PutTifULong(pS, offPos, 0)); offPos += 4;
   348  
   349      //================
   350      // TifDEMisc
   351      if (tifDE.uCount > 1)
   352      {
   353          assert(tifDEMisc.offBitsPerSample == offPos);
   354          if (PI.bdBitDepth == BD_565)
   355          {
   356              Call(PutTifUShort(pS, offPos, 5)); offPos += 2;
   357              Call(PutTifUShort(pS, offPos, 6)); offPos += 2;
   358              Call(PutTifUShort(pS, offPos, 5)); offPos += 2;
   359          }
   360          else
   361          {
   362              for (j = 0; j < tifDE.uCount; j++)
   363              {
   364                  Call(PutTifUShort(pS, offPos, (U16)tifDEMisc.bps)); offPos += 2;
   365              }
   366          }
   367  
   368          assert(tifDEMisc.offSampleFormat == offPos);
   369          for (j = 0; j < tifDE.uCount; j++)
   370          {
   371              Call(PutTifUShort(pS, offPos, (U16)tifDEMisc.sf)); offPos += 2;
   372          }
   373      }
   374      
   375      assert(tifDEMisc.offXResolution == offPos);
   376      Call(PutTifULong(pS, offPos, tifDEMisc.resXF)); offPos += 4;
   377      Call(PutTifULong(pS, offPos, tifDEMisc.resXD)); offPos += 4;
   378  
   379      assert(tifDEMisc.offYResolution == offPos);
   380      Call(PutTifULong(pS, offPos, tifDEMisc.resYF)); offPos += 4;
   381      Call(PutTifULong(pS, offPos, tifDEMisc.resYD)); offPos += 4;
   382  
   383      assert(pIE->offPixel == offPos);
   384  
   385      pIE->fHeaderDone = !FALSE;
   386  
   387  Cleanup:
   388      return err;
   389  }
   390  
   391  //================================================================
   392  // PKImageEncode_TIF
   393  //================================================================
   394  ERR PKImageEncode_WritePixels_TIF(
   395      PKImageEncode* pIE,
   396      U32 cLine,
   397      U8* pbPixel,
   398      U32 cbStride)
   399  {
   400      ERR err = WMP_errSuccess;
   401  
   402      struct WMPStream* pS = pIE->pStream;
   403      PKPixelInfo PI;
   404      size_t cbLine = 0;
   405      size_t offPos = 0;
   406      size_t i = 0;
   407  
   408      // header
   409      if (!pIE->fHeaderDone)
   410      {
   411          Call(WriteTifHeader(pIE));
   412      }
   413  
   414      // body
   415      PI.pGUIDPixFmt = &pIE->guidPixFormat;
   416      PixelFormatLookup(&PI, LOOKUP_FORWARD);
   417  
   418      cbLine = (BD_1 == PI.bdBitDepth ? ((PI.cbitUnit * pIE->uWidth + 7) >> 3) : (((PI.cbitUnit + 7) >> 3) * pIE->uWidth)); 
   419  
   420      FailIf(cbStride < cbLine, WMP_errInvalidParameter);
   421  
   422      offPos = pIE->offPixel + cbLine * pIE->idxCurrentLine;
   423      Call(pS->SetPos(pS, offPos));
   424  
   425      for (i = 0; i < cLine; ++i)
   426      {
   427          Call(pS->Write(pS, pbPixel + cbStride * i, cbLine));
   428      }
   429      pIE->idxCurrentLine += cLine;
   430  
   431  Cleanup:
   432      return err;
   433  }
   434  
   435  ERR PKImageEncode_Create_TIF(PKImageEncode** ppIE)
   436  {
   437      ERR err = WMP_errSuccess;
   438  
   439      PKImageEncode* pIE = NULL;
   440  
   441      Call(PKImageEncode_Create(ppIE));
   442  
   443      pIE = *ppIE;
   444      pIE->WritePixels = PKImageEncode_WritePixels_TIF;
   445  
   446  Cleanup:
   447      return err;
   448  }
   449  
   450  
   451  //================================================================
   452  // PKImageDecode_TIF helpers
   453  //================================================================
   454  ERR GetTifUShort(
   455      struct WMPStream* pWS,
   456      size_t offPos,
   457      Bool fLittleEndian,
   458      U16* puValue)
   459  {
   460      ERR err = WMP_errSuccess;
   461      U8 buf[2];
   462  
   463      Call(pWS->SetPos(pWS, offPos));
   464      Call(pWS->Read(pWS, buf, sizeof2(buf)));
   465  
   466      if (fLittleEndian)
   467      {
   468          *puValue = buf[0] + ((U16)buf[1] << 8);
   469      }
   470      else
   471      {
   472          *puValue = ((U16)buf[0] << 8) + buf[1];
   473      }
   474  
   475  Cleanup:
   476      return err;
   477  }
   478  
   479  ERR GetTifULong(
   480      struct WMPStream* pWS,
   481      size_t offPos,
   482      Bool fLittleEndian,
   483      U32* puValue)
   484  {
   485      ERR err = WMP_errSuccess;
   486      U8 buf[4];
   487  
   488      Call(pWS->SetPos(pWS, offPos));
   489      Call(pWS->Read(pWS, buf, sizeof2(buf)));
   490  
   491      if (fLittleEndian)
   492      {
   493          *puValue = buf[0] + ((U32)buf[1] << 8) + ((U32)buf[2] << 16) + ((U32)buf[3] << 24);
   494      }
   495      else
   496      {
   497          *puValue = ((U32)buf[0] << 24) + ((U32)buf[1] << 16) + ((U32)buf[2] << 8) + buf[3];
   498      }
   499  
   500  Cleanup:
   501      return err;
   502  }
   503  
   504  ERR GetTifULongArray(
   505      struct WMPStream* pWS,
   506      size_t offPos,
   507      size_t cElements,
   508      Bool fLittleEndian,
   509      U32* puValue)
   510  {
   511      ERR err = WMP_errSuccess;
   512  
   513      if (1 == cElements)
   514      {
   515          puValue[0] = (U32)offPos;
   516      }
   517      else
   518      {
   519          size_t i = 0;
   520          for (i = 0; i < cElements; ++i)
   521          {
   522              Call(GetTifULong(pWS, offPos, fLittleEndian, &puValue[i]));
   523              offPos += sizeof(*puValue);
   524          }
   525      }
   526  
   527  Cleanup:
   528      return err;
   529  }
   530  
   531  ERR ParseTifDEValue(
   532      PKTestDecode* pID,
   533      U16 uTag,
   534      U16 uType,
   535      U32 uCount)
   536  {
   537      ERR err = WMP_errSuccess;
   538  
   539      struct WMPStream* pWS = pID->pStream;
   540      U16 bpc[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
   541      U16 sf[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
   542      U32 uPos = 0;
   543      U16 usValue = 0;
   544      U32 uValue0 = 0;
   545      U32 uValue1 = 0;
   546      size_t i, offPos = 0;
   547  
   548      //================================
   549      Call(pWS->GetPos(pWS, &offPos));
   550  
   551      //================================
   552      switch (uType)
   553      {
   554          case TIF_typSHORT:
   555              Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &usValue));
   556              uValue0 = usValue;
   557              break;
   558  
   559          case TIF_typLONG:
   560              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uValue0));
   561              break;
   562      }
   563  
   564      //================================
   565      switch (uTag)
   566      {
   567          case TIF_tagNewSubfileType:
   568              FailIf(0 != uValue0, WMP_errUnsupportedFormat);
   569              break;
   570  
   571          case TIF_tagSubfileType:
   572          case TIF_tagPredictor:
   573              FailIf(1 != uValue0, WMP_errUnsupportedFormat);
   574              break;
   575  
   576          case TIF_tagImageWidth:
   577              pID->uWidth = uValue0;
   578              break;
   579  
   580          case TIF_tagImageLength:
   581              pID->uHeight = uValue0;
   582              break;
   583  
   584          case TIF_tagBitsPerSample:
   585              if (1 == uCount)
   586              {
   587                  pID->EXT.TIF.uBitsPerSample = uValue0; 
   588              }
   589              else
   590              {
   591                  Bool bpcAnd = 1;
   592  
   593                  Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uPos));
   594                  offPos = uPos;
   595  
   596                  Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &bpc[0]));
   597  
   598                  for (i = 1; i < uCount; i++)
   599                  {
   600                      Call(GetTifUShort(pWS, offPos + (i << 1) , pID->EXT.TIF.fLittleEndian, &bpc[i]));
   601                      bpcAnd = (bpcAnd && (bpc[0] == bpc[i]));
   602                  }
   603  
   604                  if (bpcAnd)
   605                      pID->EXT.TIF.uBitsPerSample = bpc[0];
   606                  else
   607                      Call(WMP_errUnsupportedFormat);
   608              }
   609              break;
   610  
   611          case TIF_tagExtraSamples:
   612              FailIf(0 != uValue0 && 1 != uValue0 && 2 != uValue0, WMP_errUnsupportedFormat);
   613              pID->EXT.TIF.uExtraSamples = uValue0;
   614              break;
   615  
   616          case TIF_tagSampleFormat:
   617              if (1 == uCount)
   618              {
   619                  pID->EXT.TIF.uSampleFormat = uValue0; 
   620              }
   621              else
   622              {
   623                  Bool sfAnd = 1;
   624  
   625                  Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uPos));
   626                  offPos = uPos;
   627  
   628                  Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &sf[0]));
   629  
   630                  for (i = 1; i < uCount; i++)
   631                  {
   632                      Call(GetTifUShort(pWS, offPos + (i << 1) , pID->EXT.TIF.fLittleEndian, &sf[i]));
   633                      sfAnd = (sfAnd && (sf[0] == sf[i]));
   634                  }
   635  
   636                  if (sfAnd)
   637                      pID->EXT.TIF.uSampleFormat = sf[0];
   638                  else
   639                      Call(WMP_errUnsupportedFormat);
   640              }
   641              break;
   642  
   643          case TIF_tagCompression:
   644              FailIf(1 != uValue0, WMP_errUnsupportedFormat);
   645              break;
   646  
   647          case TIF_tagPhotometricInterpretation:
   648              Test(PK_PI_W0 == uValue0 || PK_PI_B0 == uValue0 || PK_PI_RGB == uValue0 
   649                  || PK_PI_RGBPalette == uValue0 || PK_PI_TransparencyMask == uValue0
   650                  || PK_PI_CMYK == uValue0 || PK_PI_YCbCr == uValue0
   651                  || PK_PI_CIELab == uValue0, WMP_errUnsupportedFormat);
   652  
   653              pID->EXT.TIF.uInterpretation = uValue0; 
   654              break;
   655  
   656          case TIF_tagStripOffsets:
   657              Call(WMPAlloc((void **) &pID->EXT.TIF.uStripOffsets, sizeof(*pID->EXT.TIF.uStripOffsets) * uCount));
   658              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uValue0));
   659              Call(GetTifULongArray(pWS, uValue0, uCount, pID->EXT.TIF.fLittleEndian, pID->EXT.TIF.uStripOffsets));
   660              break;
   661  
   662          case TIF_tagOrientation:
   663          case TIF_tagSamplesPerPixel:
   664              pID->EXT.TIF.uSamplePerPixel = uValue0;
   665              break;
   666  
   667          case TIF_tagRowsPerStrip:
   668              pID->EXT.TIF.uRowsPerStrip = uValue0;
   669              break;
   670  
   671          case TIF_tagStripByteCounts:
   672              Call(WMPAlloc((void **) &pID->EXT.TIF.uStripByteCounts, sizeof(*pID->EXT.TIF.uStripByteCounts) * uCount));
   673              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uValue0));
   674              Call(GetTifULongArray(pWS, uValue0, uCount, pID->EXT.TIF.fLittleEndian, pID->EXT.TIF.uStripByteCounts));
   675              break;
   676  
   677          case TIF_tagXResolution:
   678              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uPos));
   679              offPos = uPos;
   680  
   681              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uValue0));//numerator
   682              Call(GetTifULong(pWS, offPos + 4, pID->EXT.TIF.fLittleEndian, &uValue1));//denominator
   683  
   684              pID->EXT.TIF.fResX = (Float)uValue0/(Float)uValue1;
   685              break;
   686  
   687          case TIF_tagYResolution:
   688              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uPos));
   689              offPos = uPos;
   690  
   691              Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uValue0));//numerator
   692              Call(GetTifULong(pWS, offPos + 4, pID->EXT.TIF.fLittleEndian, &uValue1));//denominator
   693              pID->EXT.TIF.fResY = (Float)uValue0/(Float)uValue1;
   694              break;
   695  
   696          case TIF_tagResolutionUnit:
   697              pID->EXT.TIF.uResolutionUnit = usValue;
   698              break;
   699  
   700          case TIF_tagPlanarConfiguration:
   701          case TIF_tagSoftware:
   702          case TIF_tagColorMap:
   703              break;
   704  
   705          default:
   706              printf("Unrecognized TIFTag: %d(%#x), %d, %d" CRLF, (int)uTag, (int)uTag, (int)uType, (int)uCount);
   707              break;
   708      }
   709  
   710  Cleanup:
   711      return err;
   712  }
   713  
   714  ERR ParseTifDEArray(
   715      PKTestDecode* pID,
   716      size_t offPos)
   717  {
   718      ERR err = WMP_errSuccess;
   719  
   720      struct WMPStream* pWS = pID->pStream;
   721      U16 uTag = 0;
   722      U16 uType = 0;
   723      U32 uCount = 0;
   724  
   725      Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uTag));
   726      offPos += 2;
   727  
   728      Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uType));
   729      offPos += 2;
   730  
   731      Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uCount));
   732      offPos += 4;
   733  
   734      Call(ParseTifDEValue(pID, uTag, uType, uCount));
   735  
   736  Cleanup:
   737      return err;
   738  }
   739  
   740  ERR ParseTifHeader(
   741      PKTestDecode* pID,
   742      struct WMPStream* pWS)
   743  {
   744      ERR err = WMP_errSuccess;
   745      PKPixelInfo PI;
   746  
   747      size_t offPosBase = 0;
   748      size_t offPos = 0;
   749  
   750      U8 szSig[3] = {0, 0, '\0'};
   751      U16 uTiffId = 0;
   752      U32 uOffNextIFD = 0;
   753      U16 uCountDE = 0, i = 0;
   754  
   755      //default
   756      pID->EXT.TIF.uRowsPerStrip = (U32) -1;
   757      pID->EXT.TIF.uInterpretation = (U32) -1;
   758      pID->EXT.TIF.uSamplePerPixel = (U32) -1;
   759      pID->EXT.TIF.uBitsPerSample = (U32) -1;
   760      pID->EXT.TIF.uSampleFormat = 1;
   761      pID->EXT.TIF.uResolutionUnit = 2;
   762      pID->EXT.TIF.fResX = 96;
   763      pID->EXT.TIF.fResY = 96;
   764      
   765      //================================
   766      Call(pWS->GetPos(pWS, &offPosBase));
   767      FailIf(0 != offPosBase, WMP_errUnsupportedFormat);
   768  
   769      //================================
   770      // Header
   771      Call(pWS->Read(pWS, szSig, 2));
   772      offPos += 2;
   773      if (szSig == (U8 *) strstr((char *) szSig, "II"))
   774      {
   775          pID->EXT.TIF.fLittleEndian = !FALSE;
   776      }
   777      else if (szSig == (U8 *) strstr((char *) szSig, "MM"))
   778      {
   779          pID->EXT.TIF.fLittleEndian = FALSE;
   780      }
   781      else
   782      {
   783          Call(WMP_errUnsupportedFormat);
   784      }
   785  
   786      Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uTiffId));
   787      offPos += 2;
   788      FailIf(42 != uTiffId, WMP_errUnsupportedFormat);
   789  
   790      Call(GetTifULong(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uOffNextIFD));
   791      offPos += 4;
   792  
   793      //================================
   794      // IFD
   795      offPos = (size_t)uOffNextIFD;
   796      Call(GetTifUShort(pWS, offPos, pID->EXT.TIF.fLittleEndian, &uCountDE));
   797      offPos += 2;
   798  
   799      for (i = 0; i < uCountDE; ++i)
   800      {
   801          Call(ParseTifDEArray(pID, offPos));
   802          offPos += 12;
   803      }
   804  
   805      if(pID->EXT.TIF.uRowsPerStrip == -1)
   806          pID->EXT.TIF.uRowsPerStrip = pID->uHeight;//default
   807  
   808      FailIf((-1 == pID->EXT.TIF.uInterpretation 
   809          || -1 == pID->EXT.TIF.uSamplePerPixel
   810          || -1 == pID->EXT.TIF.uBitsPerSample), WMP_errUnsupportedFormat);
   811  
   812      PI.uInterpretation = pID->EXT.TIF.uInterpretation;
   813      PI.uSamplePerPixel = pID->EXT.TIF.uSamplePerPixel;
   814      PI.uBitsPerSample = pID->EXT.TIF.uBitsPerSample;
   815      PI.uSampleFormat = pID->EXT.TIF.uSampleFormat;
   816  
   817      PI.grBit = pID->EXT.TIF.uExtraSamples == 1 || pID->EXT.TIF.uExtraSamples == 2 ||
   818          /* Workaround for some images without correct info about alpha channel */
   819          (pID->EXT.TIF.uExtraSamples == 0 &&  pID->EXT.TIF.uSamplePerPixel > 3) ? PK_pixfmtHasAlpha : 0x0;
   820      PI.grBit |= pID->EXT.TIF.uExtraSamples == 1 ? PK_pixfmtPreMul : 0x0;
   821  
   822      pID->fResX = (3 == pID->EXT.TIF.uResolutionUnit ? (Float)(pID->EXT.TIF.fResX * 2.54) : pID->EXT.TIF.fResX);//cm -> inch
   823      pID->fResY = (3 == pID->EXT.TIF.uResolutionUnit ? (Float)(pID->EXT.TIF.fResY * 2.54) : pID->EXT.TIF.fResY);//cm -> inch
   824  
   825      Call(PixelFormatLookup(&PI, LOOKUP_BACKWARD_TIF));
   826  
   827      pID->guidPixFormat = *(PI.pGUIDPixFmt);
   828  
   829  Cleanup:
   830      return err;
   831  }
   832  
   833  //================================================================
   834  // PKImageDecode_TIF
   835  //================================================================
   836  ERR PKImageDecode_Initialize_TIF(
   837      PKTestDecode* pID,
   838      struct WMPStream* pWS)
   839  {
   840      ERR err = WMP_errSuccess;
   841  
   842      Call(PKTestDecode_Initialize(pID, pWS));
   843      Call(ParseTifHeader(pID, pWS));
   844  
   845  Cleanup:
   846      return err;
   847  }
   848  
   849  ERR GetScanLineOffset(
   850      PKTestDecode* pID,
   851      I32 iLine,
   852      U32 cbLine,
   853      U32 *offLine)
   854  {
   855      *offLine = pID->EXT.TIF.uRowsPerStrip ? 
   856          (pID->EXT.TIF.uStripOffsets[iLine / pID->EXT.TIF.uRowsPerStrip] +
   857          cbLine * (iLine % pID->EXT.TIF.uRowsPerStrip)) :
   858          0;        
   859  
   860      return WMP_errSuccess;
   861  }
   862  
   863  ERR PKImageDecode_Copy_TIF(
   864      PKTestDecode* pID,
   865      const PKRect* pRect,
   866      U8* pb,
   867      U32 cbStride)
   868  {
   869      ERR err = WMP_errSuccess;
   870  
   871      struct WMPStream* pS = pID->pStream;
   872      PKPixelInfo PI;
   873      U32 cbLine = 0;
   874      I32 i = 0;
   875  
   876      PI.pGUIDPixFmt = &pID->guidPixFormat;
   877      PixelFormatLookup(&PI, LOOKUP_FORWARD);
   878  
   879      cbLine = (BD_1 == PI.bdBitDepth ? ((PI.cbitUnit * pRect->Width + 7) >> 3) : (((PI.cbitUnit + 7) >> 3) * pRect->Width)); 
   880  
   881      assert(0 == pRect->X && pID->uWidth == (U32)pRect->Width);
   882      assert(cbLine <= cbStride);
   883  
   884      for (i = 0; i < pRect->Height; ++i)
   885      {
   886          U32 offPixels = 0;
   887          Call(GetScanLineOffset(pID, pRect->Y + i, cbLine, &offPixels));
   888  
   889          Call(pS->SetPos(pS, offPixels));
   890          Call(pS->Read(pS, pb + cbStride * i, cbLine));
   891  
   892          if (PK_PI_W0 == pID->EXT.TIF.uInterpretation) 
   893          {
   894              U32 j, begin = cbStride * (U32)i, end = begin + cbLine;
   895              for (j = begin; j < end; ++j)
   896              {
   897                  pb[j] = ~pb[j];
   898              }
   899          }
   900      }
   901  
   902  Cleanup:
   903      return err;
   904  }
   905  
   906  ERR PKImageDecode_Release_TIF(PKTestDecode** ppID)
   907  {
   908      ERR err = WMP_errSuccess;
   909  
   910      PKTestDecode *pID = *ppID;
   911  
   912      Call(WMPFree(&pID->EXT.TIF.uStripOffsets));
   913      Call(WMPFree(&pID->EXT.TIF.uStripByteCounts));
   914  
   915      Call(PKTestDecode_Release(ppID));
   916  
   917  Cleanup:
   918      return err;
   919  }
   920  
   921  ERR PKImageDecode_Create_TIF(PKTestDecode** ppID)
   922  {
   923      ERR err = WMP_errSuccess;
   924      PKTestDecode* pID = NULL;
   925  
   926      Call(PKTestDecode_Create(ppID));
   927  
   928      pID = *ppID;
   929      pID->Initialize = PKImageDecode_Initialize_TIF;
   930      pID->Copy = PKImageDecode_Copy_TIF;
   931      pID->Release = PKImageDecode_Release_TIF;
   932  
   933  Cleanup:
   934      return err;
   935  }
   936