summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2005-02-24 04:41:35 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2005-02-24 04:41:35 +0000
commit534d584ba69a9b4c1ceabd17e4498ecc63335607 (patch)
tree0afb6d0d5b2fb43d0ac1d39b8c310a1a38211d8f
parentc06df5a44c552cc757b802ec57cfbb4508be0dae (diff)
downloadgdk-pixbuf-534d584ba69a9b4c1ceabd17e4498ecc63335607.tar.gz
Document BMP saving support.
2005-02-23 Matthias Clasen <mclasen@redhat.com> * gdk-pixbuf-io.c: Document BMP saving support. * io-bmp.c: Support saving as BMP. (168173, Ivan Wong)
-rw-r--r--gdk-pixbuf/ChangeLog4
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.c12
-rw-r--r--gdk-pixbuf/io-bmp.c119
3 files changed, 128 insertions, 7 deletions
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog
index 4bde8bd49..35ad83df4 100644
--- a/gdk-pixbuf/ChangeLog
+++ b/gdk-pixbuf/ChangeLog
@@ -1,5 +1,9 @@
2005-02-23 Matthias Clasen <mclasen@redhat.com>
+ * gdk-pixbuf-io.c: Document BMP saving support.
+
+ * io-bmp.c: Support saving as BMP. (168173, Ivan Wong)
+
* io-ico.c: Fix a typo. (#168173, Ivan Wong)
2005-02-15 Matthias Clasen <mclasen@redhat.com>
diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
index 3afb09f19..28ccaec7b 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.c
+++ b/gdk-pixbuf/gdk-pixbuf-io.c
@@ -1528,8 +1528,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:
*
@@ -1608,7 +1608,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.
*
@@ -1738,7 +1738,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
@@ -1784,7 +1784,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
@@ -1872,7 +1872,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 2724914ab..82882048d 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -1123,12 +1123,129 @@ gdk_pixbuf__bmp_image_load_increment(gpointer data,
return TRUE;
}
+/* for our convenience when filling file header */
+#define put16u(buf,data) { *(guint16*)(buf) = GUINT16_TO_LE (data); buf += 2; }
+#define put32u(buf,data) { *(guint32*)(buf) = GUINT32_TO_LE (data); buf += 4; }
+#define put16(buf,data) { *(gint16*)(buf) = GINT16_TO_LE (data); buf += 2; }
+#define put32(buf,data) { *(gint32*)(buf) = GINT32_TO_LE (data); 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';
+ put32u (dst, size + 14 + 40); /* bfSize */
+ put32u (dst, 0); /* bfReserved1 + bfReserved2 */
+ put32u (dst, 14 + 40); /* bfOffBits */
+
+ /* filling BIH */
+ put32u (dst, 40); /* biSize */
+ put32 (dst, width); /* biWidth */
+ put32 (dst, height); /* biHeight */
+ put16 (dst, 1); /* biPlanes */
+ put16 (dst, 24); /* biBitCount */
+ put32u (dst, BI_RGB); /* biCompression */
+ put32u (dst, size); /* biSizeImage */
+ put32 (dst, 0); /* biXPelsPerMeter */
+ put32 (dst, 0); /* biYPelsPerMeter */
+ put32u (dst, 0); /* biClrUsed */
+ put32u (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
@@ -1154,7 +1271,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";
}