Re: gdk-pixbuf-save



On Thu, Jun 22, 2000 at 09:18:37AM -0400, Owen Taylor wrote:

> OK, I finally had a chance to look at your patch - I've just gotten
> around to integrating gdk-pixbuf into GTK+-1.3 after spending a lot
> of time on other issues. It looks pretty good, and I see no reason
> it shouldn't go in.

Great, thankyou for taking the time to go through it.

> I do have a number of comments and suggestions, of course :-)

Much appreciated.

> I suspect the save module should be allowed to fail internally and return
> a status:

>  return (* image_module->save) (filehandle, pixbuf, imginfo);

Done.

> +	fclose (filehandle);

> If you don't open the filehandle, don't close it. If the file handle came
> from popen(), then you would need pclose() to close it, etc. If you were
> closing the stream, you would need to check for error here.

Oops, good point.

> +
> +/* It would probably be best if this were a void pointer to whatever
> +   data we want to associate with an image */
> +typedef struct {
> +    int quality;
> +} GdkPixbufInfo;

> IMO, the right way to do it it with string pairs - this strikes a balance
> between simplicity and flexibility:

> gboolean gdk_pixbuf_save_to_file       (GdkPixbuf     *pixbuf,
> 					const char    *filename,
> 					const char    *format,
> 					...);
> gboolean gdk_pixbuf_save_to_filev      (GdkPixbuf     *pixbuf,
> 					const char    *filename,
> 					const char    *format,
> 					char **        args);

> The 'v' format would be the one that the module-interface would use.
> (The args array is NULL terminated.)

> So, you have:

>  gdk_pixbuf_save_to_file (pixbuf, "my.jpg", "jpeg", "quality", "0.8", NULL);

> Or something like that. People will sometimes have to do:

>  char *val = g_strdup_printf ("%f", quality);
>  gdk_pixbuf_save_to_file (pixbuf, "my.jpg", "jpeg", "quality", val, NULL);
>  g_free (val);

Ok, this is a good idea.  I think there is some possibility for
discussion in this area, though.  The current interface was something
I put together when it looked like Federico was not at all interested
in putting this functionality in.  However, if "gdk-pixbuf-save" is
not a seperate library, then it is possible to carry this data through
the life cycle of an image (in some cases).  I.e., at load time, you
could get some information about the image, store it, and possibly
access it when you go to save it.

I get the feeling that people would not like to get too complex, so it
shouldn't be anything that must be used, or that adds a lot of
overhead - but it might be convenient.

> I think the names here should be a bit different. I would use:

>  gdk_pixbuf_save (...const char *filename....)
>  gdk_pixbuf_save_to_file (...FILE *filehandle...)

Done.

> +static void 
> +error_handler(j_common_ptr cinfo)

In a c++ program I was working with, these seemed to be causing some
problems, so I ifdef'ed and commented everything out aside from the
original fatal error handler.  I'm afraid I don't understand the
interaction between all these pieces well enough to really get a
handle on what the problem was.  (Nor was it the only problem - using
c++ filestreams on a totally unrelated text file caused corruption on
saving a jpeg, in a different part of the program...wierd!).

>  /* Destroy notification function for the pixbuf */
>  static void
>  free_buffer (guchar *pixels, gpointer data)
> @@ -168,6 +190,8 @@
>  	/* setup error handler */
>  	cinfo.err = jpeg_std_error (&jerr.pub);
>  	jerr.pub.error_exit = fatal_error_handler;
> +	jerr.pub.output_message = error_handler;
> +	jerr.pub.emit_message = error_handler2;

These are the things I commented out.

Ok, I have attached a patch with all of these things taken care of (I
hope).

Thankyou for your time and feedback,
-- 
David N. Welton, Responsabile Progetti Open Source, Linuxcare Italia spa
tel +39.049.8043411 fax +39.049.8043412 cel +39.348.2879508
davidw@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/Makefile.am gdk-pixbuf/gdk-pixbuf/Makefile.am
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/Makefile.am	Mon May  8 11:51:43 2000
+++ gdk-pixbuf/gdk-pixbuf/Makefile.am	Fri Jun 23 12:03:53 2000
@@ -138,7 +138,7 @@
 builtin_libraries = 
 endif
 
-noinst_PROGRAMS = test-gdk-pixbuf testpixbuf testpixbuf-drawable testanimation testpixbuf-scale
+noinst_PROGRAMS = test-gdk-pixbuf testpixbuf testpixbuf-drawable testpixbuf-save testanimation testpixbuf-scale
 TESTS = test-gdk-pixbuf
 
 DEPS = libgdk_pixbuf.la
