1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #if defined(SDL_IMAGE_USE_WIC_BACKEND)
23 
24 #include "SDL_image.h"
25 #define COBJMACROS
26 #include <initguid.h>
27 #include <wincodec.h>
28 
29 static IWICImagingFactory* wicFactory = NULL;
30 
WIC_Init()31 static int WIC_Init()
32 {
33     if (wicFactory == NULL) {
34         HRESULT hr = CoCreateInstance(
35             &CLSID_WICImagingFactory,
36             NULL,
37             CLSCTX_INPROC_SERVER,
38             &IID_IWICImagingFactory,
39             (void**)&wicFactory
40         );
41         if (FAILED(hr)) {
42             return -1;
43         }
44     }
45 
46     return 0;
47 }
48 
WIC_Quit()49 static void WIC_Quit()
50 {
51     if (wicFactory) {
52         IWICImagingFactory_Release(wicFactory);
53     }
54 }
55 
IMG_InitPNG()56 int IMG_InitPNG()
57 {
58     return WIC_Init();
59 }
60 
IMG_QuitPNG()61 void IMG_QuitPNG()
62 {
63     WIC_Quit();
64 }
65 
IMG_InitJPG()66 int IMG_InitJPG()
67 {
68     return WIC_Init();
69 }
70 
IMG_QuitJPG()71 void IMG_QuitJPG()
72 {
73     WIC_Quit();
74 }
75 
IMG_InitTIF()76 int IMG_InitTIF()
77 {
78     return WIC_Init();
79 }
80 
IMG_QuitTIF()81 void IMG_QuitTIF()
82 {
83     WIC_Quit();
84 }
85 
IMG_isPNG(SDL_RWops * src)86 int IMG_isPNG(SDL_RWops *src)
87 {
88     Sint64 start;
89     int is_PNG;
90     Uint8 magic[4];
91 
92     if ( !src ) {
93         return 0;
94     }
95 
96     start = SDL_RWtell(src);
97     is_PNG = 0;
98     if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
99         if ( magic[0] == 0x89 &&
100              magic[1] == 'P' &&
101              magic[2] == 'N' &&
102              magic[3] == 'G' ) {
103             is_PNG = 1;
104         }
105     }
106     SDL_RWseek(src, start, RW_SEEK_SET);
107     return(is_PNG);
108 }
109 
IMG_isJPG(SDL_RWops * src)110 int IMG_isJPG(SDL_RWops *src)
111 {
112     Sint64 start;
113     int is_JPG;
114     int in_scan;
115     Uint8 magic[4];
116 
117     /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
118     /* Blame me, not Sam, if this doesn't work right. */
119     /* And don't forget to report the problem to the the sdl list too! */
120 
121     if (!src)
122         return 0;
123     start = SDL_RWtell(src);
124     is_JPG = 0;
125     in_scan = 0;
126     if (SDL_RWread(src, magic, 2, 1)) {
127         if ((magic[0] == 0xFF) && (magic[1] == 0xD8)) {
128             is_JPG = 1;
129             while (is_JPG == 1) {
130                 if (SDL_RWread(src, magic, 1, 2) != 2) {
131                     is_JPG = 0;
132                 }
133                 else if ((magic[0] != 0xFF) && (in_scan == 0)) {
134                     is_JPG = 0;
135                 }
136                 else if ((magic[0] != 0xFF) || (magic[1] == 0xFF)) {
137                     /* Extra padding in JPEG (legal) */
138                     /* or this is data and we are scanning */
139                     SDL_RWseek(src, -1, RW_SEEK_CUR);
140                 }
141                 else if (magic[1] == 0xD9) {
142                     /* Got to end of good JPEG */
143                     break;
144                 }
145                 else if ((in_scan == 1) && (magic[1] == 0x00)) {
146                     /* This is an encoded 0xFF within the data */
147                 }
148                 else if ((magic[1] >= 0xD0) && (magic[1] < 0xD9)) {
149                     /* These have nothing else */
150                 }
151                 else if (SDL_RWread(src, magic + 2, 1, 2) != 2) {
152                     is_JPG = 0;
153                 }
154                 else {
155                     /* Yes, it's big-endian */
156                     Sint64 innerStart;
157                     Uint32 size;
158                     Sint64 end;
159                     innerStart = SDL_RWtell(src);
160                     size = (magic[2] << 8) + magic[3];
161                     end = SDL_RWseek(src, size - 2, RW_SEEK_CUR);
162                     if (end != innerStart + size - 2) is_JPG = 0;
163                     if (magic[1] == 0xDA) {
164                         /* Now comes the actual JPEG meat */
165 #ifdef  FAST_IS_JPEG
166                         /* Ok, I'm convinced.  It is a JPEG. */
167                         break;
168 #else
169                         /* I'm not convinced.  Prove it! */
170                         in_scan = 1;
171 #endif
172                     }
173                 }
174             }
175         }
176     }
177     SDL_RWseek(src, start, RW_SEEK_SET);
178     return(is_JPG);
179 }
180 
IMG_isTIF(SDL_RWops * src)181 int IMG_isTIF(SDL_RWops* src)
182 {
183     Sint64 start;
184     int is_TIF;
185     Uint8 magic[4];
186 
187     if (!src)
188         return 0;
189     start = SDL_RWtell(src);
190     is_TIF = 0;
191     if (SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic)) {
192         if ((magic[0] == 'I' &&
193             magic[1] == 'I' &&
194             magic[2] == 0x2a &&
195             magic[3] == 0x00) ||
196             (magic[0] == 'M' &&
197             magic[1] == 'M' &&
198             magic[2] == 0x00 &&
199             magic[3] == 0x2a)) {
200             is_TIF = 1;
201         }
202     }
203     SDL_RWseek(src, start, RW_SEEK_SET);
204     return(is_TIF);
205 }
206 
WIC_LoadImage(SDL_RWops * src)207 static SDL_Surface* WIC_LoadImage(SDL_RWops *src)
208 {
209     SDL_Surface* surface = NULL;
210 
211     IWICStream* stream = NULL;
212     IWICBitmapDecoder* bitmapDecoder = NULL;
213     IWICBitmapFrameDecode* bitmapFrame = NULL;
214     IWICFormatConverter* formatConverter = NULL;
215     UINT width, height;
216 
217     if (wicFactory == NULL && (WIC_Init() < 0)) {
218         IMG_SetError("WIC failed to initialize!");
219         return NULL;
220     }
221 
222     Sint64 fileSize = SDL_RWsize(src);
223     Uint8* memoryBuffer = (Uint8*)SDL_malloc(fileSize);
224     if (!memoryBuffer) {
225         SDL_OutOfMemory();
226         return NULL;
227     }
228 
229     SDL_RWread(src, memoryBuffer, 1, fileSize);
230 
231 #define DONE_IF_FAILED(X) if (FAILED((X))) { goto done; }
232     DONE_IF_FAILED(IWICImagingFactory_CreateStream(wicFactory, &stream));
233     DONE_IF_FAILED(IWICStream_InitializeFromMemory(stream, memoryBuffer, fileSize));
234     DONE_IF_FAILED(IWICImagingFactory_CreateDecoderFromStream(
235         wicFactory,
236         (IStream*)stream,
237         NULL,
238         WICDecodeMetadataCacheOnDemand,
239         &bitmapDecoder
240     ));
241     DONE_IF_FAILED(IWICBitmapDecoder_GetFrame(bitmapDecoder, 0, &bitmapFrame));
242     DONE_IF_FAILED(IWICImagingFactory_CreateFormatConverter(wicFactory, &formatConverter));
243     DONE_IF_FAILED(IWICFormatConverter_Initialize(
244         formatConverter,
245         (IWICBitmapSource*)bitmapFrame,
246         &GUID_WICPixelFormat32bppPRGBA,
247         WICBitmapDitherTypeNone,
248         NULL,
249         0.0,
250         WICBitmapPaletteTypeCustom
251     ));
252     DONE_IF_FAILED(IWICBitmapFrameDecode_GetSize(bitmapFrame, &width, &height));
253 #undef DONE_IF_FAILED
254 
255     surface = SDL_CreateRGBSurface(
256         0,
257         width,
258         height,
259         32,
260         0x000000FF,
261         0x0000FF00,
262         0x00FF0000,
263         0xFF000000
264     );
265     IWICFormatConverter_CopyPixels(
266         formatConverter,
267         NULL,
268         width * 4,
269         width * height * 4,
270         (BYTE*)surface->pixels
271     );
272 
273 done:
274     if (formatConverter) {
275         IWICFormatConverter_Release(formatConverter);
276     }
277     if (bitmapFrame) {
278         IWICBitmapFrameDecode_Release(bitmapFrame);
279     }
280     if (bitmapDecoder) {
281         IWICBitmapDecoder_Release(bitmapDecoder);
282     }
283     if (stream) {
284         IWICStream_Release(stream);
285     }
286 
287  SDL_free(memoryBuffer);
288 
289  return surface;
290 }
291 
IMG_LoadPNG_RW(SDL_RWops * src)292 SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
293 {
294     return WIC_LoadImage(src);
295 }
296 
IMG_LoadJPG_RW(SDL_RWops * src)297 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
298 {
299     return WIC_LoadImage(src);
300 }
301 
IMG_LoadTIF_RW(SDL_RWops * src)302 SDL_Surface *IMG_LoadTIF_RW(SDL_RWops *src)
303 {
304     return WIC_LoadImage(src);
305 }
306 
307 #endif /* SDL_IMAGE_USE_WIC_BACKEND */
308 
309