1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
4 * Copyright (C) 2008 Dominic Lachowicz
5 * Copyright (C) 2008 Alberto Ruiz
7 * Authors: Dominic Lachowicz <domlachowicz@gmail.com>
8 * Alberto Ruiz <aruiz@gnome.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
27 #include "io-gdip-utils.h"
28 #include "io-gdip-native.h"
29 #include "io-gdip-propertytags.h"
30 #include "io-gdip-animation.h"
32 #define LOAD_BUFFER_SIZE 65536
34 static GdiplusStartupFunc GdiplusStartup;
35 static GdipCreateBitmapFromStreamFunc GdipCreateBitmapFromStream;
36 static GdipBitmapGetPixelFunc GdipBitmapGetPixel;
37 static GdipGetImageHeightFunc GdipGetImageHeight;
38 static GdipDisposeImageFunc GdipDisposeImage;
39 static GdipGetImageFlagsFunc GdipGetImageFlags;
40 static GdipGetImageWidthFunc GdipGetImageWidth;
41 static GdipImageGetFrameCountFunc GdipImageGetFrameCount;
42 static GdipImageSelectActiveFrameFunc GdipImageSelectActiveFrame;
43 static GdipGetPropertyItemSizeFunc GdipGetPropertyItemSize;
44 static GdipGetPropertyItemFunc GdipGetPropertyItem;
45 static GdipGetPropertyCountFunc GdipGetPropertyCount;
46 static GdipGetPropertyIdListFunc GdipGetPropertyIdList;
47 static GdipCreateBitmapFromScan0Func GdipCreateBitmapFromScan0;
48 static GdipSaveImageToStreamFunc GdipSaveImageToStream;
49 static GdipBitmapSetPixelFunc GdipBitmapSetPixel;
50 static GdipDrawImageIFunc GdipDrawImageI;
51 static GdipGetImageGraphicsContextFunc GdipGetImageGraphicsContext;
52 static GdipFlushFunc GdipFlush;
53 static GdipGraphicsClearFunc GdipGraphicsClear;
54 static GdipBitmapSetResolutionFunc GdipBitmapSetResolution;
55 static GdipGetImageHorizontalResolutionFunc GdipGetImageHorizontalResolution;
56 static GdipGetImageVerticalResolutionFunc GdipGetImageVerticalResolution;
57 static GdipLoadImageFromStreamFunc GdipLoadImageFromStream;
58 static GdipDeleteGraphicsFunc GdipDeleteGraphics;
59 static GdipGetImageEncodersFunc GdipGetImageEncoders;
60 static GdipGetImageEncodersSizeFunc GdipGetImageEncodersSize;
61 static GdipBitmapLockBitsFunc GdipBitmapLockBits;
62 static GdipBitmapUnlockBitsFunc GdipBitmapUnlockBits;
63 static GdipGetImagePixelFormatFunc GdipGetImagePixelFormat;
64 static GdipCloneBitmapAreaIFunc GdipCloneBitmapAreaI;
66 DEFINE_GUID(FrameDimensionTime, 0x6aedbd6d,0x3fb5,0x418a,0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72);
67 DEFINE_GUID(FrameDimensionPage, 0x7462dc86,0x6180,0x4c7e,0x8e,0x3f,0xee,0x73,0x33,0xa7,0xa4,0x83);
70 gdip_set_error_from_hresult (GError **error, gint code, HRESULT hr, const char *format)
74 msg = g_win32_error_message (hr);
77 g_set_error (error, GDK_PIXBUF_ERROR, code, format, msg);
83 gdip_set_error_from_gpstatus (GError **error, gint code, GpStatus status)
89 #define CASE(x) case x: msg = #x; break
91 CASE (InvalidParameter);
94 CASE (InsufficientBuffer);
95 CASE (NotImplemented);
100 CASE (ValueOverflow);
102 CASE (UnknownImageFormat);
103 CASE (FontFamilyNotFound);
104 CASE (FontStyleNotFound);
105 CASE (NotTrueTypeFont);
106 CASE (UnsupportedGdiplusVersion);
107 CASE (GdiplusNotInitialized);
108 CASE (PropertyNotFound);
109 CASE (PropertyNotSupported);
110 CASE (ProfileNotFound);
112 msg = "Unknown error";
114 g_set_error_literal (error, GDK_PIXBUF_ERROR, code, msg);
120 GdiplusStartupInput input;
121 ULONG_PTR gdiplusToken = 0;
122 static HINSTANCE gdipluslib = NULL;
125 gdipluslib = LoadLibrary ("gdiplus.dll");
127 return TRUE; /* gdip_init() is idempotent */
132 #define LOOKUP(func) \
134 func = (func##Func) GetProcAddress (gdipluslib, #func); \
136 g_warning ("Couldn't find GDI+ function %s\n", #func); \
141 LOOKUP (GdiplusStartup);
142 LOOKUP (GdipCreateBitmapFromStream);
143 LOOKUP (GdipBitmapGetPixel);
144 LOOKUP (GdipGetImageHeight);
145 LOOKUP (GdipDisposeImage);
146 LOOKUP (GdipGetImageFlags);
147 LOOKUP (GdipGetImageWidth);
148 LOOKUP (GdipImageGetFrameCount);
149 LOOKUP (GdipImageSelectActiveFrame);
150 LOOKUP (GdipGetPropertyItemSize);
151 LOOKUP (GdipGetPropertyItem);
152 LOOKUP (GdipGetPropertyCount);
153 LOOKUP (GdipGetPropertyIdList);
154 LOOKUP (GdipCreateBitmapFromScan0);
155 LOOKUP (GdipSaveImageToStream);
156 LOOKUP (GdipBitmapSetPixel);
157 LOOKUP (GdipDrawImageI);
158 LOOKUP (GdipGetImageGraphicsContext);
160 LOOKUP (GdipGraphicsClear);
161 LOOKUP (GdipBitmapSetResolution);
162 LOOKUP (GdipGetImageHorizontalResolution);
163 LOOKUP (GdipGetImageVerticalResolution);
164 LOOKUP (GdipLoadImageFromStream);
165 LOOKUP (GdipDeleteGraphics);
166 LOOKUP (GdipGetImageEncoders);
167 LOOKUP (GdipGetImageEncodersSize);
168 LOOKUP (GdipBitmapLockBits);
169 LOOKUP (GdipBitmapUnlockBits);
170 LOOKUP (GdipGetImagePixelFormat);
171 LOOKUP (GdipCloneBitmapAreaI);
175 input.GdiplusVersion = 1;
176 input.DebugEventCallback = NULL;
177 input.SuppressBackgroundThread = input.SuppressExternalCodecs = FALSE;
179 return (GdiplusStartup (&gdiplusToken, &input, NULL) == 0 ? TRUE : FALSE);
183 GetEncoderClsid (const WCHAR *format, CLSID *pClsid)
187 ImageCodecInfo *pImageCodecInfo;
189 if (Ok != GdipGetImageEncodersSize (&num, &size))
192 pImageCodecInfo = (ImageCodecInfo *) g_malloc (size);
194 if (Ok != GdipGetImageEncoders (num, size, pImageCodecInfo)) {
195 g_free (pImageCodecInfo);
199 for (j = 0; j < num; j++) {
200 if (wcscmp (pImageCodecInfo[j].MimeType, format) == 0) {
201 *pClsid = pImageCodecInfo[j].Clsid;
202 g_free (pImageCodecInfo);
207 g_free (pImageCodecInfo);
213 gdip_buffer_to_hglobal (const gchar *buffer, size_t size, GError **error)
217 hg = GlobalAlloc (GPTR, size);
220 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, GetLastError (), _("Could not allocate memory: %s"));
224 CopyMemory (hg, buffer, size);
230 gdip_save_bitmap_to_callback (GpBitmap *bitmap,
232 const EncoderParameters *encoder_params,
233 GdkPixbufSaveFunc save_func,
238 IStream *streamOut = NULL;
239 gboolean success = FALSE;
243 hr = CreateStreamOnHGlobal (NULL, TRUE, &streamOut);
244 if (!SUCCEEDED (hr)) {
245 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
249 status = GdipSaveImageToStream ((GpImage *)bitmap, streamOut, format, encoder_params);
251 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
252 IStream_Release (streamOut);
256 /* seek back to the beginning of the stream */
257 hr = IStream_Seek (streamOut, *(LARGE_INTEGER *)&zero, STREAM_SEEK_SET, NULL);
258 if (!SUCCEEDED (hr)) {
259 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not seek stream: %s"));
260 IStream_Release (streamOut);
265 char buffer[LOAD_BUFFER_SIZE];
268 hr = IStream_Read (streamOut, buffer, sizeof(buffer), &nread);
271 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not read from stream: %s"));
274 else if (0 == nread) {
275 success = TRUE; /* EOF */
278 else if (!(*save_func) (buffer, nread, error, user_data))
282 IStream_Release (streamOut);
288 gdip_pixbuf_to_bitmap (GdkPixbuf *pixbuf)
290 GpBitmap *bitmap = NULL;
292 int width, height, stride, n_channels;
295 width = gdk_pixbuf_get_width (pixbuf);
296 height = gdk_pixbuf_get_height (pixbuf);
297 stride = gdk_pixbuf_get_rowstride (pixbuf);
298 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
299 pixels = gdk_pixbuf_get_pixels (pixbuf);
301 if (n_channels == 3 || n_channels == 4) {
302 /* rgbX. need to convert to argb. pass a null data to get an empty bitmap */
303 GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
308 for (y = 0; y < height; y++) {
309 for (x = 0; x < width; x++) {
312 guchar *base = pixels + (y * stride + (x * n_channels));
322 guint8 red = base[0];
323 guint8 green = base[1];
324 guint8 blue = base[2];
326 p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
329 GdipBitmapSetPixel (bitmap, x, y, p);
335 g_warning ("Unsupported number of channels: %d\n", n_channels);
342 gdip_buffer_to_bitmap (const gchar *buffer, size_t size, GError **error)
346 GpBitmap *bitmap = NULL;
347 IStream *stream = NULL;
349 guint64 size64 = size;
351 hg = gdip_buffer_to_hglobal (buffer, size, error);
356 hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
358 if (!SUCCEEDED (hr)) {
359 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
364 IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
366 status = GdipCreateBitmapFromStream (stream, &bitmap);
369 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
371 IStream_Release (stream);
378 gdip_buffer_to_image (const gchar *buffer, size_t size, GError **error)
382 GpImage *image = NULL;
383 IStream *stream = NULL;
385 guint64 size64 = size;
387 hg = gdip_buffer_to_hglobal (buffer, size, error);
392 hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
394 if (!SUCCEEDED (hr)) {
395 gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
400 IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
401 status = GdipLoadImageFromStream (stream, &image);
404 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
406 IStream_Release (stream);
413 gdip_bitmap_get_size (GpBitmap *bitmap, guint *width, guint *height)
415 if (bitmap == NULL || width == NULL || height == NULL)
418 *width = *height = 0;
420 GdipGetImageWidth ((GpImage *) bitmap, width);
421 GdipGetImageHeight ((GpImage *) bitmap, height);
425 gdip_bitmap_get_has_alpha (GpBitmap *bitmap, gboolean *has_alpha)
429 if (bitmap == NULL || has_alpha == NULL)
432 GdipGetImageFlags ((GpImage *) bitmap, &flags);
433 *has_alpha = (flags & ImageFlagsHasAlpha);
437 gdip_bitmap_get_n_frames (GpBitmap *bitmap, guint *n_frames, gboolean timeDimension)
439 if (bitmap == NULL || n_frames == NULL)
444 return (Ok == GdipImageGetFrameCount ((GpImage *) bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), n_frames));
448 gdip_bitmap_select_frame (GpBitmap *bitmap, guint frame, gboolean timeDimension)
453 return (Ok == GdipImageSelectActiveFrame ((GpImage *)bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), frame));
457 gdip_bitmap_get_property_as_string (GpBitmap *bitmap, guint propertyId, gchar **str)
460 gboolean success = FALSE;
462 if (bitmap == NULL || str == NULL)
467 if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, propertyId, &item_size)) {
470 item = (PropertyItem *)g_try_malloc (item_size);
471 if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, propertyId, item_size, item)) {
475 gstr = g_string_new (NULL);
478 switch (item->type) {
479 case PropertyTagTypeByte:
480 for (i = 0; i < item->length / sizeof(guint8); i++) {
481 guint8 *bytes = (guint8 *)item->value;
484 g_string_append_c(gstr, ',');
485 g_string_append_printf (gstr, "%u", (guint32)bytes[i]);
489 case PropertyTagTypeASCII:
490 g_string_append_len (gstr, (const char *)item->value, item->length);
493 case PropertyTagTypeShort:
494 for (i = 0; i < item->length / sizeof(guint16); i++) {
495 guint16 *shorts = (guint16 *)item->value;
498 g_string_append_c (gstr, ',');
499 g_string_append_printf (gstr, "%u", (guint32)shorts[i]);
503 case PropertyTagTypeLong:
504 for (i = 0; i < item->length / sizeof(guint32); i++) {
505 guint32 *longs = (guint32 *)item->value;
508 g_string_append_c (gstr, ',');
509 g_string_append_printf (gstr, "%u", longs[i]);
513 case PropertyTagTypeSLONG:
514 for (i = 0; i < item->length / sizeof(guint32); i++) {
515 gint32 *longs = (gint32 *)item->value;
518 g_string_append_c (gstr, ',');
519 g_string_append_printf (gstr, "%d", longs[i]);
529 *str = g_string_free (gstr, FALSE);
531 g_string_free (gstr, TRUE);
541 gdip_bitmap_get_frame_delay (GpBitmap *bitmap, guint *delay)
544 gboolean success = FALSE;
546 if (bitmap == NULL || delay == NULL)
551 if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagFrameDelay, &item_size)) {
554 item = (PropertyItem *)g_try_malloc (item_size);
555 if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagFrameDelay, item_size, item)) {
556 /* PropertyTagFrameDelay. Time delay, in hundredths of a second, between two frames in an animated GIF image. */
557 *delay = *((long *)item->value);
568 gdip_bitmap_get_n_loops (GpBitmap *bitmap, guint *loops)
571 gboolean success = FALSE;
573 if (bitmap == NULL || loops == NULL)
578 /* PropertyTagLoopCount. 0 == infinitely */
579 if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagLoopCount, &item_size)) {
582 item = (PropertyItem *)g_try_malloc (item_size);
583 if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagLoopCount, item_size, item)) {
584 *loops = *((short *)item->value);
594 /*************************************************************************/
595 /*************************************************************************/
597 struct _GdipContext {
598 GdkPixbufModuleUpdatedFunc updated_func;
599 GdkPixbufModulePreparedFunc prepared_func;
600 GdkPixbufModuleSizeFunc size_func;
606 typedef struct _GdipContext GdipContext;
609 destroy_gdipcontext (GdipContext *context)
611 if (context != NULL) {
612 g_byte_array_free (context->buffer, TRUE);
618 emit_updated (GdipContext *context, GdkPixbuf *pixbuf)
620 if (context->updated_func)
621 (*context->updated_func) (pixbuf,
623 gdk_pixbuf_get_width (pixbuf),
624 gdk_pixbuf_get_height (pixbuf),
629 emit_prepared (GdipContext *context, GdkPixbuf *pixbuf, GdkPixbufAnimation *anim)
631 if (context->prepared_func)
632 (*context->prepared_func) (pixbuf, anim, context->user_data);
636 gdk_pixbuf__gdip_image_begin_load (GdkPixbufModuleSizeFunc size_func,
637 GdkPixbufModulePreparedFunc prepared_func,
638 GdkPixbufModuleUpdatedFunc updated_func,
642 GdipContext *context = g_new0 (GdipContext, 1);
644 context->size_func = size_func;
645 context->prepared_func = prepared_func;
646 context->updated_func = updated_func;
647 context->user_data = user_data;
648 context->buffer = g_byte_array_new ();
654 gdk_pixbuf__gdip_image_load_increment (gpointer data,
655 const guchar *buf, guint size,
658 GdipContext *context = (GdipContext *)data;
659 GByteArray *image_buffer = context->buffer;
661 g_byte_array_append (image_buffer, (guint8 *)buf, size);
667 gdip_bitmap_to_pixbuf (GpBitmap *bitmap, GError **error)
669 GdkPixbuf *pixbuf = NULL;
670 guchar *cursor = NULL;
672 gboolean has_alpha = FALSE;
676 guint width = 0, height = 0, x, y;
678 gdip_bitmap_get_size (bitmap, &width, &height);
679 gdip_bitmap_get_has_alpha (bitmap, &has_alpha);
681 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
684 g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't load bitmap"));
688 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
689 cursor = gdk_pixbuf_get_pixels (pixbuf);
690 n_channels = gdk_pixbuf_get_n_channels (pixbuf);
692 for (y = 0; y < height; y++) {
693 for (x = 0; x < width; x++) {
696 guchar *b = cursor + (y * rowstride + (x * n_channels));
698 if (Ok != (status = GdipBitmapGetPixel (bitmap, x, y, &pixel))) {
699 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
700 g_object_unref (pixbuf);
704 b[0] = (pixel & 0xff0000) >> 16;
705 b[1] = (pixel & 0x00ff00) >> 8;
706 b[2] = (pixel & 0x0000ff) >> 0;
709 b[3] = (pixel & 0xff000000) >> 24;
713 if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagOrientation, &option)) {
714 gdk_pixbuf_set_option (pixbuf, "orientation", option);
718 if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagArtist, &option)) {
719 gdk_pixbuf_set_option (pixbuf, "Author", option);
723 if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagImageTitle, &option)) {
724 gdk_pixbuf_set_option (pixbuf, "Title", option);
732 stop_load (GpBitmap *bitmap, GdipContext *context, GError **error)
734 guint n_frames = 1, i;
735 GdkPixbufGdipAnim *animation = NULL;
737 gdip_bitmap_get_n_frames (bitmap, &n_frames, TRUE);
739 for (i = 0; i < n_frames; i++) {
740 GdkPixbuf *pixbuf = NULL;
741 GdkPixbufFrame *frame;
742 guint frame_delay = 0;
744 gdip_bitmap_select_frame (bitmap, i, TRUE);
746 pixbuf = gdip_bitmap_to_pixbuf (bitmap, error);
749 if (animation != NULL)
750 g_object_unref (G_OBJECT (animation));
752 GdipDisposeImage ((GpImage *)bitmap);
753 destroy_gdipcontext (context);
757 if (animation == NULL) {
760 animation = g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM, NULL);
761 gdip_bitmap_get_n_loops (bitmap, &n_loops);
762 animation->loop = n_loops;
765 frame = g_new (GdkPixbufFrame, 1);
766 frame->pixbuf = pixbuf;
768 gdip_bitmap_get_frame_delay (bitmap, &frame_delay);
770 animation->n_frames++;
771 animation->frames = g_list_append (animation->frames, frame);
773 animation->width = gdk_pixbuf_get_width (pixbuf);
774 animation->height = gdk_pixbuf_get_height (pixbuf);
776 /* GIF delay is in hundredths, we want thousandths */
777 frame->delay_time = frame_delay * 10;
778 frame->elapsed = animation->total_time;
780 /* Some GIFs apparently have delay time of 0,
781 * that crashes everything so set it to "fast".
782 * Also, timeouts less than 20 or so just lock up
783 * the app or make the animation choppy, so fix them.
785 if (frame->delay_time < 20)
786 frame->delay_time = 20; /* 20 = "fast" */
788 animation->total_time += frame->delay_time;
791 emit_prepared (context, pixbuf, GDK_PIXBUF_ANIMATION (animation));
793 emit_updated (context, pixbuf);
796 if (animation != NULL)
797 g_object_unref (G_OBJECT (animation));
799 GdipDisposeImage ((GpImage *)bitmap);
800 destroy_gdipcontext (context);
806 gdk_pixbuf__gdip_image_stop_load (gpointer data, GError **error)
808 GdipContext *context = (GdipContext *)data;
809 GpBitmap *bitmap = NULL;
810 GByteArray *image_buffer = context->buffer;
812 bitmap = gdip_buffer_to_bitmap ((gchar *)image_buffer->data, image_buffer->len, error);
815 destroy_gdipcontext (context);
816 g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Couldn't load bitmap"));
820 return stop_load (bitmap, context, error);
824 gdk_pixbuf__gdip_image_stop_vector_load (gpointer data, GError **error)
826 GdipContext *context = (GdipContext *)data;
827 GByteArray *image_buffer = context->buffer;
830 GpGraphics *graphics;
833 float metafile_xres, metafile_yres;
836 metafile = gdip_buffer_to_image ((gchar *)image_buffer->data, image_buffer->len, error);
838 destroy_gdipcontext (context);
839 g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Couldn't load metafile"));
843 GdipGetImageWidth (metafile, &width);
844 GdipGetImageHeight (metafile, &height);
846 status = GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
848 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
849 GdipDisposeImage (metafile);
854 GdipGetImageHorizontalResolution (metafile, &metafile_xres);
855 GdipGetImageVerticalResolution (metafile, &metafile_yres);
856 GdipBitmapSetResolution (bitmap, metafile_xres, metafile_yres);
858 status = GdipGetImageGraphicsContext ((GpImage *)bitmap, &graphics);
860 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
861 GdipDisposeImage ((GpImage *)bitmap);
862 GdipDisposeImage (metafile);
867 /* gotta clear the bitmap */
868 GdipGraphicsClear (graphics, 0xffffffff);
870 status = GdipDrawImageI (graphics, metafile, 0, 0);
872 gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
873 GdipDeleteGraphics (graphics);
874 GdipDisposeImage ((GpImage *)bitmap);
875 GdipDisposeImage (metafile);
880 GdipFlush (graphics, 1);
882 GdipDeleteGraphics (graphics);
883 GdipDisposeImage (metafile);
885 return stop_load (bitmap, context, error);
889 gdip_animation_prepare (GdkPixbuf *pixbuf,
890 GdkPixbufAnimation *animation,
893 GdkPixbufAnimation **anim;
895 anim = (GdkPixbufAnimation **)user_data;
897 /* save a reference to the animation */
898 g_object_ref (animation);
902 static GdkPixbufAnimation *
903 gdk_pixbuf__gdip_image_load_animation (FILE *file,
906 GdkPixbufAnimation *animation = NULL;
909 char buffer[LOAD_BUFFER_SIZE];
912 context = gdk_pixbuf__gdip_image_begin_load (NULL, gdip_animation_prepare, NULL, &animation, error);
914 while (!feof (file) && !ferror (file)) {
915 length = fread (buffer, 1, sizeof (buffer), file);
917 if (!gdk_pixbuf__gdip_image_load_increment (context, buffer, length, error)) {
918 gdk_pixbuf__gdip_image_stop_load (context, NULL);
921 g_object_unref (animation);
928 if (!gdk_pixbuf__gdip_image_stop_load(context, error)) {
930 g_object_unref (animation);
939 gdip_save_to_file_callback (const gchar *buf,
944 FILE *filehandle = data;
947 n = fwrite (buf, 1, count, filehandle);
949 gint save_errno = errno;
952 g_file_error_from_errno (save_errno),
953 _("Error writing to image file: %s"),
954 g_strerror (save_errno));
962 gdip_fill_vtable (GdkPixbufModule *module)
965 module->begin_load = gdk_pixbuf__gdip_image_begin_load;
966 module->stop_load = gdk_pixbuf__gdip_image_stop_load;
967 module->load_increment = gdk_pixbuf__gdip_image_load_increment;
969 /* this is the only way to get gtk_image_new_from_file() to load animations. it regrettably
970 does not use the GdkPixbufLoader interface. */
971 module->load_animation = gdk_pixbuf__gdip_image_load_animation;
976 gdip_fill_vector_vtable (GdkPixbufModule *module)
979 module->begin_load = gdk_pixbuf__gdip_image_begin_load;
980 module->stop_load = gdk_pixbuf__gdip_image_stop_vector_load;
981 module->load_increment = gdk_pixbuf__gdip_image_load_increment;
986 gdip_save_pixbuf (GdkPixbuf *pixbuf,
988 const EncoderParameters *encoder_params,
989 GdkPixbufSaveFunc save_func,
997 if (!GetEncoderClsid (format, &clsid)) {
998 g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Unsupported image format for GDI+"));
1002 image = gdip_pixbuf_to_bitmap (pixbuf);
1004 if (image == NULL) {
1005 g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Couldn't save"));
1009 success = gdip_save_bitmap_to_callback (image, &clsid, encoder_params, save_func, user_data, error);
1011 GdipDisposeImage ((GpImage *)image);