[byzanz] Update Gifenc API



commit ca30f58aace35e1b3f49d80cc4a068e1d4b99cd0
Author: Benjamin Otte <otte gnome org>
Date:   Wed Aug 19 12:33:45 2009 +0200

    Update Gifenc API
    
    It now takes a write function and emits errors when writing to it fails.
    This simplifies the gifenc API while making it more powerful at the same
    time.

 gifenc/gifenc.c      |  147 +++++++++++++++++++++++++++-----------------------
 gifenc/gifenc.h      |  109 +++++++++++++++++++++----------------
 src/byzanzrecorder.c |   48 ++++++++++++++---
 3 files changed, 183 insertions(+), 121 deletions(-)
---
diff --git a/gifenc/gifenc.c b/gifenc/gifenc.c
index d633da0..c6fa246 100644
--- a/gifenc/gifenc.c
+++ b/gifenc/gifenc.c
@@ -52,20 +52,19 @@ log2n (guint number)
 
 /*** WRITE ROUTINES ***/
 
-static void
-gifenc_write (Gifenc *enc, const guint8 *data, guint len)
+static gboolean
+gifenc_flush (Gifenc *enc, GError **error)
 {
-  ssize_t ret;
+  gboolean result;
 
-  g_return_if_fail (enc->n_bits == 0);
-  
-  while (len > 0) {
-    ret = write (enc->fd, data, len);
-    if (ret < 0)
-      g_assert_not_reached ();
-    len -= ret;
-    data += ret;
-  }
+  if (enc->buffer->len == 0)
+    return TRUE;
+
+  result = enc->write_func (enc->write_data, enc->buffer->data, 
+      enc->buffer->len, error);
+
+  g_byte_array_set_size (enc->buffer, 0);
+  return result;
 }
 
 static void
@@ -74,7 +73,7 @@ gifenc_write_uint16 (Gifenc *enc, guint16 value)
   g_return_if_fail (enc->n_bits == 0);
   
   value = GUINT16_TO_LE (value);
-  gifenc_write (enc, (guint8 *) &value, 2);
+  g_byte_array_append (enc->buffer, (guint8 *) &value, 2);
 }
 
 static void
@@ -82,7 +81,7 @@ gifenc_write_byte (Gifenc *enc, guint8 value)
 {
   g_return_if_fail (enc->n_bits == 0);
   
-  gifenc_write (enc, &value, 1);
+  g_byte_array_append (enc->buffer, &value, 1);
 }
 
 static void
@@ -108,21 +107,21 @@ gifenc_write_bits (Gifenc *enc, guint bits, guint nbits)
 static void
 gifenc_write_header (Gifenc *enc)
 {
-  gifenc_write (enc, (const guchar *) "GIF89a", 6);
+  g_byte_array_append (enc->buffer, (const guchar *) "GIF89a", 6);
 }
 
 static void
-gifenc_write_lsd (Gifenc *enc)
+gifenc_write_lsd (Gifenc *enc, GifencPalette *palette)
 {
-  g_assert (gifenc_palette_get_num_colors (enc->palette) >= 2);
+  g_assert (palette == NULL || gifenc_palette_get_num_colors (palette) >= 2);
 
   gifenc_write_uint16 (enc, enc->width);
   gifenc_write_uint16 (enc, enc->height);
-  gifenc_write_bits (enc, enc->palette ? 1 : 0, 1); /* global color table flag */
+  gifenc_write_bits (enc, palette ? 1 : 0, 1); /* global color table flag */
   gifenc_write_bits (enc, 0x7, 3); /* color resolution */
   gifenc_write_bits (enc, 0, 1); /* sort flag */
-  gifenc_write_bits (enc, enc->palette ? 
-      log2n (gifenc_palette_get_num_colors (enc->palette) - 1) - 1 : 0, 3); /* number of colors */
+  gifenc_write_bits (enc, palette ? 
+      log2n (gifenc_palette_get_num_colors (palette) - 1) - 1 : 0, 3); /* number of colors */
   gifenc_write_byte (enc, 0); /* background color */
   gifenc_write_byte (enc, 0); /* pixel aspect ratio */
 }
