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