/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, ¤tPos)); |
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 | | |