@@ -142,11 +141,11 @@ gifenc_write_color_table (Gifenc *enc, GifencPalette *palette)
     gifenc_write_byte (enc, BLUE (palette->colors[i]));
   }
   if (palette->alpha) {
-    gifenc_write (enc, (guint8 *) "\272\219\001", 3);
+    g_byte_array_append (enc->buffer, (guint8 *) "\272\219\001", 3);
     i++;
   }
   for (; i < table_size; i++) {
-    gifenc_write (enc, (guint8 *) "\0\0\0", 3);
+    g_byte_array_append (enc->buffer, (guint8 *) "\0\0\0", 3);
   }
 }
 
@@ -190,7 +189,7 @@ gifenc_buffer_write (Gifenc *enc, EncodeBuffer *buffer)
   if (buffer->bytes == 0)
     return;
   gifenc_write_byte (enc, buffer->bytes);
-  gifenc_write (enc, buffer->data, buffer->bytes);
+  g_byte_array_append (enc->buffer, buffer->data, buffer->bytes);
   buffer->bytes = 0;
 }
 
@@ -346,7 +345,7 @@ gifenc_write_loop (Gifenc *enc)
   gifenc_write_byte (enc, 0x21); /* extension */
   gifenc_write_byte (enc, 0xFF); /* application extension */
   gifenc_write_byte (enc, 11); /* block size */
-  gifenc_write (enc, (guint8 *) "NETSCAPE2.0", 11);
+  g_byte_array_append (enc->buffer, (guint8 *) "NETSCAPE2.0", 11);
   gifenc_write_byte (enc, 3); /* block size */
   gifenc_write_byte (enc, 1); /* ??? */
   gifenc_write_byte (enc, 0); /* ??? */
@@ -357,86 +356,98 @@ gifenc_write_loop (Gifenc *enc)
 /*** PUBLIC API ***/
 
 Gifenc *
-gifenc_open (const char *filename, guint width, guint height)
-{
-  int fd;
-
-  g_return_val_if_fail (width <= G_MAXUINT16, NULL);
-  g_return_val_if_fail (height <= G_MAXUINT16, NULL);
-
-  fd = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-  if (fd < 0)
-    return NULL;
-
-  return gifenc_open_fd (fd, width, height);
-}
-
-Gifenc *
-gifenc_open_fd (gint fd, guint width, guint height)
+gifenc_new (guint width, guint height, GifencWriteFunc write_func, 
+    gpointer write_data, GDestroyNotify write_destroy)
 {
   Gifenc *enc;
 
   g_return_val_if_fail (width <= G_MAXUINT16, NULL);
   g_return_val_if_fail (height <= G_MAXUINT16, NULL);
-
-  enc = g_new0 (Gifenc, 1);
-  enc->fd = fd;
+  g_return_val_if_fail (write_func, NULL);
+  
+  enc = g_slice_new0 (Gifenc);
   enc->width = width;
   enc->height = height;
-  //g_print ("created new image with size %ux%u\n", width, height);
-  gifenc_write_header (enc);
-  
+  enc->buffer = g_byte_array_new ();
+  enc->write_func = write_func;
+  enc->write_data = write_data;
+  enc->write_destroy = write_destroy;
+
   return enc;
 }
 
-void
-gifenc_set_palette (Gifenc *enc, GifencPalette *palette)
+gboolean
+gifenc_initialize (Gifenc *enc, GifencPalette *palette, gboolean loop, GError **error)
 {
-  g_return_if_fail (enc->palette == NULL);
-  g_return_if_fail (palette != NULL);
+  g_return_val_if_fail (enc != NULL, FALSE);
+  g_return_val_if_fail (enc->state == GIFENC_STATE_NEW, FALSE);
+  g_return_val_if_fail (palette != NULL, FALSE);
+
+  gifenc_write_header (enc);
+  gifenc_write_lsd (enc, palette);
+  gifenc_write_color_table (enc, palette);
+  if (loop)
+    gifenc_write_loop (enc);
+  if (!gifenc_flush (enc, error))
+    return FALSE;
 
   enc->palette = palette;
-  gifenc_write_lsd (enc);
-  gifenc_write_color_table (enc, enc->palette);
+  enc->state = GIFENC_STATE_INITIALIZED;
+  return TRUE;
 }
 
