[gegl] bin: use fast 90 degree rotation and flips from gnome-photos
- From: Øyvind "pippin" Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] bin: use fast 90 degree rotation and flips from gnome-photos
- Date: Sun, 24 Feb 2019 17:01:48 +0000 (UTC)
commit 93ce1dfab55b7c8f895e1a3bb0603fbbce92c1bf
Author: Øyvind Kolås <pippin gimp org>
Date: Sun Feb 24 17:58:54 2019 +0100
bin: use fast 90 degree rotation and flips from gnome-photos
Rotating JPGs with embedded ICC profiles is otherwise much much slower than it
needs to be.
bin/ui.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 340 insertions(+), 1 deletion(-)
---
diff --git a/bin/ui.c b/bin/ui.c
index 99b18aedf..1de89821f 100644
--- a/bin/ui.c
+++ b/bin/ui.c
@@ -5504,10 +5504,13 @@ static gboolean run_lua_file (const char *basename)
"cr = mrg:cr()\n"
"dim = mrg:height() * 0.1;\n"
"dim, dimy = cr:device_to_user_distance(dim, dim)\n"
-"centerx, centery = cr:device_to_user_coordinate(mrg:width()/2, mrg:height()/2)\n"
+"centerx, centery = cr:device_to_user(mrg:width()/2, mrg:height()/2)\n"
"source = foo.source\n");
result = lua_pcall(L, 0, LUA_MULTRET, 0);
+ if (result){
+ fprintf (stderr, "lua exec problem %s\n", lua_tostring(L, -1));
+ }
status = luaL_loadfile(L, path);
if (status)
@@ -6144,6 +6147,330 @@ static void drag_preview (MrgEvent *e)
}
}
+/* photos_gegl_buffer_apply_orientation from GNOME Photos */
+
+typedef enum {
+ PHOTOS_ORIENTATION_UNSPECIFIED = 0,
+ PHOTOS_ORIENTATION_TOP = GEXIV2_ORIENTATION_NORMAL,
+ PHOTOS_ORIENTATION_TOP_MIRROR = GEXIV2_ORIENTATION_HFLIP,
+ PHOTOS_ORIENTATION_BOTTOM = GEXIV2_ORIENTATION_ROT_180,
+ PHOTOS_ORIENTATION_BOTTOM_MIRROR = GEXIV2_ORIENTATION_VFLIP,
+ PHOTOS_ORIENTATION_LEFT_MIRROR = GEXIV2_ORIENTATION_ROT_90_HFLIP,
+ PHOTOS_ORIENTATION_RIGHT = GEXIV2_ORIENTATION_ROT_90,
+ PHOTOS_ORIENTATION_RIGHT_MIRROR =GEXIV2_ORIENTATION_ROT_90_VFLIP,
+ PHOTOS_ORIENTATION_LEFT = GEXIV2_ORIENTATION_ROT_270,
+} Orientation;
+
+static void
+photos_gegl_buffer_apply_orientation_flip_in_place (guchar *buf, gint bpp, gint n_pixels)
+{
+ gint i;
+
+ for (i = 0; i < n_pixels / 2; i++)
+ {
+ gint j;
+ guchar *pixel_left = buf + i * bpp;
+ guchar *pixel_right = buf + (n_pixels - 1 - i) * bpp;
+
+ for (j = 0; j < bpp; j++)
+ {
+ guchar tmp = pixel_left[j];
+
+ pixel_left[j] = pixel_right[j];
+ pixel_right[j] = tmp;
+ }
+ }
+}
+
+static GeglBuffer *
+photos_gegl_buffer_apply_orientation (GeglBuffer *buffer_original, Orientation 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 (GEGL_IS_BUFFER (buffer_original), NULL);
+ g_return_val_if_fail (orientation == PHOTOS_ORIENTATION_UNSPECIFIED
+ ||orientation == PHOTOS_ORIENTATION_BOTTOM
+ || orientation == PHOTOS_ORIENTATION_BOTTOM_MIRROR
+ || orientation == PHOTOS_ORIENTATION_LEFT
+ || orientation == PHOTOS_ORIENTATION_LEFT_MIRROR
+ || orientation == PHOTOS_ORIENTATION_RIGHT
+ || orientation == PHOTOS_ORIENTATION_RIGHT_MIRROR
+ || orientation == PHOTOS_ORIENTATION_TOP
+ || orientation == PHOTOS_ORIENTATION_TOP_MIRROR,
+ NULL);
+
+ if (orientation == PHOTOS_ORIENTATION_TOP ||
+ orientation == PHOTOS_ORIENTATION_UNSPECIFIED)
+ {
+ ret_val = g_object_ref (buffer_original);
+ goto out;
+ }
+
+ bbox_original = *gegl_buffer_get_extent (buffer_original);
+
+ if (orientation == PHOTOS_ORIENTATION_BOTTOM || orientation == PHOTOS_ORIENTATION_BOTTOM_MIRROR)
+ {
+ /* angle = 180 degrees */
+ /* angle = 180 degrees, axis = vertical; or, axis = horizontal */
+ 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 || orientation == PHOTOS_ORIENTATION_LEFT_MIRROR)
+ {
+ /* angle = -270 or 90 degrees counterclockwise */
+ /* angle = -270 or 90 degrees counterclockwise, axis = horizontal */
+ 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 || orientation == PHOTOS_ORIENTATION_RIGHT_MIRROR)
+ {
+ /* angle = -90 or 270 degrees counterclockwise */
+ /* angle = -90 or 270 degrees counterclockwise, axis = horizontal */
+ 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_TOP_MIRROR)
+ {
+ /* axis = vertical */
+ 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
+ {
+ 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 || orientation == PHOTOS_ORIENTATION_BOTTOM_MIRROR)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+
+ /* angle = 180 degrees */
+ /* angle = 180 degrees, axis = vertical; or, axis = horizontal */
+
+ 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;
+
+ if (orientation == PHOTOS_ORIENTATION_BOTTOM)
+ {
+ gint i;
+ g_autofree guchar *buf = NULL;
+
+ buf = g_malloc0_n (bbox_oriented.width, 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);
+ photos_gegl_buffer_apply_orientation_flip_in_place (buf, bpp, bbox_original.width);
+ gegl_buffer_set (buffer_oriented, &bbox_destination, 0, format, buf, GEGL_AUTO_ROWSTRIDE);
+
+ bbox_destination.y++;
+ bbox_source.y--;
+ }
+ }
+ else
+ {
+ gint i;
+
+ for (i = 0; i < bbox_original.height; i++)
+ {
+ gegl_buffer_copy (buffer_original, &bbox_source, GEGL_ABYSS_NONE, buffer_oriented,
&bbox_destination);
+ bbox_destination.y++;
+ bbox_source.y--;
+ }
+ }
+ }
+ else if (orientation == PHOTOS_ORIENTATION_LEFT || orientation == PHOTOS_ORIENTATION_LEFT_MIRROR)
+ {
+ GeglRectangle bbox_source;
+ g_autofree guchar *buf = NULL;
+
+ /* angle = -270 or 90 degrees counterclockwise */
+ /* angle = -270 or 90 degrees counterclockwise, axis = horizontal */
+
+ g_return_val_if_fail (bbox_oriented.height == bbox_original.width, NULL);
+ g_return_val_if_fail (bbox_oriented.width == bbox_original.height, NULL);
+
+ 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);
+
+ if (orientation == PHOTOS_ORIENTATION_LEFT)
+ {
+ GeglRectangle bbox_destination;
+ gint i;
+
+ gegl_rectangle_set (&bbox_destination, bbox_oriented.x, bbox_oriented.y, (guint)
bbox_oriented.width, 1);
+
+ 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
+ {
+ GeglRectangle bbox_destination;
+ gint i;
+
+ bbox_destination.x = bbox_oriented.x;
+ bbox_destination.y = bbox_oriented.y + bbox_oriented.height - 1;
+ bbox_destination.height = 1;
+ bbox_destination.width = bbox_oriented.width;
+
+ 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 || orientation == PHOTOS_ORIENTATION_RIGHT_MIRROR)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+ g_autofree guchar *buf = NULL;
+
+ /* angle = -90 or 270 degrees counterclockwise */
+ /* angle = -90 or 270 degrees counterclockwise, axis = horizontal */
+
+ 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);
+
+ if (orientation == PHOTOS_ORIENTATION_RIGHT)
+ {
+ gint i;
+
+ 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
+ {
+ gint i;
+
+ 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);
+ photos_gegl_buffer_apply_orientation_flip_in_place (buf, bpp, bbox_original.width);
+ gegl_buffer_set (buffer_oriented, &bbox_destination, 0, format, buf, GEGL_AUTO_ROWSTRIDE);
+ bbox_destination.x++;
+ bbox_source.y--;
+ }
+ }
+ }
+ else if (orientation == PHOTOS_ORIENTATION_TOP_MIRROR)
+ {
+ GeglRectangle bbox_destination;
+ GeglRectangle bbox_source;
+ gint i;
+
+ /* axis = vertical */
+
+ g_return_val_if_fail (bbox_oriented.height == bbox_original.height, NULL);
+ g_return_val_if_fail (bbox_oriented.width == bbox_original.width, NULL);
+
+ bbox_destination.x = bbox_oriented.x + bbox_oriented.width - 1;
+ bbox_destination.y = bbox_oriented.y;
+ bbox_destination.height = bbox_oriented.height;
+ bbox_destination.width = 1;
+
+ gegl_rectangle_set (&bbox_source, bbox_original.x, bbox_original.y, 1, (guint) bbox_original.height);
+
+ for (i = 0; i < bbox_original.width; i++)
+ {
+ gegl_buffer_copy (buffer_original, &bbox_source, GEGL_ABYSS_NONE, buffer_oriented,
&bbox_destination);
+ bbox_destination.x--;
+ bbox_source.x++;
+ }
+ }
+ else
+ {
+ g_return_val_if_reached (NULL);
+ }
+
+ ret_val = g_object_ref (buffer_oriented);
+
+ out:
+ return ret_val;
+}
+
+
+
static void load_into_buffer (GeState *o, const char *path)
{
GeglNode *gegl, *load, *sink;
@@ -6171,8 +6498,12 @@ static void load_into_buffer (GeState *o, const char *path)
gegl_node_process (sink);
g_object_unref (gegl);
+
+
+
{
GExiv2Orientation orientation = path_get_orientation (path);
+#if 0
gboolean hflip = FALSE;
gboolean vflip = FALSE;
double degrees = 0.0;
@@ -6222,6 +6553,14 @@ static void load_into_buffer (GeState *o, const char *path)
g_object_unref (o->buffer);
o->buffer = new_buffer;
}
+#else
+ {
+ GeglBuffer *orig = o->buffer;
+ fprintf (stderr, "%i\n", orientation);
+ o->buffer = photos_gegl_buffer_apply_orientation (orig, orientation);
+ g_object_unref (orig);
+ }
+#endif
}
#if 0 /* hack to see if having the data in some formats already is faster */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]