[gnome-photos] Add a sink to guess the size of a GeglBuffer after PNG compression



commit 5dac3e90a6dec980eccf670c926c31d058c9ae8c
Author: Debarshi Ray <debarshir gnome org>
Date:   Fri Jan 1 20:41:07 2016 +0100

    Add a sink to guess the size of a GeglBuffer after PNG compression
    
    https://bugzilla.gnome.org/show_bug.cgi?id=759363

 configure.ac                           |    1 +
 src/Makefile.am                        |    6 +
 src/photos-operation-png-guess-sizes.c |  369 ++++++++++++++++++++++++++++++++
 src/photos-operation-png-guess-sizes.h |   45 ++++
 src/photos-png-count.c                 |   50 +++++
 src/photos-png-count.h                 |   33 +++
 src/photos-utils.c                     |    2 +
 7 files changed, 506 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index b2261a9..0fb2b42 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,6 +95,7 @@ AC_DEFINE([GOA_API_IS_SUBJECT_TO_CHANGE], [], [We are aware that GOA's API can c
 PKG_CHECK_MODULES(GRILO, [grilo-0.3 >= $GRILO_MIN_VERSION])
 PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= $GTK_MIN_VERSION])
 PKG_CHECK_MODULES(GTK_UNIX_PRINT, [gtk+-unix-print-3.0])
+PKG_CHECK_MODULES(PNG, [libpng16])
 PKG_CHECK_MODULES(TRACKER, [tracker-control-1.0 tracker-sparql-1.0])
 
 AX_REQUIRE_DEFINED([LIBGD_INIT])
diff --git a/src/Makefile.am b/src/Makefile.am
index 559c1a4..1bd1fd3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -134,6 +134,8 @@ gnome_photos_SOURCES = \
        photos-operation-insta-filter.h \
        photos-operation-jpg-guess-sizes.c \
        photos-operation-jpg-guess-sizes.h \
+       photos-operation-png-guess-sizes.c \
+       photos-operation-png-guess-sizes.h \
        photos-organize-collection-dialog.c \
        photos-organize-collection-dialog.h \
        photos-organize-collection-model.c \
@@ -144,6 +146,8 @@ gnome_photos_SOURCES = \
        photos-overview-searchbar.h \
        photos-pipeline.c \
        photos-pipeline.h \
+       photos-png-count.c \
+       photos-png-count.h \
        photos-preview-model.c \
        photos-preview-model.h \
        photos-preview-nav-buttons.c \
@@ -282,6 +286,7 @@ AM_CPPFLAGS = \
        $(GRILO_CFLAGS) \
        $(GTK_CFLAGS) \
        $(GTK_UNIX_PRINT_CFLAGS) \
+       $(PNG_CFLAGS) \
        $(TRACKER_CFLAGS) \
        -I$(top_srcdir)/libgd \
        $(NULL)
@@ -309,6 +314,7 @@ gnome_photos_LDADD = \
        $(GTK_LIBS) \
        $(GTK_UNIX_PRINT_LIBS) \
        $(JPEG_LIBS) \
+       $(PNG_LIBS) \
        $(TRACKER_LIBS) \
        $(LIBM) \
        $(top_builddir)/libgd/libgd.la \