-void
+gboolean
 gifenc_add_image (Gifenc *enc, guint x, guint y, guint width, guint height, 
-    guint display_millis, guint8 *data, guint rowstride)
+    guint display_millis, guint8 *data, guint rowstride, GError **error)
 {
   GifencImage image = { x, y, width, height, NULL, data, rowstride };
 
-  g_return_if_fail (x + width <= enc->width);
-  g_return_if_fail (width > 0);
-  g_return_if_fail (y + height <= enc->height);
-  g_return_if_fail (height > 0);
+  g_return_val_if_fail (enc != NULL, FALSE);
+  g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE);
+  g_return_val_if_fail (width > 0, FALSE);
+  g_return_val_if_fail (x + width <= enc->width, FALSE);
+  g_return_val_if_fail (height > 0, FALSE);
+  g_return_val_if_fail (y + height <= enc->height, FALSE);
 
   //g_print ("adding image (display time %u)\n", display_millis);
   gifenc_write_graphic_control (enc, image.palette ? image.palette : enc->palette, 
       display_millis);
   gifenc_write_image_description (enc, &image);
   gifenc_write_image_data (enc, &image);
+  return gifenc_flush (enc, error);
 }
 
 gboolean
-gifenc_close (Gifenc *enc)
+gifenc_close (Gifenc *enc, GError **error)
 {
-  gifenc_write_byte (enc, 0x3B);
-  close (enc->fd);
+  g_return_val_if_fail (enc != NULL, FALSE);
+  g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE);
 
-  if (enc->palette)
-    gifenc_palette_free (enc->palette);
-  g_free (enc);
+  gifenc_write_byte (enc, 0x3B);
+  if (!gifenc_flush (enc, error))
+    return FALSE;
 
+  enc->state = GIFENC_STATE_CLOSED;
   return TRUE;
 }
 
-void
-gifenc_set_looping (Gifenc *enc)
+gboolean
+gifenc_free (Gifenc *enc)
 {
-  g_return_if_fail (enc != NULL);
+  gboolean success;
+
+  g_return_val_if_fail (enc != NULL, FALSE);
+
+  success = enc->state == GIFENC_STATE_CLOSED;
+
+  if (enc->write_destroy)
+    enc->write_destroy (enc->write_data);
+  if (enc->palette)
+    gifenc_palette_free (enc->palette);
+  g_byte_array_unref (enc->buffer);
+  g_slice_free (Gifenc, enc);
 
-  gifenc_write_loop (enc);
+  return success;
 }
 
 /* Floyd-Steinman factors */
diff --git a/gifenc/gifenc.h b/gifenc/gifenc.h
index 4d43352..0b5c602 100644
--- a/gifenc/gifenc.h
+++ b/gifenc/gifenc.h
@@ -27,6 +27,14 @@ typedef struct _GifencPalette GifencPalette;
 typedef struct _GifencColor GifencColor;
 typedef struct _Gifenc Gifenc;
 
