pixbuf saving
- From: Havoc Pennington <hp redhat com>
- To: "David N. Welton" <davidw linuxcare com>, federico helixcode com, gtk-devel-list gnome org
- Subject: pixbuf saving
- Date: 05 Oct 2000 20:36:58 -0400
Hi,
I went back to the list archives and got David's pixbuf saving patch
and revised it for GTK+ HEAD (not committed yet).
I made some small changes:
- used the key-value varargs list instead of a struct for the
save options, Owen requested this (the struct wouldn't work
really - it at minimum would need to come with a bitfield
in the way GdkWindowAttributes does)
- added GError support, though I didn't yet sort out how to get
from the setjmp/longjmp mess to actually setting the GError
(I want to do this when I add error handling for loading,
see below)
- reformatting/reindentation
- renamed save_to_file to be save_to_stream() since it saves to
a FILE*
That's it I think, patch appended.
Federico, I believe this change is unsuitable for gdk-pixbuf 1.0,
since it involves API additions and requires GError.
After merging the bugfixes to gdk-pixbuf 1.0 into HEAD, I want to add
GError support to the loader; this change is definitely for HEAD only,
because it breaks the new_from_* APIs.
If there are no objections I'll commit this shortly.
Havoc
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1416
diff -u -u -r1.1416 ChangeLog
--- ChangeLog 2000/10/05 01:04:57 1.1416
+++ ChangeLog 2000/10/06 00:34:00
@@ -1,3 +1,9 @@
+2000-10-05 Havoc Pennington <hp redhat com>
+
+ * demos/testpixbuf-save.c: add pixbuf save test
+
+ * demos/Makefile.am: add testpixbuf-save.c
+
2000-10-04 <jrb redhat com>
* gtk/gtk{tree,cell}?*.[ch]: Checked in initial draft of the new
Index: demos/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/demos/Makefile.am,v
retrieving revision 1.6
diff -u -u -r1.6 Makefile.am
--- demos/Makefile.am 2000/10/04 16:39:43 1.6
+++ demos/Makefile.am 2000/10/06 00:34:00
@@ -34,6 +34,7 @@
testpixbuf \
testpixbuf-drawable \
testanimation \
+ testpixbuf-save \
testpixbuf-scale \
pixbuf-demo
@@ -44,18 +45,21 @@
testpixbuf_DEPENDENCIES = $(DEPS)
testpixbuf_drawable_DEPENDENCIES = $(DEPS)
+testpixbuf_save_DEPENDENCIES = $(DEPS)
testpixbuf_scale_DEPENDENCIES = $(DEPS)
testanimation_DEPENDENCIES = $(DEPS)
pixbuf_demo_DEPENDENCIES = $(DEPS)
testpixbuf_LDADD = $(LDADDS)
testpixbuf_drawable_LDADD = $(LDADDS)
+testpixbuf_save_LDADD = $(LDADDS)
testpixbuf_scale_LDADD = $(LDADDS)
testanimation_LDADD = $(LDADDS)
pixbuf_demo_LDADD = $(LDADDS)
testpixbuf_SOURCES = testpixbuf.c pixbuf-init.c
testpixbuf_drawable_SOURCES = testpixbuf-drawable.c pixbuf-init.c
+testpixbuf_save_SOURCES = testpixbuf-save.c
testpixbuf_scale_SOURCES = testpixbuf-scale.c pixbuf-init.c
testanimation_SOURCES = testanimation.c pixbuf-init.c
pixbuf_demo_SOURCES = pixbuf-demo.c pixbuf-init.c
Index: demos/testpixbuf-save.c
===================================================================
RCS file: testpixbuf-save.c
diff -N testpixbuf-save.c
--- /dev/null Tue May 5 16:32:27 1998
+++ testpixbuf-save.c Thu Oct 5 20:34:00 2000
@@ -0,0 +1,153 @@
+
+#include <config.h>
+/* if building outside GTK, remove /x11 part */
+#include <gdk/x11/gdkx.h>
+#include <gtk/gtk.h>
+
+
+void
+keypress_check (GtkWidget *widget, GdkEventKey *evt, gpointer data)
+{
+ GdkPixbuf *pixbuf;
+ GtkDrawingArea *da = (GtkDrawingArea*)data;
+ GError *err = NULL;
+
+ pixbuf = (GdkPixbuf *) gtk_object_get_data (GTK_OBJECT (da), "pixbuf");
+
+ if (evt->keyval == 'q')
+ gtk_main_quit ();
+ if (evt->keyval == 's') {
+ if (pixbuf == NULL) {
+ fprintf (stderr, "PIXBUF NULL\n");
+ return;
+ }
+
+ if (!gdk_pixbuf_save (pixbuf, "foo.jpg", "jpeg",
+ &err,
+ "quality", "100",
+ NULL)) {
+ fprintf (stderr, "%s", err->message);
+ g_error_free (err);
+ }
+
+ } else if (evt->keyval == 'p') {
+ if (pixbuf == NULL) {
+ fprintf (stderr, "PIXBUF NULL\n");
+ return;
+ }
+
+ if (!gdk_pixbuf_save (pixbuf, "foo.png", "png", &err, NULL)) {
+ fprintf (stderr, "%s", err->message);
+ g_error_free (err);
+ }
+ }
+}
+
+
+int
+close_app (GtkWidget *widget, gpointer data)
+{
+ gtk_main_quit ();
+ return TRUE;
+}
+
+int
+expose_cb (GtkWidget *drawing_area, GdkEventExpose *evt, gpointer data)
+{
+ GdkPixbuf *pixbuf;
+
+ pixbuf = (GdkPixbuf *) gtk_object_get_data (GTK_OBJECT (drawing_area),
+ "pixbuf");
+ if (gdk_pixbuf_get_has_alpha (pixbuf)) {
+ gdk_draw_rgb_32_image (drawing_area->window,
+ drawing_area->style->black_gc,
+ evt->area.x, evt->area.y,
+ evt->area.width,
+ evt->area.height,
+ GDK_RGB_DITHER_MAX,
+ gdk_pixbuf_get_pixels (pixbuf) +
+ (evt->area.y * gdk_pixbuf_get_rowstride (pixbuf)) +
+ (evt->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
+ gdk_pixbuf_get_rowstride (pixbuf));
+ } else {
+ gdk_draw_rgb_image (drawing_area->window,
+ drawing_area->style->black_gc,
+ evt->area.x, evt->area.y,
+ evt->area.width,
+ evt->area.height,
+ GDK_RGB_DITHER_NORMAL,
+ gdk_pixbuf_get_pixels (pixbuf) +
+ (evt->area.y * gdk_pixbuf_get_rowstride (pixbuf)) +
+ (evt->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
+ gdk_pixbuf_get_rowstride (pixbuf));
+ }
+ return FALSE;
+}
+
+int
+configure_cb (GtkWidget *drawing_area, GdkEventConfigure *evt, gpointer data)
+{
+ GdkPixbuf *pixbuf;
+
+ pixbuf = (GdkPixbuf *) gtk_object_get_data (GTK_OBJECT (drawing_area),
+ "pixbuf");
+
+ g_print ("X:%d Y:%d\n", evt->width, evt->height);
+ if (evt->width != gdk_pixbuf_get_width (pixbuf) || evt->height != gdk_pixbuf_get_height (pixbuf)) {
+ GdkWindow *root;
+ GdkPixbuf *new_pixbuf;
+
+ root = GDK_ROOT_PARENT ();
+ new_pixbuf = gdk_pixbuf_get_from_drawable (NULL, root, NULL,
+ 0, 0, 0, 0, evt->width, evt->height);
+ gtk_object_set_data (GTK_OBJECT (drawing_area), "pixbuf", new_pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ }
+
+ return FALSE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GdkWindow *root;
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *drawing_area;
+ GdkPixbuf *pixbuf;
+
+ gtk_init (&argc, &argv);
+
+ gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
+
+ root = GDK_ROOT_PARENT ();
+ pixbuf = gdk_pixbuf_get_from_drawable (NULL, root, NULL,
+ 0, 0, 0, 0, 150, 160);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (close_app), NULL);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC (close_app), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ drawing_area = gtk_drawing_area_new ();
+ gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area),
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf));
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+ GTK_SIGNAL_FUNC (expose_cb), NULL);
+
+ gtk_signal_connect (GTK_OBJECT (drawing_area), "configure_event",
+ GTK_SIGNAL_FUNC (configure_cb), NULL);
+ gtk_signal_connect (GTK_OBJECT (window), "key_press_event",
+ GTK_SIGNAL_FUNC (keypress_check), drawing_area);
+ gtk_object_set_data (GTK_OBJECT (drawing_area), "pixbuf", pixbuf);
+ gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (window);
+ gtk_main ();
+ return 0;
+}
Index: gdk-pixbuf/ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/ChangeLog,v
retrieving revision 1.251
diff -u -u -r1.251 ChangeLog
--- gdk-pixbuf/ChangeLog 2000/10/05 21:40:37 1.251
+++ gdk-pixbuf/ChangeLog 2000/10/06 00:34:00
@@ -1,3 +1,25 @@
+2000-10-05 Havoc Pennington <hp redhat com>
+
+ * Makefile.am (GDK_PIXBUF_LIBS): add INTLLIBS
+ (libgdk_pixbuf_1_3_la_SOURCES): add gdk-pixbuf-i18n.h
+
+ * gdk-pixbuf-i18n.h: Add _() to gdk-pixbuf
+
+ * io-png.c (gdk_pixbuf__png_image_save): PNG save routine.
+
+ * io-jpeg.c (gdk_pixbuf__jpeg_image_save): JPEG save routine.
+
+ * gdk-pixbuf-io.c (gdk_pixbuf_save):
+ (gdk_pixbuf_save_to_stream): Implement pixbuf saving routines
+
+ * gdk-pixbuf.c (gdk_pixbuf_error_quark): pixbuf error quark
+ function
+
+ * gdk-pixbuf.h: Add public save routines; add pixbuf error
+ types
+
+ * gdk-pixbuf-io.h: Add save function to GdkPixbufModule
+
2000-10-05 Dan Winship <danw helixcode com>
* io-png.c, io-tiff.c, io-xpm.c: Fix comments to not claim that
Index: gdk-pixbuf/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/Makefile.am,v
retrieving revision 1.76
diff -u -u -r1.76 Makefile.am
--- gdk-pixbuf/Makefile.am 2000/09/26 20:22:17 1.76
+++ gdk-pixbuf/Makefile.am 2000/10/06 00:34:00
@@ -154,7 +154,7 @@
make_inline_pixbuf_LDADD = $(LDADDS)
-GDK_PIXBUF_LIBS = $(GLIB_LIBS)
+GDK_PIXBUF_LIBS = $(GLIB_LIBS) $(INTLLIBS)
#
# The GdkPixBuf library
@@ -163,6 +163,7 @@
libgdk_pixbufincludedir = $(includedir)/gtk-2.0/gdk-pixbuf
libgdk_pixbuf_1_3_la_SOURCES = \
+ gdk-pixbuf-i18n.h \
gdk-pixbuf.c \
gdk-pixbuf-animation.c \
gdk-pixbuf-data.c \
Index: gdk-pixbuf/gdk-pixbuf-i18n.h
===================================================================
RCS file: gdk-pixbuf-i18n.h
diff -N gdk-pixbuf-i18n.h
--- /dev/null Tue May 5 16:32:27 1998
+++ gdk-pixbuf-i18n.h Thu Oct 5 20:34:00 2000
@@ -0,0 +1,24 @@
+#ifndef __GDKPIXBUFINTL_H__
+#define __GDKPIXBUFINTL_H__
+
+#include "config.h"
+
+#ifdef ENABLE_NLS
+#include<libintl.h>
+#define _(String) dgettext(GETTEXT_PACKAGE,String)
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#else /* NLS is disabled */
+#define _(String) (String)
+#define N_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define bindtextdomain(Domain,Directory) (Domain)
+#endif
+
+#endif
Index: gdk-pixbuf/gdk-pixbuf-io.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.c,v
retrieving revision 1.44
diff -u -u -r1.44 gdk-pixbuf-io.c
--- gdk-pixbuf/gdk-pixbuf-io.c 2000/07/28 00:16:17 1.44
+++ gdk-pixbuf/gdk-pixbuf-io.c 2000/10/06 00:34:00
@@ -24,6 +24,7 @@
#include <config.h>
#include <string.h>
#include <glib.h>
+#include <errno.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"
@@ -185,17 +186,17 @@
}
static GdkPixbufModule file_formats [] = {
- { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL },
- { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL },
- { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL },
- { "gif", pixbuf_check_gif, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL, NULL, },
+ { "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "tiff", pixbuf_check_tiff, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "gif", pixbuf_check_gif, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
#define XPM_FILE_FORMAT_INDEX 4
- { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL },
- { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL },
- { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL },
- { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL },
- { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL },
- { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "xpm", pixbuf_check_xpm, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "pnm", pixbuf_check_pnm, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
+ { "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -281,6 +282,7 @@
char *path;
GModule *module;
gpointer load_sym;
+ gpointer save_sym;
char *name;
g_return_if_fail (image_module->module == NULL);
@@ -333,6 +335,9 @@
if (pixbuf_module_symbol (module, name, "image_load_animation", &load_sym))
image_module->load_animation = load_sym;
+
+ if (pixbuf_module_symbol (module, name, "image_save", &save_sym))
+ image_module->save = save_sym;
}
#else
@@ -354,6 +359,7 @@
m_begin_load (png);
m_load_increment (png);
m_stop_load (png);
+m_save (png);
/* BMP */
m_load (bmp);
m_begin_load (bmp);
@@ -380,6 +386,7 @@
m_begin_load (jpeg);
m_load_increment (jpeg);
m_stop_load (jpeg);
+m_save (jpeg);
/* PNM */
m_load (pnm);
m_begin_load (pnm);
@@ -409,6 +416,7 @@
image_module->begin_load = mname (png,begin_load);
image_module->load_increment = mname (png,load_increment);
image_module->stop_load = mname (png,stop_load);
+ image_module->save = mname (png,save);
return;
}
@@ -450,6 +458,7 @@
image_module->begin_load = mname (jpeg,begin_load);
image_module->load_increment = mname (jpeg,load_increment);
image_module->stop_load = mname (jpeg,stop_load);
+ image_module->save = mname (jpeg,save);
return;
}
if (strcmp (image_module->module_name, "pnm") == 0){
@@ -595,4 +604,205 @@
pixbuf = (* load_xpm_data) (data);
return pixbuf;
+}
+
+static void
+collect_save_options (va_list opts,
+ gchar ***keys,
+ gchar ***vals)
+{
+ gchar *key;
+ gchar *val;
+ gchar *next;
+ gint count;
+
+ count = 0;
+ *keys = NULL;
+ *vals = NULL;
+
+ next = va_arg (opts, gchar*);
+ while (next)
+ {
+ key = next;
+ val = va_arg (opts, gchar*);
+
+ ++count;
+
+ *keys = g_realloc (*keys, sizeof(gchar*) * (count + 1));
+ *vals = g_realloc (*vals, sizeof(gchar*) * (count + 1));
+
+ (*keys)[count-1] = g_strdup (key);
+ (*vals)[count-1] = g_strdup (val);
+
+ (*keys)[count] = NULL;
+ (*vals)[count] = NULL;
+
+ next = va_arg (opts, gchar*);
+ }
+}
+
+static gboolean
+gdk_pixbuf_real_save (GdkPixbuf *pixbuf,
+ FILE *filehandle,
+ const char *format,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ int i;
+ GdkPixbufModule *image_module = NULL;
+
+ for (i = 0; file_formats[i].module_name; i++) {
+ if (!strcmp (file_formats[i].module_name, format))
+ image_module = &(file_formats[i]);
+ }
+
+ g_return_val_if_fail (image_module != NULL, FALSE);
+ if (!image_module) {
+ g_warning ("gdk-pixbuf does not support the format: %s", format);
+ fclose (filehandle);
+ return FALSE;
+ }
+
+ if (image_module->module == NULL)
+ gdk_pixbuf_load_module (image_module);
+
+ g_return_val_if_fail (image_module->save != NULL, FALSE);
+
+
+
+ return (* image_module->save) (filehandle, pixbuf,
+ keys, values,
+ error);
+}
+
+/**
+ * gdk_pixbuf_save_to_stream:
+ * @pixbuf: pointer to GdkPixbuf.
+ * @filehandle: FILE* to save to.
+ * @format: name of file format.
+ * @error: error return location, or NULL
+ * @Varargs: key-value pairs of properties affecting the save
+ *
+ * Saves pixbuf to a filehandle in @format. @format can be "png" or "jpeg".
+ * @error is a return location for an error while saving. The variable
+ * argument list should be NULL-terminated; if not empty, it should contain
+ * pairs of strings that modify the save parameters. For example:
+ *
+ * <programlisting>
+ * gdk_pixbuf_save_to_file (pixbuf, handle, "jpeg", &error,
+ * "quality", "100", NULL);
+ * </programlisting>
+ *
+ * The only save parameter that currently exists is the "quality" field
+ * for JPEG images; its value should be in the range [0,100].
+ *
+ * Return value: TRUE on success, FALSE on failure.
+ **/
+
+gboolean
+gdk_pixbuf_save_to_stream (GdkPixbuf *pixbuf,
+ FILE *filehandle,
+ const char *format,
+ GError **error,
+ ...)
+{
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+ gboolean result;
+
+ g_return_val_if_fail (filehandle != NULL, FALSE);
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ va_start (args, error);
+
+ collect_save_options (args, &keys, &values);
+
+ va_end (args);
+
+ result = gdk_pixbuf_real_save (pixbuf, filehandle, format,
+ keys, values, error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ return result;
+}
+
+
+/**
+ * gdk_pixbuf_save:
+ * @pixbuf: pointer to GdkPixbuf.
+ * @filename: Name of file to save.
+ * @format: name of file format.
+ * @error: return location for error, or NULL
+ * @Varargs: list of key-value save options
+ *
+ * Saves pixbuf to a file in @format, which is currently "jpeg" or "png".
+ * If @error is set, FALSE will be returned. The variable argument list
+ * should be NULL-terminated and should be key-value pairs setting
+ * options for the save. See gdk_pixbuf_save_to_stream() for more
+ * details.
+ *
+ * Return value: whether an error was set
+ **/
+
+
+gboolean
+gdk_pixbuf_save (GdkPixbuf *pixbuf,
+ const char *filename,
+ const char *format,
+ GError **error,
+ ...)
+{
+ FILE *f = NULL;
+ gchar **keys = NULL;
+ gchar **values = NULL;
+ va_list args;
+ gboolean result;
+
+
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (format != NULL, FALSE);
+
+ f = fopen (filename, "w");
+
+ if (f == NULL) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_IO,
+ _("Failed to open '%s' for writing: %s"),
+ filename, g_strerror (errno));
+ return FALSE;
+ }
+
+ va_start (args, error);
+
+ collect_save_options (args, &keys, &values);
+
+ va_end (args);
+
+ result = gdk_pixbuf_real_save (pixbuf, f, format,
+ keys, values, error);
+
+ g_strfreev (keys);
+ g_strfreev (values);
+
+ if (!result) {
+ g_return_val_if_fail (error == NULL || *error != NULL, FALSE);
+ fclose (f);
+ return FALSE;
+ }
+
+ if (fclose (f) < 0) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_IO,
+ _("Failed to close '%s' while writing image, all data may not have been saved: %s"),
+ filename, g_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
}
Index: gdk-pixbuf/gdk-pixbuf-io.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf-io.h,v
retrieving revision 1.20
diff -u -u -r1.20 gdk-pixbuf-io.h
--- gdk-pixbuf/gdk-pixbuf-io.h 2000/07/28 00:09:35 1.20
+++ gdk-pixbuf/gdk-pixbuf-io.h 2000/10/06 00:34:00
@@ -31,6 +31,7 @@
#include <gmodule.h>
#include <stdio.h>
#include "gdk-pixbuf.h"
+#include "gdk-pixbuf-i18n.h"
#ifdef __cplusplus
extern "C" {
@@ -64,11 +65,19 @@
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data);
- void (* stop_load) (gpointer context);
- gboolean (* load_increment) (gpointer context, const guchar *buf, guint size);
+ void (* stop_load) (gpointer context);
+ gboolean (* load_increment) (gpointer context,
+ const guchar *buf,
+ guint size);
/* Animation loading */
GdkPixbufAnimation *(* load_animation) (FILE *f);
+
+ gboolean (* save) (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **param_keys,
+ gchar **param_values,
+ GError **err);
};
Index: gdk-pixbuf/gdk-pixbuf.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.c,v
retrieving revision 1.35
diff -u -u -r1.35 gdk-pixbuf.c
--- gdk-pixbuf/gdk-pixbuf.c 2000/07/26 11:32:39 1.35
+++ gdk-pixbuf/gdk-pixbuf.c 2000/10/06 00:34:00
@@ -361,3 +361,14 @@
gdk_pixbuf_preinit (NULL, NULL);
gdk_pixbuf_postinit (NULL, NULL);
}
+
+/* Error quark */
+GQuark
+gdk_pixbuf_error_quark (void)
+{
+ static GQuark q = 0;
+ if (q == 0)
+ q = g_quark_from_static_string ("gdk-pixbuf-error-quark");
+
+ return q;
+}
Index: gdk-pixbuf/gdk-pixbuf.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/gdk-pixbuf.h,v
retrieving revision 1.46
diff -u -u -r1.46 gdk-pixbuf.h
--- gdk-pixbuf/gdk-pixbuf.h 2000/09/26 20:22:17 1.46
+++ gdk-pixbuf/gdk-pixbuf.h 2000/10/06 00:34:00
@@ -29,6 +29,7 @@
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf-features.h>
#include <gobject/gobject.h>
+#include <stdio.h>
#ifdef __cplusplus
extern "C" {
@@ -61,6 +62,18 @@
/* Handler that must free the pixel array */
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
+#define GDK_PIXBUF_ERROR gdk_pixbuf_error_quark ()
+
+typedef enum {
+ /* some kind of failure reading or writing files */
+ GDK_PIXBUF_ERROR_IO,
+ /* bad option passed to save routine */
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ GDK_PIXBUF_ERROR_FAILED
+} GdkPixbufErrorType;
+
+GQuark gdk_pixbuf_error_quark () G_GNUC_CONST;
+
GType gdk_pixbuf_get_type (void) G_GNUC_CONST;
@@ -110,6 +123,21 @@
GdkPixbuf *gdk_pixbuf_new_from_inline (const guchar *inline_pixbuf,
gboolean copy_pixels,
int length);
+
+
+/* Saving */
+
+
+gboolean gdk_pixbuf_save_to_stream (GdkPixbuf *pixbuf,
+ FILE *filehandle,
+ const char *format,
+ GError **error,
+ ...);
+gboolean gdk_pixbuf_save (GdkPixbuf *pixbuf,
+ const char *filename,
+ const char *format,
+ GError **err,
+ ...);
/* Adding an alpha channel */
GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color,
Index: gdk-pixbuf/io-jpeg.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-jpeg.c,v
retrieving revision 1.31
diff -u -u -r1.31 io-jpeg.c
--- gdk-pixbuf/io-jpeg.c 2000/07/26 11:32:40 1.31
+++ gdk-pixbuf/io-jpeg.c 2000/10/06 00:34:00
@@ -565,3 +565,114 @@
return TRUE;
}
+
+gboolean
+gdk_pixbuf__jpeg_image_save (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ /* FIXME error handling is broken */
+
+ struct jpeg_compress_struct cinfo;
+ guchar *buf = NULL;
+ guchar *ptr;
+ guchar *pixels = NULL;
+ JSAMPROW *jbuf;
+ int y = 0;
+ int quality = 75; /* default; must be between 0 and 100 */
+ int i, j;
+ int w, h = 0;
+ int rowstride = 0;
+ struct error_handler_data jerr;
+
+ if (keys && *keys) {
+ gchar **kiter = keys;
+ gchar **viter = values;
+
+ while (*kiter) {
+ if (strcmp (*kiter, "quality") == 0) {
+ quality = atoi (*viter);
+ if (quality < 0 ||
+ quality > 100) {
+ /* This is a user-visible error;
+ * lets people skip the range-checking
+ * in their app.
+ */
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_BAD_OPTION,
+ _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."),
+ quality);
+
+ return FALSE;
+ }
+ } else {
+ g_warning ("Bad option name '%s' passed to JPEG saver",
+ *kiter);
+ return FALSE;
+ }
+
+ ++kiter;
+ ++viter;
+ }
+ }
+
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+
+ /* no image data? abort */
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ g_return_val_if_fail (pixels != NULL, FALSE);
+
+ /* allocate a small buffer to convert image data */
+ buf = malloc (w * 3 * sizeof (guchar));
+ g_return_val_if_fail (buf != NULL, FALSE);
+
+ /* set up error handling */
+ jerr.pub.error_exit = fatal_error_handler;
+
+ cinfo.err = jpeg_std_error (&(jerr.pub));
+ if (sigsetjmp (jerr.setjmp_buffer, 1)) {
+ jpeg_destroy_compress (&cinfo);
+ free (buf);
+ return FALSE;
+ }
+
+ /* setup compress params */
+ jpeg_create_compress (&cinfo);
+ jpeg_stdio_dest (&cinfo, f);
+ cinfo.image_width = w;
+ cinfo.image_height = h;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ /* set up jepg compression parameters */
+ jpeg_set_defaults (&cinfo);
+ jpeg_set_quality (&cinfo, quality, TRUE);
+ jpeg_start_compress (&cinfo, TRUE);
+ /* get the start pointer */
+ ptr = pixels;
+ /* go one scanline at a time... and save */
+ i = 0;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* convert scanline from ARGB to RGB packed */
+ for (j = 0; j < w; j++)
+ memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*3]), 3);
+
+ /* write scanline */
+ jbuf = (JSAMPROW *)(&buf);
+ jpeg_write_scanlines (&cinfo, jbuf, 1);
+ i++;
+ y++;
+
+ }
+
+ /* finish off */
+ jpeg_finish_compress (&cinfo);
+ free (buf);
+ return TRUE;
+}
Index: gdk-pixbuf/io-png.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk-pixbuf/io-png.c,v
retrieving revision 1.32
diff -u -u -r1.32 io-png.c
--- gdk-pixbuf/io-png.c 2000/10/05 21:40:37 1.32
+++ gdk-pixbuf/io-png.c 2000/10/06 00:34:00
@@ -537,5 +537,112 @@
}
+/* Save */
+gboolean
+gdk_pixbuf__png_image_save (FILE *f,
+ GdkPixbuf *pixbuf,
+ gchar **keys,
+ gchar **values,
+ GError **error)
+{
+ /* FIXME error handling is broken */
+
+ png_structp png_ptr;
+ png_infop info_ptr;
+ guchar *ptr;
+ guchar *pixels;
+ int x, y, j;
+ png_bytep row_ptr, data = NULL;
+ png_color_8 sig_bit;
+ int w, h, rowstride;
+ int has_alpha;
+ int bpc;
+
+ if (keys && *keys) {
+ g_warning ("Bad option name '%s' passed to JPEG saver",
+ *keys);
+ return FALSE;
+#if 0
+ gchar **kiter = keys;
+ gchar **viter = values;
+
+
+ while (*kiter) {
+
+ ++kiter;
+ ++viter;
+ }
+#endif
+ }
+
+ bpc = gdk_pixbuf_get_bits_per_sample (pixbuf);
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+
+ g_return_val_if_fail (png_ptr != NULL, FALSE);
+
+ info_ptr = png_create_info_struct (png_ptr);
+ if (info_ptr == NULL) {
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+ if (setjmp (png_ptr->jmpbuf)) {
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+ return FALSE;
+ }
+ png_init_io (png_ptr, f);
+ if (has_alpha) {
+ png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
+ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+#ifdef WORDS_BIGENDIAN
+ png_set_swap_alpha (png_ptr);
+#else
+ png_set_bgr (png_ptr);
+#endif
+ } else {
+ png_set_IHDR (png_ptr, info_ptr, w, h, bpc,
+ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+ data = malloc (w * 3 * sizeof (char));
+ }
+ sig_bit.red = bpc;
+ sig_bit.green = bpc;
+ sig_bit.blue = bpc;
+ sig_bit.alpha = bpc;
+ png_set_sBIT (png_ptr, info_ptr, &sig_bit);
+ png_write_info (png_ptr, info_ptr);
+ png_set_shift (png_ptr, &sig_bit);
+ png_set_packing (png_ptr);
+
+ ptr = pixels;
+ for (y = 0; y < h; y++) {
+ if (has_alpha)
+ row_ptr = (png_bytep)ptr;
+ else {
+ for (j = 0, x = 0; x < w; x++)
+ memcpy (&(data[x*3]), &(ptr[x*3]), 3);
+
+ row_ptr = (png_bytep)data;
+ }
+ png_write_rows (png_ptr, &row_ptr, 1);
+ ptr += rowstride;
+ }
+
+ if (data)
+ free (data);
+
+ png_write_end (png_ptr, info_ptr);
+ png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+
+ return TRUE;
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]