|
Packit |
a4058c |
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
Packit |
a4058c |
/* GdkPixbuf library - Win32 GDI+ Pixbuf Loader
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* Copyright (C) 2008 Dominic Lachowicz
|
|
Packit |
a4058c |
* Copyright (C) 2008 Alberto Ruiz
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* Authors: Dominic Lachowicz <domlachowicz@gmail.com>
|
|
Packit |
a4058c |
* Alberto Ruiz <aruiz@gnome.org>
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* This library is free software; you can redistribute it and/or
|
|
Packit |
a4058c |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4058c |
* License as published by the Free Software Foundation; either
|
|
Packit |
a4058c |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
a4058c |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4058c |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4058c |
* Lesser General Public License for more * You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4058c |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#define INITGUID
|
|
Packit |
a4058c |
#include "config.h"
|
|
Packit |
a4058c |
#include <glib/gi18n-lib.h>
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#include <ole2.h>
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#include "io-gdip-utils.h"
|
|
Packit |
a4058c |
#include "io-gdip-native.h"
|
|
Packit |
a4058c |
#include "io-gdip-propertytags.h"
|
|
Packit |
a4058c |
#include "io-gdip-animation.h"
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#define LOAD_BUFFER_SIZE 65536
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
struct _GdipContext {
|
|
Packit |
a4058c |
GdkPixbufModuleUpdatedFunc updated_func;
|
|
Packit |
a4058c |
GdkPixbufModulePreparedFunc prepared_func;
|
|
Packit |
a4058c |
GdkPixbufModuleSizeFunc size_func;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gpointer user_data;
|
|
Packit |
a4058c |
GByteArray *buffer;
|
|
Packit |
a4058c |
IStream *stream;
|
|
Packit |
a4058c |
HGLOBAL hg;
|
|
Packit |
a4058c |
};
|
|
Packit |
a4058c |
typedef struct _GdipContext GdipContext;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
DEFINE_GUID(FrameDimensionTime, 0x6aedbd6d,0x3fb5,0x418a,0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72);
|
|
Packit |
a4058c |
DEFINE_GUID(FrameDimensionPage, 0x7462dc86,0x6180,0x4c7e,0x8e,0x3f,0xee,0x73,0x33,0xa7,0xa4,0x83);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (GError **error, gint code, HRESULT hr, const char *format)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gchar *msg;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
msg = g_win32_error_message (hr);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (msg) {
|
|
Packit |
a4058c |
g_set_error (error, GDK_PIXBUF_ERROR, code, format, msg);
|
|
Packit |
a4058c |
g_free (msg);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (GError **error, gint code, GpStatus status)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
const char *msg;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
switch (status)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
#define CASE(x) case x: msg = #x; break
|
|
Packit |
a4058c |
CASE (GenericError);
|
|
Packit |
a4058c |
CASE (InvalidParameter);
|
|
Packit |
a4058c |
CASE (OutOfMemory);
|
|
Packit |
a4058c |
CASE (ObjectBusy);
|
|
Packit |
a4058c |
CASE (InsufficientBuffer);
|
|
Packit |
a4058c |
CASE (NotImplemented);
|
|
Packit |
a4058c |
CASE (Win32Error);
|
|
Packit |
a4058c |
CASE (WrongState);
|
|
Packit |
a4058c |
CASE (Aborted);
|
|
Packit |
a4058c |
CASE (FileNotFound);
|
|
Packit |
a4058c |
CASE (ValueOverflow);
|
|
Packit |
a4058c |
CASE (AccessDenied);
|
|
Packit |
a4058c |
CASE (UnknownImageFormat);
|
|
Packit |
a4058c |
CASE (FontFamilyNotFound);
|
|
Packit |
a4058c |
CASE (FontStyleNotFound);
|
|
Packit |
a4058c |
CASE (NotTrueTypeFont);
|
|
Packit |
a4058c |
CASE (UnsupportedGdiplusVersion);
|
|
Packit |
a4058c |
CASE (GdiplusNotInitialized);
|
|
Packit |
a4058c |
CASE (PropertyNotFound);
|
|
Packit |
a4058c |
CASE (PropertyNotSupported);
|
|
Packit |
a4058c |
CASE (ProfileNotFound);
|
|
Packit |
a4058c |
default:
|
|
Packit |
a4058c |
msg = "Unknown error";
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR, code, msg);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_init (void)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdiplusStartupInput input;
|
|
Packit |
a4058c |
ULONG_PTR gdiplusToken = 0;
|
|
Packit |
a4058c |
static gboolean beenhere = FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (beenhere)
|
|
Packit |
a4058c |
return TRUE; /* gdip_init() is idempotent */
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
beenhere = TRUE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
input.GdiplusVersion = 1;
|
|
Packit |
a4058c |
input.DebugEventCallback = NULL;
|
|
Packit |
a4058c |
input.SuppressBackgroundThread = input.SuppressExternalCodecs = FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return (GdiplusStartup (&gdiplusToken, &input, NULL) == 0 ? TRUE : FALSE);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
GetEncoderClsid (const WCHAR *format, CLSID *pClsid)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
UINT num, size;
|
|
Packit |
a4058c |
int j;
|
|
Packit |
a4058c |
ImageCodecInfo *pImageCodecInfo;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok != GdipGetImageEncodersSize (&num, &size))
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
pImageCodecInfo = (ImageCodecInfo *) g_malloc (size);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok != GdipGetImageEncoders (num, size, pImageCodecInfo)) {
|
|
Packit |
a4058c |
g_free (pImageCodecInfo);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for (j = 0; j < num; j++) {
|
|
Packit |
a4058c |
if (wcscmp (pImageCodecInfo[j].MimeType, format) == 0) {
|
|
Packit |
a4058c |
*pClsid = pImageCodecInfo[j].Clsid;
|
|
Packit |
a4058c |
g_free (pImageCodecInfo);
|
|
Packit |
a4058c |
return TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
g_free (pImageCodecInfo);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static HGLOBAL
|
|
Packit |
a4058c |
gdip_buffer_to_hglobal (const gchar *buffer, size_t size, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
HGLOBAL hg = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hg = GlobalAlloc (GPTR, size);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!hg) {
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, GetLastError (), _("Could not allocate memory: %s"));
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
CopyMemory (hg, buffer, size);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return hg;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_save_bitmap_to_callback (GpBitmap *bitmap,
|
|
Packit |
a4058c |
const CLSID *format,
|
|
Packit |
a4058c |
const EncoderParameters *encoder_params,
|
|
Packit |
a4058c |
GdkPixbufSaveFunc save_func,
|
|
Packit |
a4058c |
gpointer user_data,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
HRESULT hr;
|
|
Packit |
a4058c |
IStream *streamOut = NULL;
|
|
Packit |
a4058c |
gboolean success = FALSE;
|
|
Packit |
a4058c |
guint64 zero = 0;
|
|
Packit |
a4058c |
GpStatus status;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hr = CreateStreamOnHGlobal (NULL, TRUE, &streamOut);
|
|
Packit |
a4058c |
if (!SUCCEEDED (hr)) {
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
status = GdipSaveImageToStream ((GpImage *)bitmap, streamOut, format, encoder_params);
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
IStream_Release (streamOut);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* seek back to the beginning of the stream */
|
|
Packit |
a4058c |
hr = IStream_Seek (streamOut, *(LARGE_INTEGER *)&zero, STREAM_SEEK_SET, NULL);
|
|
Packit |
a4058c |
if (!SUCCEEDED (hr)) {
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not seek stream: %s"));
|
|
Packit |
a4058c |
IStream_Release (streamOut);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for (;;) {
|
|
Packit |
a4058c |
char buffer[LOAD_BUFFER_SIZE];
|
|
Packit |
a4058c |
ULONG nread;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hr = IStream_Read (streamOut, buffer, sizeof(buffer), &nread);
|
|
Packit |
a4058c |
if (!SUCCEEDED (hr))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not read from stream: %s"));
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
else if (0 == nread) {
|
|
Packit |
a4058c |
success = TRUE; /* EOF */
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
else if (!(*save_func) (buffer, nread, error, user_data))
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
IStream_Release (streamOut);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return success;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static GpBitmap *
|
|
Packit |
a4058c |
gdip_pixbuf_to_bitmap (GdkPixbuf *pixbuf)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GpBitmap *bitmap = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
int width, height, stride, n_channels;
|
|
Packit |
a4058c |
guint8 *pixels;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
width = gdk_pixbuf_get_width (pixbuf);
|
|
Packit |
a4058c |
height = gdk_pixbuf_get_height (pixbuf);
|
|
Packit |
a4058c |
stride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
Packit |
a4058c |
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
|
|
Packit |
a4058c |
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (n_channels == 3 || n_channels == 4) {
|
|
Packit |
a4058c |
/* rgbX. need to convert to argb. pass a null data to get an empty bitmap */
|
|
Packit |
a4058c |
GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (bitmap) {
|
|
Packit |
a4058c |
int x, y;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for (y = 0; y < height; y++) {
|
|
Packit |
a4058c |
for (x = 0; x < width; x++) {
|
|
Packit |
a4058c |
ARGB p;
|
|
Packit |
a4058c |
guint8 alpha;
|
|
Packit |
a4058c |
guchar *base = pixels + (y * stride + (x * n_channels));
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (n_channels == 4)
|
|
Packit |
a4058c |
alpha = base[3];
|
|
Packit |
a4058c |
else
|
|
Packit |
a4058c |
alpha = 0xff;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (alpha == 0)
|
|
Packit |
a4058c |
p = 0;
|
|
Packit |
a4058c |
else {
|
|
Packit |
a4058c |
guint8 red = base[0];
|
|
Packit |
a4058c |
guint8 green = base[1];
|
|
Packit |
a4058c |
guint8 blue = base[2];
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipBitmapSetPixel (bitmap, x, y, p);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
else {
|
|
Packit |
a4058c |
g_warning ("Unsupported number of channels: %d\n", n_channels);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return bitmap;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static GpBitmap *
|
|
Packit |
a4058c |
gdip_buffer_to_bitmap (GdipContext *context, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
HRESULT hr;
|
|
Packit |
a4058c |
HGLOBAL hg = NULL;
|
|
Packit |
a4058c |
GpBitmap *bitmap = NULL;
|
|
Packit |
a4058c |
IStream *stream = NULL;
|
|
Packit |
a4058c |
GpStatus status;
|
|
Packit |
a4058c |
guint64 size64 = context->buffer->len;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hg = gdip_buffer_to_hglobal (context->buffer->data, context->buffer->len, error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!hg)
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!SUCCEEDED (hr)) {
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
|
|
Packit |
a4058c |
GlobalFree (hg);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
status = GdipCreateBitmapFromStream (stream, &bitmap);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
IStream_Release (stream);
|
|
Packit |
a4058c |
GlobalFree (hg);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
context->stream = stream;
|
|
Packit |
a4058c |
context->hg = hg;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return bitmap;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static GpImage *
|
|
Packit |
a4058c |
gdip_buffer_to_image (GdipContext *context, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
HRESULT hr;
|
|
Packit |
a4058c |
HGLOBAL hg = NULL;
|
|
Packit |
a4058c |
GpImage *image = NULL;
|
|
Packit |
a4058c |
IStream *stream = NULL;
|
|
Packit |
a4058c |
GpStatus status;
|
|
Packit |
a4058c |
guint64 size64 = context->buffer->len;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hg = gdip_buffer_to_hglobal (context->buffer->data, context->buffer->len, error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!hg)
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hr = CreateStreamOnHGlobal (hg, FALSE, (LPSTREAM *)&stream);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!SUCCEEDED (hr)) {
|
|
Packit |
a4058c |
gdip_set_error_from_hresult (error, GDK_PIXBUF_ERROR_FAILED, hr, _("Could not create stream: %s"));
|
|
Packit |
a4058c |
GlobalFree (hg);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
IStream_SetSize (stream, *(ULARGE_INTEGER *)&size64);
|
|
Packit |
a4058c |
status = GdipLoadImageFromStream (stream, &image);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
IStream_Release (stream);
|
|
Packit |
a4058c |
GlobalFree (hg);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
context->stream = stream;
|
|
Packit |
a4058c |
context->hg = hg;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return image;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
gdip_bitmap_get_size (GpBitmap *bitmap, guint *width, guint *height)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (bitmap == NULL || width == NULL || height == NULL)
|
|
Packit |
a4058c |
return;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
*width = *height = 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipGetImageWidth ((GpImage *) bitmap, width);
|
|
Packit |
a4058c |
GdipGetImageHeight ((GpImage *) bitmap, height);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
gdip_bitmap_get_has_alpha (GpBitmap *bitmap, gboolean *has_alpha)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint flags = 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (bitmap == NULL || has_alpha == NULL)
|
|
Packit |
a4058c |
return;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipGetImageFlags ((GpImage *) bitmap, &flags);
|
|
Packit |
a4058c |
*has_alpha = (flags & ImageFlagsHasAlpha);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_bitmap_get_n_frames (GpBitmap *bitmap, guint *n_frames, gboolean timeDimension)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (bitmap == NULL || n_frames == NULL)
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
*n_frames = 1;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return (Ok == GdipImageGetFrameCount ((GpImage *) bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), n_frames));
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_bitmap_select_frame (GpBitmap *bitmap, guint frame, gboolean timeDimension)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (bitmap == NULL)
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return (Ok == GdipImageSelectActiveFrame ((GpImage *)bitmap, (timeDimension ? &FrameDimensionTime : &FrameDimensionPage), frame));
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_bitmap_get_property_as_string (GpBitmap *bitmap, guint propertyId, gchar **str)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint item_size;
|
|
Packit |
a4058c |
gboolean success = FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (bitmap == NULL || str == NULL)
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
*str = 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, propertyId, &item_size)) {
|
|
Packit |
a4058c |
PropertyItem *item;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
item = (PropertyItem *)g_try_malloc (item_size);
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, propertyId, item_size, item)) {
|
|
Packit |
a4058c |
GString *gstr;
|
|
Packit |
a4058c |
int i;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gstr = g_string_new (NULL);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
success = TRUE;
|
|
Packit |
a4058c |
switch (item->type) {
|
|
Packit |
a4058c |
case PropertyTagTypeByte:
|
|
Packit |
a4058c |
for (i = 0; i < item->length / sizeof(guint8); i++) {
|
|
Packit |
a4058c |
guint8 *bytes = (guint8 *)item->value;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gstr->len != 0)
|
|
Packit |
a4058c |
g_string_append_c(gstr, ',');
|
|
Packit |
a4058c |
g_string_append_printf (gstr, "%u", (guint32)bytes[i]);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
case PropertyTagTypeASCII:
|
|
Packit |
a4058c |
g_string_append_len (gstr, (const char *)item->value, item->length);
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
case PropertyTagTypeShort:
|
|
Packit |
a4058c |
for (i = 0; i < item->length / sizeof(guint16); i++) {
|
|
Packit |
a4058c |
guint16 *shorts = (guint16 *)item->value;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gstr->len != 0)
|
|
Packit |
a4058c |
g_string_append_c (gstr, ',');
|
|
Packit |
a4058c |
g_string_append_printf (gstr, "%u", (guint32)shorts[i]);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
case PropertyTagTypeLong:
|
|
Packit |
a4058c |
for (i = 0; i < item->length / sizeof(guint32); i++) {
|
|
Packit |
a4058c |
guint32 *longs = (guint32 *)item->value;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gstr->len != 0)
|
|
Packit |
a4058c |
g_string_append_c (gstr, ',');
|
|
Packit |
a4058c |
g_string_append_printf (gstr, "%u", longs[i]);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
case PropertyTagTypeSLONG:
|
|
Packit |
a4058c |
for (i = 0; i < item->length / sizeof(guint32); i++) {
|
|
Packit |
a4058c |
gint32 *longs = (gint32 *)item->value;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gstr->len != 0)
|
|
Packit |
a4058c |
g_string_append_c (gstr, ',');
|
|
Packit |
a4058c |
g_string_append_printf (gstr, "%d", longs[i]);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
default:
|
|
Packit |
a4058c |
success = FALSE;
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gstr->len > 0)
|
|
Packit |
a4058c |
*str = g_string_free (gstr, FALSE);
|
|
Packit |
a4058c |
else
|
|
Packit |
a4058c |
g_string_free (gstr, TRUE);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
g_free (item);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return success;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_bitmap_get_frame_delay (GpBitmap *bitmap, guint frame, guint *delay)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint item_size, item_count;
|
|
Packit |
a4058c |
gboolean success = FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (bitmap == NULL || delay == NULL)
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
*delay = 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagFrameDelay, &item_size)) {
|
|
Packit |
a4058c |
PropertyItem *item;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
item = (PropertyItem *)g_try_malloc (item_size);
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagFrameDelay, item_size, item)) {
|
|
Packit |
a4058c |
item_count = item_size / sizeof(long);
|
|
Packit |
a4058c |
/* PropertyTagFrameDelay. Time delay, in hundredths of a second, between two frames in an animated GIF image. */
|
|
Packit |
a4058c |
*delay = ((long *)item->value)[(frame < item_count) ? frame : item_count - 1];
|
|
Packit |
a4058c |
success = TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
g_free (item);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return success;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdip_bitmap_get_n_loops (GpBitmap *bitmap, guint *loops)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint item_size;
|
|
Packit |
a4058c |
gboolean success = FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (bitmap == NULL || loops == NULL)
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
*loops = 1;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* PropertyTagLoopCount. 0 == infinitely */
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItemSize ((GpImage *)bitmap, PropertyTagLoopCount, &item_size)) {
|
|
Packit |
a4058c |
PropertyItem *item;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
item = (PropertyItem *)g_try_malloc (item_size);
|
|
Packit |
a4058c |
if (Ok == GdipGetPropertyItem ((GpImage *)bitmap, PropertyTagLoopCount, item_size, item)) {
|
|
Packit |
a4058c |
*loops = *((short *)item->value);
|
|
Packit |
a4058c |
success = TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
g_free (item);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return success;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
destroy_gdipcontext (GdipContext *context)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (context != NULL) {
|
|
Packit |
a4058c |
if (context->stream != NULL) {
|
|
Packit |
a4058c |
IStream_Release(context->stream);
|
|
Packit |
a4058c |
GlobalFree (context->hg);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
g_byte_array_free (context->buffer, TRUE);
|
|
Packit |
a4058c |
g_free (context);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
emit_updated (GdipContext *context, GdkPixbuf *pixbuf)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (context->updated_func)
|
|
Packit |
a4058c |
(*context->updated_func) (pixbuf,
|
|
Packit |
a4058c |
0, 0,
|
|
Packit |
a4058c |
gdk_pixbuf_get_width (pixbuf),
|
|
Packit |
a4058c |
gdk_pixbuf_get_height (pixbuf),
|
|
Packit |
a4058c |
context->user_data);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void
|
|
Packit |
a4058c |
emit_prepared (GdipContext *context, GdkPixbuf *pixbuf, GdkPixbufAnimation *anim)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (context->prepared_func)
|
|
Packit |
a4058c |
(*context->prepared_func) (pixbuf, anim, context->user_data);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gpointer
|
|
Packit |
a4058c |
gdk_pixbuf__gdip_image_begin_load (GdkPixbufModuleSizeFunc size_func,
|
|
Packit |
a4058c |
GdkPixbufModulePreparedFunc prepared_func,
|
|
Packit |
a4058c |
GdkPixbufModuleUpdatedFunc updated_func,
|
|
Packit |
a4058c |
gpointer user_data,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdipContext *context = g_new0 (GdipContext, 1);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
context->size_func = size_func;
|
|
Packit |
a4058c |
context->prepared_func = prepared_func;
|
|
Packit |
a4058c |
context->updated_func = updated_func;
|
|
Packit |
a4058c |
context->user_data = user_data;
|
|
Packit |
a4058c |
context->buffer = g_byte_array_new ();
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return context;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdk_pixbuf__gdip_image_load_increment (gpointer data,
|
|
Packit |
a4058c |
const guchar *buf, guint size,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdipContext *context = (GdipContext *)data;
|
|
Packit |
a4058c |
GByteArray *image_buffer = context->buffer;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
g_byte_array_append (image_buffer, (guint8 *)buf, size);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static GdkPixbuf *
|
|
Packit |
a4058c |
gdip_bitmap_to_pixbuf (GpBitmap *bitmap, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf = NULL;
|
|
Packit |
a4058c |
guchar *cursor = NULL;
|
|
Packit |
a4058c |
gint rowstride;
|
|
Packit |
a4058c |
gboolean has_alpha = FALSE;
|
|
Packit |
a4058c |
gint n_channels = 0;
|
|
Packit |
a4058c |
gchar *option;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
guint width = 0, height = 0, x, y;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gdip_bitmap_get_size (bitmap, &width, &height);
|
|
Packit |
a4058c |
gdip_bitmap_get_has_alpha (bitmap, &has_alpha);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8, width, height);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!pixbuf) {
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't load bitmap"));
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
Packit |
a4058c |
cursor = gdk_pixbuf_get_pixels (pixbuf);
|
|
Packit |
a4058c |
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for (y = 0; y < height; y++) {
|
|
Packit |
a4058c |
for (x = 0; x < width; x++) {
|
|
Packit |
a4058c |
ARGB pixel;
|
|
Packit |
a4058c |
GpStatus status;
|
|
Packit |
a4058c |
guchar *b = cursor + (y * rowstride + (x * n_channels));
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (Ok != (status = GdipBitmapGetPixel (bitmap, x, y, &pixel))) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
g_object_unref (pixbuf);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
b[0] = (pixel & 0xff0000) >> 16;
|
|
Packit |
a4058c |
b[1] = (pixel & 0x00ff00) >> 8;
|
|
Packit |
a4058c |
b[2] = (pixel & 0x0000ff) >> 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (has_alpha)
|
|
Packit |
a4058c |
b[3] = (pixel & 0xff000000) >> 24;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagOrientation, &option)) {
|
|
Packit |
a4058c |
gdk_pixbuf_set_option (pixbuf, "orientation", option);
|
|
Packit |
a4058c |
g_free (option);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagArtist, &option)) {
|
|
Packit |
a4058c |
gdk_pixbuf_set_option (pixbuf, "Author", option);
|
|
Packit |
a4058c |
g_free (option);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (gdip_bitmap_get_property_as_string (bitmap, PropertyTagImageTitle, &option)) {
|
|
Packit |
a4058c |
gdk_pixbuf_set_option (pixbuf, "Title", option);
|
|
Packit |
a4058c |
g_free (option);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return pixbuf;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
stop_load (GpBitmap *bitmap, GdipContext *context, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint n_frames = 1, i;
|
|
Packit |
a4058c |
GdkPixbufGdipAnim *animation = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gdip_bitmap_get_n_frames (bitmap, &n_frames, TRUE);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for (i = 0; i < n_frames; i++) {
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf = NULL;
|
|
Packit |
a4058c |
GdkPixbufFrame *frame;
|
|
Packit |
a4058c |
guint frame_delay = 0;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gdip_bitmap_select_frame (bitmap, i, TRUE);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
pixbuf = gdip_bitmap_to_pixbuf (bitmap, error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!pixbuf) {
|
|
Packit |
a4058c |
if (animation != NULL)
|
|
Packit |
a4058c |
g_object_unref (G_OBJECT (animation));
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipDisposeImage ((GpImage *)bitmap);
|
|
Packit |
a4058c |
destroy_gdipcontext (context);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (animation == NULL) {
|
|
Packit |
a4058c |
guint n_loops = 1;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
animation = g_object_new (GDK_TYPE_PIXBUF_GDIP_ANIM, NULL);
|
|
Packit |
a4058c |
gdip_bitmap_get_n_loops (bitmap, &n_loops);
|
|
Packit |
a4058c |
animation->loop = n_loops;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
frame = g_new (GdkPixbufFrame, 1);
|
|
Packit |
a4058c |
frame->pixbuf = pixbuf;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gdip_bitmap_get_frame_delay (bitmap, i, &frame_delay);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
animation->n_frames++;
|
|
Packit |
a4058c |
animation->frames = g_list_append (animation->frames, frame);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
animation->width = gdk_pixbuf_get_width (pixbuf);
|
|
Packit |
a4058c |
animation->height = gdk_pixbuf_get_height (pixbuf);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* GIF delay is in hundredths, we want thousandths */
|
|
Packit |
a4058c |
frame->delay_time = frame_delay * 10;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* GIFs with delay time 0 are mostly broken, but they
|
|
Packit |
a4058c |
* just want a default, "not that fast" delay.
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
if (frame->delay_time == 0)
|
|
Packit |
a4058c |
frame->delay_time = 100;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* No GIFs gets to play faster than 50 fps. They just
|
|
Packit |
a4058c |
* lock up poor gtk.
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
else if (frame->delay_time < 20)
|
|
Packit |
a4058c |
frame->delay_time = 20; /* 20 = "fast" */
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
frame->elapsed = animation->total_time;
|
|
Packit |
a4058c |
animation->total_time += frame->delay_time;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (i == 0)
|
|
Packit |
a4058c |
emit_prepared (context, pixbuf, GDK_PIXBUF_ANIMATION (animation));
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
emit_updated (context, pixbuf);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (animation != NULL)
|
|
Packit |
a4058c |
g_object_unref (G_OBJECT (animation));
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipDisposeImage ((GpImage *)bitmap);
|
|
Packit |
a4058c |
destroy_gdipcontext (context);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdk_pixbuf__gdip_image_stop_load (gpointer data, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdipContext *context = (GdipContext *)data;
|
|
Packit |
a4058c |
GpBitmap *bitmap = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
bitmap = gdip_buffer_to_bitmap (context, error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!bitmap) {
|
|
Packit |
a4058c |
destroy_gdipcontext (context);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return stop_load (bitmap, context, error);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static gboolean
|
|
Packit |
a4058c |
gdk_pixbuf__gdip_image_stop_vector_load (gpointer data, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdipContext *context = (GdipContext *)data;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GpImage *metafile;
|
|
Packit |
a4058c |
GpGraphics *graphics;
|
|
Packit |
a4058c |
GpBitmap *bitmap;
|
|
Packit |
a4058c |
GpStatus status;
|
|
Packit |
a4058c |
float metafile_xres, metafile_yres;
|
|
Packit |
a4058c |
guint width, height;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
metafile = gdip_buffer_to_image (context, error);
|
|
Packit |
a4058c |
if (!metafile) {
|
|
Packit |
a4058c |
destroy_gdipcontext (context);
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Couldn't load metafile"));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipGetImageWidth (metafile, &width);
|
|
Packit |
a4058c |
GdipGetImageHeight (metafile, &height);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
status = GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, NULL, &bitmap);
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
GdipDisposeImage (metafile);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipGetImageHorizontalResolution (metafile, &metafile_xres);
|
|
Packit |
a4058c |
GdipGetImageVerticalResolution (metafile, &metafile_yres);
|
|
Packit |
a4058c |
GdipBitmapSetResolution (bitmap, metafile_xres, metafile_yres);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
status = GdipGetImageGraphicsContext ((GpImage *)bitmap, &graphics);
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
GdipDisposeImage ((GpImage *)bitmap);
|
|
Packit |
a4058c |
GdipDisposeImage (metafile);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* gotta clear the bitmap */
|
|
Packit |
a4058c |
GdipGraphicsClear (graphics, 0xffffffff);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
status = GdipDrawImageI (graphics, metafile, 0, 0);
|
|
Packit |
a4058c |
if (Ok != status) {
|
|
Packit |
a4058c |
gdip_set_error_from_gpstatus (error, GDK_PIXBUF_ERROR_FAILED, status);
|
|
Packit |
a4058c |
GdipDeleteGraphics (graphics);
|
|
Packit |
a4058c |
GdipDisposeImage ((GpImage *)bitmap);
|
|
Packit |
a4058c |
GdipDisposeImage (metafile);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipFlush (graphics, 1);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipDeleteGraphics (graphics);
|
|
Packit |
a4058c |
GdipDisposeImage (metafile);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return stop_load (bitmap, context, error);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gboolean
|
|
Packit |
a4058c |
gdip_save_to_file_callback (const gchar *buf,
|
|
Packit |
a4058c |
gsize count,
|
|
Packit |
a4058c |
GError **error,
|
|
Packit |
a4058c |
gpointer data)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
FILE *filehandle = data;
|
|
Packit |
a4058c |
gsize n;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
n = fwrite (buf, 1, count, filehandle);
|
|
Packit |
a4058c |
if (n != count) {
|
|
Packit |
a4058c |
gint save_errno = errno;
|
|
Packit |
a4058c |
g_set_error (error,
|
|
Packit |
a4058c |
G_FILE_ERROR,
|
|
Packit |
a4058c |
g_file_error_from_errno (save_errno),
|
|
Packit |
a4058c |
_("Error writing to image file: %s"),
|
|
Packit |
a4058c |
g_strerror (save_errno));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
void
|
|
Packit |
a4058c |
gdip_fill_vtable (GdkPixbufModule *module)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (gdip_init ()) {
|
|
Packit |
a4058c |
module->begin_load = gdk_pixbuf__gdip_image_begin_load;
|
|
Packit |
a4058c |
module->stop_load = gdk_pixbuf__gdip_image_stop_load;
|
|
Packit |
a4058c |
module->load_increment = gdk_pixbuf__gdip_image_load_increment;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
void
|
|
Packit |
a4058c |
gdip_fill_vector_vtable (GdkPixbufModule *module)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if (gdip_init ()) {
|
|
Packit |
a4058c |
module->begin_load = gdk_pixbuf__gdip_image_begin_load;
|
|
Packit |
a4058c |
module->stop_load = gdk_pixbuf__gdip_image_stop_vector_load;
|
|
Packit |
a4058c |
module->load_increment = gdk_pixbuf__gdip_image_load_increment;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
gboolean
|
|
Packit |
a4058c |
gdip_save_pixbuf (GdkPixbuf *pixbuf,
|
|
Packit |
a4058c |
const WCHAR *format,
|
|
Packit |
a4058c |
const EncoderParameters *encoder_params,
|
|
Packit |
a4058c |
GdkPixbufSaveFunc save_func,
|
|
Packit |
a4058c |
gpointer user_data,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GpBitmap *image;
|
|
Packit |
a4058c |
CLSID clsid;
|
|
Packit |
a4058c |
gboolean success;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (!GetEncoderClsid (format, &clsid)) {
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Unsupported image format for GDI+"));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
image = gdip_pixbuf_to_bitmap (pixbuf);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if (image == NULL) {
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Couldn't save"));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
success = gdip_save_bitmap_to_callback (image, &clsid, encoder_params, save_func, user_data, error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdipDisposeImage ((GpImage *)image);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return success;
|
|
Packit |
a4058c |
}
|