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