github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/jxr/jxrlib/jxrtestlib/JXRTestBmp.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 <JXRTest.h>
    32  
    33  #pragma pack(push, 1)
    34  
    35  #define BI_RGB 0
    36  #define BI_BITFIELDS 3
    37  
    38  #define BI_RGB555_MASK_B 0x001F
    39  #define BI_RGB555_MASK_G 0x03E0
    40  #define BI_RGB555_MASK_R 0x7C00
    41  
    42  #define BI_RGB565_MASK_B 0x001F
    43  #define BI_RGB565_MASK_G 0x07E0
    44  #define BI_RGB565_MASK_R 0xF800
    45  
    46  #define BI_RGB101010_MASK_B 0x000003FF
    47  #define BI_RGB101010_MASK_G 0x000FFC00
    48  #define BI_RGB101010_MASK_R 0x3FF00000
    49  
    50  typedef struct tagBITMAPFILEHEADER { 
    51      U8 szBM[2];
    52      U32 uSize;
    53      U16 reserved1;
    54      U16 reserved2;
    55      U32 uOffBits;
    56  } BITMAPFILEHEADER, *PBITMAPFILEHEADER; 
    57  
    58  typedef struct tagBITMAPINFOHEADER{
    59      U32 uSize;
    60      I32 iWidth;
    61      I32 iHeight;
    62      I16 iPlanes;
    63      I16 iBitCount;
    64      U32 uCompression;
    65      U32 uImageSize;
    66      I32 iPelsPerMeterX;
    67      I32 iPelsPerMeterY;
    68      U32 uColorUsed;
    69      U32 uColorImportant;
    70  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
    71  
    72  typedef struct tagBITMAPINFOHEADEREXT{
    73      U32 uA;
    74      U32 uB;
    75      U32 uC;
    76      U32 uD;
    77  } BITMAPINFOHEADEREXT, *PBITMAPINFOHEADEREXT;
    78  
    79  
    80  #pragma pack(pop)
    81  
    82  //================================================================
    83  // PKImageEncode_BMP
    84  //================================================================
    85  ERR WriteBMPHeader(
    86      PKImageEncode* pIE)
    87  {
    88      ERR err = WMP_errSuccess;
    89  
    90      static U32 rguColorTable[256] = {0};
    91      size_t cbColorTable = 0;
    92      size_t cbLineS = 0;
    93      U32 i = 0;
    94  
    95      struct WMPStream* pS = pIE->pStream;
    96      BITMAPFILEHEADER bmpFH = { 0, };
    97      BITMAPINFOHEADER bmpIH = {sizeof(bmpIH), 0, };
    98  
    99      bmpFH.szBM[0] = 'B';
   100      bmpFH.szBM[1] = 'M';
   101  
   102      if (IsEqualGUID(&GUID_PKPixelFormat24bppRGB, &pIE->guidPixFormat) || IsEqualGUID(&GUID_PKPixelFormat24bppBGR, &pIE->guidPixFormat))
   103      {
   104          pIE->cbPixel = 3;
   105          cbColorTable = 0;
   106      }
   107      else if (IsEqualGUID(&GUID_PKPixelFormat32bppBGRA, &pIE->guidPixFormat) 
   108          || IsEqualGUID(&GUID_PKPixelFormat32bppBGR, &pIE->guidPixFormat)
   109          || IsEqualGUID(&GUID_PKPixelFormat32bppPBGRA, &pIE->guidPixFormat))
   110      {
   111          pIE->cbPixel = 4;
   112          cbColorTable = 0;
   113      }
   114      else if (IsEqualGUID(&GUID_PKPixelFormat8bppGray, &pIE->guidPixFormat))
   115      {
   116          pIE->cbPixel = 1;
   117  
   118          cbColorTable = sizeof(rguColorTable);
   119          for (i = 0; i < sizeof2(rguColorTable); ++i)
   120          {
   121              rguColorTable[i] = i | (i << 8) | (i << 16);
   122          }
   123      }
   124      else if (IsEqualGUID(&GUID_PKPixelFormat16bppRGB555, &pIE->guidPixFormat))
   125      {
   126          pIE->cbPixel = 2;
   127          bmpIH.uCompression = BI_BITFIELDS;
   128  
   129          cbColorTable = sizeof(rguColorTable[0]) * 3;
   130          rguColorTable[0] = BI_RGB555_MASK_R;
   131          rguColorTable[1] = BI_RGB555_MASK_G;
   132          rguColorTable[2] = BI_RGB555_MASK_B;
   133      }
   134      else if (IsEqualGUID(&GUID_PKPixelFormat16bppRGB565, &pIE->guidPixFormat))
   135      {
   136          pIE->cbPixel = 2;
   137          bmpIH.uCompression = BI_BITFIELDS;
   138  
   139          cbColorTable = sizeof(rguColorTable[0]) * 3;
   140          rguColorTable[0] = BI_RGB565_MASK_R;
   141          rguColorTable[1] = BI_RGB565_MASK_G;
   142          rguColorTable[2] = BI_RGB565_MASK_B;
   143      }
   144      else if (IsEqualGUID(&GUID_PKPixelFormat32bppRGB101010, &pIE->guidPixFormat))
   145      {
   146          pIE->cbPixel = 4;
   147          bmpIH.uCompression = BI_BITFIELDS;
   148  
   149          cbColorTable = sizeof(rguColorTable[0]) * 3;
   150          rguColorTable[0] = BI_RGB101010_MASK_R;
   151          rguColorTable[1] = BI_RGB101010_MASK_G;
   152          rguColorTable[2] = BI_RGB101010_MASK_B;
   153      }            
   154      else
   155          Call(WMP_errUnsupportedFormat);
   156  
   157      cbLineS = (pIE->cbPixel * pIE->uWidth + 3) / 4 * 4;
   158  
   159      bmpFH.uOffBits = (U32)(sizeof(bmpFH) + sizeof(bmpIH) + cbColorTable);
   160      bmpFH.uSize = (U32)(bmpFH.uOffBits + cbLineS * pIE->uHeight);
   161  
   162      bmpIH.iWidth = pIE->uWidth;
   163      bmpIH.iHeight = pIE->uHeight;
   164      bmpIH.iPlanes = 1;
   165      bmpIH.iBitCount = (I16)(8 * pIE->cbPixel);
   166      bmpIH.uImageSize = (U32)(cbLineS * pIE->uHeight);
   167      bmpIH.iPelsPerMeterX = (I32)(pIE->fResX * 39.37);
   168      bmpIH.iPelsPerMeterY = (I32)(pIE->fResY * 39.37);
   169  
   170      Call(pS->Write(pS, &bmpFH, sizeof(bmpFH)));
   171      Call(pS->Write(pS, &bmpIH, sizeof(bmpIH)));
   172      Call(pS->Write(pS, rguColorTable, cbColorTable));
   173  
   174      pIE->offPixel = pIE->offStart + bmpFH.uOffBits;
   175      pIE->fHeaderDone = !FALSE;
   176  
   177  Cleanup:
   178      return err;
   179  }
   180  
   181  ERR PKImageEncode_WritePixels_BMP(
   182      PKImageEncode* pIE,
   183      U32 cLine,
   184      U8* pbPixel,
   185      U32 cbStride)
   186  {
   187      ERR err = WMP_errSuccess;
   188  
   189      struct WMPStream* pS = pIE->pStream;
   190      size_t cbLineM = 0, cbLineS = 0;
   191      I32 i = 0;
   192      static U8 pPadding[4] = {0};
   193  
   194      // header
   195      if (!pIE->fHeaderDone)
   196      {
   197          // WriteBMPHeader() also inits this object
   198          Call(WriteBMPHeader(pIE));
   199      }
   200  
   201      // body
   202      // calculate line size in memory and in stream
   203      cbLineM = pIE->cbPixel * pIE->uWidth;
   204      cbLineS = (cbLineM + 3) / 4 * 4;
   205  
   206      //FailIf(pRect->X < 0 || pID->uWidth <= pRect->X, WMP_errInvalidParameter);
   207      //FailIf(pRect->Y < 0 || pID->uHeight <= pRect->Y, WMP_errInvalidParameter);
   208      //FailIf(pRect->Width < 0 || pID->uWidth < pRect->X + pRect->Width, WMP_errInvalidParameter);
   209      //FailIf(pRect->Height < 0 || pID->uHeight < pRect->Y + pRect->Height, WMP_errInvalidParameter);
   210      FailIf(cbStride < cbLineM, WMP_errInvalidParameter);
   211  
   212      for (i = cLine - 1; 0 <= i; --i)
   213      {
   214          size_t offM = cbStride * i;
   215          size_t offS = cbLineS * (pIE->uHeight - (pIE->idxCurrentLine + i + 1));
   216  
   217          Call(pS->SetPos(pS, pIE->offPixel + offS));
   218          Call(pS->Write(pS, pbPixel + offM, cbLineM));
   219      }
   220      Call(pS->Write(pS, pPadding, (cbLineS - cbLineM)));
   221      pIE->idxCurrentLine += cLine;
   222  
   223  Cleanup:
   224      return err;
   225  }
   226  
   227  ERR PKImageEncode_Create_BMP(
   228      PKImageEncode** ppIE)
   229  {
   230      ERR err = WMP_errSuccess;
   231      PKImageEncode* pIE = NULL;
   232  
   233      Call(PKImageEncode_Create(ppIE));
   234  
   235      pIE = *ppIE;
   236      pIE->WritePixels = PKImageEncode_WritePixels_BMP;
   237  
   238  Cleanup:
   239      return err;
   240  }
   241  
   242  
   243  //================================================================
   244  // PKImageDecode_BMP
   245  //================================================================
   246  ERR ParseBMPHeader(
   247      PKTestDecode* pID,
   248      struct WMPStream* pWS)
   249  {
   250      ERR err = WMP_errSuccess;
   251  
   252      BITMAPFILEHEADER bmpFH = {0};
   253      BITMAPINFOHEADER bmpIH = {0};
   254      static U32 bmpIHE[32] = {0};    // should be >= sizeof(BITMAPV5HEADER) - sizeof(BITMAPINFOHEADER)
   255      static U32 rguColorTable[256] = {0};
   256      U32 i = 0;
   257  
   258      Call(pWS->Read(pWS, &bmpFH, sizeof(bmpFH)));
   259      FailIf(bmpFH.szBM != (U8 *) strstr((char *) bmpFH.szBM, "BM"), WMP_errUnsupportedFormat);
   260  
   261      Call(pWS->Read(pWS, &bmpIH, sizeof(bmpIH)));
   262  
   263      FailIf(((sizeof(bmpIH) > bmpIH.uSize) || ((sizeof(bmpIH) + sizeof(bmpIHE)) < bmpIH.uSize)), WMP_errUnsupportedFormat);
   264  
   265      if (sizeof(bmpIH) < bmpIH.uSize)
   266          Call(pWS->Read(pWS, &bmpIHE, bmpIH.uSize - sizeof(bmpIH)));
   267  
   268      switch (bmpIH.iBitCount)
   269      {
   270          case 8:
   271              // check the color table to verify the image is actually gray scale
   272              Call(pWS->Read(pWS, rguColorTable, sizeof(rguColorTable)));
   273              for (i = 0; i < sizeof2(rguColorTable); ++i)
   274              {
   275                  U32 c = i | (i << 8) | (i << 16);
   276                  FailIf(c != rguColorTable[i], WMP_errUnsupportedFormat);
   277              }
   278              
   279              pID->guidPixFormat = GUID_PKPixelFormat8bppGray;
   280              pID->EXT.BMP.cbPixel = 1;
   281              break;
   282  
   283          case 16:
   284  //            Call(pWS->Read(pWS, rguColorTable, sizeof(rguColorTable[0] * 3)));
   285  /*            if (BI_RGB555_MASK_B == rguColorTable[0] && BI_RGB555_MASK_G == rguColorTable[1] && BI_RGB555_MASK_R == rguColorTable[2])
   286              {
   287                  pID->guidPixFormat = GUID_PKPixelFormat16bppRGB555;
   288              }
   289              if (BI_RGB565_MASK_B == rguColorTable[0] && BI_RGB565_MASK_G == rguColorTable[1] && BI_RGB565_MASK_R == rguColorTable[2])
   290              {
   291                  pID->guidPixFormat = GUID_PKPixelFormat16bppRGB565;
   292              }
   293              else
   294              {
   295                  Call(WMP_errUnsupportedFormat);
   296              }
   297  */
   298              pID->EXT.BMP.cbPixel = 2;
   299              break;
   300              
   301          case 24:
   302              pID->guidPixFormat = GUID_PKPixelFormat24bppBGR;
   303              pID->EXT.BMP.cbPixel = 3;
   304              break;
   305  
   306          case 32:
   307  /*            Call(pWS->Read(pWS, rguColorTable, sizeof(rguColorTable[0] * 3)));
   308              if (BI_RGB101010_MASK_B == rguColorTable[0] && BI_RGB101010_MASK_G == rguColorTable[1] && BI_RGB101010_MASK_R == rguColorTable[2])
   309              {
   310                  pID->guidPixFormat = GUID_PKPixelFormat32bppRGB101010;
   311              }
   312              else
   313              {
   314                  Call(WMP_errUnsupportedFormat);
   315              }
   316  */
   317  //            pID->guidPixFormat = GUID_PKPixelFormat32bppBGRA;
   318              pID->EXT.BMP.cbPixel = 4;
   319              break;
   320              
   321          default:
   322              Call(WMP_errUnsupportedFormat);
   323              break;
   324      }
   325  
   326      pID->uWidth = (U32)bmpIH.iWidth;
   327      pID->uHeight = (U32)bmpIH.iHeight;
   328  
   329      pID->fResX = (0 == bmpIH.iPelsPerMeterX ? 96 : (Float)(bmpIH.iPelsPerMeterX * .0254));
   330      pID->fResY = (0 == bmpIH.iPelsPerMeterY ? 96 : (Float)(bmpIH.iPelsPerMeterY * .0254));
   331      
   332      pID->EXT.BMP.offPixel = pID->offStart + bmpFH.uOffBits;
   333  
   334  Cleanup:
   335      return err;
   336  }
   337  
   338  ERR PKImageDecode_Initialize_BMP(
   339      PKTestDecode* pID,
   340      struct WMPStream* pWS)
   341  {
   342      ERR err = WMP_errSuccess;
   343  
   344      Call(PKTestDecode_Initialize(pID, pWS));
   345      Call(ParseBMPHeader(pID, pWS));
   346  
   347  Cleanup:
   348      return err;
   349  }
   350  
   351  ERR PKImageDecode_Copy_BMP(
   352      PKTestDecode* pID,
   353      const PKRect* pRect,
   354      U8* pb,
   355      U32 cbStride)
   356  {
   357      ERR err = WMP_errSuccess;
   358  
   359      struct WMPStream* pS = pID->pStream;
   360  
   361      size_t cbLineS = (pID->EXT.BMP.cbPixel * pID->uWidth + 3) / 4 * 4;
   362      size_t cbLineM = pID->EXT.BMP.cbPixel * pRect->Width;
   363      
   364      I32 i = 0;
   365  
   366      //FailIf(pRect->X < 0 || pID->uWidth <= pRect->X, WMP_errInvalidParameter);
   367      //FailIf(pRect->Y < 0 || pID->uHeight <= pRect->Y, WMP_errInvalidParameter);
   368      //FailIf(pRect->Width < 0 || pID->uWidth < pRect->X + pRect->Width, WMP_errInvalidParameter);
   369      //FailIf(pRect->Height < 0 || pID->uHeight < pRect->Y + pRect->Height, WMP_errInvalidParameter);
   370      FailIf(cbStride < cbLineM, WMP_errInvalidParameter);
   371  
   372      for (i = pRect->Y + pRect->Height - 1; pRect->Y <= i; --i)
   373      {
   374          size_t offLine = pID->EXT.BMP.cbPixel * pRect->X;
   375          size_t offS = cbLineS * (pID->uHeight - i - 1) + offLine;
   376          size_t offM = cbStride * (i - pRect->Y) + offLine;
   377  
   378          Call(pS->SetPos(pS, pID->EXT.BMP.offPixel + offS));
   379          Call(pS->Read(pS, pb + offM, cbLineM));
   380      }
   381  
   382  Cleanup:
   383      return err;
   384  }
   385  
   386  ERR PKImageDecode_Create_BMP(
   387      PKTestDecode** ppID)
   388  {
   389      ERR err = WMP_errSuccess;
   390      PKTestDecode* pID = NULL;
   391  
   392      Call(PKTestDecode_Create(ppID));
   393  
   394      pID = *ppID;
   395      pID->Initialize = PKImageDecode_Initialize_BMP;
   396      pID->Copy = PKImageDecode_Copy_BMP;
   397  
   398  Cleanup:
   399      return err;
   400  }
   401