From a39beed50362e8a27edcba944c45d9bbf9c3c0b4 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 30 Mar 2005 19:42:30 +0000 Subject: [PATCH] Document BMP saving support. 2005-03-30 Matthias Clasen * gdk-pixbuf-io.c: Document BMP saving support. * io-bmp.c: Support saving as BMP. (168173, Ivan Wong) --- gdk-pixbuf/ChangeLog | 6 ++ gdk-pixbuf/gdk-pixbuf-io.c | 12 ++-- gdk-pixbuf/io-bmp.c | 123 ++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index 81895b247d..27beb89f93 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,9 @@ +2005-03-30 Matthias Clasen + + * gdk-pixbuf-io.c: Document BMP saving support. + + * io-bmp.c: Support saving as BMP. (168173, Ivan Wong) + 2005-03-29 Matthias Clasen * io-tga.c (parse_rle_data): Fix the update areas for incremental diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c index 5a3ccadf0a..8d9d748345 100644 --- a/gdk-pixbuf/gdk-pixbuf-io.c +++ b/gdk-pixbuf/gdk-pixbuf-io.c @@ -1527,8 +1527,8 @@ gdk_pixbuf_real_save_to_callback (GdkPixbuf *pixbuf, * @error: return location for error, or %NULL * @Varargs: list of key-value save options * - * Saves pixbuf to a file in format @type. By default, "jpeg", "png" and - * "ico" are possible file formats to save in, but more formats may be + * Saves pixbuf to a file in format @type. By default, "jpeg", "png", "ico" + * and "bmp" are possible file formats to save in, but more formats may be * installed. The list of all writable formats can be determined in the * following way: * @@ -1651,7 +1651,7 @@ gdk_pixbuf_save (GdkPixbuf *pixbuf, * @option_values: values for named options * @error: return location for error, or %NULL * - * Saves pixbuf to a file in @type, which is currently "jpeg", "png" or "ico". + * Saves pixbuf to a file in @type, which is currently "jpeg", "png", "ico" or "bmp". * If @error is set, %FALSE will be returned. * See gdk_pixbuf_save () for more details. * @@ -1812,7 +1812,7 @@ gdk_pixbuf_save_to_callback (GdkPixbuf *pixbuf, * @error: return location for error, or %NULL * * Saves pixbuf to a callback in format @type, which is currently "jpeg", - * "png" or "ico". If @error is set, %FALSE will be returned. See + * "png", "ico" or "bmp". If @error is set, %FALSE will be returned. See * gdk_pixbuf_save_to_callback () for more details. * * Return value: whether an error was set @@ -1858,7 +1858,7 @@ gdk_pixbuf_save_to_callbackv (GdkPixbuf *pixbuf, * @Varargs: list of key-value save options * * Saves pixbuf to a new buffer in format @type, which is currently "jpeg", - * "png" or "ico". This is a convenience function that uses + * "png", "ico" or "bmp". This is a convenience function that uses * gdk_pixbuf_save_to_callback() to do the real work. Note that the buffer * is not nul-terminated and may contain embedded nuls. * If @error is set, %FALSE will be returned and @string will be set to @@ -1946,7 +1946,7 @@ save_to_buffer_callback (const gchar *data, * @error: return location for error, or %NULL * * Saves pixbuf to a new buffer in format @type, which is currently "jpeg", - * "png" or "ico". See gdk_pixbuf_save_to_buffer() for more details. + * "png", "ico" or "bmp". See gdk_pixbuf_save_to_buffer() for more details. * * Return value: whether an error was set * diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c index 9b6292cfab..4cdcc112c3 100644 --- a/gdk-pixbuf/io-bmp.c +++ b/gdk-pixbuf/io-bmp.c @@ -1136,12 +1136,133 @@ gdk_pixbuf__bmp_image_load_increment(gpointer data, return TRUE; } +/* for our convenience when filling file header */ +#define put16(buf,data) { guint16 x; \ + x = GUINT16_TO_LE (data); \ + memcpy(buf, &x, 2); \ + buf += 2; } +#define put32(buf,data) { guint32 x; \ + x = GUINT32_TO_LE (data); \ + memcpy(buf, &x, 4); \ + buf += 4; } + +static gboolean +gdk_pixbuf__bmp_image_save_to_callback (GdkPixbufSaveFunc save_func, + gpointer user_data, + GdkPixbuf *pixbuf, + gchar **keys, + gchar **values, + GError **error) +{ + guint width, height, channel, size, stride, src_stride, x, y; + guchar BFH_BIH[40], *pixels, *buf, *src, *dst, *dst_line; + gboolean ret; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + channel = gdk_pixbuf_get_n_channels (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + src_stride = gdk_pixbuf_get_rowstride (pixbuf); + stride = (width * 3 + 3) & ~3; + size = stride * height; + + /* filling BFH */ + dst = BFH_BIH; + *dst++ = 'B'; /* bfType */ + *dst++ = 'M'; + put32 (dst, size + 14 + 40); /* bfSize */ + put32 (dst, 0); /* bfReserved1 + bfReserved2 */ + put32 (dst, 14 + 40); /* bfOffBits */ + + /* filling BIH */ + put32 (dst, 40); /* biSize */ + put32 (dst, width); /* biWidth */ + put32 (dst, height); /* biHeight */ + put16 (dst, 1); /* biPlanes */ + put16 (dst, 24); /* biBitCount */ + put32 (dst, BI_RGB); /* biCompression */ + put32 (dst, size); /* biSizeImage */ + put32 (dst, 0); /* biXPelsPerMeter */ + put32 (dst, 0); /* biYPelsPerMeter */ + put32 (dst, 0); /* biClrUsed */ + put32 (dst, 0); /* biClrImportant */ + + if (!save_func (BFH_BIH, 14 + 40, error, user_data)) + return FALSE; + + dst_line = buf = g_try_malloc (size); + if (!buf) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, + _("Couldn't allocate memory for saving BMP file")); + return FALSE; + } + + /* saving as a bottom-up bmp */ + pixels += (height - 1) * src_stride; + for (y = 0; y < height; ++y, pixels -= src_stride, dst_line += stride) { + dst = dst_line; + src = pixels; + for (x = 0; x < width; ++x, dst += 3, src += channel) { + dst[0] = src[2]; + dst[1] = src[1]; + dst[2] = src[0]; + } + } + ret = save_func (buf, size, error, user_data); + g_free (buf); + + return ret; +} + +static gboolean +save_to_file_cb (const gchar *buf, + gsize count, + GError **error, + gpointer data) +{ + gint bytes; + + while (count > 0) { + bytes = fwrite (buf, sizeof (gchar), count, (FILE *) data); + if (bytes <= 0) + break; + count -= bytes; + buf += bytes; + } + + if (count) { + g_set_error (error, + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + _("Couldn't write to BMP file")); + return FALSE; + } + + return TRUE; +} + +static gboolean +gdk_pixbuf__bmp_image_save (FILE *f, + GdkPixbuf *pixbuf, + gchar **keys, + gchar **values, + GError **error) +{ + return gdk_pixbuf__bmp_image_save_to_callback (save_to_file_cb, + f, pixbuf, keys, + values, error); +} + void MODULE_ENTRY (bmp, fill_vtable) (GdkPixbufModule *module) { module->begin_load = gdk_pixbuf__bmp_image_begin_load; module->stop_load = gdk_pixbuf__bmp_image_stop_load; module->load_increment = gdk_pixbuf__bmp_image_load_increment; + module->save = gdk_pixbuf__bmp_image_save; + module->save_to_callback = gdk_pixbuf__bmp_image_save_to_callback; } void @@ -1167,7 +1288,7 @@ MODULE_ENTRY (bmp, fill_info) (GdkPixbufFormat *info) info->description = N_("The BMP image format"); info->mime_types = mime_types; info->extensions = extensions; - info->flags = GDK_PIXBUF_FORMAT_THREADSAFE; + info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE; info->license = "LGPL"; }