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