+typedef gboolean (* GifencWriteFunc) (gpointer closure, const guchar *data, gsize len, GError **error);
+
+typedef enum {
+  GIFENC_STATE_NEW = 0,
+  GIFENC_STATE_INITIALIZED,
+  GIFENC_STATE_CLOSED,
+} GifencState;
+
 struct _GifencPalette {
   gboolean	alpha;
   guint32 *	colors;
@@ -40,8 +48,14 @@ struct _GifencPalette {
 };
 
 struct _Gifenc {
+  /* error checking */
+  GifencState           state;
+
   /* output */
-  int			fd;
+  GifencWriteFunc       write_func;
+  gpointer              write_data;
+  GDestroyNotify        write_destroy;
+  GByteArray *          buffer;
   guint			bits;
   guint			n_bits;
   
@@ -52,60 +66,63 @@ struct _Gifenc {
   GifencPalette *	palette;
 };
 
-Gifenc *	gifenc_open		(const char *	filename,
-					 guint		width,
-					 guint		height);
-Gifenc *	gifenc_open_fd		(int		fd,
-					 guint		width,
-					 guint		height);
+Gifenc *        gifenc_new              (guint                  width,
+                                         guint                  height,
+                                         GifencWriteFunc        write_func,
+                                         gpointer               write_data,
+                                         GDestroyNotify         write_destroy);
+gboolean        gifenc_free             (Gifenc *		enc);
 					 
-void		gifenc_set_palette	(Gifenc *	enc,
-					 GifencPalette *palette);
-void		gifenc_set_looping	(Gifenc *	enc);
-void		gifenc_add_image	(Gifenc *	enc,
-					 guint		x,
-					 guint		y,
-					 guint		width,
-					 guint		height,
-					 guint		display_millis,
-					 guint8 *	data,
-					 guint		rowstride);
-gboolean	gifenc_close		(Gifenc *	enc);
+gboolean        gifenc_initialize	(Gifenc *		enc,
+					 GifencPalette *	palette,
+                                         gboolean       	loop,
+                                         GError **      	error);
+gboolean        gifenc_add_image	(Gifenc *		enc,
+					 guint			x,
+					 guint			y,
+					 guint			width,
+					 guint			height,
+					 guint			display_millis,
+					 guint8 *		data,
+					 guint			rowstride,
+                                         GError **		error);
+gboolean        gifenc_close            (Gifenc *       	gifenc,
+                                         GError **      	error);
 
-void		gifenc_dither_rgb	(guint8 *	target,
-					 guint		target_rowstride,
+void		gifenc_dither_rgb	(guint8 *		target,
+					 guint			target_rowstride,
 					 const GifencPalette *	palette,
-					 const guint8 *	data,
-					 guint		width,
-					 guint		height,
-					 guint		rowstride);
+					 const guint8 *		data,
+					 guint			width,
+					 guint			height,
+					 guint			rowstride);
 gboolean	gifenc_dither_rgb_with_full_image
-					(guint8 *	target,
-					 guint		target_rowstride,
-					 guint8 *	full,
-					 guint		full_rowstride,
+					(guint8 *		target,
+					 guint			target_rowstride,
+					 guint8 *		full,
+					 guint			full_rowstride,
 					 const GifencPalette *	palette,
-					 const guint8 *	data,
-					 guint		width,
-					 guint		height,
-					 guint		rowstride,
-					 GdkRectangle *	rect_out);
+					 const guint8 *		data,
+					 guint			width,
+					 guint			height,
+					 guint			rowstride,
+					 GdkRectangle *		rect_out);
 
 /* from quantize.c */
-void		gifenc_palette_free	(GifencPalette *palette);
-GifencPalette *	gifenc_palette_get_simple (gboolean	alpha);
-GifencPalette *	gifenc_quantize_image	(const guint8 *	data,
-					 guint		width, 
-					 guint		height,
-					 guint		rowstride, 
-					 gboolean	alpha,
-					 guint		max_colors);
+void		gifenc_palette_free	(GifencPalette *	palette);
+GifencPalette *	gifenc_palette_get_simple (gboolean		alpha);
+GifencPalette *	gifenc_quantize_image	(const guint8 *		data,
+					 guint			width, 
+					 guint			height,
+					 guint			rowstride, 
+					 gboolean		alpha,
+					 guint			max_colors);
 guint		gifenc_palette_get_alpha_index
-					(const GifencPalette *palette);
+					(const GifencPalette *	palette);
 guint		gifenc_palette_get_num_colors
-					(const GifencPalette *palette);
-guint32		gifenc_palette_get_color(const GifencPalette *palette,
-					 guint		id);
+					(const GifencPalette *	palette);
+guint32		gifenc_palette_get_color(const GifencPalette *	palette,
+					 guint			id);
 					
 
 #endif /* __HAVE_GIFENC_H__ */
diff --git a/src/byzanzrecorder.c b/src/byzanzrecorder.c
index e5dfc4d..df70e47 100644
--- a/src/byzanzrecorder.c
+++ b/src/byzanzrecorder.c
@@ -22,11 +22,13 @@
 #endif
 
 #include "byzanzrecorder.h"
+
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
 #include <cairo.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
@@ -307,7 +309,7 @@ byzanz_recorder_add_image (ByzanzRecorder *rec, const GTimeVal *tv)
     gifenc_add_image (rec->gifenc, rec->relevant_data.x, rec->relevant_data.y, 
 	rec->relevant_data.width, rec->relevant_data.height, msecs,
 	rec->data + rec->area.width * rec->relevant_data.y + rec->relevant_data.x,
-	rec->area.width);
+	rec->area.width, NULL);
     rec->current = *tv;
   }
 }
