This source file includes following definitions.
- gdiplus_init
- gdiplus_startup
- w32_gdiplus_shutdown
- w32_can_use_native_image_api
- decode_delay
- w32_frame_delay
- w32_select_active_frame
- w32_image_bg_color
- w32_load_image
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include <config.h>
23 #include "lisp.h"
24 #include "dispextern.h"
25 #define COBJMACROS
26 #ifdef MINGW_W64
27
28 #include <objidl.h>
29 #endif
30 #include <wtypes.h>
31 #include <gdiplus.h>
32 #include <shlwapi.h>
33 #include "w32common.h"
34 #include "w32term.h"
35 #ifdef WINDOWSNT
36 #include "w32.h"
37 #endif
38 #include "frame.h"
39 #include "coding.h"
40
41 #ifdef WINDOWSNT
42
43 typedef GpStatus (WINGDIPAPI *GdiplusStartup_Proc)
44 (ULONG_PTR *, GdiplusStartupInput *, GdiplusStartupOutput *);
45 typedef VOID (WINGDIPAPI *GdiplusShutdown_Proc) (ULONG_PTR);
46 typedef GpStatus (WINGDIPAPI *GdipGetPropertyItemSize_Proc)
47 (GpImage *, PROPID, UINT *);
48 typedef GpStatus (WINGDIPAPI *GdipGetPropertyItem_Proc)
49 (GpImage *, PROPID, UINT, PropertyItem *);
50 typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsCount_Proc)
51 (GpImage *, UINT *);
52 typedef GpStatus (WINGDIPAPI *GdipImageGetFrameDimensionsList_Proc)
53 (GpImage *, GUID *, UINT);
54 typedef GpStatus (WINGDIPAPI *GdipImageGetFrameCount_Proc)
55 (GpImage *, GDIPCONST GUID *, UINT *);
56 typedef GpStatus (WINGDIPAPI *GdipImageSelectActiveFrame_Proc)
57 (GpImage*, GDIPCONST GUID *, UINT);
58 typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromFile_Proc)
59 (WCHAR *, GpBitmap **);
60 typedef GpStatus (WINGDIPAPI *GdipCreateBitmapFromStream_Proc)
61 (IStream *, GpBitmap **);
62 typedef IStream * (WINAPI *SHCreateMemStream_Proc) (const BYTE *, UINT);
63 typedef GpStatus (WINGDIPAPI *GdipCreateHBITMAPFromBitmap_Proc)
64 (GpBitmap *, HBITMAP *, ARGB);
65 typedef GpStatus (WINGDIPAPI *GdipDisposeImage_Proc) (GpImage *);
66 typedef GpStatus (WINGDIPAPI *GdipGetImageHeight_Proc) (GpImage *, UINT *);
67 typedef GpStatus (WINGDIPAPI *GdipGetImageWidth_Proc) (GpImage *, UINT *);
68
69 GdiplusStartup_Proc fn_GdiplusStartup;
70 GdiplusShutdown_Proc fn_GdiplusShutdown;
71 GdipGetPropertyItemSize_Proc fn_GdipGetPropertyItemSize;
72 GdipGetPropertyItem_Proc fn_GdipGetPropertyItem;
73 GdipImageGetFrameDimensionsCount_Proc fn_GdipImageGetFrameDimensionsCount;
74 GdipImageGetFrameDimensionsList_Proc fn_GdipImageGetFrameDimensionsList;
75 GdipImageGetFrameCount_Proc fn_GdipImageGetFrameCount;
76 GdipImageSelectActiveFrame_Proc fn_GdipImageSelectActiveFrame;
77 GdipCreateBitmapFromFile_Proc fn_GdipCreateBitmapFromFile;
78 GdipCreateBitmapFromStream_Proc fn_GdipCreateBitmapFromStream;
79 SHCreateMemStream_Proc fn_SHCreateMemStream;
80 GdipCreateHBITMAPFromBitmap_Proc fn_GdipCreateHBITMAPFromBitmap;
81 GdipDisposeImage_Proc fn_GdipDisposeImage;
82 GdipGetImageHeight_Proc fn_GdipGetImageHeight;
83 GdipGetImageWidth_Proc fn_GdipGetImageWidth;
84
85 static bool
86 gdiplus_init (void)
87 {
88 HANDLE gdiplus_lib, shlwapi_lib;
89
90 if (!((gdiplus_lib = w32_delayed_load (Qgdiplus))
91 && (shlwapi_lib = w32_delayed_load (Qshlwapi))))
92 return false;
93
94 fn_GdiplusStartup = (GdiplusStartup_Proc)
95 get_proc_addr (gdiplus_lib, "GdiplusStartup");
96 if (!fn_GdiplusStartup)
97 return false;
98 fn_GdiplusShutdown = (GdiplusShutdown_Proc)
99 get_proc_addr (gdiplus_lib, "GdiplusShutdown");
100 if (!fn_GdiplusShutdown)
101 return false;
102 fn_GdipGetPropertyItemSize = (GdipGetPropertyItemSize_Proc)
103 get_proc_addr (gdiplus_lib, "GdipGetPropertyItemSize");
104 if (!fn_GdipGetPropertyItemSize)
105 return false;
106 fn_GdipGetPropertyItem = (GdipGetPropertyItem_Proc)
107 get_proc_addr (gdiplus_lib, "GdipGetPropertyItem");
108 if (!fn_GdipGetPropertyItem)
109 return false;
110 fn_GdipImageGetFrameDimensionsCount = (GdipImageGetFrameDimensionsCount_Proc)
111 get_proc_addr (gdiplus_lib, "GdipImageGetFrameDimensionsCount");
112 if (!fn_GdipImageGetFrameDimensionsCount)
113 return false;
114 fn_GdipImageGetFrameDimensionsList = (GdipImageGetFrameDimensionsList_Proc)
115 get_proc_addr (gdiplus_lib, "GdipImageGetFrameDimensionsList");
116 if (!fn_GdipImageGetFrameDimensionsList)
117 return false;
118 fn_GdipImageGetFrameCount = (GdipImageGetFrameCount_Proc)
119 get_proc_addr (gdiplus_lib, "GdipImageGetFrameCount");
120 if (!fn_GdipImageGetFrameCount)
121 return false;
122 fn_GdipImageSelectActiveFrame = (GdipImageSelectActiveFrame_Proc)
123 get_proc_addr (gdiplus_lib, "GdipImageSelectActiveFrame");
124 if (!fn_GdipImageSelectActiveFrame)
125 return false;
126 fn_GdipCreateBitmapFromFile = (GdipCreateBitmapFromFile_Proc)
127 get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromFile");
128 if (!fn_GdipCreateBitmapFromFile)
129 return false;
130 fn_GdipCreateBitmapFromStream = (GdipCreateBitmapFromStream_Proc)
131 get_proc_addr (gdiplus_lib, "GdipCreateBitmapFromStream");
132 if (!fn_GdipCreateBitmapFromStream)
133 return false;
134 fn_GdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmap_Proc)
135 get_proc_addr (gdiplus_lib, "GdipCreateHBITMAPFromBitmap");
136 if (!fn_GdipCreateHBITMAPFromBitmap)
137 return false;
138 fn_GdipDisposeImage = (GdipDisposeImage_Proc)
139 get_proc_addr (gdiplus_lib, "GdipDisposeImage");
140 if (!fn_GdipDisposeImage)
141 return false;
142 fn_GdipGetImageHeight = (GdipGetImageHeight_Proc)
143 get_proc_addr (gdiplus_lib, "GdipGetImageHeight");
144 if (!fn_GdipGetImageHeight)
145 return false;
146 fn_GdipGetImageWidth = (GdipGetImageWidth_Proc)
147 get_proc_addr (gdiplus_lib, "GdipGetImageWidth");
148 if (!fn_GdipGetImageWidth)
149 return false;
150
151
152
153
154
155 fn_SHCreateMemStream = (SHCreateMemStream_Proc)
156 get_proc_addr (shlwapi_lib, "SHCreateMemStream");
157 if (!fn_SHCreateMemStream)
158 {
159 fn_SHCreateMemStream = (SHCreateMemStream_Proc)
160 get_proc_addr (shlwapi_lib, MAKEINTRESOURCEA (12));
161 if (!fn_SHCreateMemStream)
162 return false;
163 }
164
165 return true;
166 }
167
168 # undef GdiplusStartup
169 # undef GdiplusShutdown
170 # undef GdipGetPropertyItemSize
171 # undef GdipGetPropertyItem
172 # undef GdipImageGetFrameDimensionsCount
173 # undef GdipImageGetFrameDimensionsList
174 # undef GdipImageGetFrameCount
175 # undef GdipImageSelectActiveFrame
176 # undef GdipCreateBitmapFromFile
177 # undef GdipCreateBitmapFromStream
178 # undef SHCreateMemStream
179 # undef GdipCreateHBITMAPFromBitmap
180 # undef GdipDisposeImage
181 # undef GdipGetImageHeight
182 # undef GdipGetImageWidth
183
184 # define GdiplusStartup fn_GdiplusStartup
185 # define GdiplusShutdown fn_GdiplusShutdown
186 # define GdipGetPropertyItemSize fn_GdipGetPropertyItemSize
187 # define GdipGetPropertyItem fn_GdipGetPropertyItem
188 # define GdipImageGetFrameDimensionsCount fn_GdipImageGetFrameDimensionsCount
189 # define GdipImageGetFrameDimensionsList fn_GdipImageGetFrameDimensionsList
190 # define GdipImageGetFrameCount fn_GdipImageGetFrameCount
191 # define GdipImageSelectActiveFrame fn_GdipImageSelectActiveFrame
192 # define GdipCreateBitmapFromFile fn_GdipCreateBitmapFromFile
193 # define GdipCreateBitmapFromStream fn_GdipCreateBitmapFromStream
194 # define SHCreateMemStream fn_SHCreateMemStream
195 # define GdipCreateHBITMAPFromBitmap fn_GdipCreateHBITMAPFromBitmap
196 # define GdipDisposeImage fn_GdipDisposeImage
197 # define GdipGetImageHeight fn_GdipGetImageHeight
198 # define GdipGetImageWidth fn_GdipGetImageWidth
199
200 #endif
201
202 static int gdip_initialized;
203 static bool gdiplus_started;
204 static ULONG_PTR token;
205 static GdiplusStartupInput input;
206 static GdiplusStartupOutput output;
207
208
209
210 static bool
211 gdiplus_startup (void)
212 {
213 GpStatus status;
214
215 if (gdiplus_started)
216 return true;
217 #ifdef WINDOWSNT
218 if (!gdip_initialized)
219 gdip_initialized = gdiplus_init () ? 1 : -1;
220 #else
221 gdip_initialized = 1;
222 #endif
223 if (gdip_initialized > 0)
224 {
225 input.GdiplusVersion = 1;
226 input.DebugEventCallback = NULL;
227 input.SuppressBackgroundThread = FALSE;
228 input.SuppressExternalCodecs = FALSE;
229
230 status = GdiplusStartup (&token, &input, &output);
231 if (status == Ok)
232 gdiplus_started = true;
233 return (status == Ok);
234 }
235 return false;
236 }
237
238
239 void
240 w32_gdiplus_shutdown (void)
241 {
242 if (gdiplus_started)
243 GdiplusShutdown (token);
244 gdiplus_started = false;
245 }
246
247 bool
248 w32_can_use_native_image_api (Lisp_Object type)
249 {
250 if (!w32_use_native_image_api)
251 return false;
252 if (!(EQ (type, Qjpeg)
253 || EQ (type, Qpng)
254 || EQ (type, Qgif)
255 || EQ (type, Qtiff)
256 || EQ (type, Qbmp)
257 || EQ (type, Qnative_image)))
258 {
259
260
261 return false;
262 }
263 return gdiplus_startup ();
264 }
265
266 enum PropertyItem_type {
267 PI_BYTE = 1,
268 PI_ASCIIZ = 2,
269 PI_USHORT = 3,
270 PI_ULONG = 4,
271 PI_ULONG_PAIR = 5,
272 PI_BYTE_ANY = 6,
273 PI_LONG = 7,
274 PI_LONG_PAIR = 10
275 };
276
277 static double
278 decode_delay (PropertyItem *propertyItem, int frame)
279 {
280 enum PropertyItem_type type = propertyItem[0].type;
281 unsigned long udelay;
282 double retval;
283
284 switch (type)
285 {
286 case PI_BYTE:
287 case PI_BYTE_ANY:
288 udelay = ((unsigned char *)propertyItem[0].value)[frame];
289 retval = udelay;
290 break;
291 case PI_USHORT:
292 udelay = ((unsigned short *)propertyItem[0].value)[frame];
293 retval = udelay;
294 break;
295 case PI_ULONG:
296 case PI_LONG:
297 udelay = ((unsigned long *)propertyItem[0].value)[frame];
298 retval = udelay;
299 break;
300 default:
301
302
303 add_to_log ("Invalid or unknown propertyItem type in w32image.c");
304 retval = -1.0;
305 }
306
307 return retval;
308 }
309
310 static double
311 w32_frame_delay (GpBitmap *pBitmap, int frame)
312 {
313 UINT size;
314 PropertyItem *propertyItem;
315 double delay = -1.0;
316
317
318
319
320 GpStatus status = GdipGetPropertyItemSize (pBitmap, PropertyTagFrameDelay,
321 &size);
322
323 if (status == Ok)
324 {
325
326 propertyItem = malloc (size);
327 if (propertyItem != NULL)
328 {
329
330 GdipGetPropertyItem (pBitmap, PropertyTagFrameDelay, size,
331 propertyItem);
332 delay = decode_delay (propertyItem, frame);
333 if (delay <= 0)
334 {
335
336
337 delay = decode_delay (propertyItem, 0);
338 }
339 delay /= 100.0;
340 free (propertyItem);
341 }
342 }
343 return delay;
344 }
345
346 static GpStatus
347 w32_select_active_frame (GpBitmap *pBitmap, int frame, int *nframes,
348 double *delay)
349 {
350 UINT count, frameCount;
351 GUID pDimensionIDs[1];
352 GpStatus status = Ok;
353
354 status = GdipImageGetFrameDimensionsCount (pBitmap, &count);
355 frameCount = *nframes = 0;
356 *delay = -1.0;
357 if (count)
358 {
359
360
361
362
363
364 status = GdipImageGetFrameDimensionsList (pBitmap, pDimensionIDs, 1);
365 status = GdipImageGetFrameCount (pBitmap, &pDimensionIDs[0], &frameCount);
366 if (status == Ok && frameCount > 1)
367 {
368 if (frame < 0 || frame >= frameCount)
369 status = GenericError;
370 else
371 {
372 status = GdipImageSelectActiveFrame (pBitmap, &pDimensionIDs[0],
373 frame);
374 *delay = w32_frame_delay (pBitmap, frame);
375 *nframes = frameCount;
376 }
377 }
378 }
379 return status;
380 }
381
382 static ARGB
383 w32_image_bg_color (struct frame *f, struct image *img)
384 {
385 Lisp_Object specified_bg = plist_get (XCDR (img->spec), QCbackground);
386 Emacs_Color color;
387
388
389
390
391 if (STRINGP (specified_bg)
392 ? w32_defined_color (f, SSDATA (specified_bg), &color, false, false)
393 : (w32_query_frame_background_color (f, &color), true))
394
395 {
396 DWORD red = (((DWORD) color.red) & 0xff00) << 8;
397 DWORD green = ((DWORD) color.green) & 0xff00;
398 DWORD blue = ((DWORD) color.blue) >> 8;
399 return (ARGB) (red | green | blue);
400 }
401 return (ARGB) 0xff000000;
402 }
403
404 int
405 w32_load_image (struct frame *f, struct image *img,
406 Lisp_Object spec_file, Lisp_Object spec_data)
407 {
408 GpStatus status = GenericError;
409 GpBitmap *pBitmap;
410 Lisp_Object metadata;
411
412 eassert (valid_image_p (img->spec));
413
414
415
416 if (STRINGP (spec_file))
417 {
418 const char *fn = map_w32_filename (SSDATA (spec_file), NULL);
419 wchar_t filename_w[MAX_PATH];
420 filename_to_utf16 (fn, filename_w);
421 status = GdipCreateBitmapFromFile (filename_w, &pBitmap);
422 }
423 else if (STRINGP (spec_data))
424 {
425 IStream *pStream = SHCreateMemStream ((BYTE *) SDATA (spec_data),
426 SBYTES (spec_data));
427 if (pStream != NULL)
428 {
429 status = GdipCreateBitmapFromStream (pStream, &pBitmap);
430 IStream_Release (pStream);
431 }
432 }
433
434 metadata = Qnil;
435 if (status == Ok)
436 {
437
438 Lisp_Object lisp_index = plist_get (XCDR (img->spec), QCindex);
439 int index = FIXNATP (lisp_index) ? XFIXNAT (lisp_index) : 0;
440 int nframes;
441 double delay;
442 status = w32_select_active_frame (pBitmap, index, &nframes, &delay);
443 if (status == Ok)
444 {
445 if (nframes > 1)
446 metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata));
447 if (delay >= 0)
448 metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata));
449 }
450 }
451
452 if (status == Ok)
453 {
454 ARGB bg_color = w32_image_bg_color (f, img);
455 Emacs_Pixmap pixmap;
456
457 status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color);
458 if (status == Ok)
459 {
460 UINT width, height;
461 GdipGetImageWidth (pBitmap, &width);
462 GdipGetImageHeight (pBitmap, &height);
463 img->width = width;
464 img->height = height;
465 img->pixmap = pixmap;
466 img->lisp_data = metadata;
467 }
468
469 GdipDisposeImage (pBitmap);
470 }
471
472 if (status != Ok)
473 {
474 add_to_log ("Unable to load image %s", img->spec);
475 return 0;
476 }
477 return 1;
478 }