1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Last modified: 02/09/2009
5 //
6 // Filename: src-IL/src/il_wdp.c
7 //
8 // Description: Reads a Microsoft HD Photo (.wdp or .hdp)
9 // Based very much on the Microsoft HD Photo Device Porting Kit 1.0
10 // available at
11 // http://www.microsoft.com/downloads/details.aspx?FamilyID=285eeffd-d86c-48c3-ab93-3abd5ee7f1ce&displaylang=en.
12 //
13 // Note: The license that the Device Porting Kit is under is not very clear.
14 // Commentary on the license can be found at http://en.wikipedia.org/wiki/HD_Photo.
15 // Lots of this code is taken from the examples in the DPK and from code
16 // within the DPK itself. For this reason, this file is not under the LGPL
17 // license, unlike the rest of DevIL.
18 //
19 //-----------------------------------------------------------------------------
20
21
22 #include "il_internal.h"
23 #ifndef IL_NO_WDP
24 #include <WMPGlue.h>
25 #include "il_wdp.h"
26
27 #if defined(_WIN32) && defined(IL_USE_PRAGMA_LIBS)
28 #if defined(_MSC_VER) || defined(__BORLANDC__)
29 #ifndef _DEBUG
30 #pragma comment(lib, "wmplib.lib")
31 #else
32 #pragma comment(lib, "wmplib-d.lib")
33 #endif
34 #endif
35 #endif
36
37
38 //! Reads a WDP file
ilLoadWdp(ILconst_string FileName)39 ILboolean ilLoadWdp(ILconst_string FileName)
40 {
41 ILHANDLE WdpFile;
42 ILboolean bWdp = IL_FALSE;
43
44 WdpFile = iopenr(FileName);
45 if (WdpFile == NULL) {
46 ilSetError(IL_COULD_NOT_OPEN_FILE);
47 return bWdp;
48 }
49
50 bWdp = ilLoadWdpF(WdpFile);
51 icloser(WdpFile);
52
53 return bWdp;
54 }
55
56
57 //! Reads an already-opened WDP file
ilLoadWdpF(ILHANDLE File)58 ILboolean ilLoadWdpF(ILHANDLE File)
59 {
60 ILuint FirstPos;
61 ILboolean bRet;
62
63 iSetInputFile(File);
64 FirstPos = itell();
65 bRet = iLoadWdpInternal();
66 iseek(FirstPos, IL_SEEK_SET);
67
68 return bRet;
69 }
70
71
72 //! Reads from a memory "lump" that contains a WDP
ilLoadWdpL(const void * Lump,ILuint Size)73 ILboolean ilLoadWdpL(const void *Lump, ILuint Size)
74 {
75 iSetInputLump(Lump, Size);
76 return iLoadWdpInternal();
77 }
78
79 //@TODO: Put in ilPKImageEncode_WritePixels_DevIL?
WriteDevILHeader(PKImageEncode * pIE)80 ERR WriteDevILHeader(PKImageEncode* pIE)
81 {
82 struct WMPStream* pS = pIE->pStream;
83
84 if (IsEqualGUID(&GUID_PKPixelFormat24bppRGB, &pIE->guidPixFormat) || IsEqualGUID(&GUID_PKPixelFormat24bppBGR, &pIE->guidPixFormat))
85 {
86 pIE->cbPixel = 3;
87 }
88 else if (IsEqualGUID(&GUID_PKPixelFormat32bppBGRA, &pIE->guidPixFormat)
89 || IsEqualGUID(&GUID_PKPixelFormat32bppBGR, &pIE->guidPixFormat)
90 || IsEqualGUID(&GUID_PKPixelFormat32bppPBGRA, &pIE->guidPixFormat))
91 {
92 pIE->cbPixel = 4;
93 }
94 else if (IsEqualGUID(&GUID_PKPixelFormat8bppGray, &pIE->guidPixFormat))
95 {
96 pIE->cbPixel = 1;
97 }
98 else if (IsEqualGUID(&GUID_PKPixelFormat16bppGray, &pIE->guidPixFormat))
99 {
100 pIE->cbPixel = 2;
101 }
102 else if (IsEqualGUID(&GUID_PKPixelFormat128bppRGBAFloat, &pIE->guidPixFormat))
103 {
104 pIE->cbPixel = 16;//4;
105 }
106
107
108 pIE->offPixel = pIE->offStart;
109 pIE->fHeaderDone = !IL_FALSE;
110
111 return WMP_errSuccess;
112 }
113
ilPKImageEncode_WritePixels_DevIL(PKImageEncode * pIE,U32 cLine,U8 * pbPixel,U32 cbStride)114 ERR ilPKImageEncode_WritePixels_DevIL(PKImageEncode* pIE, U32 cLine, U8* pbPixel, U32 cbStride)
115 {
116 ERR err = WMP_errSuccess;
117
118 struct WMPStream* pS = pIE->pStream;
119 size_t cbLineM = 0, cbLineS = 0;
120 I32 i = 0;
121 static U8 pPadding[4] = {0};
122
123 // header
124 if (!pIE->fHeaderDone)
125 {
126 // WriteBMPHeader() also inits this object
127 Call(WriteDevILHeader(pIE));
128 }
129
130 // body
131 // calculate line size in memory and in stream
132 cbLineM = pIE->cbPixel * pIE->uWidth;
133 cbLineS = (cbLineM + 3) / 4 * 4;
134
135 //FailIf(pRect->X < 0 || pID->uWidth <= pRect->X, WMP_errInvalidParameter);
136 //FailIf(pRect->Y < 0 || pID->uHeight <= pRect->Y, WMP_errInvalidParameter);
137 //FailIf(pRect->Width < 0 || pID->uWidth < pRect->X + pRect->Width, WMP_errInvalidParameter);
138 //FailIf(pRect->Height < 0 || pID->uHeight < pRect->Y + pRect->Height, WMP_errInvalidParameter);
139 FailIf(cbStride < cbLineM, WMP_errInvalidParameter);
140
141 for (i = cLine - 1; 0 <= i; --i)
142 {
143 size_t offM = cbStride * i;
144 size_t offS = cbLineS * (pIE->uHeight - (pIE->idxCurrentLine + i + 1));
145
146 Call(pS->SetPos(pS, pIE->offPixel + offS));
147 Call(pS->Write(pS, pbPixel + offM, cbLineM));
148 }
149 Call(pS->Write(pS, pPadding, (cbLineS - cbLineM)));
150 pIE->idxCurrentLine += cLine;
151
152 Cleanup:
153 return err;
154 }
155
156
PKImageEncode_Create_DevIL(PKImageEncode ** ppIE)157 ERR PKImageEncode_Create_DevIL(
158 PKImageEncode** ppIE)
159 {
160 ERR err = WMP_errSuccess;
161 PKImageEncode* pIE = NULL;
162
163 Call(PKImageEncode_Create(ppIE));
164
165 pIE = *ppIE;
166 pIE->WritePixels = ilPKImageEncode_WritePixels_DevIL;
167
168 Cleanup:
169 return err;
170 }
171
172
iWmpDecAppCreateEncoderFromExt(PKCodecFactory * pCFactory,const char * szExt,PKImageEncode ** ppIE)173 ERR iWmpDecAppCreateEncoderFromExt(
174 PKCodecFactory* pCFactory,
175 const char* szExt,
176 PKImageEncode** ppIE)
177 {
178 ERR err = WMP_errSuccess;
179 const PKIID* pIID = NULL;
180
181 // get encod PKIID
182 Call(GetImageEncodeIID(szExt, &pIID));
183
184 // Create encoder
185 //Call(PKCodecFactory_CreateCodec(pIID, ppIE));
186
187 Call(PKImageEncode_Create_DevIL(ppIE));
188
189 Cleanup:
190 return err;
191 }
192
193
iCloseWS_File(struct WMPStream ** ppWS)194 ERR iCloseWS_File(struct WMPStream** ppWS)
195 {
196 ERR err = WMP_errSuccess;
197 /*struct WMPStream* pWS = *ppWS;
198
199 fclose(pWS->state.file.pFile);
200 Call(WMPFree((void**)ppWS));
201
202 Cleanup:*/
203 return err;
204 }
205
iEOSWS_File(struct WMPStream * pWS)206 Bool iEOSWS_File(struct WMPStream* pWS)
207 {
208 //return feof(pWS->state.file.pFile);
209 return ieof();
210 }
211
iReadWS_File(struct WMPStream * pWS,void * pv,size_t cb)212 ERR iReadWS_File(struct WMPStream* pWS, void* pv, size_t cb)
213 {
214 // For some reason, the WDP images load just fine, but it tries to read too much,
215 // so IL_FILE_READ_ERROR is set. So we get rid of the error.
216 if (iread(pv, 1, (ILuint)cb) != cb)
217 ilGetError();
218 return WMP_errSuccess;
219 }
220
iWriteWS_File(struct WMPStream * pWS,const void * pv,size_t cb)221 ERR iWriteWS_File(struct WMPStream* pWS, const void* pv, size_t cb)
222 {
223 ERR err = WMP_errSuccess;
224
225 if (0 != cb) {
226 FailIf(1 != iwrite(pv, (ILuint)cb, 1), WMP_errFileIO);
227 }
228
229 Cleanup:
230 return err;
231 }
232
iSetPosWS_File(struct WMPStream * pWS,size_t offPos)233 ERR iSetPosWS_File(struct WMPStream* pWS, size_t offPos)
234 {
235 ERR err = WMP_errSuccess;
236
237 //FailIf(0 != fseek(pWS->state.file.pFile, (long)offPos, SEEK_SET), WMP_errFileIO);
238 FailIf(0 != iseek((ILuint)offPos, IL_SEEK_SET), WMP_errFileIO);
239
240 Cleanup:
241 return err;
242 }
243
iGetPosWS_File(struct WMPStream * pWS,size_t * poffPos)244 ERR iGetPosWS_File(struct WMPStream* pWS, size_t* poffPos)
245 {
246 ERR err = WMP_errSuccess;
247 long lOff = 0;
248
249 //FailIf(-1 == (lOff = ftell(pWS->state.file.pFile)), WMP_errFileIO);
250 lOff = itell();
251 *poffPos = (size_t)lOff;
252
253 Cleanup:
254 return err;
255 }
256
ilCreateWS_File(struct WMPStream ** ppWS,const char * szFilename,const char * szMode)257 ERR ilCreateWS_File(struct WMPStream** ppWS, const char* szFilename, const char* szMode)
258 {
259 ERR err = WMP_errSuccess;
260 struct WMPStream* pWS = NULL;
261
262 *ppWS = icalloc(1, sizeof(**ppWS));
263 if (*ppWS == NULL)
264 return WMP_errOutOfMemory;
265 pWS = *ppWS;
266
267 pWS->Close = iCloseWS_File;
268 pWS->EOS = iEOSWS_File;
269
270 pWS->Read = iReadWS_File;
271 pWS->Write = iWriteWS_File;
272 //pWS->GetLine = GetLineWS_File;
273
274 pWS->SetPos = iSetPosWS_File;
275 pWS->GetPos = iGetPosWS_File;
276
277 //pWS->state.file.pFile = fopen(szFilename, szMode);
278 pWS->state.file.pFile = NULL;
279 //FailIf(NULL == pWS->state.file.pFile, WMP_errFileIO);
280
281 Cleanup:
282 return err;
283 }
284
285
ilPKCodecFactory_CreateDecoderFromFile(PKImageDecode ** ppDecoder)286 ERR ilPKCodecFactory_CreateDecoderFromFile(PKImageDecode** ppDecoder)
287 {
288 ERR err = WMP_errSuccess;
289
290 char *pExt = ".wdp"; // We are loading a WDP file, so we have to tell the library that with this extension.
291 PKIID* pIID = NULL;
292
293 struct WMPStream* pStream = NULL;
294 PKImageDecode* pDecoder = NULL;
295
296 // get decode PKIID
297 Call(GetImageDecodeIID(pExt, &pIID));
298
299 // create stream
300 Call(ilCreateWS_File(&pStream, NULL, "rb"));
301
302 // Create decoder
303 Call(PKCodecFactory_CreateCodec(pIID, ppDecoder));
304 pDecoder = *ppDecoder;
305
306 // attach stream to decoder
307 Call(pDecoder->Initialize(pDecoder, pStream));
308 pDecoder->fStreamOwner = !0;
309
310 Cleanup:
311 return err;
312 }
313
314
ilPKCreateFactory(PKFactory ** ppFactory,U32 uVersion)315 ERR ilPKCreateFactory(PKFactory** ppFactory, U32 uVersion)
316 {
317 ERR err = WMP_errSuccess;
318 PKFactory* pFactory = NULL;
319
320 Call(PKAlloc(ppFactory, sizeof(**ppFactory)));
321 pFactory = *ppFactory;
322
323 pFactory->CreateStream = PKCreateFactory_CreateStream;
324
325 pFactory->CreateStreamFromFilename = ilCreateWS_File;
326 pFactory->CreateStreamFromMemory = CreateWS_Memory;
327
328 pFactory->Release = PKCreateFactory_Release;
329
330 Cleanup:
331 return err;
332 }
333
iLoadWdpInternal()334 ILboolean iLoadWdpInternal(/*ILconst_string FileName*/)
335 {
336 ERR err = WMP_errSuccess;
337 PKFactory* pFactory = NULL;
338 PKCodecFactory* pCodecFactory = NULL;
339 PKImageDecode* pDecoder = NULL;
340 PKPixelInfo PI;
341 PKPixelFormatGUID guidPixFormat;
342 PKFormatConverter* pConverter = NULL;
343 U32 cFrame = 0, i = 0;
344 PKRect Rect;
345 struct WMPStream* pEncodeStream = NULL;
346 PKImageEncode* pEncoder = NULL;
347
348 //Call(PKCreateFactory(&pFactory, PK_SDK_VERSION));
349 //Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
350 //Call(pCodecFactory->CreateDecoderFromFile(FileName, &pDecoder));
351 Call(ilPKCreateFactory(&pFactory, PK_SDK_VERSION));
352 Call(PKCreateCodecFactory(&pCodecFactory, WMP_SDK_VERSION));
353 Call(ilPKCodecFactory_CreateDecoderFromFile(&pDecoder));
354
355 //guidPixFormat = GUID_PKPixelFormat24bppRGB;
356 guidPixFormat = GUID_PKPixelFormat32bppBGRA;
357 //guidPixFormat = GUID_PKPixelFormat8bppGray;
358 //guidPixFormat = GUID_PKPixelFormat16bppGray;
359
360 // Color transcoding
361 if (IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat8bppGray) || IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat16bppGray)){ // ** => Y transcoding
362 pDecoder->guidPixFormat = guidPixFormat;
363 pDecoder->WMP.wmiI.cfColorFormat = Y_ONLY;
364 }
365 else if(IsEqualGUID(&guidPixFormat, &GUID_PKPixelFormat24bppRGB) && pDecoder->WMP.wmiI.cfColorFormat == CMYK){ // CMYK = > RGB
366 pDecoder->WMP.wmiI.cfColorFormat = CF_RGB;
367 pDecoder->guidPixFormat = guidPixFormat;
368 pDecoder->WMP.wmiI.bRGB = 1; //RGB
369 }
370
371 PI.pGUIDPixFmt = &guidPixFormat;
372 PixelFormatLookup(&PI, LOOKUP_FORWARD);
373
374 pDecoder->WMP.wmiSCP.bfBitstreamFormat = 0;
375 pDecoder->WMP.wmiSCP.uAlphaMode = 0;
376 pDecoder->WMP.wmiSCP.sbSubband = SB_ALL;
377 pDecoder->WMP.bIgnoreOverlap = FALSE;
378
379 pDecoder->WMP.wmiI.cfColorFormat = PI.cfColorFormat;
380
381 pDecoder->WMP.wmiI.bdBitDepth = PI.bdBitDepth;
382 pDecoder->WMP.wmiI.cBitsPerUnit = PI.cbitUnit;
383
384 //==== Validate thumbnail decode parameters =====
385 pDecoder->WMP.wmiI.cThumbnailWidth = pDecoder->WMP.wmiI.cWidth;
386 pDecoder->WMP.wmiI.cThumbnailHeight = pDecoder->WMP.wmiI.cHeight;
387 pDecoder->WMP.wmiI.bSkipFlexbits = FALSE;
388
389 pCodecFactory->CreateFormatConverter(&pConverter);
390 pConverter->Initialize(pConverter, pDecoder, NULL, guidPixFormat);
391
392 // Right now, we are just assuming one frame.
393 // @TODO: Deal with multiple frames.
394 //pDecoder->GetFrameCount(pDecoder, &cFrame);
395 //pDecoder->SelectFrame(pDecoder, 1);
396
397 if (!ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 4, IL_BGRA, IL_UNSIGNED_BYTE, NULL))
398 goto Cleanup;
399 //ilTexImage(pDecoder->uWidth, pDecoder->uHeight, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, Data);
400
401 pFactory->CreateStreamFromMemory(&pEncodeStream, iCurImage->Data, iCurImage->SizeOfData);
402 iWmpDecAppCreateEncoderFromExt(pCodecFactory, ".wdp", &pEncoder);
403 pEncoder->Initialize(pEncoder, pEncodeStream, ".wdp", 0);
404
405 pEncoder->pStream->GetPos(pEncoder->pStream, &pEncoder->offStart);
406
407 // Set the region that we want to be the whole image.
408 Rect.X = 0; Rect.Y = 0; Rect.Height = pDecoder->uHeight; Rect.Width = pDecoder->uWidth;
409 pEncoder->SetPixelFormat(pEncoder, guidPixFormat);
410 pEncoder->SetSize(pEncoder, Rect.Width, Rect.Height);
411 pEncoder->WriteSource = PKImageEncode_Transcode;
412 pEncoder->WriteSource(pEncoder, pConverter, &Rect);
413
414
415 Cleanup:
416 // Release everything all at the end.
417 PKImageDecode_Release(&pDecoder);
418 if (pEncoder)
419 PKImageEncode_Release(&pEncoder);
420 PKCreateCodecFactory_Release(&pCodecFactory);
421 PKCreateFactory_Release(&pFactory);
422 PKFormatConverter_Release(&pConverter);
423
424 if (err != WMP_errSuccess)
425 return IL_FALSE;
426 return IL_TRUE;
427 }
428
429 #endif//IL_NO_WDP
430