@@ -155,12 +155,14 @@
 testpixbuf_LDADD = $(LDADDS) -lgmodule
 testpixbuf_drawable_LDADD = $(LDADDS)
 testpixbuf_scale_LDADD = $(LDADDS)
+testpixbuf_save_LDADD = $(LDADDS)
 testanimation_LDADD = $(LDADDS) -lgmodule
 else
 test_gdk_pixbuf_LDADD = $(LDADDS) $(GNOME_LIBS) -lgmodule
 testpixbuf_LDADD = $(LDADDS) $(GNOME_LIBS) -lgmodule
 testpixbuf_drawable_LDADD = $(LDADDS) $(GNOME_LIBS)
 testpixbuf_scale_LDADD = $(LDADDS) $(GNOME_LIBS)
+testpixbuf_save_LDADD = $(LDADDS) $(GNOME_LIBS)
 testanimation_LDADD = $(LDADDS) $(GNOME_LIBS) -lgmodule
 endif
 
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/Makefile.in gdk-pixbuf/gdk-pixbuf/Makefile.in
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.c gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.c
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.c	Mon Apr 17 18:56:01 2000
+++ gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.c	Fri Jun 23 12:02:06 2000
@@ -168,17 +168,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 },
-	{ NULL, NULL, 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 },
+	{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
 #ifdef USE_GMODULE 
@@ -204,6 +204,7 @@
 	char *path;
 	GModule *module;
 	gpointer load_sym;
+	gpointer save_sym;
 	char *name;
 	
         g_return_if_fail (image_module->module == NULL);
@@ -252,6 +253,10 @@
 
         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
 
@@ -267,40 +272,51 @@
 #define m_stop_load(type)  extern void mname(type,stop_load) (gpointer context);
 #define m_load_increment(type)  extern gboolean mname(type,load_increment) (gpointer context, const guchar *buf, guint size);
 #define m_load_animation(type)  extern GdkPixbufAnimation * mname(type,load_animation) (FILE *f);
+#define m_save(type)  extern int mname(type,save) (FILE *f, GdkPixbuf *pixbuf, GdkPixbufInfo *imginfo);
 
 m_load (png);
 m_begin_load (png);
 m_load_increment (png);
 m_stop_load (png);
+m_save (png);
+
 m_load (bmp);
 m_begin_load (bmp);
 m_load_increment (bmp);
 m_stop_load (bmp);
+
 m_load (gif);
 m_begin_load (gif);
 m_load_increment (gif);
 m_stop_load (gif);
 m_load_animation (gif);
+
 m_load (ico);
 m_begin_load (ico);
 m_load_increment (ico);
 m_stop_load (ico);
+
 m_load (jpeg);
 m_begin_load (jpeg);
 m_load_increment (jpeg);
 m_stop_load (jpeg);
+m_save (jpeg);
+
 m_load (pnm);
 m_begin_load (pnm);
 m_load_increment (pnm);
 m_stop_load (pnm);
+
 m_load (ras);
 m_begin_load (ras);
 m_load_increment (ras);
 m_stop_load (ras);
+
 m_load (tiff);
 m_begin_load (tiff);
 m_load_increment (tiff);
 m_stop_load (tiff);
+
 m_load (xpm);
 m_load_xpm_data (xpm);
 
@@ -314,6 +330,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;
 	}
 
