Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/jxr/jxrgluelib/JXRGlueJxr.c
4395 views
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
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
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
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
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
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
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
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
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
//================================================================
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
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
//================================================
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
759
ERR PKImageEncode_Terminate_WMP(
760
PKImageEncode* pIE)
761
{
762
ERR err = WMP_errSuccess;
763
UNREFERENCED_PARAMETER( pIE );
764
return err;
765
}
766
767
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
//----------------------------------------------------------------
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
//================================================================
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
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
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
//================================================
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
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
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
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
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
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
ERR PKImageDecode_GetXMPMetadata_WMP(PKImageDecode *pID, U8 *pbXMPMetadata, U32 *pcbXMPMetadata)
2184
{
2185
return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uXMPMetadataOffset,
2186
pID->WMP.wmiDEMisc.uXMPMetadataByteCount, pbXMPMetadata, pcbXMPMetadata);
2187
}
2188
2189
2190
ERR PKImageDecode_GetEXIFMetadata_WMP(PKImageDecode *pID, U8 *pbEXIFMetadata, U32 *pcbEXIFMetadata)
2191
{
2192
return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uEXIFMetadataOffset,
2193
pID->WMP.wmiDEMisc.uEXIFMetadataByteCount, pbEXIFMetadata, pcbEXIFMetadata);
2194
}
2195
2196
2197
ERR PKImageDecode_GetGPSInfoMetadata_WMP(PKImageDecode *pID, U8 *pbGPSInfoMetadata, U32 *pcbGPSInfoMetadata)
2198
{
2199
return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uGPSInfoMetadataOffset,
2200
pID->WMP.wmiDEMisc.uGPSInfoMetadataByteCount, pbGPSInfoMetadata, pcbGPSInfoMetadata);
2201
}
2202
2203
2204
ERR PKImageDecode_GetIPTCNAAMetadata_WMP(PKImageDecode *pID, U8 *pbIPTCNAAMetadata, U32 *pcbIPTCNAAMetadata)
2205
{
2206
return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uIPTCNAAMetadataOffset,
2207
pID->WMP.wmiDEMisc.uIPTCNAAMetadataByteCount, pbIPTCNAAMetadata, pcbIPTCNAAMetadata);
2208
}
2209
2210
2211
ERR PKImageDecode_GetPhotoshopMetadata_WMP(PKImageDecode *pID, U8 *pbPhotoshopMetadata, U32 *pcbPhotoshopMetadata)
2212
{
2213
return PKImageDecode_GetMetadata_WMP(pID, pID->WMP.wmiDEMisc.uPhotoshopMetadataOffset,
2214
pID->WMP.wmiDEMisc.uPhotoshopMetadataByteCount, pbPhotoshopMetadata, pcbPhotoshopMetadata);
2215
}
2216
2217
2218
ERR PKImageDecode_GetDescriptiveMetadata_WMP(PKImageDecode *pID, DESCRIPTIVEMETADATA *pDescMetadata)
2219
{
2220
ERR err = WMP_errSuccess;
2221
*pDescMetadata = pID->WMP.sDescMetadata;
2222
return err;
2223
}
2224
2225
2226
ERR PKImageDecode_Release_WMP(PKImageDecode** ppID)
2227
{
2228
ERR err = WMP_errSuccess;
2229
PKImageDecode *pID;
2230
2231
if (NULL == ppID)
2232
goto Cleanup;
2233
2234
pID = *ppID;
2235
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);
2251
2252
// Release base class
2253
Call(PKImageDecode_Release(ppID));
2254
2255
Cleanup:
2256
return err;
2257
}
2258
2259
2260
2261
ERR PKImageDecode_Create_WMP(PKImageDecode** ppID)
2262
{
2263
ERR err = WMP_errSuccess;
2264
PKImageDecode* pID = NULL;
2265
2266
Call(PKImageDecode_Create(ppID));
2267
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;
2276
2277
Cleanup:
2278
return err;
2279
}
2280
2281
2282