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