Coverage Report

Created: 2023-12-08 06:53

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