[gegl] png-load: Refactor stream handling to avoid reading twice
- From: Jon Nordby <jonnor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] png-load: Refactor stream handling to avoid reading twice
- Date: Sun, 9 Nov 2014 21:10:28 +0000 (UTC)
commit f230a543beac04bdcbf718c9df007cbf31abe2b8
Author: Jon Nordby <jononor gmail com>
Date: Sun Nov 9 21:48:37 2014 +0100
png-load: Refactor stream handling to avoid reading twice
Also moves some things out to dedicated functions and adds
GError based error handling.
operations/external/png-load.c | 251 ++++++++++++++++++++++++----------------
1 files changed, 150 insertions(+), 101 deletions(-)
---
diff --git a/operations/external/png-load.c b/operations/external/png-load.c
index d3b34c6..e9ac06f 100644
--- a/operations/external/png-load.c
+++ b/operations/external/png-load.c
@@ -38,6 +38,24 @@ property_string (uri, _("URI"), "")
#include "gegl-op.h"
#include <png.h>
+
+#define WARN_IF_ERROR(gerror) \
+do { \
+ if (gerror) { \
+ g_warning("gegl:png-load %s", gerror->message); \
+ } \
+} while(0)
+
+typedef enum {
+ LOAD_PNG_TOO_SHORT,
+ LOAD_PNG_WRONG_HEADER
+} LoadPngErrors;
+
+static GQuark error_quark(void)
+{
+ return g_quark_from_static_string ("gegl:load-png-error-quark");
+}
+
static void
read_fn(png_structp png_ptr, png_bytep buffer, png_size_t length)
{
@@ -59,16 +77,51 @@ error_fn(png_structp png_ptr, png_const_charp msg)
g_printerr("LIBPNG ERROR: %s", msg);
}
-static GFile * open_png(const gchar *uri, const gchar *path)
+static gboolean
+check_valid_png_header(GInputStream *stream, GError **err)
{
- GError *err = NULL;
- GFile *infile = NULL;
- GInputStream *fis = NULL;
const size_t hdr_size=8;
gssize hdr_read_size;
unsigned char header[hdr_size];
+ hdr_read_size = g_input_stream_read(G_INPUT_STREAM(stream), header, hdr_size, NULL, err);
+ if (hdr_read_size == -1)
+ {
+ // err should be set by _read()
+ return FALSE;
+ }
+ else if (hdr_read_size < hdr_size)
+ {
+ g_set_error(err, error_quark(), LOAD_PNG_TOO_SHORT,
+ "too short for a png file, only %lu bytes.",
+ (unsigned long)hdr_read_size);
+
+ return FALSE;
+ }
+ else if (hdr_read_size > hdr_size)
+ {
+ const gboolean reached = TRUE;
+ g_assert(!reached);
+ }
+
+ if (png_sig_cmp (header, 0, hdr_size))
+ {
+ g_set_error(err, error_quark(), LOAD_PNG_WRONG_HEADER, "wrong png header");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+static GInputStream *
+open_stream(const gchar *uri, const gchar *path, GFile **out_file, GError **err)
+{
+ GFile *infile = NULL;
+ GInputStream *fis = NULL;
+
g_return_val_if_fail(uri || path, NULL);
+ g_return_val_if_fail(out_file, NULL);
if (strlen(uri) > 0)
{
@@ -85,34 +138,61 @@ static GFile * open_png(const gchar *uri, const gchar *path)
}
g_return_val_if_fail(infile, NULL);
- fis = G_INPUT_STREAM(g_file_read(infile, NULL, &err));
- hdr_read_size = g_input_stream_read(G_INPUT_STREAM(fis), header, hdr_size, NULL, &err);
- if (hdr_read_size != hdr_size)
- {
- g_input_stream_close(fis, NULL, NULL);
- g_object_unref(fis);
-
- if (err) {
- g_printerr("%s", err->message);
- } else {
- g_warning ("%s is too short for a png file, only %lu bytes.",
- path, (unsigned long)hdr_read_size);
- }
-
- return NULL;
- }
+ fis = G_INPUT_STREAM(g_file_read(infile, NULL, err));
- if (png_sig_cmp (header, 0, hdr_size))
+ if (infile)
{
- g_input_stream_close(fis, NULL, NULL);
- g_object_unref(fis);
- g_warning ("%s is not a png file", path);
- return NULL;
+ *out_file = infile;
}
- g_input_stream_close(fis, NULL, NULL); // consumer should open new
- g_object_unref(fis);
- return infile;
+ return fis;
+}
+
+static const Babl *
+get_babl_format(int bit_depth, int color_type)
+{
+ gchar format_string[32];
+
+ if (color_type & PNG_COLOR_TYPE_RGB)
+ {
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ strcpy (format_string, "R'G'B'A ");
+ else
+ strcpy (format_string, "R'G'B' ");
+ }
+ else if ((color_type & PNG_COLOR_TYPE_GRAY) == PNG_COLOR_TYPE_GRAY)
+ {
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ strcpy (format_string, "Y'A ");
+ else
+ strcpy (format_string, "Y' ");
+ }
+ else if (color_type & PNG_COLOR_TYPE_PALETTE)
+ {
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ strcpy (format_string, "R'G'B'A ");
+ else
+ strcpy (format_string, "R'G'B' ");
+ }
+ else
+ {
+ return NULL;
+ }
+
+ if (bit_depth <= 8)
+ {
+ strcat (format_string, "u8");
+ }
+ else if(bit_depth == 16)
+ {
+ strcat (format_string, "u16");
+ }
+ else
+ {
+ return NULL;
+ }
+
+ return babl_format (format_string);
}
static gint
@@ -122,7 +202,8 @@ gegl_buffer_import_png (GeglBuffer *gegl_buffer,
gint dest_y,
gint *ret_width,
gint *ret_height,
- gpointer format)
+ const Babl *format, // can be NULL
+ GError **err)
{
gint width;
gint bit_depth;
@@ -141,6 +222,11 @@ gegl_buffer_import_png (GeglBuffer *gegl_buffer,
g_return_val_if_fail(stream, -1);
+ if (!check_valid_png_header(stream, err))
+ {
+ return -1;
+ }
+
load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL);
if (!load_png_ptr)
@@ -165,7 +251,7 @@ gegl_buffer_import_png (GeglBuffer *gegl_buffer,
png_set_read_fn(load_png_ptr, stream, read_fn);
-// png_set_sig_bytes (load_png_ptr, 8);
+ png_set_sig_bytes (load_png_ptr, 8); // we already read header
png_read_info (load_png_ptr, load_info_ptr);
{
int color_type;
@@ -228,6 +314,9 @@ gegl_buffer_import_png (GeglBuffer *gegl_buffer,
if (bit_depth == 16)
bpp = bpp << 1;
+ if (!format)
+ format = get_babl_format(bit_depth, color_type);
+
#if BYTE_ORDER == LITTLE_ENDIAN
if (bit_depth == 16)
png_set_swap (load_png_ptr);
@@ -281,10 +370,13 @@ gegl_buffer_import_png (GeglBuffer *gegl_buffer,
return 0;
}
+
+
static gint query_png (GInputStream *stream,
gint *width,
gint *height,
- gpointer *format)
+ const Babl **format,
+ GError **err)
{
png_uint_32 w;
png_uint_32 h;
@@ -292,9 +384,13 @@ static gint query_png (GInputStream *stream,
png_infop load_info_ptr;
png_bytep *row_p = NULL;
-
g_return_val_if_fail(stream, -1);
+ if (!check_valid_png_header(stream, err))
+ {
+ return -1;
+ }
+
load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL);
if (!load_png_ptr)
{
@@ -317,12 +413,12 @@ static gint query_png (GInputStream *stream,
}
png_set_read_fn(load_png_ptr, stream, read_fn);
-// png_set_sig_bytes (load_png_ptr, 8);
+ png_set_sig_bytes (load_png_ptr, 8); // we already read header
png_read_info (load_png_ptr, load_info_ptr);
{
int bit_depth;
int color_type;
- gchar format_string[32];
+ const Babl *f;
png_get_IHDR (load_png_ptr,
load_info_ptr,
@@ -336,50 +432,14 @@ static gint query_png (GInputStream *stream,
if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_tRNS))
color_type |= PNG_COLOR_MASK_ALPHA;
- if (color_type & PNG_COLOR_TYPE_RGB)
- {
- if (color_type & PNG_COLOR_MASK_ALPHA)
- strcpy (format_string, "R'G'B'A ");
- else
- strcpy (format_string, "R'G'B' ");
- }
- else if ((color_type & PNG_COLOR_TYPE_GRAY) == PNG_COLOR_TYPE_GRAY)
- {
- if (color_type & PNG_COLOR_MASK_ALPHA)
- strcpy (format_string, "Y'A ");
- else
- strcpy (format_string, "Y' ");
- }
- else if (color_type & PNG_COLOR_TYPE_PALETTE)
- {
- if (color_type & PNG_COLOR_MASK_ALPHA)
- strcpy (format_string, "R'G'B'A ");
- else
- strcpy (format_string, "R'G'B' ");
- }
- else
- {
- g_warning ("color type mismatch");
- png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
- return -1;
- }
-
- if (bit_depth <= 8)
+ f = get_babl_format(bit_depth, color_type);
+ if (!f)
{
- strcat (format_string, "u8");
- }
- else if(bit_depth == 16)
- {
- strcat (format_string, "u16");
- }
- else
- {
- g_warning ("bit depth mismatch");
png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
return -1;
}
-
- *format = (void*)babl_format (format_string);
+ *format = f;
+
}
png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
return 0;
@@ -392,14 +452,17 @@ get_bounding_box (GeglOperation *operation)
GeglRectangle result = {0,0,0,0};
gint width, height;
gint status;
- gpointer format;
+ const Babl * format;
GError *err = NULL;
+ GFile *infile = NULL;
- GFile *infile = open_png(o->uri, o->path);
- GInputStream *stream = G_INPUT_STREAM(g_file_read(infile, NULL, &err));
- status = query_png (stream, &width, &height, &format);
+ GInputStream *stream = open_stream(o->uri, o->path, &infile, &err);
+ WARN_IF_ERROR(err);
+ status = query_png(stream, &width, &height, &format, &err);
+ WARN_IF_ERROR(err);
g_input_stream_close(stream, NULL, NULL);
+ g_assert(status == 0);
if (status)
{
width = 0;
@@ -410,7 +473,7 @@ get_bounding_box (GeglOperation *operation)
result.width = width;
result.height = height;
- g_object_unref(infile);
+ if (infile) g_object_unref(infile);
g_object_unref(stream);
return result;
}
@@ -423,30 +486,16 @@ process (GeglOperation *operation,
{
GeglProperties *o = GEGL_PROPERTIES (operation);
gint problem;
- gpointer format;
gint width, height;
- GFile *infile = open_png(o->uri, o->path);
+ Babl *format = NULL;
GError *err = NULL;
-
- GInputStream *stream = G_INPUT_STREAM(g_file_read(infile, NULL, &err));
-
- problem = query_png (stream, &width, &height, &format);
- if (problem)
- {
- g_object_unref(infile);
- g_object_unref(stream);
- g_warning ("%s is %s really a PNG file?",
- G_OBJECT_TYPE_NAME (operation), o->path);
- return FALSE;
- }
-
- // TEMP: avoding having to recreate stream. import_png should do query??
- g_input_stream_close(stream, NULL, NULL);
- g_object_unref(stream);
- stream = G_INPUT_STREAM(g_file_read(infile, NULL, &err));
-
+ GFile *infile = NULL;
+ GInputStream *stream = open_stream(o->uri, o->path, &infile, &err);
+ WARN_IF_ERROR(err);
problem = gegl_buffer_import_png (output, stream, 0, 0,
- &width, &height, format);
+ &width, &height, format, &err);
+ WARN_IF_ERROR(err);
+ g_input_stream_close(stream, NULL, NULL);
if (problem)
{
@@ -456,7 +505,7 @@ process (GeglOperation *operation,
G_OBJECT_TYPE_NAME (operation), o->path);
return FALSE;
}
- g_object_unref(infile);
+ if (infile) g_object_unref(infile);
g_object_unref(stream);
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]