wined3d: Respect the BO memory offset in wined3d_context_gl_map_bo_address().
[wine.git] / libs / jxr / jxrgluelib / JXRGlueJxr.c
blob57fa9ed6f04cbb6466ce35af757bf1d671c834ea
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.
28 //*@@@---@@@@******************************************************************
29 #include <limits.h>
30 #include <JXRGlue.h>
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);
38 void CalcMetadataSizeLPSTR(const DPKPROPVARIANT var,
39 U16 *pcInactiveMetadata,
40 U32 *pcbOffsetSize,
41 U32 *pcbCount)
43 if (DPKVT_EMPTY != var.vt)
45 U32 uiLenWithNull = (U32)strlen(var.VT.pszVal) + 1; // +1 for NULL;
46 assert(DPKVT_LPSTR == var.vt);
48 // We only use offset if size > 4
49 if (uiLenWithNull > 4)
50 *pcbOffsetSize += uiLenWithNull;
52 if (pcbCount)
53 *pcbCount = uiLenWithNull;
55 else
56 *pcInactiveMetadata += 1;
59 void CalcMetadataSizeLPWSTR(const DPKPROPVARIANT var,
60 U16 *pcInactiveMetadata,
61 U32 *pcbOffsetSize,
62 U32 *pcbCount)
64 if (DPKVT_EMPTY != var.vt)
66 U32 uiCBWithNull = sizeof(U16) * ((U32)wcslen((wchar_t *) var.VT.pwszVal) + 1); // +1 for NULL term;
67 assert(DPKVT_LPWSTR == var.vt);
69 // We only use offset if size > 4
70 if (uiCBWithNull > 4)
71 *pcbOffsetSize += uiCBWithNull;
73 if (pcbCount)
74 *pcbCount = uiCBWithNull;
76 else
77 *pcInactiveMetadata += 1;
80 void CalcMetadataSizeUI2(const DPKPROPVARIANT var,
81 U16 *pcInactiveMetadata,
82 U32 *pcbMetadataSize)
84 UNREFERENCED_PARAMETER( pcbMetadataSize );
85 if (DPKVT_EMPTY != var.vt)
87 assert(DPKVT_UI2 == var.vt);
88 // This is a single UI2, so it will not be written via offset, but rather as value
90 else
91 *pcInactiveMetadata += 1;
94 void CalcMetadataSizeUI4(const DPKPROPVARIANT var,
95 U16 *pcInactiveMetadata,
96 U32 *pcbContainer)
98 UNREFERENCED_PARAMETER( pcbContainer );
99 if (DPKVT_EMPTY != var.vt)
101 assert(DPKVT_UI4 == var.vt);
102 // This is a single UI4, so it will not be written via offset, but rather as value
104 else
105 *pcInactiveMetadata += 1;
108 ERR CalcMetadataOffsetSize(PKImageEncode* pIE,
109 U16 *pcInactiveMetadata,
110 U32 *pcbMetadataSize)
112 ERR err = WMP_errSuccess;
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);
129 return err;
133 ERR CopyDescMetadata(DPKPROPVARIANT *pvarDst,
134 const DPKPROPVARIANT varSrc)
136 ERR err = WMP_errSuccess;
137 size_t uiSize;
139 pvarDst->vt = varSrc.vt;
140 switch (varSrc.vt)
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;
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;
156 case DPKVT_UI2:
157 pvarDst->VT.uiVal = varSrc.VT.uiVal;
158 break;
160 case DPKVT_UI4:
161 pvarDst->VT.ulVal = varSrc.VT.ulVal;
162 break;
164 default:
165 assert(FALSE); // This case is not handled
166 FailIf(TRUE, WMP_errNotYetImplemented);
168 // *** FALL THROUGH ***
170 case DPKVT_EMPTY:
171 memset(pvarDst, 0, sizeof(*pvarDst));
172 assert(DPKVT_EMPTY == pvarDst->vt);
173 break;
176 Cleanup:
177 return err;
181 void FreeDescMetadata(DPKPROPVARIANT *pvar)
183 switch (pvar->vt)
185 case DPKVT_LPSTR:
186 PKFree((void **) &pvar->VT.pszVal);
187 break;
189 case DPKVT_LPWSTR:
190 PKFree((void **) &pvar->VT.pwszVal);
191 break;
193 default:
194 assert(FALSE); // This case is not handled
195 break;
197 case DPKVT_EMPTY:
198 case DPKVT_UI2:
199 case DPKVT_UI4:
200 break;
205 ERR WriteDescMetadata(PKImageEncode *pIE,
206 const DPKPROPVARIANT var,
207 WmpDE *pwmpDE,
208 U32 *puiCurrDescMetadataOffset,
209 size_t *poffPos)
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;
219 if (0 == pDEMisc->uDescMetadataOffset || 0 == pDEMisc->uDescMetadataByteCount)
220 goto Cleanup; // Nothing to do here
222 // Sanity check before - can be equal due to remaining metadata being DPKVT_EMPTY
223 assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount);
225 switch (var.vt)
227 case DPKVT_EMPTY:
228 break;
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;
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;
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;
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;
258 default:
259 assert(FALSE); // This case is not handled
260 FailIf(TRUE, WMP_errNotYetImplemented);
261 break;
264 *puiCurrDescMetadataOffset += uiDataWrittenToOffset;
266 // Sanity check after
267 assert(*puiCurrDescMetadataOffset <= pDEMisc->uDescMetadataByteCount); // Can be equal
269 Cleanup:
270 return err;
275 //================================================================
276 // PKImageEncode_WMP
277 //================================================================
278 ERR WriteContainerPre(
279 PKImageEncode* pIE)
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;
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;
294 static WmpDE wmpDEs[] =
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
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},
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},
329 U16 cWmpDEs = sizeof(wmpDEs) / sizeof(wmpDEs[0]);
330 WmpDE wmpDE = {0};
331 size_t i = 0;
333 U8* pbEXIFMetadata = NULL;
334 U8* pbGPSInfoMetadata = NULL;
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);
340 //================
341 Call(pWS->GetPos(pWS, &offPos));
342 FailIf(0 != offPos, WMP_errUnsupportedFormat);
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;
350 //================
351 // Write overflow area
352 pDEMisc->uOffPixelFormat = (U32)offPos;
353 PI.pGUIDPixFmt = &pIE->guidPixFormat;
354 PixelFormatLookup(&PI, LOOKUP_FORWARD);
356 //Call(pWS->Write(pWS, PI.pGUIDPixFmt, sizeof(*PI.pGUIDPixFmt))); offPos += 16;
357 /** following code is endian-agnostic **/
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;
367 //================
368 // Tally up space required for descriptive metadata
369 Call(CalcMetadataOffsetSize(pIE, &cInactiveMetadata, &cbMetadataOffsetSize));
370 cWmpDEs -= cInactiveMetadata;
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;
379 if (!pIE->WMP.bHasAlpha || pIE->WMP.wmiSCP.uAlphaMode != 2) //no planar alpha
380 cWmpDEs -= 2;
382 if (0 == pIE->cbXMPMetadataByteCount)
383 cWmpDEs -= 1; // No XMP metadata
385 if (0 == pIE->cbIPTCNAAMetadataByteCount)
386 cWmpDEs -= 1; // No IPTCNAA metadata
388 if (0 == pIE->cbPhotoshopMetadataByteCount)
389 cWmpDEs -= 1; // No Photoshop metadata
391 if (0 == pIE->cbEXIFMetadataByteCount)
392 cWmpDEs -= 1; // No EXIF metadata
394 if (0 == pIE->cbColorContext)
395 cWmpDEs -= 1; // No color context
397 if (0 == pIE->cbGPSInfoMetadataByteCount)
398 cWmpDEs -= 1; // No GPSInfo metadata
400 pDEMisc->uImageOffset = (U32)(offPos + sizeof(U16) + SizeofIFDEntry * cWmpDEs + sizeof(U32));
402 if (cbMetadataOffsetSize > 0)
404 pDEMisc->uDescMetadataByteCount = cbMetadataOffsetSize;
405 pDEMisc->uDescMetadataOffset = pDEMisc->uImageOffset;
406 pDEMisc->uImageOffset += cbMetadataOffsetSize;
409 if (pIE->cbXMPMetadataByteCount > 0)
411 pDEMisc->uXMPMetadataOffset = pDEMisc->uImageOffset;
412 pDEMisc->uImageOffset += pIE->cbXMPMetadataByteCount;
415 if (pIE->cbIPTCNAAMetadataByteCount > 0)
417 pDEMisc->uIPTCNAAMetadataOffset = pDEMisc->uImageOffset;
418 pDEMisc->uImageOffset += pIE->cbIPTCNAAMetadataByteCount;
421 if (pIE->cbPhotoshopMetadataByteCount > 0)
423 pDEMisc->uPhotoshopMetadataOffset = pDEMisc->uImageOffset;
424 pDEMisc->uImageOffset += pIE->cbPhotoshopMetadataByteCount;
427 if (pIE->cbEXIFMetadataByteCount > 0)
429 pDEMisc->uEXIFMetadataOffset = pDEMisc->uImageOffset;
430 pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
431 pDEMisc->uImageOffset += pIE->cbEXIFMetadataByteCount;
434 if (pIE->cbColorContext > 0)
436 pDEMisc->uColorProfileOffset = pDEMisc->uImageOffset;
437 pDEMisc->uImageOffset += pIE->cbColorContext;
440 if (pIE->cbGPSInfoMetadataByteCount > 0)
442 pDEMisc->uGPSInfoMetadataOffset = pDEMisc->uImageOffset;
443 pDEMisc->uImageOffset += (pDEMisc->uImageOffset & 1);
444 pDEMisc->uImageOffset += pIE->cbGPSInfoMetadataByteCount;
447 Call(PutUShort(pWS, offPos, cWmpDEs)); offPos += 2;
448 Call(pWS->Write(pWS, Zero, SizeofIFDEntry * cWmpDEs + sizeof(U32)));
450 //================
451 wmpDE = wmpDEs[i++];
452 assert(WMP_tagDocumentName == wmpDE.uTag);
453 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDocumentName, &wmpDE,
454 &uiCurrDescMetadataOffset, &offPos));
456 wmpDE = wmpDEs[i++];
457 assert(WMP_tagImageDescription == wmpDE.uTag);
458 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarImageDescription, &wmpDE,
459 &uiCurrDescMetadataOffset, &offPos));
461 wmpDE = wmpDEs[i++];
462 assert(WMP_tagCameraMake == wmpDE.uTag);
463 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraMake, &wmpDE,
464 &uiCurrDescMetadataOffset, &offPos));
466 wmpDE = wmpDEs[i++];
467 assert(WMP_tagCameraModel == wmpDE.uTag);
468 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCameraModel, &wmpDE,
469 &uiCurrDescMetadataOffset, &offPos));
471 wmpDE = wmpDEs[i++];
472 assert(WMP_tagPageName == wmpDE.uTag);
473 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageName, &wmpDE,
474 &uiCurrDescMetadataOffset, &offPos));
476 wmpDE = wmpDEs[i++];
477 assert(WMP_tagPageNumber == wmpDE.uTag);
478 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarPageNumber, &wmpDE,
479 &uiCurrDescMetadataOffset, &offPos));
481 wmpDE = wmpDEs[i++];
482 assert(WMP_tagSoftware == wmpDE.uTag);
483 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarSoftware, &wmpDE,
484 &uiCurrDescMetadataOffset, &offPos));
486 wmpDE = wmpDEs[i++];
487 assert(WMP_tagDateTime == wmpDE.uTag);
488 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarDateTime, &wmpDE,
489 &uiCurrDescMetadataOffset, &offPos));
491 wmpDE = wmpDEs[i++];
492 assert(WMP_tagArtist == wmpDE.uTag);
493 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarArtist, &wmpDE,
494 &uiCurrDescMetadataOffset, &offPos));
496 wmpDE = wmpDEs[i++];
497 assert(WMP_tagHostComputer == wmpDE.uTag);
498 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarHostComputer, &wmpDE,
499 &uiCurrDescMetadataOffset, &offPos));
501 wmpDE = wmpDEs[i++];
502 assert(WMP_tagRatingStars == wmpDE.uTag);
503 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingStars, &wmpDE,
504 &uiCurrDescMetadataOffset, &offPos));
506 wmpDE = wmpDEs[i++];
507 assert(WMP_tagRatingValue == wmpDE.uTag);
508 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarRatingValue, &wmpDE,
509 &uiCurrDescMetadataOffset, &offPos));
511 wmpDE = wmpDEs[i++];
512 assert(WMP_tagCopyright == wmpDE.uTag);
513 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCopyright, &wmpDE,
514 &uiCurrDescMetadataOffset, &offPos));
516 wmpDE = wmpDEs[i++];
517 assert(WMP_tagCaption == wmpDE.uTag);
518 Call(WriteDescMetadata(pIE, pIE->sDescMetadata.pvarCaption, &wmpDE,
519 &uiCurrDescMetadataOffset, &offPos));
521 // XMP Metadata
522 wmpDE = wmpDEs[i++];
523 assert(WMP_tagXMPMetadata == wmpDE.uTag);
524 if (pIE->cbXMPMetadataByteCount > 0)
526 U32 uiTemp;
527 wmpDE.uCount = pIE->cbXMPMetadataByteCount;
528 wmpDE.uValueOrOffset = pDEMisc->uXMPMetadataOffset;
529 Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbXMPMetadata, &uiTemp));
532 // IPTCNAA Metadata
533 wmpDE = wmpDEs[i++];
534 assert(WMP_tagIPTCNAAMetadata == wmpDE.uTag);
535 if (pIE->cbIPTCNAAMetadataByteCount > 0)
537 U32 uiTemp;
538 wmpDE.uCount = pIE->cbIPTCNAAMetadataByteCount;
539 wmpDE.uValueOrOffset = pDEMisc->uIPTCNAAMetadataOffset;
540 Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbIPTCNAAMetadata, &uiTemp));
543 // Photoshop Metadata
544 wmpDE = wmpDEs[i++];
545 assert(WMP_tagPhotoshopMetadata == wmpDE.uTag);
546 if (pIE->cbPhotoshopMetadataByteCount > 0)
548 U32 uiTemp;
549 wmpDE.uCount = pIE->cbPhotoshopMetadataByteCount;
550 wmpDE.uValueOrOffset = pDEMisc->uPhotoshopMetadataOffset;
551 Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbPhotoshopMetadata, &uiTemp));
554 // EXIF Metadata
555 wmpDE = wmpDEs[i++];
556 assert(WMP_tagEXIFMetadata == wmpDE.uTag);
557 if (pIE->cbEXIFMetadataByteCount > 0)
559 U32 uiTemp;
560 if ((pDEMisc->uEXIFMetadataOffset & 1) != 0)
562 Call(pWS->SetPos(pWS, pDEMisc->uEXIFMetadataOffset));
563 Call(pWS->Write(pWS, Zero, 1));
565 pDEMisc->uEXIFMetadataOffset += (pDEMisc->uEXIFMetadataOffset & 1);
566 wmpDE.uValueOrOffset = pDEMisc->uEXIFMetadataOffset;
567 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
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));
577 // ICC Profile
578 wmpDE = wmpDEs[i++];
579 assert(WMP_tagIccProfile == wmpDE.uTag);
580 if (pIE->cbColorContext > 0)
582 U32 uiTemp;
583 wmpDE.uCount = pIE->cbColorContext;
584 wmpDE.uValueOrOffset = pDEMisc->uColorProfileOffset;
585 Call(WriteWmpDE(pWS, &offPos, &wmpDE, pIE->pbColorContext, &uiTemp));
588 // GPSInfo Metadata
589 wmpDE = wmpDEs[i++];
590 assert(WMP_tagGPSInfoMetadata == wmpDE.uTag);
591 if (pIE->cbGPSInfoMetadataByteCount > 0)
593 U32 uiTemp;
594 if ((pDEMisc->uGPSInfoMetadataOffset & 1) != 0)
596 Call(pWS->SetPos(pWS, pDEMisc->uGPSInfoMetadataOffset));
597 Call(pWS->Write(pWS, Zero, 1));
599 pDEMisc->uGPSInfoMetadataOffset += (pDEMisc->uGPSInfoMetadataOffset & 1);
600 wmpDE.uValueOrOffset = pDEMisc->uGPSInfoMetadataOffset;
601 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
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));
611 wmpDE = wmpDEs[i++];
612 assert(WMP_tagPixelFormat == wmpDE.uTag);
613 wmpDE.uValueOrOffset = pDEMisc->uOffPixelFormat;
614 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
616 wmpDE = wmpDEs[i++];
617 assert(WMP_tagTransformation == wmpDE.uTag);
618 wmpDE.uValueOrOffset = pIE->WMP.oOrientation;
619 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
621 wmpDE = wmpDEs[i++];
622 assert(WMP_tagImageWidth == wmpDE.uTag);
623 wmpDE.uValueOrOffset = pIE->uWidth;
624 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
626 wmpDE = wmpDEs[i++];
627 assert(WMP_tagImageHeight == wmpDE.uTag);
628 wmpDE.uValueOrOffset = pIE->uHeight;
629 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
631 wmpDE = wmpDEs[i++];
632 assert(WMP_tagWidthResolution == wmpDE.uTag);
633 *((float *) &wmpDE.uValueOrOffset) = pIE->fResX;
634 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
636 wmpDE = wmpDEs[i++];
637 assert(WMP_tagHeightResolution == wmpDE.uTag);
638 *((float *) &wmpDE.uValueOrOffset) = pIE->fResY;
639 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
641 wmpDE = wmpDEs[i++];
642 assert(WMP_tagImageOffset == wmpDE.uTag);
643 wmpDE.uValueOrOffset = pDEMisc->uImageOffset;
644 Call(WriteWmpDE(pWS, &offPos, &wmpDE, NULL, NULL));
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));
653 if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
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));
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));
670 //================
671 Call(PutULong(pWS, offPos, 0)); offPos += 4;
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)
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);
687 // OK, now skip to image offset
688 Call(pWS->SetPos(pWS, pDEMisc->uImageOffset));
689 offPos = pDEMisc->uImageOffset;
691 assert(pDEMisc->uImageOffset == offPos);
693 Cleanup:
694 if (pbEXIFMetadata != NULL)
695 PKFree((void **) &pbEXIFMetadata);
696 if (pbGPSInfoMetadata != NULL)
697 PKFree((void **) &pbGPSInfoMetadata);
698 return err;
703 ERR WriteContainerPost(
704 PKImageEncode* pIE)
706 ERR err = WMP_errSuccess;
708 struct WMPStream* pWS = pIE->pStream;
709 WmpDEMisc* pDEMisc = &pIE->WMP.wmiDEMisc;
710 size_t offPos;
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};
716 deImageByteCount.uValueOrOffset = pIE->WMP.nCbImage;
717 offPos = pDEMisc->uOffImageByteCount;
718 Call(WriteWmpDE(pWS, &offPos, &deImageByteCount, NULL, NULL));
720 //Alpha
721 if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
723 deAlphaOffset.uValueOrOffset = pIE->WMP.nOffAlpha;
724 offPos = pDEMisc->uOffAlphaOffset;
725 Call(WriteWmpDE(pWS, &offPos, &deAlphaOffset, NULL, NULL));
727 deAlphaByteCount.uValueOrOffset = pIE->WMP.nCbAlpha + pIE->WMP.nOffAlpha;
728 offPos = pDEMisc->uOffAlphaByteCount;
729 Call(WriteWmpDE(pWS, &offPos, &deAlphaByteCount, NULL, NULL));
732 Cleanup:
733 return err;
737 //================================================
738 ERR PKImageEncode_Initialize_WMP(
739 PKImageEncode* pIE,
740 struct WMPStream* pStream,
741 void* pvParam,
742 size_t cbParam)
744 ERR err = WMP_errSuccess;
746 FailIf(sizeof(pIE->WMP.wmiSCP) != cbParam, WMP_errInvalidArgument);
748 pIE->WMP.wmiSCP = *(CWMIStrCodecParam*)pvParam;
749 pIE->WMP.wmiSCP_Alpha = *(CWMIStrCodecParam*)pvParam;
750 pIE->pStream = pStream;
752 pIE->WMP.wmiSCP.pWStream = pIE->pStream;
753 pIE->WMP.wmiSCP_Alpha.pWStream = pIE->pStream;
755 Cleanup:
756 return err;
759 ERR PKImageEncode_Terminate_WMP(
760 PKImageEncode* pIE)
762 ERR err = WMP_errSuccess;
763 UNREFERENCED_PARAMETER( pIE );
764 return err;
768 ERR PKImageEncode_EncodeContent_Init(
769 PKImageEncode* pIE,
770 PKPixelInfo PI,
771 U32 cLine,
772 U8* pbPixels,
773 U32 cbStride)
775 ERR err = WMP_errSuccess;
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;
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
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
797 //if (pIE->WMP.bHasAlpha)
799 // pIE->WMP.wmiSCP.cChannel = PI.cChannel - 1;
800 // pIE->WMP.wmiI.cfColorFormat = PI.cfStripAlpha;
802 //else
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)
809 pIE->idxCurrentLine = 0;
811 pIE->WMP.wmiSCP.fMeasurePerf = TRUE;
812 FailIf(ICERR_OK != ImageStrEncInit(&pIE->WMP.wmiI, &pIE->WMP.wmiSCP, &pIE->WMP.ctxSC), WMP_errFail);
814 Cleanup:
815 return err;
818 ERR PKImageEncode_EncodeContent_Encode(
819 PKImageEncode* pIE,
820 U32 cLine,
821 U8* pbPixels,
822 U32 cbStride)
824 ERR err = WMP_errSuccess;
825 U32 i = 0;
827 //================================
828 for (i = 0; i < cLine; i += 16)
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);
838 pIE->idxCurrentLine += cLine;
840 Cleanup:
841 return err;
844 ERR PKImageEncode_EncodeContent_Term(PKImageEncode* pIE)
846 ERR err = WMP_errSuccess;
848 FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC), WMP_errFail);
850 Cleanup:
851 return err;
854 ERR PKImageEncode_EncodeContent(
855 PKImageEncode* pIE,
856 PKPixelInfo PI,
857 U32 cLine,
858 U8* pbPixels,
859 U32 cbStride)
861 ERR err = WMP_errSuccess;
862 size_t offPos = 0;
864 Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
865 pIE->WMP.nOffImage = (Long)offPos;
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));
871 Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
872 pIE->WMP.nCbImage = (Long)offPos - pIE->WMP.nOffImage;
874 Cleanup:
875 return err;
879 ERR PKImageEncode_EncodeAlpha_Init(
880 PKImageEncode* pIE,
881 PKPixelInfo PI,
882 U32 cLine,
883 U8* pbPixels,
884 U32 cbStride)
886 ERR err = WMP_errSuccess;
888 UNREFERENCED_PARAMETER( cLine );
889 UNREFERENCED_PARAMETER( pbPixels );
890 UNREFERENCED_PARAMETER( cbStride );
892 pIE->WMP.wmiI_Alpha = pIE->WMP.wmiI;
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;
903 switch (pIE->WMP.wmiI.bdBitDepth)
905 case BD_8:
906 pIE->WMP.wmiI_Alpha.cLeadingPadding += (pIE->WMP.wmiI.cBitsPerUnit >> 3) - 1;
907 break;
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;
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;
921 case BD_5:
922 case BD_10:
923 case BD_565:
924 default:
925 break;
928 // pIE->WMP.wmiSCP_Alpha.uAlphaMode = 1;
931 //assert(pIE->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
932 pIE->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
934 pIE->WMP.wmiSCP_Alpha.cfColorFormat = Y_ONLY;
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);
940 Cleanup:
941 return err;
944 ERR PKImageEncode_EncodeAlpha_Encode(
945 PKImageEncode* pIE,
946 U32 cLine,
947 U8* pbPixels,
948 U32 cbStride)
950 ERR err = WMP_errSuccess;
951 U32 i = 0;
953 //================================
954 for (i = 0; i < cLine; i += 16)
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);
962 pIE->idxCurrentLine += cLine;
964 Cleanup:
965 return err;
968 ERR PKImageEncode_EncodeAlpha_Term(PKImageEncode* pIE)
970 ERR err = WMP_errSuccess;
972 FailIf(ICERR_OK != ImageStrEncTerm(pIE->WMP.ctxSC_Alpha), WMP_errFail);
974 Cleanup:
975 return err;
978 ERR PKImageEncode_EncodeAlpha(
979 PKImageEncode* pIE,
980 PKPixelInfo PI,
981 U32 cLine,
982 U8* pbPixels,
983 U32 cbStride)
985 ERR err = WMP_errSuccess;
986 size_t offPos = 0;
988 Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
989 if ((offPos & 1) != 0)
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++;
996 pIE->WMP.nOffAlpha = (Long)offPos;
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));
1002 Call(pIE->pStream->GetPos(pIE->pStream, &offPos));
1003 pIE->WMP.nCbAlpha = (Long)offPos - pIE->WMP.nOffAlpha;
1005 Cleanup:
1006 return err;
1011 static ERR SetMetadata(PKImageEncode *pIE, const U8 *pbMetadata, U32 cbMetadata, U8** pbSet, U32* pcbSet)
1013 ERR err = WMP_errSuccess;
1015 // Fail if the caller called us after we've already written the header out
1016 if (pIE->fHeaderDone)
1018 assert(FALSE); // Message to programmer
1019 err = WMP_errOutOfSequence;
1020 goto Cleanup;
1023 // Make a copy of the metadata
1024 PKFree((void **) pbSet);
1025 *pcbSet = 0;
1027 Call(PKAlloc((void **) pbSet, cbMetadata));
1028 memcpy(*pbSet, pbMetadata, cbMetadata);
1029 *pcbSet = cbMetadata;
1031 Cleanup:
1032 return err;
1037 ERR PKImageEncode_SetColorContext_WMP(PKImageEncode *pIE,
1038 const U8 *pbColorContext,
1039 U32 cbColorContext)
1041 return SetMetadata(pIE, pbColorContext, cbColorContext, &pIE->pbColorContext, &pIE->cbColorContext);
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;
1055 // Fail if the caller called us after we've already written the header out
1056 FailIf(pIE->fHeaderDone, WMP_errOutOfSequence);
1058 // Free any previously set XMP metadata
1059 PKFree((void **) &pIE->pbXMPMetadata);
1060 pIE->cbXMPMetadataByteCount = 0;
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 )
1074 char* pszFormatEnd;
1075 const char* pszLessThan;
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;
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 ));
1094 else
1096 cbTemp = cbXMPMetadata;
1099 pIE->pbXMPMetadata = (U8 *) pbTemp;
1100 pIE->cbXMPMetadataByteCount = cbTemp;
1101 return ( err );
1103 Cleanup:
1104 PKFree((void **) &pbTemp);
1105 pIE->cbXMPMetadataByteCount = 0;
1106 return err;
1111 ERR PKImageEncode_SetEXIFMetadata_WMP(PKImageEncode *pIE, const U8 *pbEXIFMetadata, U32 cbEXIFMetadata)
1113 return SetMetadata(pIE, pbEXIFMetadata, cbEXIFMetadata,
1114 &pIE->pbEXIFMetadata, &pIE->cbEXIFMetadataByteCount);
1119 ERR PKImageEncode_SetGPSInfoMetadata_WMP(PKImageEncode *pIE, const U8 *pbGPSInfoMetadata, U32 cbGPSInfoMetadata)
1121 return SetMetadata(pIE, pbGPSInfoMetadata, cbGPSInfoMetadata,
1122 &pIE->pbGPSInfoMetadata, &pIE->cbGPSInfoMetadataByteCount);
1127 ERR PKImageEncode_SetIPTCNAAMetadata_WMP(PKImageEncode *pIE, const U8 *pbIPTCNAAMetadata, U32 cbIPTCNAAMetadata)
1129 return SetMetadata(pIE, pbIPTCNAAMetadata, cbIPTCNAAMetadata,
1130 &pIE->pbIPTCNAAMetadata, &pIE->cbIPTCNAAMetadataByteCount);
1135 ERR PKImageEncode_SetPhotoshopMetadata_WMP(PKImageEncode *pIE, const U8 *pbPhotoshopMetadata, U32 cbPhotoshopMetadata)
1137 return SetMetadata(pIE, pbPhotoshopMetadata, cbPhotoshopMetadata,
1138 &pIE->pbPhotoshopMetadata, &pIE->cbPhotoshopMetadataByteCount);
1143 ERR PKImageEncode_SetDescriptiveMetadata_WMP(PKImageEncode *pIE, const DESCRIPTIVEMETADATA *pSrcMeta)
1145 ERR err = WMP_errSuccess;
1146 DESCRIPTIVEMETADATA *pDstMeta = &pIE->sDescMetadata;
1148 // Fail if the caller called us after we've already written the header out
1149 if (pIE->fHeaderDone)
1151 assert(FALSE); // Message to programmer
1152 FailIf(TRUE, WMP_errOutOfSequence);
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));
1171 Cleanup:
1172 return err;
1177 ERR PKImageEncode_WritePixels_WMP(
1178 PKImageEncode* pIE,
1179 U32 cLine,
1180 U8* pbPixels,
1181 U32 cbStride)
1183 ERR err = WMP_errSuccess;
1184 // U32 i = 0;
1185 PKPixelInfo PI;
1187 // Performing non-banded encode
1188 assert(BANDEDENCSTATE_UNINITIALIZED == pIE->WMP.eBandedEncState);
1189 pIE->WMP.eBandedEncState = BANDEDENCSTATE_NONBANDEDENCODE;
1191 PI.pGUIDPixFmt = &pIE->guidPixFormat;
1192 PixelFormatLookup(&PI, LOOKUP_FORWARD);
1193 pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1195 if (!pIE->fHeaderDone)
1197 // write metadata
1198 Call(WriteContainerPre(pIE));
1200 pIE->fHeaderDone = !FALSE;
1203 /* if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2){
1204 pIE->WMP.wmiSCP_Alpha = pIE->WMP.wmiSCP;
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));
1212 Call(WriteContainerPost(pIE));
1214 Cleanup:
1215 return err;
1219 ERR PKImageEncode_WritePixelsBandedBegin_WMP(PKImageEncode* pIE, struct WMPStream *pPATempFile)
1221 ERR err = WMP_errSuccess;
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;
1227 // Save the planar alpha tempfile for future use
1228 pIE->WMP.pPATempFile = pPATempFile;
1230 //Cleanup:
1231 return err;
1234 ERR PKImageEncode_WritePixelsBanded_WMP(PKImageEncode* pIE, U32 cLine, U8* pbPixels, U32 cbStride, Bool fLastCall)
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;
1242 // Unless this is the last call, reject inputs which are not multiples of 16
1243 FailIf(!fLastCall && 0 != cLine % 16, WMP_errMustBeMultipleOf16LinesUntilLastCall);
1245 if (!pIE->fHeaderDone || BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
1247 PI.pGUIDPixFmt = &pIE->guidPixFormat;
1248 PixelFormatLookup(&PI, LOOKUP_FORWARD);
1249 pIE->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1250 fPI = TRUE;
1252 // Check if this is planar alpha: banded encode requires temp file
1253 if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1255 FailIf(NULL == pPATempFile, WMP_errPlanarAlphaBandedEncRequiresTempFile);
1259 if (!pIE->fHeaderDone)
1261 // write metadata
1262 assert(fPI);
1263 Call(WriteContainerPre(pIE));
1264 pIE->fHeaderDone = !FALSE;
1267 if (BANDEDENCSTATE_INIT == pIE->WMP.eBandedEncState)
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;
1274 assert(fPI);
1275 Call(PKImageEncode_EncodeContent_Init(pIE, PI, cLine, pbPixels, cbStride));
1276 pIE->WMP.eBandedEncState = BANDEDENCSTATE_ENCODING;
1279 Call(PKImageEncode_EncodeContent_Encode(pIE, cLine, pbPixels, cbStride));
1280 if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1282 //planar alpha
1283 if (BANDEDENCSTATE_INIT == eEncStateOrig)
1285 size_t offStart;
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);
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));
1297 Call(PKImageEncode_EncodeAlpha_Encode(pIE, cLine, pbPixels, cbStride));
1300 Cleanup:
1301 return err;
1304 ERR PKImageEncode_WritePixelsBandedEnd_WMP(PKImageEncode* pIE)
1306 ERR err = WMP_errSuccess;
1307 struct WMPStream *pMainStream = pIE->WMP.wmiSCP.pWStream;
1308 size_t offAlpha;
1310 assert(BANDEDENCSTATE_ENCODING == pIE->WMP.eBandedEncState);
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;
1317 if (pIE->WMP.bHasAlpha && pIE->WMP.wmiSCP.uAlphaMode == 2)
1319 size_t cbAlpha;
1320 size_t cbBytesCopied;
1321 struct WMPStream *pAlphaStream = pIE->WMP.wmiSCP_Alpha.pWStream;
1323 assert(pAlphaStream != pMainStream); // Otherwise we didn't use a temp file
1325 // Close it up - this causes write to temp file
1326 Call(PKImageEncode_EncodeAlpha_Term(pIE));
1328 // Calculate size of alpha bitstream and its new offset
1329 Call(pAlphaStream->GetPos(pAlphaStream, &cbAlpha));
1331 // Copy alpha bitstream to end of main stream
1332 cbBytesCopied = 0;
1333 Call(pAlphaStream->SetPos(pAlphaStream, 0));
1334 while (cbBytesCopied < cbAlpha)
1336 char rgbBuf[TEMPFILE_COPYBUF_SIZE];
1337 size_t cbCopy;
1339 cbCopy = min(sizeof(rgbBuf), cbAlpha - cbBytesCopied);
1340 Call(pAlphaStream->Read(pAlphaStream, rgbBuf, cbCopy));
1341 Call(pMainStream->Write(pMainStream, rgbBuf, cbCopy));
1343 cbBytesCopied += cbCopy;
1345 assert(cbBytesCopied == cbAlpha);
1347 // Update alpha offset/length for WriteContainerPost
1348 pIE->WMP.nOffAlpha = (Long)offAlpha;
1349 pIE->WMP.nCbAlpha = (Long)cbAlpha;
1352 Call(WriteContainerPost(pIE));
1354 Cleanup:
1355 return err;
1359 ERR PKImageEncode_Transcode_WMP(
1360 PKImageEncode* pIE,
1361 PKImageDecode* pID,
1362 CWMTranscodingParam* pParam)
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;
1372 struct WMPStream* pWSDec = NULL;
1373 struct WMPStream* pWSEnc= pIE->pStream;
1375 // pass through metadata
1376 Call(pID->GetPixelFormat(pID, &pixGUID));
1377 Call(pIE->SetPixelFormat(pIE, pixGUID));
1379 Call(pIE->SetSize(pIE, (I32)pParam->cWidth, (I32)pParam->cHeight));
1381 Call(pID->GetResolution(pID, &fResX, &fResY));
1382 Call(pIE->SetResolution(pIE, fResX, fResY));
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!
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
1401 fPlanarAlpha = pIE->WMP.bHasAlpha && (2 == pParam->uAlphaMode);
1403 // write matadata
1404 Call(WriteContainerPre(pIE));
1406 // Copy transcoding params for alpha (codec changes the struct)
1407 if (fPlanarAlpha)
1408 tcParamAlpha = *pParam;
1410 // write compressed bitstream
1411 Call(pID->GetRawStream(pID, &pWSDec));
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;
1417 if (fPlanarAlpha)
1419 pIE->WMP.nOffAlpha = (Long)offPos;
1421 // Cue the stream to alpha block
1422 assert(pID->WMP.wmiDEMisc.uAlphaOffset > 0);
1423 Call(pWSDec->SetPos(pWSDec, pID->WMP.wmiDEMisc.uAlphaOffset));
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;
1430 // fixup matadata
1431 Call(WriteContainerPost(pIE));
1433 Cleanup:
1434 return err;
1437 ERR PKImageEncode_CreateNewFrame_WMP(
1438 PKImageEncode* pIE,
1439 void* pvParam,
1440 size_t cbParam)
1442 ERR err = WMP_errSuccess;
1444 UNREFERENCED_PARAMETER( pIE );
1445 UNREFERENCED_PARAMETER( pvParam );
1446 UNREFERENCED_PARAMETER( cbParam );
1448 Call(WMP_errNotYetImplemented);
1450 Cleanup:
1451 return err;
1454 ERR PKImageEncode_Release_WMP(
1455 PKImageEncode** ppIE)
1457 ERR err = WMP_errSuccess;
1459 PKImageEncode *pIE = *ppIE;
1460 pIE->pStream->Close(&pIE->pStream);
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;
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);
1491 Call(PKFree((void **) ppIE));
1493 Cleanup:
1494 return err;
1497 //----------------------------------------------------------------
1498 ERR PKImageEncode_Create_WMP(PKImageEncode** ppIE)
1500 ERR err = WMP_errSuccess;
1502 PKImageEncode* pIE = NULL;
1504 Call(PKImageEncode_Create(ppIE));
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;
1513 pIE->WritePixelsBandedBegin = PKImageEncode_WritePixelsBandedBegin_WMP;
1514 pIE->WritePixelsBanded = PKImageEncode_WritePixelsBanded_WMP;
1515 pIE->WritePixelsBandedEnd = PKImageEncode_WritePixelsBandedEnd_WMP;
1517 pIE->Transcode = PKImageEncode_Transcode_WMP;
1518 pIE->CreateNewFrame = PKImageEncode_CreateNewFrame_WMP;
1519 pIE->Release = PKImageEncode_Release_WMP;
1520 pIE->bWMP = TRUE;
1522 Cleanup:
1523 return err;
1527 //================================================================
1528 // PKImageDecode_WMP
1529 //================================================================
1530 ERR ParsePFDEntry(
1531 PKImageDecode* pID,
1532 U16 uTag,
1533 U16 uType,
1534 U32 uCount,
1535 U32 uValue)
1537 ERR err = WMP_errSuccess;
1538 ERR errTmp = WMP_errSuccess;
1539 PKPixelInfo PI;
1540 struct WMPStream* pWS = pID->pStream;
1541 // size_t offPos = 0;
1543 union uf{
1544 U32 uVal;
1545 Float fVal;
1546 }ufValue = {0};
1548 //================================
1549 switch (uTag)
1551 case WMP_tagPixelFormat:
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));
1560 PI.pGUIDPixFmt = &pID->guidPixFormat;
1561 PixelFormatLookup(&PI, LOOKUP_FORWARD);
1563 pID->WMP.bHasAlpha = !!(PI.grBit & PK_pixfmtHasAlpha);
1564 pID->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
1565 pID->WMP.wmiI.bRGB = !(PI.grBit & PK_pixfmtBGR);
1567 break;
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;
1577 case WMP_tagImageWidth:
1578 FailIf(0 == uValue, WMP_errUnsupportedFormat);
1579 break;
1581 case WMP_tagImageHeight:
1582 FailIf(0 == uValue, WMP_errUnsupportedFormat);
1583 break;
1585 case WMP_tagImageOffset:
1586 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1587 pID->WMP.wmiDEMisc.uImageOffset = uValue;
1588 break;
1590 case WMP_tagImageByteCount:
1591 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1592 pID->WMP.wmiDEMisc.uImageByteCount = uValue;
1593 break;
1595 case WMP_tagAlphaOffset:
1596 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1597 pID->WMP.wmiDEMisc.uAlphaOffset = uValue;
1598 break;
1600 case WMP_tagAlphaByteCount:
1601 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1602 pID->WMP.wmiDEMisc.uAlphaByteCount = uValue;
1603 break;
1605 case WMP_tagWidthResolution:
1606 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1607 ufValue.uVal = uValue;
1608 pID->fResX = ufValue.fVal;
1609 break;
1611 case WMP_tagHeightResolution:
1612 FailIf(1 != uCount, WMP_errUnsupportedFormat);
1613 ufValue.uVal = uValue;
1614 pID->fResY = ufValue.fVal;
1615 break;
1617 case WMP_tagIccProfile:
1618 pID->WMP.wmiDEMisc.uColorProfileByteCount = uCount;
1619 pID->WMP.wmiDEMisc.uColorProfileOffset = uValue;
1620 break;
1622 case WMP_tagXMPMetadata:
1623 pID->WMP.wmiDEMisc.uXMPMetadataByteCount = uCount;
1624 pID->WMP.wmiDEMisc.uXMPMetadataOffset = uValue;
1625 break;
1627 case WMP_tagEXIFMetadata:
1628 pID->WMP.wmiDEMisc.uEXIFMetadataOffset = uValue;
1629 CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uEXIFMetadataByteCount));
1630 break;
1632 case WMP_tagGPSInfoMetadata:
1633 pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset = uValue;
1634 CallIgnoreError(errTmp, StreamCalcIFDSize(pWS, uValue, &pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount));
1635 break;
1637 case WMP_tagIPTCNAAMetadata:
1638 pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount = uCount;
1639 pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset = uValue;
1640 break;
1642 case WMP_tagPhotoshopMetadata:
1643 pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount = uCount;
1644 pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset = uValue;
1645 break;
1647 case WMP_tagCompression:
1648 case WMP_tagImageType:
1649 case WMP_tagImageDataDiscard:
1650 case WMP_tagAlphaDataDiscard:
1651 break;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
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;
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;
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;
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;
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;
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;
1752 Cleanup:
1753 return err;
1756 ERR ParsePFD(
1757 PKImageDecode* pID,
1758 size_t offPos,
1759 U16 cEntry)
1761 ERR err = WMP_errSuccess;
1762 struct WMPStream* pWS = pID->pStream;
1763 U16 i = 0;
1765 for (i = 0; i < cEntry; ++i)
1767 U16 uTag = 0;
1768 U16 uType = 0;
1769 U32 uCount = 0;
1770 U32 uValue = 0;
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;
1777 Call(ParsePFDEntry(pID, uTag, uType, uCount, uValue));
1780 pID->WMP.bHasAlpha = ((pID->WMP.bHasAlpha) && (pID->WMP.wmiDEMisc.uAlphaOffset != 0) && (pID->WMP.wmiDEMisc.uAlphaByteCount != 0));//has planar alpha
1782 Cleanup:
1783 return err;
1786 ERR ReadContainer(
1787 PKImageDecode* pID)
1789 ERR err = WMP_errSuccess;
1791 struct WMPStream* pWS = pID->pStream;
1792 size_t offPos = 0;
1794 char szSig[2] = {0};
1795 U16 uWmpID = 0;
1796 U32 offPFD = 0;
1797 U16 cPFDEntry = 0;
1798 U8 bVersion;
1800 //================================
1801 Call(pWS->GetPos(pWS, &offPos));
1802 FailIf(0 != offPos, WMP_errUnsupportedFormat);
1804 //================================
1805 // Header
1806 Call(pWS->Read(pWS, szSig, sizeof(szSig))); offPos += 2;
1807 FailIf(szSig != strstr(szSig, "II"), WMP_errUnsupportedFormat);
1809 Call(GetUShort(pWS, offPos, &uWmpID)); offPos += 2;
1810 FailIf(WMP_valWMPhotoID != (0x00FF & uWmpID), WMP_errUnsupportedFormat);
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);
1816 Call(GetULong(pWS, offPos, &offPFD)); offPos += 4;
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));
1825 //================================
1826 Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
1828 Cleanup:
1829 return err;
1833 //================================================
1834 ERR PKImageDecode_Initialize_WMP(
1835 PKImageDecode* pID,
1836 struct WMPStream* pWS)
1838 ERR err = WMP_errSuccess;
1840 CWMImageInfo* pII = NULL;
1842 //================================
1843 Call(PKImageDecode_Initialize(pID, pWS));
1845 //================================
1846 Call(ReadContainer(pID));
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;
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);
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)
1864 pID->WMP.wmiI.oOrientation = pID->WMP.oOrientationFromContainer;
1866 else
1868 // Force to O_NONE to match Vista decode behaviour
1869 pID->WMP.wmiI.oOrientation = O_NONE;
1872 pII = &pID->WMP.wmiI;
1873 pID->uWidth = (U32)pII->cWidth;
1874 pID->uHeight = (U32)pII->cHeight;
1876 Cleanup:
1877 return err;
1881 ERR PKImageDecode_GetSize_WMP(
1882 PKImageDecode* pID,
1883 I32* piWidth,
1884 I32* piHeight)
1886 if (pID->WMP.wmiI.oOrientation >= O_RCW)
1888 *piWidth = (I32)pID->uHeight;
1889 *piHeight = (I32)pID->uWidth;
1891 else
1893 *piWidth = (I32)pID->uWidth;
1894 *piHeight = (I32)pID->uHeight;
1896 return WMP_errSuccess;
1900 ERR PKImageDecode_GetRawStream_WMP(
1901 PKImageDecode* pID,
1902 struct WMPStream** ppWS)
1904 ERR err = WMP_errSuccess;
1905 struct WMPStream* pWS = pID->pStream;
1907 *ppWS = NULL;
1908 Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uImageOffset));
1909 *ppWS = pWS;
1911 Cleanup:
1912 return err;
1915 ERR PKImageDecode_Copy_WMP(
1916 PKImageDecode* pID,
1917 const PKRect* pRect,
1918 U8* pb,
1919 U32 cbStride)
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
1942 cThumbnailScale = 1;
1943 if (pID->WMP.wmiI.cThumbnailWidth > 0)
1945 while(cThumbnailScale * pID->WMP.wmiI.cThumbnailWidth < pID->uWidth)
1946 cThumbnailScale <<= 1;
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;
1954 #ifdef REENTRANT_MODE
1955 if (0 == pID->WMP.DecoderCurrMBRow)
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
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
1968 #ifdef REENTRANT_MODE
1970 #endif // REENTRANT_MODE
1971 //if(pID->WMP.wmiSCP.uAlphaMode != 1)
1972 if((!pID->WMP.bHasAlpha) || (pID->WMP.wmiSCP.uAlphaMode != 1))
1974 if(pID->WMP.bHasAlpha)//planar alpha
1976 tempAlphaMode = pID->WMP.wmiSCP.uAlphaMode;
1977 pID->WMP.wmiSCP.uAlphaMode = 0;
1979 pID->WMP.wmiSCP.fMeasurePerf = TRUE;
1980 #ifdef REENTRANT_MODE
1981 if (0 == pID->WMP.DecoderCurrMBRow)
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);
1986 // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR
1987 cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
1988 (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
1989 linesperMBRow + 1;
1990 cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1;
1991 // if current request starts before current state, then rewind.
1992 if (cMBRowStart < pID->WMP.DecoderCurrMBRow)
1994 pID->WMP.DecoderCurrMBRow = 0;
1995 pID->WMP.cLinesDecoded = 0;
1996 pID->WMP.cLinesCropped = 0;
1997 pID->WMP.fFirstNonZeroDecode = FALSE;
1998 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
1999 Call(pID->WMP.wmiSCP.pWStream->SetPos(pID->WMP.wmiSCP.pWStream, pID->WMP.cMarker));
2000 FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
2003 // In "Low Memory mode", we don't have full frame buffer. We therefore cannot rotate the image.
2004 // We can flip H, V and HV, but no rotations.
2005 FailIf(pID->WMP.wmiI.oOrientation >= O_RCW, WMP_errFail);
2007 // In low-memory mode, the full frame buffer is unavailable. This doesn't seem to
2008 // matter in O_NONE and O_FLIPH, but for O_FLIPV and O_FLIPVH, outputMBRow tries to write to
2009 // the bottom of full-frame buffer. Adjust the buffer pointer to compensate.
2010 if (O_FLIPV == pID->WMP.wmiI.oOrientation || O_FLIPVH == pID->WMP.wmiI.oOrientation)
2012 I32 iActualY2 = pRect->Y + pRect->Height;
2013 pbLowMemAdj = pb - (pID->WMP.wmiI.cROIHeight - (iActualY2 - pID->WMP.cLinesCropped)) * cbStride;
2015 else
2017 pbLowMemAdj = pb - pRect->Y * cbStride;
2019 wmiBI.pv = pbLowMemAdj;
2021 for (i = (U32)pID->WMP.DecoderCurrMBRow; i < cMBRow; i++)
2023 size_t cLinesDecoded;
2024 wmiBI.uiFirstMBRow = i;
2025 wmiBI.uiLastMBRow = i;
2026 FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI, &cLinesDecoded), WMP_errFail);
2027 pID->WMP.cLinesDecoded = cLinesDecoded;
2028 if (FALSE == pID->WMP.fFirstNonZeroDecode && cLinesDecoded > 0)
2030 pID->WMP.cLinesCropped += (linesperMBRow - cLinesDecoded);
2031 pID->WMP.fFirstNonZeroDecode = TRUE;
2032 // update cMBRow if partial MB row cropped
2033 cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
2034 (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
2035 linesperMBRow + 1;
2038 if (0 == cLinesDecoded && i > 0)
2040 pID->WMP.cLinesCropped += linesperMBRow;
2041 // update cMBRow if whole MB row cropped
2042 cMBRow++;
2045 wmiBI.pv = pbLowMemAdj;
2047 // If we're past the top of the image, then we're done, so terminate.
2048 if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) {
2049 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
2051 pID->WMP.DecoderCurrMBRow = cMBRow; // Set to next possible MBRow that is decodable
2053 #else
2054 FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI, &pID->WMP.wmiSCP, &pID->WMP.ctxSC), WMP_errFail);
2055 FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC, &wmiBI), WMP_errFail);
2056 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC), WMP_errFail);
2057 #endif //REENTRANT_MODE
2059 if(pID->WMP.bHasAlpha)//planar alpha
2061 pID->WMP.wmiSCP.uAlphaMode = tempAlphaMode;
2065 // if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode == 2)
2066 // if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 1)
2067 if(pID->WMP.bHasAlpha && pID->WMP.wmiSCP.uAlphaMode != 0)
2069 pID->WMP.wmiI_Alpha = pID->WMP.wmiI;
2070 pID->WMP.wmiSCP_Alpha = pID->WMP.wmiSCP;
2072 // assert(pID->WMP.wmiI_Alpha.cfColorFormat == CF_RGB); // only RGBA is supported for now!
2073 pID->WMP.wmiI_Alpha.cfColorFormat = Y_ONLY;
2075 switch (pID->WMP.wmiI.bdBitDepth)
2077 case BD_8:
2078 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) - 1;
2079 break;
2081 case BD_16:
2082 case BD_16S:
2083 case BD_16F:
2084 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(U16) - 1;
2085 break;
2087 case BD_32:
2088 case BD_32S:
2089 case BD_32F:
2090 pID->WMP.wmiI_Alpha.cLeadingPadding += (pID->WMP.wmiI.cBitsPerUnit >> 3) / sizeof(float) - 1;
2091 break;
2093 case BD_5:
2094 case BD_10:
2095 case BD_565:
2096 default:
2097 break;
2100 pID->WMP.wmiSCP_Alpha.fMeasurePerf = TRUE;
2101 Call(pWS->SetPos(pWS, pID->WMP.wmiDEMisc.uAlphaOffset));
2102 #ifdef REENTRANT_MODE
2103 if (0 == pID->WMP.DecoderCurrAlphaMBRow) // add this to WMP struct!
2105 FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2108 // Re-entrant mode incurs 1 MBR delay, so to get 0th MBR, we have to ask for 1st MBR
2109 cMBRow = ((U32) pID->WMP.cLinesCropped + pRect->Y + pRect->Height +
2110 (pRect->Y + pRect->Height >= (I32) pID->WMP.wmiI.cROIHeight ? linesperMBRow - 1 : 0)) / // round up if last MBR
2111 linesperMBRow + 1;
2112 cMBRowStart = ((U32) pID->WMP.cLinesCropped + pRect->Y) / linesperMBRow + 1;
2113 // if current request starts before current state, then rewind.
2114 if (cMBRowStart < pID->WMP.DecoderCurrAlphaMBRow)
2116 pID->WMP.DecoderCurrAlphaMBRow = 0;
2117 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2118 FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2121 for (i = (U32)pID->WMP.DecoderCurrAlphaMBRow; i < cMBRow; i++)
2123 size_t cLinesDecoded;
2124 wmiBI.uiFirstMBRow = i;
2125 wmiBI.uiLastMBRow = i;
2126 FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI, &cLinesDecoded), WMP_errFail);
2129 // If we're past the top of the image, then we're done, so terminate
2130 if (linesperMBRow * (cMBRow - 1) >= (U32) pID->WMP.cLinesCropped + pID->WMP.wmiI.cROIHeight) {
2131 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2133 pID->WMP.DecoderCurrAlphaMBRow = cMBRow; // Set to next possible MBRow that is decodable
2134 wmiBI.pv = pb;
2135 #else
2136 FailIf(ICERR_OK != ImageStrDecInit(&pID->WMP.wmiI_Alpha, &pID->WMP.wmiSCP_Alpha, &pID->WMP.ctxSC_Alpha), WMP_errFail);
2137 FailIf(ICERR_OK != ImageStrDecDecode(pID->WMP.ctxSC_Alpha, &wmiBI), WMP_errFail);
2138 FailIf(ICERR_OK != ImageStrDecTerm(pID->WMP.ctxSC_Alpha), WMP_errFail);
2139 #endif //REENTRANT_MODE
2142 pID->idxCurrentLine += pRect->Height;
2144 Cleanup:
2145 return err;
2149 ERR PKImageDecode_GetMetadata_WMP(PKImageDecode *pID, U32 uOffset, U32 uByteCount, U8 *pbGot, U32 *pcbGot)
2151 ERR err = WMP_errSuccess;
2153 if (pbGot && uOffset)
2155 struct WMPStream* pWS = pID->pStream;
2156 size_t iCurrPos;
2158 FailIf(*pcbGot < uByteCount, WMP_errBufferOverflow);
2159 Call(pWS->GetPos(pWS, &iCurrPos));
2160 Call(pWS->SetPos(pWS, uOffset));
2161 Call(pWS->Read(pWS, pbGot, uByteCount));
2162 Call(pWS->SetPos(pWS, iCurrPos));
2165 Cleanup:
2166 if (Failed(err))
2167 *pcbGot = 0;
2168 else
2169 *pcbGot = uByteCount;
2171 return err;
2176 ERR PKImageDecode_GetColorContext_WMP(PKImageDecode *pID, U8 *pbColorContext, U32 *pcbColorContext)
2178 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uColorProfileOffset,
2179 pID->WMP.wmiDEMisc.uColorProfileByteCount, pbColorContext, pcbColorContext);
2183 ERR PKImageDecode_GetXMPMetadata_WMP(PKImageDecode *pID, U8 *pbXMPMetadata, U32 *pcbXMPMetadata)
2185 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uXMPMetadataOffset,
2186 pID->WMP.wmiDEMisc.uXMPMetadataByteCount, pbXMPMetadata, pcbXMPMetadata);
2190 ERR PKImageDecode_GetEXIFMetadata_WMP(PKImageDecode *pID, U8 *pbEXIFMetadata, U32 *pcbEXIFMetadata)
2192 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uEXIFMetadataOffset,
2193 pID->WMP.wmiDEMisc.uEXIFMetadataByteCount, pbEXIFMetadata, pcbEXIFMetadata);
2197 ERR PKImageDecode_GetGPSInfoMetadata_WMP(PKImageDecode *pID, U8 *pbGPSInfoMetadata, U32 *pcbGPSInfoMetadata)
2199 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset,
2200 pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount, pbGPSInfoMetadata, pcbGPSInfoMetadata);
2204 ERR PKImageDecode_GetIPTCNAAMetadata_WMP(PKImageDecode *pID, U8 *pbIPTCNAAMetadata, U32 *pcbIPTCNAAMetadata)
2206 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset,
2207 pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount, pbIPTCNAAMetadata, pcbIPTCNAAMetadata);
2211 ERR PKImageDecode_GetPhotoshopMetadata_WMP(PKImageDecode *pID, U8 *pbPhotoshopMetadata, U32 *pcbPhotoshopMetadata)
2213 return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset,
2214 pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount, pbPhotoshopMetadata, pcbPhotoshopMetadata);
2218 ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata)
2220 ERR err = WMP_errSuccess;
2221 *pDescMetadata = pID->WMP.sDescMetadata;
2222 return err;
2226 ERR PKImageDecode_Release_WMP(PKImageDecode** ppID)
2228 ERR err = WMP_errSuccess;
2229 PKImageDecode *pID;
2231 if (NULL == ppID)
2232 goto Cleanup;
2234 pID = *ppID;
2236 // Free descriptive metadata
2237 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarImageDescription);
2238 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraMake);
2239 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCameraModel);
2240 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarSoftware);
2241 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDateTime);
2242 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarArtist);
2243 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCopyright);
2244 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingStars);
2245 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarRatingValue);
2246 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarCaption);
2247 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarDocumentName);
2248 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageName);
2249 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarPageNumber);
2250 FreeDescMetadata(&pID->WMP.sDescMetadata.pvarHostComputer);
2252 // Release base class
2253 Call(PKImageDecode_Release(ppID));
2255 Cleanup:
2256 return err;
2261 ERR PKImageDecode_Create_WMP(PKImageDecode** ppID)
2263 ERR err = WMP_errSuccess;
2264 PKImageDecode* pID = NULL;
2266 Call(PKImageDecode_Create(ppID));
2268 pID = *ppID;
2269 pID->Initialize = PKImageDecode_Initialize_WMP;
2270 pID->GetSize = PKImageDecode_GetSize_WMP;
2271 pID->GetRawStream = PKImageDecode_GetRawStream_WMP;
2272 pID->Copy = PKImageDecode_Copy_WMP;
2273 pID->GetColorContext = PKImageDecode_GetColorContext_WMP;
2274 pID->GetDescriptiveMetadata = PKImageDecode_GetDescriptiveMetadata_WMP;
2275 pID->Release = PKImageDecode_Release_WMP;
2277 Cleanup:
2278 return err;