[gnome-photos] gegl: Add photos_gegl_buffer_apply_orientation
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos] gegl: Add photos_gegl_buffer_apply_orientation
- Date: Sun, 26 Nov 2017 10:12:16 +0000 (UTC)
commit b4e7b56f9863654f07de61d444ccbc947b6c0838
Author: Debarshi Ray <debarshir gnome org>
Date: Thu Nov 23 15:58:19 2017 +0100
gegl: Add photos_gegl_buffer_apply_orientation
Directly rearranging the pixels by avoiding the sampling and matrix
multiplication used by gegl:rotate-on-center makes the whole process
of decoding pixels off an image file and applying the orientation ten
times faster! It is true even for the worst case where angle of
rotation is 180 degrees, and pixels need to be swapped in addition to
rearranging the rows and columns.
This is part of a new set of APIs for GeglBuffer that don't require the
creation of a graph. These will allow decoding and encoding image file
formats to and from a GeglBuffer through asynchronous and cancellable
methods with error handling. These will follow GIO idioms and be
similar to the codec APIs for GdkPixbuf. There will be a compatibility
layer to convert a GeglBuffer to and from GdkPixbuf for legacy reasons.
These APIs will address the current lack of cancellation and error
handling in gegl:load, and make it easier to port existing code away
from GdkPixbuf.
https://bugzilla.gnome.org/show_bug.cgi?id=781736
src/photos-gegl.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/photos-gegl.h | 2 +
2 files changed, 181 insertions(+), 0 deletions(-)
---
diff --git a/src/photos-gegl.c b/src/photos-gegl.c
index 356a426..2127efb 100644
--- a/src/photos-gegl.c
+++ b/src/photos-gegl.c
@@ -18,6 +18,10 @@
* 02110-1301, USA.
*/
+/* Based on code from:
+ * + GIMP
+ */
+
#include "config.h"
@@ -69,6 +73,181 @@ static const gchar *REQUIRED_GEGL_OPS[] =
GeglBuffer *
+photos_gegl_buffer_apply_orientation (GeglBuffer *buffer_original, GQuark orientation)
+{
+ const Babl *format;
+ g_autoptr (GeglBuffer) buffer_oriented = NULL;
+ GeglBuffer *ret_val = NULL;
+ GeglRectangle bbox_oriented;
+ GeglRectangle bbox_original;
+ gint bpp;
+
+ g_return_val_if_fail (orientation == PHOTOS_ORIENTATION_BOTTOM
+ || orientation == PHOTOS_ORIENTATION_LEFT
+ || orientation == PHOTOS_ORIENTATION_RIGHT
+ || orientation == PHOTOS_ORIENTATION_TOP,
+ NULL);
+
+ if (orientation == PHOTOS_ORIENTATION_TOP)
+ {
+ ret_val = g_object_ref (buffer_original);
+ goto out;
+ }
+
+ bbox_original = *gegl_buffer_get_extent (buffer_original);
+
+ if (orientation == PHOTOS_ORIENTATION_BOTTOM)
+ {
+ /* angle = 180 degrees */
+ bbox_oriented.height = bbox_original.height;
+ bbox_oriented.width = bbox_original.width;
+ bbox_oriented.x = bbox_original.x;
+ bbox_oriented.y = bbox_original.y;
+ }
+ else if (orientation == PHOTOS_ORIENTATION_LEFT)
+ {
+ /* angle = -270 or 90 degrees counterclockwise */
+ bbox_oriented.height = bbox_original.width;
+ bbox_oriented.width = bbox_original.height;
+ bbox_oriented.x = bbox_original.x;
+ bbox_oriented.y = bbox_original.y;
+ }
+ else if (orientation == PHOTOS_ORIENTATION_RIGHT)
+ {
+ /* angle = -90 or 270 degrees counterclockwise */
+ bbox_oriented.height = bbox_original.width;
+ bbox_oriented.width = bbox_original.height;
+ bbox_oriented.x = bbox_original.x;
+ bbox_oriented.y = bbox_original.y;
+ }
+ else
+ {
+ g_return_val_if_reached (NULL);
+ }
+
+ format = gegl_buffer_get_format (buffer_original);
+ bpp = babl_format_get_bytes_per_pixel (format);
+ buffer_oriented = gegl_buffer_new (&bbox_oriented, format);
+
+ if (orientation == PHOTOS_ORIENTATION_BOTTOM)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+ gint i;
+ g_autofree guchar *buf = NULL;
+
+ /* angle = 180 degrees */
+
+ g_return_val_if_fail (bbox_oriented.height == bbox_original.height, NULL);
+ g_return_val_if_fail (bbox_oriented.width == bbox_original.width, NULL);
+
+ gegl_rectangle_set (&bbox_destination, bbox_oriented.x, bbox_oriented.y, (guint) bbox_oriented.width,
1);
+
+ bbox_source.x = bbox_original.x;
+ bbox_source.y = bbox_original.y + bbox_original.height - 1;
+ bbox_source.height = 1;
+ bbox_source.width = bbox_original.width;
+
+ buf = g_malloc0_n (bbox_oriented.width, bpp);
+
+ for (i = 0; i < bbox_original.height; i++)
+ {
+ gint j;
+
+ gegl_buffer_get (buffer_original, &bbox_source, 1.0, format, buf, GEGL_AUTO_ROWSTRIDE,
GEGL_ABYSS_NONE);
+
+ for (j = 0; j < bbox_original.width / 2; j++)
+ {
+ gint k;
+ guchar *pixel_left = buf + j * bpp;
+ guchar *pixel_right = buf + (bbox_original.width - 1 - j) * bpp;
+
+ for (k = 0; k < bpp; k++)
+ {
+ guchar tmp = pixel_left[k];
+
+ pixel_left[k] = pixel_right[k];
+ pixel_right[k] = tmp;
+ }
+ }
+
+ gegl_buffer_set (buffer_oriented, &bbox_destination, 0, format, buf, GEGL_AUTO_ROWSTRIDE);
+
+ bbox_destination.y++;
+ bbox_source.y--;
+ }
+ }
+ else if (orientation == PHOTOS_ORIENTATION_LEFT)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+ gint i;
+ g_autofree guchar *buf = NULL;
+
+ /* angle = -270 or 90 degrees counterclockwise */
+
+ g_return_val_if_fail (bbox_oriented.height == bbox_original.width, NULL);
+ g_return_val_if_fail (bbox_oriented.width == bbox_original.height, NULL);
+
+ gegl_rectangle_set (&bbox_destination, bbox_oriented.x, bbox_oriented.y, (guint) bbox_oriented.width,
1);
+
+ bbox_source.x = bbox_original.x + bbox_original.width - 1;
+ bbox_source.y = bbox_original.y;
+ bbox_source.height = bbox_original.height;
+ bbox_source.width = 1;
+
+ buf = g_malloc0_n (bbox_oriented.width, bpp);
+
+ for (i = 0; i < bbox_original.width; i++)
+ {
+ gegl_buffer_get (buffer_original, &bbox_source, 1.0, format, buf, GEGL_AUTO_ROWSTRIDE,
GEGL_ABYSS_NONE);
+ gegl_buffer_set (buffer_oriented, &bbox_destination, 0, format, buf, GEGL_AUTO_ROWSTRIDE);
+ bbox_destination.y++;
+ bbox_source.x--;
+ }
+ }
+ else if (orientation == PHOTOS_ORIENTATION_RIGHT)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+ gint i;
+ g_autofree guchar *buf = NULL;
+
+ /* angle = -90 or 270 degrees counterclockwise */
+
+ g_return_val_if_fail (bbox_oriented.height == bbox_original.width, NULL);
+ g_return_val_if_fail (bbox_oriented.width == bbox_original.height, NULL);
+
+ gegl_rectangle_set (&bbox_destination, bbox_oriented.x, bbox_oriented.y, 1, (guint)
bbox_oriented.height);
+
+ bbox_source.x = bbox_original.x;
+ bbox_source.y = bbox_original.y + bbox_original.height - 1;
+ bbox_source.height = 1;
+ bbox_source.width = bbox_original.width;
+
+ buf = g_malloc0_n (bbox_oriented.height, bpp);
+
+ for (i = 0; i < bbox_original.height; i++)
+ {
+ gegl_buffer_get (buffer_original, &bbox_source, 1.0, format, buf, GEGL_AUTO_ROWSTRIDE,
GEGL_ABYSS_NONE);
+ gegl_buffer_set (buffer_oriented, &bbox_destination, 0, format, buf, GEGL_AUTO_ROWSTRIDE);
+ bbox_destination.x++;
+ bbox_source.y--;
+ }
+ }
+ else
+ {
+ g_return_val_if_reached (NULL);
+ }
+
+ ret_val = g_object_ref (buffer_oriented);
+
+ out:
+ return ret_val;
+}
+
+
+GeglBuffer *
photos_gegl_buffer_new_from_pixbuf (GdkPixbuf *pixbuf)
{
const Babl *format;
diff --git a/src/photos-gegl.h b/src/photos-gegl.h
index 83cb2ed..01e7cc9 100644
--- a/src/photos-gegl.h
+++ b/src/photos-gegl.h
@@ -29,6 +29,8 @@
G_BEGIN_DECLS
+GeglBuffer *photos_gegl_buffer_apply_orientation (GeglBuffer *buffer_original, GQuark orientation);
+
GeglBuffer *photos_gegl_buffer_new_from_pixbuf (GdkPixbuf *pixbuf);
void photos_gegl_buffer_zoom_async (GeglBuffer *buffer,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]