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
;
62 DEFINE_GUID(FrameDimensionTime
, 0x6aedbd6d,0x3fb5,0x418a,0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72);
63 DEFINE_GUID(FrameDimensionPage
, 0x7462dc86,0x6180,0x4c7e,0x8e,0x3f,0xee,0x73,0x33,0xa7,0xa4,0x83);
66 gdip_set_error_from_hresult (GError
**error
, gint code
, HRESULT hr
, const char *format
)
70 msg
= g_win32_error_message (hr
);
73 g_set_error (error
, GDK_PIXBUF_ERROR
, code
, format
, msg
);
79 gdip_set_error_from_gpstatus (GError
**error
, gint code
, GpStatus status
)
85 #define CASE(x) case x: msg = #x; break
87 CASE (InvalidParameter
);
90 CASE (InsufficientBuffer
);
91 CASE (NotImplemented
);
98 CASE (UnknownImageFormat
);
99 CASE (FontFamilyNotFound
);
100 CASE (FontStyleNotFound
);
101 CASE (NotTrueTypeFont
);
102 CASE (UnsupportedGdiplusVersion
);
103 CASE (GdiplusNotInitialized
);
104 CASE (PropertyNotFound
);
105 CASE (PropertyNotSupported
);
106 CASE (ProfileNotFound
);
108 msg
= "Unknown error";
110 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, code
, msg
);
116 GdiplusStartupInput input
;
117 ULONG_PTR gdiplusToken
= 0;
118 static HINSTANCE gdipluslib
= NULL
;
121 gdipluslib
= LoadLibrary ("gdiplus.dll");
123 return TRUE
; /* gdip_init() is idempotent */
128 #define LOOKUP(func) \
130 func = (func##Func) GetProcAddress (gdipluslib, #func); \
132 g_warning ("Couldn't find GDI+ function %s\n", #func); \
137 LOOKUP (GdiplusStartup
);
138 LOOKUP (GdipCreateBitmapFromStream
);
139 LOOKUP (GdipBitmapGetPixel
);
140 LOOKUP (GdipGetImageHeight
);
141 LOOKUP (GdipDisposeImage
);
142 LOOKUP (GdipGetImageFlags
);
143 LOOKUP (GdipGetImageWidth
);
144 LOOKUP (GdipImageGetFrameCount
);
145 LOOKUP (GdipImageSelectActiveFrame
);
146 LOOKUP (GdipGetPropertyItemSize
);
147 LOOKUP (GdipGetPropertyItem
);
148 LOOKUP (GdipGetPropertyCount
);
149 LOOKUP (GdipGetPropertyIdList
);
150 LOOKUP (GdipCreateBitmapFromScan0
);
151 LOOKUP (GdipSaveImageToStream
);
152 LOOKUP (GdipBitmapSetPixel
);
153 LOOKUP (GdipDrawImageI
);
154 LOOKUP (GdipGetImageGraphicsContext
);
156 LOOKUP (GdipGraphicsClear
);
157 LOOKUP (GdipBitmapSetResolution
);
158 LOOKUP (GdipGetImageHorizontalResolution
);
159 LOOKUP (GdipGetImageVerticalResolution
);
160 LOOKUP (GdipLoadImageFromStream
);
161 LOOKUP (GdipDeleteGraphics
);
162 LOOKUP (GdipGetImageEncoders
);
163 LOOKUP (GdipGetImageEncodersSize
);
167 input
.GdiplusVersion
= 1;
168 input
.DebugEventCallback
= NULL
;
169 input
.SuppressBackgroundThread
= input
.SuppressExternalCodecs
= FALSE
;
171 return (GdiplusStartup (&gdiplusToken
, &input
, NULL
) == 0 ? TRUE
: FALSE
);
175 GetEncoderClsid (const WCHAR
*format
, CLSID
*pClsid
)
179 ImageCodecInfo
*pImageCodecInfo
;
181 if (Ok
!= GdipGetImageEncodersSize (&num
, &size
))
184 pImageCodecInfo
= (ImageCodecInfo
*) g_malloc (size
);
186 if (Ok
!= GdipGetImageEncoders (num
, size
, pImageCodecInfo
)) {
187 g_free (pImageCodecInfo
);
191 for (j
= 0; j
< num
; j
++) {
192 if (wcscmp (pImageCodecInfo
[j
].MimeType
, format
) == 0) {
193 *pClsid
= pImageCodecInfo
[j
].Clsid
;
194 g_free (pImageCodecInfo
);
199 g_free (pImageCodecInfo
);
205 gdip_buffer_to_hglobal (const gchar
*buffer
, size_t size
, GError
**error
)
209 hg
= GlobalAlloc (GPTR
, size
);
212 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, GetLastError (), _("Could not allocate memory: %s"));
216 CopyMemory (hg
, buffer
, size
);
222 gdip_save_bitmap_to_callback (GpBitmap
*bitmap
,
224 const EncoderParameters
*encoder_params
,
225 GdkPixbufSaveFunc save_func
,
230 IStream
*streamOut
= NULL
;
231 gboolean success
= FALSE
;
235 hr
= CreateStreamOnHGlobal (NULL
, TRUE
, &streamOut
);
236 if (!SUCCEEDED (hr
)) {
237 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, hr
, _("Could not create stream: %s"));
241 status
= GdipSaveImageToStream ((GpImage
*)bitmap
, streamOut
, format
, encoder_params
);
243 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
244 IStream_Release (streamOut
);
248 /* seek back to the beginning of the stream */
249 hr
= IStream_Seek (streamOut
, *(LARGE_INTEGER
*)&zero
, STREAM_SEEK_SET
, NULL
);
250 if (!SUCCEEDED (hr
)) {
251 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, hr
, _("Could not seek stream: %s"));
252 IStream_Release (streamOut
);
257 char buffer
[LOAD_BUFFER_SIZE
];
260 hr
= IStream_Read (streamOut
, buffer
, sizeof(buffer
), &nread
);
263 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, hr
, _("Could not read from stream: %s"));
266 else if (0 == nread
) {
267 success
= TRUE
; /* EOF */
270 else if (!(*save_func
) (buffer
, nread
, error
, user_data
))
274 IStream_Release (streamOut
);
280 gdip_pixbuf_to_bitmap (GdkPixbuf
*pixbuf
)
282 GpBitmap
*bitmap
= NULL
;
284 int width
, height
, stride
, n_channels
;
287 width
= gdk_pixbuf_get_width (pixbuf
);
288 height
= gdk_pixbuf_get_height (pixbuf
);
289 stride
= gdk_pixbuf_get_rowstride (pixbuf
);
290 n_channels
= gdk_pixbuf_get_n_channels (pixbuf
);
291 pixels
= gdk_pixbuf_get_pixels (pixbuf
);
293 if (n_channels
== 3 || n_channels
== 4) {
294 /* rgbX. need to convert to argb. pass a null data to get an empty bitmap */
295 GdipCreateBitmapFromScan0 (width
, height
, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
300 for (y
= 0; y
< height
; y
++) {
301 for (x
= 0; x
< width
; x
++) {
304 guchar
*base
= pixels
+ (y
* stride
+ (x
* n_channels
));
314 guint8 red
= base
[0];
315 guint8 green
= base
[1];
316 guint8 blue
= base
[2];
318 p
= (alpha
<< 24) | (red
<< 16) | (green
<< 8) | (blue
<< 0);
321 GdipBitmapSetPixel (bitmap
, x
, y
, p
);
327 g_warning ("Unsupported number of channels: %d\n", n_channels
);
334 gdip_buffer_to_bitmap (const gchar
*buffer
, size_t size
, GError
**error
)
338 GpBitmap
*bitmap
= NULL
;
339 IStream
*stream
= NULL
;
342 hg
= gdip_buffer_to_hglobal (buffer
, size
, error
);
347 hr
= CreateStreamOnHGlobal (hg
, FALSE
, (LPSTREAM
*)&stream
);
349 if (!SUCCEEDED (hr
)) {
350 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, hr
, _("Could not create stream: %s"));
355 status
= GdipCreateBitmapFromStream (stream
, &bitmap
);
358 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
360 IStream_Release (stream
);
367 gdip_buffer_to_image (const gchar
*buffer
, size_t size
, GError
**error
)
371 GpImage
*image
= NULL
;
372 IStream
*stream
= NULL
;
375 hg
= gdip_buffer_to_hglobal (buffer
, size
, error
);
380 hr
= CreateStreamOnHGlobal (hg
, FALSE
, (LPSTREAM
*)&stream
);
382 if (!SUCCEEDED (hr
)) {
383 gdip_set_error_from_hresult (error
, GDK_PIXBUF_ERROR_FAILED
, hr
, _("Could not create stream: %s"));
388 status
= GdipLoadImageFromStream (stream
, &image
);
391 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
393 IStream_Release (stream
);
400 gdip_bitmap_get_size (GpBitmap
*bitmap
, guint
*width
, guint
*height
)
402 if (bitmap
== NULL
|| width
== NULL
|| height
== NULL
)
405 *width
= *height
= 0;
407 GdipGetImageWidth ((GpImage
*) bitmap
, width
);
408 GdipGetImageHeight ((GpImage
*) bitmap
, height
);
412 gdip_bitmap_get_has_alpha (GpBitmap
*bitmap
, gboolean
*has_alpha
)
416 if (bitmap
== NULL
|| has_alpha
== NULL
)
419 GdipGetImageFlags ((GpImage
*) bitmap
, &flags
);
420 *has_alpha
= (flags
& ImageFlagsHasAlpha
);
424 gdip_bitmap_get_n_frames (GpBitmap
*bitmap
, guint
*n_frames
, gboolean timeDimension
)
426 if (bitmap
== NULL
|| n_frames
== NULL
)
431 return (Ok
== GdipImageGetFrameCount ((GpImage
*) bitmap
, (timeDimension
? &FrameDimensionTime
: &FrameDimensionPage
), n_frames
));
435 gdip_bitmap_select_frame (GpBitmap
*bitmap
, guint frame
, gboolean timeDimension
)
440 return (Ok
== GdipImageSelectActiveFrame ((GpImage
*)bitmap
, (timeDimension
? &FrameDimensionTime
: &FrameDimensionPage
), frame
));
444 gdip_bitmap_get_property_as_string (GpBitmap
*bitmap
, guint propertyId
, gchar
**str
)
447 gboolean success
= FALSE
;
449 if (bitmap
== NULL
|| str
== NULL
)
454 if (Ok
== GdipGetPropertyItemSize ((GpImage
*)bitmap
, propertyId
, &item_size
)) {
457 item
= (PropertyItem
*)g_try_malloc (item_size
);
458 if (Ok
== GdipGetPropertyItem ((GpImage
*)bitmap
, propertyId
, item_size
, item
)) {
462 gstr
= g_string_new (NULL
);
465 switch (item
->type
) {
466 case PropertyTagTypeByte
:
467 for (i
= 0; i
< item
->length
/ sizeof(guint8
); i
++) {
468 guint8
*bytes
= (guint8
*)item
->value
;
471 g_string_append_c(gstr
, ',');
472 g_string_append_printf (gstr
, "%u", (guint32
)bytes
[i
]);
476 case PropertyTagTypeASCII
:
477 g_string_append_len (gstr
, (const char *)item
->value
, item
->length
);
480 case PropertyTagTypeShort
:
481 for (i
= 0; i
< item
->length
/ sizeof(guint16
); i
++) {
482 guint16
*shorts
= (guint16
*)item
->value
;
485 g_string_append_c (gstr
, ',');
486 g_string_append_printf (gstr
, "%u", (guint32
)shorts
[i
]);
490 case PropertyTagTypeLong
:
491 for (i
= 0; i
< item
->length
/ sizeof(guint32
); i
++) {
492 guint32
*longs
= (guint32
*)item
->value
;
495 g_string_append_c (gstr
, ',');
496 g_string_append_printf (gstr
, "%u", longs
[i
]);
500 case PropertyTagTypeSLONG
:
501 for (i
= 0; i
< item
->length
/ sizeof(guint32
); i
++) {
502 gint32
*longs
= (gint32
*)item
->value
;
505 g_string_append_c (gstr
, ',');
506 g_string_append_printf (gstr
, "%d", longs
[i
]);
516 *str
= g_string_free (gstr
, FALSE
);
518 g_string_free (gstr
, TRUE
);
528 gdip_bitmap_get_frame_delay (GpBitmap
*bitmap
, guint
*delay
)
531 gboolean success
= FALSE
;
533 if (bitmap
== NULL
|| delay
== NULL
)
538 if (Ok
== GdipGetPropertyItemSize ((GpImage
*)bitmap
, PropertyTagFrameDelay
, &item_size
)) {
541 item
= (PropertyItem
*)g_try_malloc (item_size
);
542 if (Ok
== GdipGetPropertyItem ((GpImage
*)bitmap
, PropertyTagFrameDelay
, item_size
, item
)) {
543 /* PropertyTagFrameDelay. Time delay, in hundredths of a second, between two frames in an animated GIF image. */
544 *delay
= *((long *)item
->value
);
555 gdip_bitmap_get_n_loops (GpBitmap
*bitmap
, guint
*loops
)
558 gboolean success
= FALSE
;
560 if (bitmap
== NULL
|| loops
== NULL
)
565 /* PropertyTagLoopCount. 0 == infinitely */
566 if (Ok
== GdipGetPropertyItemSize ((GpImage
*)bitmap
, PropertyTagLoopCount
, &item_size
)) {
569 item
= (PropertyItem
*)g_try_malloc (item_size
);
570 if (Ok
== GdipGetPropertyItem ((GpImage
*)bitmap
, PropertyTagLoopCount
, item_size
, item
)) {
571 *loops
= *((short *)item
->value
);
581 /*************************************************************************/
582 /*************************************************************************/
584 struct _GdipContext
{
585 GdkPixbufModuleUpdatedFunc updated_func
;
586 GdkPixbufModulePreparedFunc prepared_func
;
587 GdkPixbufModuleSizeFunc size_func
;
593 typedef struct _GdipContext GdipContext
;
596 destroy_gdipcontext (GdipContext
*context
)
598 if (context
!= NULL
) {
599 g_byte_array_free (context
->buffer
, TRUE
);
605 emit_updated (GdipContext
*context
, GdkPixbuf
*pixbuf
)
607 if (context
->updated_func
)
608 (*context
->updated_func
) (pixbuf
,
610 gdk_pixbuf_get_width (pixbuf
),
611 gdk_pixbuf_get_height (pixbuf
),
616 emit_prepared (GdipContext
*context
, GdkPixbuf
*pixbuf
, GdkPixbufAnimation
*anim
)
618 if (context
->prepared_func
)
619 (*context
->prepared_func
) (pixbuf
, anim
, context
->user_data
);
623 gdk_pixbuf__gdip_image_begin_load (GdkPixbufModuleSizeFunc size_func
,
624 GdkPixbufModulePreparedFunc prepared_func
,
625 GdkPixbufModuleUpdatedFunc updated_func
,
629 GdipContext
*context
= g_new0 (GdipContext
, 1);
631 context
->size_func
= size_func
;
632 context
->prepared_func
= prepared_func
;
633 context
->updated_func
= updated_func
;
634 context
->user_data
= user_data
;
635 context
->buffer
= g_byte_array_new ();
641 gdk_pixbuf__gdip_image_load_increment (gpointer data
,
642 const guchar
*buf
, guint size
,
645 GdipContext
*context
= (GdipContext
*)data
;
646 GByteArray
*image_buffer
= context
->buffer
;
648 g_byte_array_append (image_buffer
, (guint8
*)buf
, size
);
654 gdip_bitmap_to_pixbuf (GpBitmap
*bitmap
)
656 GdkPixbuf
*pixbuf
= NULL
;
657 guchar
*cursor
= NULL
;
659 gboolean has_alpha
= FALSE
;
663 guint width
= 0, height
= 0, x
, y
;
665 gdip_bitmap_get_size (bitmap
, &width
, &height
);
666 gdip_bitmap_get_has_alpha (bitmap
, &has_alpha
);
668 pixbuf
= gdk_pixbuf_new (GDK_COLORSPACE_RGB
, has_alpha
, 8, width
, height
);
673 rowstride
= gdk_pixbuf_get_rowstride (pixbuf
);
674 cursor
= gdk_pixbuf_get_pixels (pixbuf
);
675 n_channels
= gdk_pixbuf_get_n_channels (pixbuf
);
677 for (y
= 0; y
< height
; y
++) {
678 for (x
= 0; x
< width
; x
++) {
680 guchar
*b
= cursor
+ (y
* rowstride
+ (x
* n_channels
));
682 if (Ok
!= GdipBitmapGetPixel (bitmap
, x
, y
, &pixel
)) {
683 g_object_unref (pixbuf
);
687 b
[0] = (pixel
& 0xff0000) >> 16;
688 b
[1] = (pixel
& 0x00ff00) >> 8;
689 b
[2] = (pixel
& 0x0000ff) >> 0;
692 b
[3] = (pixel
& 0xff000000) >> 24;
696 if (gdip_bitmap_get_property_as_string (bitmap
, PropertyTagOrientation
, &option
)) {
697 gdk_pixbuf_set_option (pixbuf
, "orientation", option
);
701 if (gdip_bitmap_get_property_as_string (bitmap
, PropertyTagArtist
, &option
)) {
702 gdk_pixbuf_set_option (pixbuf
, "Author", option
);
706 if (gdip_bitmap_get_property_as_string (bitmap
, PropertyTagImageTitle
, &option
)) {
707 gdk_pixbuf_set_option (pixbuf
, "Title", option
);
715 stop_load (GpBitmap
*bitmap
, GdipContext
*context
, GError
**error
)
717 guint n_frames
= 1, i
;
718 GdkPixbufGdipAnim
*animation
= NULL
;
720 gdip_bitmap_get_n_frames (bitmap
, &n_frames
, TRUE
);
722 for (i
= 0; i
< n_frames
; i
++) {
723 GdkPixbuf
*pixbuf
= NULL
;
724 GdkPixbufFrame
*frame
;
725 guint frame_delay
= 0;
727 gdip_bitmap_select_frame (bitmap
, i
, TRUE
);
729 pixbuf
= gdip_bitmap_to_pixbuf (bitmap
);
732 if (animation
!= NULL
)
733 g_object_unref (G_OBJECT (animation
));
735 destroy_gdipcontext (context
);
736 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY
, _("Couldn't create pixbuf"));
740 if (animation
== NULL
) {
743 animation
= g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM
, NULL
);
744 gdip_bitmap_get_n_loops (bitmap
, &n_loops
);
745 animation
->loop
= n_loops
;
748 frame
= g_new (GdkPixbufFrame
, 1);
749 frame
->pixbuf
= pixbuf
;
751 gdip_bitmap_get_frame_delay (bitmap
, &frame_delay
);
753 animation
->n_frames
++;
754 animation
->frames
= g_list_append (animation
->frames
, frame
);
756 animation
->width
= gdk_pixbuf_get_width (pixbuf
);
757 animation
->height
= gdk_pixbuf_get_height (pixbuf
);
759 /* GIF delay is in hundredths, we want thousandths */
760 frame
->delay_time
= frame_delay
* 10;
761 frame
->elapsed
= animation
->total_time
;
763 /* Some GIFs apparently have delay time of 0,
764 * that crashes everything so set it to "fast".
765 * Also, timeouts less than 20 or so just lock up
766 * the app or make the animation choppy, so fix them.
768 if (frame
->delay_time
< 20)
769 frame
->delay_time
= 20; /* 20 = "fast" */
771 animation
->total_time
+= frame
->delay_time
;
774 emit_prepared (context
, pixbuf
, GDK_PIXBUF_ANIMATION (animation
));
776 emit_updated (context
, pixbuf
);
779 if (animation
!= NULL
)
780 g_object_unref (G_OBJECT (animation
));
782 destroy_gdipcontext (context
);
788 gdk_pixbuf__gdip_image_stop_load (gpointer data
, GError
**error
)
790 GdipContext
*context
= (GdipContext
*)data
;
791 GpBitmap
*bitmap
= NULL
;
792 GByteArray
*image_buffer
= context
->buffer
;
794 bitmap
= gdip_buffer_to_bitmap ((gchar
*)image_buffer
->data
, image_buffer
->len
, error
);
797 destroy_gdipcontext (context
);
798 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, GDK_PIXBUF_ERROR_CORRUPT_IMAGE
, _("Couldn't load bitmap"));
802 return stop_load (bitmap
, context
, error
);
806 gdk_pixbuf__gdip_image_stop_vector_load (gpointer data
, GError
**error
)
808 GdipContext
*context
= (GdipContext
*)data
;
809 GByteArray
*image_buffer
= context
->buffer
;
812 GpGraphics
*graphics
;
815 float metafile_xres
, metafile_yres
;
818 metafile
= gdip_buffer_to_image ((gchar
*)image_buffer
->data
, image_buffer
->len
, error
);
820 destroy_gdipcontext (context
);
821 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, GDK_PIXBUF_ERROR_CORRUPT_IMAGE
, _("Couldn't load metafile"));
825 GdipGetImageWidth (metafile
, &width
);
826 GdipGetImageHeight (metafile
, &height
);
828 status
= GdipCreateBitmapFromScan0 (width
, height
, 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
830 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
831 GdipDisposeImage (metafile
);
836 GdipGetImageHorizontalResolution (metafile
, &metafile_xres
);
837 GdipGetImageVerticalResolution (metafile
, &metafile_yres
);
838 GdipBitmapSetResolution (bitmap
, metafile_xres
, metafile_yres
);
840 status
= GdipGetImageGraphicsContext ((GpImage
*)bitmap
, &graphics
);
842 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
843 GdipDisposeImage ((GpImage
*)bitmap
);
844 GdipDisposeImage (metafile
);
849 /* gotta clear the bitmap */
850 GdipGraphicsClear (graphics
, 0xffffffff);
852 status
= GdipDrawImageI (graphics
, metafile
, 0, 0);
854 gdip_set_error_from_gpstatus (error
, GDK_PIXBUF_ERROR_FAILED
, status
);
855 GdipDeleteGraphics (graphics
);
856 GdipDisposeImage ((GpImage
*)bitmap
);
857 GdipDisposeImage (metafile
);
862 GdipFlush (graphics
, 1);
864 GdipDeleteGraphics (graphics
);
865 GdipDisposeImage (metafile
);
867 return stop_load (bitmap
, context
, error
);
871 gdip_animation_prepare (GdkPixbuf
*pixbuf
,
872 GdkPixbufAnimation
*animation
,
875 GdkPixbufAnimation
**anim
;
877 anim
= (GdkPixbufAnimation
**)user_data
;
879 /* save a reference to the animation */
880 g_object_ref (animation
);
884 static GdkPixbufAnimation
*
885 gdk_pixbuf__gdip_image_load_animation (FILE *file
,
888 GdkPixbufAnimation
*animation
= NULL
;
891 char buffer
[LOAD_BUFFER_SIZE
];
894 context
= gdk_pixbuf__gdip_image_begin_load (NULL
, gdip_animation_prepare
, NULL
, &animation
, error
);
896 while (!feof (file
) && !ferror (file
)) {
897 length
= fread (buffer
, 1, sizeof (buffer
), file
);
899 if (!gdk_pixbuf__gdip_image_load_increment (context
, buffer
, length
, error
)) {
900 gdk_pixbuf__gdip_image_stop_load (context
, NULL
);
903 g_object_unref (animation
);
910 if (!gdk_pixbuf__gdip_image_stop_load(context
, error
)) {
912 g_object_unref (animation
);
921 gdip_save_to_file_callback (const gchar
*buf
,
926 FILE *filehandle
= data
;
929 n
= fwrite (buf
, 1, count
, filehandle
);
931 gint save_errno
= errno
;
934 g_file_error_from_errno (save_errno
),
935 _("Error writing to image file: %s"),
936 g_strerror (save_errno
));
944 gdip_fill_vtable (GdkPixbufModule
*module
)
947 module
->begin_load
= gdk_pixbuf__gdip_image_begin_load
;
948 module
->stop_load
= gdk_pixbuf__gdip_image_stop_load
;
949 module
->load_increment
= gdk_pixbuf__gdip_image_load_increment
;
951 /* this is the only way to get gtk_image_new_from_file() to load animations. it regrettably
952 does not use the GdkPixbufLoader interface. */
953 module
->load_animation
= gdk_pixbuf__gdip_image_load_animation
;
958 gdip_fill_vector_vtable (GdkPixbufModule
*module
)
961 module
->begin_load
= gdk_pixbuf__gdip_image_begin_load
;
962 module
->stop_load
= gdk_pixbuf__gdip_image_stop_vector_load
;
963 module
->load_increment
= gdk_pixbuf__gdip_image_load_increment
;
968 gdip_save_pixbuf (GdkPixbuf
*pixbuf
,
970 const EncoderParameters
*encoder_params
,
971 GdkPixbufSaveFunc save_func
,
979 if (!GetEncoderClsid (format
, &clsid
)) {
980 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, GDK_PIXBUF_ERROR_FAILED
, _("Unsupported image format for GDI+"));
984 image
= gdip_pixbuf_to_bitmap (pixbuf
);
987 g_set_error_literal (error
, GDK_PIXBUF_ERROR
, GDK_PIXBUF_ERROR_FAILED
, _("Couldn't save"));
991 success
= gdip_save_bitmap_to_callback (image
, &clsid
, encoder_params
, save_func
, user_data
, error
);
993 GdipDisposeImage ((GpImage
*)image
);