@@ -347,6 +364,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){
@@ -467,7 +485,7 @@
 {
 	GdkPixbuf *(* load_xpm_data) (const char **data);
 	GdkPixbuf *pixbuf;
-
+	
 	if (file_formats[XPM_FILE_FORMAT_INDEX].module == NULL)
 		gdk_pixbuf_load_module (&file_formats[XPM_FILE_FORMAT_INDEX]);
 
@@ -482,4 +500,77 @@
 
 	pixbuf = (* load_xpm_data) (data);
 	return pixbuf;
+}
+
+/**
+ * gdk_pixbuf_save_to_file:
+ * @pixbuf: pointer to GdkPixbuf.
+ * @filehandle: FILE* to save to.
+ * @format: name of file format.
+ * @imginfo: GdkPixbufInfo - information about image.
+ *
+ * Saves pixbuf to a filehandle.
+ *
+ * Return value: TRUE on success, FALSE on failure. 
+ **/
+
+gboolean 
+gdk_pixbuf_save_to_file (GdkPixbuf *pixbuf, 
+			 FILE *filehandle, 
+			 char *format, 
+			 GdkPixbufInfo *imginfo)
+{
+	int i;
+	GdkPixbufModule *image_module = NULL;
+	
+	g_return_val_if_fail(filehandle != NULL, FALSE);
+
+	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 ("Unable to find handler for 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, imginfo);
+}
+
+/**
+ * gdk_pixbuf_save:
+ * @pixbuf: pointer to GdkPixbuf.
+ * @filename: Name of file to save.
+ * @format: name of file format.
+ * @imginfo: GdkPixbufInfo - information about image.
+ *
+ * Saves pixbuf to a file.
+ *
+ * Return value: value of gdk_pixbuf_save_to_filehandle 
+ **/
+
+
+gboolean
+gdk_pixbuf_save (GdkPixbuf *pixbuf, 
+		 const char *filename, 
+		 char *format, 
+		 GdkPixbufInfo *imginfo)
+{
+	int i;
+	FILE *f = NULL;
+	gboolean result;
+	
+	f = fopen (filename, "w");
+	g_return_val_if_fail(f != NULL, FALSE);
+	result = gdk_pixbuf_save_to_file(pixbuf, f, format, imginfo);
+	fclose(f);
+	return result;
 }
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.h gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.h
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.h	Fri Jan  7 19:29:13 2000
+++ gdk-pixbuf/gdk-pixbuf/gdk-pixbuf-io.h	Thu Jun 22 19:34:42 2000
@@ -55,6 +55,7 @@
 	gboolean (* format_check) (guchar *buffer, int size);
 	GModule *module;
 	GdkPixbuf *(* load) (FILE *f);
+        gboolean (* save) (FILE *f, GdkPixbuf *pixbuf, GdkPixbufInfo *imginfo);
         GdkPixbuf *(* load_xpm_data) (const char **data);
 
         /* Incremental loading */
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf.h gdk-pixbuf/gdk-pixbuf/gdk-pixbuf.h
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/gdk-pixbuf.h	Mon Apr 17 18:56:02 2000
+++ gdk-pixbuf/gdk-pixbuf/gdk-pixbuf.h	Thu Jun 22 20:03:43 2000
@@ -26,6 +26,7 @@
 #ifndef GDK_PIXBUF_H
 #define GDK_PIXBUF_H
 
+#include <stdio.h>
 #include <gdk/gdk.h>
 
 #ifdef __cplusplus
@@ -100,6 +101,21 @@
 				     gpointer destroy_fn_data);
 
 GdkPixbuf *gdk_pixbuf_new_from_xpm_data (const char **data);
+
+/* It would probably be best if this were a void pointer to whatever
+   data we want to associate with an image */
+typedef struct {
+    int quality;
+} GdkPixbufInfo;
+gboolean gdk_pixbuf_save (GdkPixbuf *pixbuf, 
+			  const char *filename, 
+			  char *format, 
+			  GdkPixbufInfo *imginfo);
+    
+gboolean gdk_pixbuf_save_to_file (GdkPixbuf *pixbuf, 
+				  FILE *filehandle, 
+				  char *format, 
+				  GdkPixbufInfo *imginfo);
 
 /* Adding an alpha channel */
 GdkPixbuf *gdk_pixbuf_add_alpha (const GdkPixbuf *pixbuf, gboolean substitute_color,
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/io-jpeg.c gdk-pixbuf/gdk-pixbuf/io-jpeg.c
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/io-jpeg.c	Tue Apr 11 12:02:27 2000
+++ gdk-pixbuf/gdk-pixbuf/io-jpeg.c	Thu Jun 22 20:22:24 2000
@@ -97,6 +97,7 @@
 gboolean gdk_pixbuf__jpeg_image_load_increment(gpointer context, guchar *buf, guint size);
 
 
+
 static void
 fatal_error_handler (j_common_ptr cinfo)
 {
@@ -111,6 +112,30 @@
 	return;
 }
 
+#if 0  
+static void 
+error_handler(j_common_ptr cinfo)
+{
+    struct error_handler_data *errmgr;
+    errmgr = (struct error_handler_data *) cinfo->err;
+    cinfo->err->output_message (cinfo);
+    siglongjmp (errmgr->setjmp_buffer, 1);
+    return;
+}
+
+static void 
+error_handler2(j_common_ptr cinfo, int msg_level)
+{
+    struct error_handler_data *errmgr;
+    errmgr = (struct error_handler_data *) cinfo->err;
+    cinfo->err->output_message (cinfo);
+    siglongjmp (errmgr->setjmp_buffer, 1);
+    msg_level = 0;
+    return;
+}  
+#endif
+
+
 /* Destroy notification function for the pixbuf */
 static void
 free_buffer (guchar *pixels, gpointer data)
@@ -168,6 +193,8 @@
 	/* setup error handler */
 	cinfo.err = jpeg_std_error (&jerr.pub);
 	jerr.pub.error_exit = fatal_error_handler;
+/* 	jerr.pub.output_message = error_handler;
+	jerr.pub.emit_message = error_handler2;  */
 
 	if (sigsetjmp (jerr.setjmp_buffer, 1)) {
 		/* Whoops there was a jpeg error */
@@ -546,5 +573,97 @@
 		}
 	}
 
+	return TRUE;
+}
+
+gboolean
+gdk_pixbuf__jpeg_image_save(FILE *f, 
+			    GdkPixbuf *pixbuf, 
+			    GdkPixbufInfo *imginfo)
+{
+	struct jpeg_compress_struct cinfo;
+	guchar *buf = NULL;
+	guchar *ptr;
+	guchar *pixels = NULL;
+	JSAMPROW *jbuf;
+	int y = 0, quality;
+	int i, j;
+	int w, h = 0;
+	int rowstride = 0;
+	struct error_handler_data jerr;
+
+	if (imginfo)
+	    quality = imginfo->quality;
+
+	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;
+/* 	
+	These caused me trouble when used with a C++ program - davidw
+
+	jerr.pub.emit_message = error_handler2;
+	jerr.pub.output_message = 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;
+ 
+	/* look for tags attached to image to get extra parameters liek quality */
+	/* settigns etc. - thsi si the "api" to hint for extra information for */
+	/* saver modules */
+/*     tag = __imlib_GetTag(im, "quality");
+       if (tag)
+       quality = tag->val;
+       if (quality < 1)
+       quality = 1;
+       if (quality > 100)
+       quality = 100;  */
+
+	/* 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;
 }
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/io-png.c gdk-pixbuf/gdk-pixbuf/io-png.c
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/io-png.c	Tue Apr 11 12:02:27 2000
+++ gdk-pixbuf/gdk-pixbuf/io-png.c	Thu Jun 22 20:18:33 2000
@@ -522,3 +522,92 @@
         
         fprintf(stderr, "Warning loading PNG: %s\n", warning_msg);
 }
+
+gboolean
+gdk_pixbuf__png_image_save (FILE *f, 
+			    GdkPixbuf *pixbuf, 
+			    GdkPixbufInfo *imginfo)
+{
+	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;
+
+	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 0;
+}
diff -ruN /home/davidw/download/gdk-pixbuf/gdk-pixbuf/testpixbuf-save.c gdk-pixbuf/gdk-pixbuf/testpixbuf-save.c
--- /home/davidw/download/gdk-pixbuf/gdk-pixbuf/testpixbuf-save.c	Thu Jan  1 01:00:00 1970
+++ gdk-pixbuf/gdk-pixbuf/testpixbuf-save.c	Thu Jun 22 21:26:18 2000
@@ -0,0 +1,145 @@
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include "gdk-pixbuf.h"
+
+void keypress_check(GtkWidget *widget, GdkEventKey *evt, gpointer data)
+{
+    GdkPixbuf *pixbuf;
+    GtkDrawingArea *da = (GtkDrawingArea*)data;
+    GdkPixbufInfo pbufinfo;
+
+    pbufinfo.quality = 100;
+    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, "PIXBUFF NULL\n");
+	    return;
+	}	
+	gdk_pixbuf_save(pixbuf, "foo.jpg", "jpeg", &pbufinfo);
+    } else if (evt->keyval == 'p') {
+	if(pixbuf == NULL)
+	{
+	    fprintf(stderr, "PIXBUFF NULL\n");
+	    return;
+	}	
+	gdk_pixbuf_save(pixbuf, "foo.png", "png", &pbufinfo);
+    }
+}
+
+
+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);   
+    gdk_rgb_set_verbose(TRUE);
+    gdk_rgb_init();
+
+    gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
+    gtk_widget_set_default_visual(gdk_rgb_get_visual());
+
+    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;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]