@@ -461,9 +463,7 @@ byzanz_recorder_quantize (ByzanzRecorder *rec, cairo_surface_t *image)
   palette = gifenc_quantize_image (cairo_image_surface_get_data (image),
       rec->area.width, rec->area.height, cairo_image_surface_get_stride (image), TRUE, 255);
   
-  gifenc_set_palette (rec->gifenc, palette);
-  if (rec->loop)
-    gifenc_set_looping (rec->gifenc);
+  gifenc_initialize (rec->gifenc, palette, rec->loop, NULL);
 }
 
 static gboolean 
@@ -562,6 +562,7 @@ loop:
   }
   
   byzanz_recorder_add_image (rec, &quit_tv);
+  gifenc_close (rec->gifenc, NULL);
 
   g_free (rec->data);
   rec->data = NULL;
@@ -794,6 +795,38 @@ byzanz_recorder_new (const gchar *filename, GdkWindow *window, GdkRectangle *are
   return byzanz_recorder_new_fd (fd, window, area, loop, record_cursor);
 }
 
+static gboolean
+recorder_gifenc_write (gpointer closure, const guchar *data, gsize len, GError **error)
+{
+  gssize written;
+  int fd = GPOINTER_TO_INT (closure);
+  
+  do {
+    written = write (fd, data, len);
+    if (written < 0) {
+      int err = errno;
+
+      if (err == EINTR)
+	continue;
+	  
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (err),
+          _("Error writing: %s"), g_strerror (err));
+      return FALSE;
+    } else {
+      len -= written;
+      data += written;
+    }
+  } while (len > 0);
+
+  return TRUE;
+}
+
+static void
+recorder_gifenc_close (gpointer closure)
+{
+  close (GPOINTER_TO_INT (closure));
+}
+
 ByzanzRecorder *
 byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
     gboolean loop, gboolean record_cursor)
@@ -835,7 +868,8 @@ byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
   gdk_drawable_get_size (recorder->window,
       &root_rect.width, &root_rect.height);
   gdk_rectangle_intersect (&recorder->area, &root_rect, &recorder->area);
-  recorder->gifenc = gifenc_open_fd (fd, recorder->area.width, recorder->area.height);
+  recorder->gifenc = gifenc_new (recorder->area.width, recorder->area.height, 
+      recorder_gifenc_write, GINT_TO_POINTER (fd), recorder_gifenc_close);
   if (!recorder->gifenc) {
     g_free (recorder);
     return NULL;
@@ -846,7 +880,7 @@ byzanz_recorder_new_fd (gint fd, GdkWindow *window, GdkRectangle *area,
   recorder->encoder = g_thread_create (byzanz_recorder_run_encoder, recorder, 
       TRUE, NULL);
   if (!recorder->encoder) {
-    gifenc_close (recorder->gifenc);
+    gifenc_free (recorder->gifenc);
     g_async_queue_unref (recorder->jobs);
     g_free (recorder);
     return NULL;
@@ -965,7 +999,7 @@ byzanz_recorder_destroy (ByzanzRecorder *rec)
   if (IS_RECORDING_CURSOR (rec))
     g_hash_table_destroy (rec->cursors);
 
-  gifenc_close (rec->gifenc);
+  gifenc_free (rec->gifenc);
   g_object_unref (rec->window);
 
   g_assert (g_async_queue_length (rec->jobs) == 0);



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