diff --git a/src/photos-operation-png-guess-sizes.c b/src/photos-operation-png-guess-sizes.c
new file mode 100644
index 0000000..afeec0f
--- /dev/null
+++ b/src/photos-operation-png-guess-sizes.c
@@ -0,0 +1,369 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include <babl/babl.h>
+#include <gegl.h>
+#include <gegl-plugin.h>
+#include <png.h>
+
+#include "photos-png-count.h"
+#include "photos-operation-png-guess-sizes.h"
+
+
+struct _PhotosOperationPngGuessSizes
+{
+  GeglOperationSink parent_instance;
+  gboolean background;
+  gint bitdepth;
+  gint compression;
+  gsize sizes[2];
+};
+
+struct _PhotosOperationPngGuessSizesClass
+{
+  GeglOperationSinkClass parent_class;
+};
+
+enum
+{
+  PROP_0,
+  PROP_BACKGROUND,
+  PROP_BITDEPTH,
+  PROP_COMPRESSION,
+  PROP_SIZE,
+  PROP_SIZE_1
+};
+
+
+G_DEFINE_TYPE (PhotosOperationPngGuessSizes, photos_operation_png_guess_sizes, GEGL_TYPE_OPERATION_SINK);
+
+
+static gsize
+photos_operation_png_guess_sizes_count (GeglBuffer *buffer,
+                                        gint compression,
+                                        gint bitdepth,
+                                        gboolean background,
+                                        gdouble zoom,
+                                        gint src_x,
+                                        gint src_y,
+                                        gint width,
+                                        gint height)
+{
+  gint bpp;
+  gint i;
+  gint png_color_type;
+  gchar format_string[16];
+  const Babl *format;
+  const Babl *format_buffer;
+  gsize ret_val = 0;
+  gsize size;
+  guchar *pixels = NULL;
+  png_infop info_ptr = NULL;
+  png_structp png_ptr = NULL;
+
+  format_buffer = gegl_buffer_get_format (buffer);
+  if (babl_format_has_alpha (format_buffer))
+    {
+      if (babl_format_get_n_components (format_buffer) != 2)
+        {
+          png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+          strcpy (format_string, "R'G'B'A ");
+        }
+      else
+        {
+          png_color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+          strcpy (format_string, "Y'A ");
+        }
+    }
+  else
+    {
+      if (babl_format_get_n_components (format_buffer) != 1)
+        {
+          png_color_type = PNG_COLOR_TYPE_RGB;
+          strcpy (format_string, "R'G'B' ");
+        }
+      else
+        {
+          png_color_type = PNG_COLOR_TYPE_GRAY;
+          strcpy (format_string, "Y' ");
+        }
+    }
+
+  if (bitdepth == 16)
+    strcat (format_string, "u16");
+  else
+    strcat (format_string, "u8");
+
+  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if (png_ptr == NULL)
+    goto out;
+
+  info_ptr = png_create_info_struct (png_ptr);
+  if (info_ptr == NULL)
+    goto out;
+
+  if (setjmp (png_jmpbuf (png_ptr)))
+    goto out;
+
+  if (compression >= 0)
+    png_set_compression_level (png_ptr, compression);
+
+  photos_png_init_count (png_ptr, &size);
+
+  png_set_IHDR (png_ptr,
+                info_ptr,
+                width,
+                height,
+                bitdepth,
+                png_color_type,
+                PNG_INTERLACE_NONE,
+                PNG_COMPRESSION_TYPE_BASE,
+                PNG_FILTER_TYPE_DEFAULT);
+
+  if (background)
+    {
+      png_color_16 white;
+
+      if (png_color_type == PNG_COLOR_TYPE_RGB || png_color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+        {
+          white.red = 0xff;
+          white.blue = 0xff;
+          white.green = 0xff;
+        }
+      else
+        {
+          white.gray = 0xff;
+        }
+
+      png_set_bKGD (png_ptr, info_ptr, &white);
+    }
+
+  png_write_info (png_ptr, info_ptr);
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+  if (bitdepth > 8)
+    png_set_swap (png_ptr);
+#endif
+
+  format = babl_format (format_string);
+  bpp = babl_format_get_bytes_per_pixel (format);
+  pixels = g_malloc0 (width * bpp);
+
+  for (i = 0; i < height; i++)
+    {
+      GeglRectangle rect;
+
+      rect.x = src_x;
+      rect.y = src_y + i;
+      rect.width = width;
+      rect.height = 1;
+      gegl_buffer_get (buffer, &rect, zoom, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+      png_write_rows (png_ptr, &pixels, 1);
+    }
+
+  png_write_end (png_ptr, info_ptr);
+  ret_val = size;
+
+ out:
+  g_free (pixels);
+  png_destroy_write_struct (&png_ptr, &info_ptr);
+  return ret_val;
+}
+
+
+static gboolean
+photos_operation_png_guess_sizes_process (GeglOperation *operation,
+                                          GeglBuffer *input,
+                                          const GeglRectangle *roi,
+                                          gint level)
+{
+  PhotosOperationPngGuessSizes *self = PHOTOS_OPERATION_PNG_GUESS_SIZES (operation);
+  gsize i;
+
+  for (i = 0; i < G_N_ELEMENTS (self->sizes); i++)
+    {
+      GeglRectangle roi_zoomed;
+      gdouble zoom = 1.0 / (gdouble) (1 << i);
+
+      roi_zoomed.height = (gint) (zoom * roi->height + 0.5);
+      roi_zoomed.width = (gint) (zoom * roi->width + 0.5);
+      roi_zoomed.x = (gint) (zoom * roi->x + 0.5);
+      roi_zoomed.y = (gint) (zoom * roi->y + 0.5);
+
+      self->sizes[i] = photos_operation_png_guess_sizes_count (input,
+                                                               self->compression,
+                                                               self->bitdepth,
+                                                               self->background,
+                                                               zoom,
+                                                               roi_zoomed.x,
+                                                               roi_zoomed.y,
+                                                               roi_zoomed.width,
+                                                               roi_zoomed.height);
+    }
+
+  return TRUE;
+}
+
+
+static void
+photos_operation_png_guess_sizes_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec 
*pspec)
+{
+  PhotosOperationPngGuessSizes *self = PHOTOS_OPERATION_PNG_GUESS_SIZES (object);
+
+  switch (prop_id)
+    {
+    case PROP_BACKGROUND:
+      g_value_set_boolean (value, self->background);
+      break;
+
+    case PROP_BITDEPTH:
+      g_value_set_int (value, self->bitdepth);
+      break;
+
+    case PROP_COMPRESSION:
+      g_value_set_int (value, self->compression);
+      break;
+
+    case PROP_SIZE:
+      g_value_set_uint64 (value, (guint64) self->sizes[0]);
+      break;
+
+    case PROP_SIZE_1:
+      g_value_set_uint64 (value, (guint64) self->sizes[1]);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+photos_operation_png_guess_sizes_set_property (GObject *object,
+                                               guint prop_id,
+                                               const GValue *value,
+                                               GParamSpec *pspec)
+{
+  PhotosOperationPngGuessSizes *self = PHOTOS_OPERATION_PNG_GUESS_SIZES (object);
+
+  switch (prop_id)
+    {
+    case PROP_BACKGROUND:
+      self->background = g_value_get_boolean (value);
+      break;
+
+    case PROP_BITDEPTH:
+      self->bitdepth = g_value_get_int (value);
+      break;
+
+    case PROP_COMPRESSION:
+      self->compression = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+photos_operation_png_guess_sizes_init (PhotosOperationPngGuessSizes *self)
+{
+}
+
+
+static void
+photos_operation_png_guess_sizes_class_init (PhotosOperationPngGuessSizesClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (class);
+  GeglOperationSinkClass *sink_class = GEGL_OPERATION_SINK_CLASS (class);
+
+  operation_class->opencl_support = FALSE;
+  sink_class->needs_full = TRUE;
+
+  object_class->get_property = photos_operation_png_guess_sizes_get_property;
+  object_class->set_property = photos_operation_png_guess_sizes_set_property;
+  sink_class->process = photos_operation_png_guess_sizes_process;
+
+  g_object_class_install_property (object_class,
+                                   PROP_BACKGROUND,
+                                   g_param_spec_boolean ("background",
+                                                         "Background",
+                                                         "Set bKGD chunk information",
+                                                         TRUE,
+                                                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_BITDEPTH,
+                                   g_param_spec_int ("bitdepth",
+                                                     "Bitdepth",
+                                                     "Number of bits per channel — 8 and 16 are the 
currently "
+                                                     "accepted values",
+                                                     8,
+                                                     16,
+                                                     16,
+                                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_COMPRESSION,
+                                   g_param_spec_int ("compression",
+                                                     "Compression",
+                                                     "PNG compression level (between -1 and 9)",
+                                                     -1,
+                                                     9,
+                                                     3,
+                                                     G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SIZE,
+                                   g_param_spec_uint64 ("size",
+                                                        "Size (level=0)",
+                                                        "Approximate size in bytes after applying PNG 
compression"
+                                                        "at zoom=1.0",
+                                                        0,
+                                                        G_MAXSIZE,
+                                                        0,
+                                                        G_PARAM_READABLE));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SIZE_1,
+                                   g_param_spec_uint64 ("size-1",
+                                                        "Size (level=1)",
+                                                        "Approximate size in bytes after applying PNG 
compression"
+                                                        "at zoom=0.5",
+                                                        0,
+                                                        G_MAXSIZE,
+                                                        0,
+                                                        G_PARAM_READABLE));
+
+  gegl_operation_class_set_keys (operation_class,
+                                 "name", "photos:png-guess-sizes",
+                                 "title", "PNG Guess Sizes",
+                                 "description", "Guesses the size of a GeglBuffer after applying PNG 
compression",
+                                 NULL);
+}
diff --git a/src/photos-operation-png-guess-sizes.h b/src/photos-operation-png-guess-sizes.h
new file mode 100644
index 0000000..4fe4288
--- /dev/null
+++ b/src/photos-operation-png-guess-sizes.h
@@ -0,0 +1,45 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef PHOTOS_OPERATION_PNG_GUESS_SIZES_H
+#define PHOTOS_OPERATION_PNG_GUESS_SIZES_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PHOTOS_TYPE_OPERATION_PNG_GUESS_SIZES (photos_operation_png_guess_sizes_get_type ())
+
+#define PHOTOS_OPERATION_PNG_GUESS_SIZES(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   PHOTOS_TYPE_OPERATION_PNG_GUESS_SIZES, PhotosOperationPngGuessSizes))
+
+#define PHOTOS_IS_OPERATION_PNG_GUESS_SIZES(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   PHOTOS_TYPE_OPERATION_PNG_GUESS_SIZES))
+
+typedef struct _PhotosOperationPngGuessSizes      PhotosOperationPngGuessSizes;
+typedef struct _PhotosOperationPngGuessSizesClass PhotosOperationPngGuessSizesClass;
+
+GType           photos_operation_png_guess_sizes_get_type       (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* PHOTOS_OPERATION_PNG_GUESS_SIZES_H */
diff --git a/src/photos-png-count.c b/src/photos-png-count.c
new file mode 100644
index 0000000..0f50184
--- /dev/null
+++ b/src/photos-png-count.c
@@ -0,0 +1,50 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "config.h"
+
+#include "photos-png-count.h"
+
+
+static void
+photos_png_count_flush_data (png_structp png_ptr)
+{
+}
+
+
+static void
+photos_png_count_write_data (png_structp png_ptr, png_bytep data, png_size_t length)
+{
+  gsize *out_count;
+
+  out_count = (gsize *) png_get_io_ptr (png_ptr);
+  if (out_count != NULL)
+    *out_count += (gsize) length;
+}
+
+
+void
+photos_png_init_count (png_structp png_ptr, gsize *out_count)
+{
+  png_set_write_fn (png_ptr, out_count, photos_png_count_write_data, photos_png_count_flush_data);
+  if (out_count != NULL)
+    *out_count = 0;
+}
diff --git a/src/photos-png-count.h b/src/photos-png-count.h
new file mode 100644
index 0000000..66c0f5e
--- /dev/null
+++ b/src/photos-png-count.h
@@ -0,0 +1,33 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2016 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef PHOTOS_PNG_COUNT_H
+#define PHOTOS_PNG_COUNT_H
+
+#include <glib.h>
+#include <png.h>
+
+G_BEGIN_DECLS
+
+void                photos_png_init_count          (png_structp png_ptr, gsize *out_count);
+
+G_END_DECLS
+
+#endif /* PHOTOS_PNG_COUNT_H */
diff --git a/src/photos-utils.c b/src/photos-utils.c
index c5c64fd..a2f2451 100644
--- a/src/photos-utils.c
+++ b/src/photos-utils.c
@@ -45,6 +45,7 @@
 #include "photos-operation-insta-curve.h"
 #include "photos-operation-insta-filter.h"
 #include "photos-operation-jpg-guess-sizes.h"
+#include "photos-operation-png-guess-sizes.h"
 #include "photos-query.h"
 #include "photos-source.h"
 #include "photos-tool.h"
@@ -812,6 +813,7 @@ photos_utils_ensure_builtins (void)
       g_type_ensure (PHOTOS_TYPE_OPERATION_INSTA_CURVE);
       g_type_ensure (PHOTOS_TYPE_OPERATION_INSTA_FILTER);
       g_type_ensure (PHOTOS_TYPE_OPERATION_JPG_GUESS_SIZES);
+      g_type_ensure (PHOTOS_TYPE_OPERATION_PNG_GUESS_SIZES);
 
       g_type_ensure (PHOTOS_TYPE_TOOL_COLORS);
       g_type_ensure (PHOTOS_TYPE_TOOL_CROP);


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