[gtk/wip/otte/memoryformat: 28/28] png: Refactor png saving




commit 20f8582ee5ea9b427556fb95c3517b0b567d1a88
Author: Benjamin Otte <otte redhat com>
Date:   Mon Sep 27 05:55:48 2021 +0200

    png: Refactor png saving
    
    Do all the memory format shenanigans in GTK now and support all the PNG
    formats.

 gdk/loaders/gdkpng.c | 139 +++++++++++++--------------------------------------
 1 file changed, 36 insertions(+), 103 deletions(-)
---
diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c
index eb8b392dea..5d9cf38cfa 100644
--- a/gdk/loaders/gdkpng.c
+++ b/gdk/loaders/gdkpng.c
@@ -127,85 +127,6 @@ png_simple_warning_callback (png_structp     png,
 {
 }
 
-/* }}} */
-/* {{{ Format conversion */
-
-static void
-unpremultiply (guchar *data,
-               int     width,
-               int     height)
-{
-  gsize x, y;
-
-  for (y = 0; y < height; y++)
-    {
-      for (x = 0; x < width; x++)
-        {
-          guchar *b = &data[x * 4];
-          guint32 pixel;
-          guchar alpha;
-
-          memcpy (&pixel, b, sizeof (guint32));
-          alpha = (pixel & 0xff000000) >> 24;
-          if (alpha == 0)
-            {
-              b[0] = 0;
-              b[1] = 0;
-              b[2] = 0;
-              b[3] = 0;
-            }
-          else
-            {
-              b[0] = (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
-              b[1] = (((pixel & 0x0000ff00) >>  8) * 255 + alpha / 2) / alpha;
-              b[2] = (((pixel & 0x000000ff) >>  0) * 255 + alpha / 2) / alpha;
-              b[3] = alpha;
-            }
-        }
-      data += width * 4;
-    }
-}
-
-static void
-unpremultiply_float_to_16bit (guchar *data,
-                              int     width,
-                              int     height)
-{
-  gsize x, y;
-  float *src = (float *)data;;
-  guint16 *dest = (guint16 *)data;
-
-  for (y = 0; y < height; y++)
-    {
-      for (x = 0; x < width; x++)
-        {
-          float r, g, b, a;
-
-          r = src[0];
-          g = src[1];
-          b = src[2];
-          a = src[3];
-          if (a == 0)
-            {
-              dest[0] = 0;
-              dest[1] = 0;
-              dest[2] = 0;
-              dest[3] = 0;
-            }
-          else
-            {
-              dest[0] = (guint16) CLAMP (65536.f * r / a, 0.f, 65535.f);
-              dest[1] = (guint16) CLAMP (65536.f * g / a, 0.f, 65535.f);
-              dest[2] = (guint16) CLAMP (65536.f * b / a, 0.f, 65535.f);
-              dest[3] = (guint16) CLAMP (65536.f * a,     0.f, 65535.f);
-            }
-
-          dest += 4;
-          src += 4;
-        }
-    }
-}
-
 /* }}} */
 /* {{{ Public API */ 
 
@@ -382,11 +303,11 @@ gdk_save_png (GdkTexture *texture)
   png_struct *png = NULL;
   png_info *info;
   png_io io = { NULL, 0, 0 };
-  guint width, height, stride;
-  guchar *data = NULL;
-  guchar *row;
+  int width, height;
+  gsize stride;
+  const guchar *data;
   int y;
-  GdkTexture *mtexture;
+  GdkMemoryTexture *memtex;
   GdkMemoryFormat format;
   int png_format;
   int depth;
@@ -395,8 +316,6 @@ gdk_save_png (GdkTexture *texture)
   height = gdk_texture_get_height (texture);
   format = gdk_texture_get_format (texture);
 
-  mtexture = GDK_TEXTURE (gdk_memory_texture_from_texture (texture, format));
-
   switch (format)
     {
     case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
@@ -406,32 +325,42 @@ gdk_save_png (GdkTexture *texture)
     case GDK_MEMORY_A8R8G8B8:
     case GDK_MEMORY_R8G8B8A8:
     case GDK_MEMORY_A8B8G8R8:
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+      format = GDK_MEMORY_R8G8B8A8;
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+      format = GDK_MEMORY_A8B8G8R8;
+#endif
+      png_format = PNG_COLOR_TYPE_RGB_ALPHA;
+      depth = 8;
+      break;
+
     case GDK_MEMORY_R8G8B8:
     case GDK_MEMORY_B8G8R8:
-      stride = width * 4;
-      data = g_malloc_n (stride, height);
-      gdk_texture_download (mtexture, data, stride);
-      unpremultiply (data, width, height);
-
-      png_format = PNG_COLOR_TYPE_RGB_ALPHA;
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+      format = GDK_MEMORY_R8G8B8;
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+      format = GDK_MEMORY_B8G8R8;
+#endif
+      png_format = PNG_COLOR_TYPE_RGB;
       depth = 8;
       break;
 
-    case GDK_MEMORY_R16G16B16:
     case GDK_MEMORY_R16G16B16A16:
     case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
-    case GDK_MEMORY_R16G16B16_FLOAT:
     case GDK_MEMORY_R16G16B16A16_FLOAT:
     case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
-    case GDK_MEMORY_R32G32B32_FLOAT:
     case GDK_MEMORY_R32G32B32A32_FLOAT:
     case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
-      data = g_malloc_n (width * 16, height);
-      gdk_texture_download_float (mtexture, (float *)data, width * 4);
-      unpremultiply_float_to_16bit (data, width, height);
-
+      format = GDK_MEMORY_R16G16B16A16;
       png_format = PNG_COLOR_TYPE_RGB_ALPHA;
-      stride = width * 8;
+      depth = 16;
+      break;
+
+    case GDK_MEMORY_R16G16B16:
+    case GDK_MEMORY_R16G16B16_FLOAT:
+    case GDK_MEMORY_R32G32B32_FLOAT:
+      format = GDK_MEMORY_R16G16B16;
+      png_format = PNG_COLOR_TYPE_RGB;
       depth = 16;
       break;
 
@@ -458,12 +387,14 @@ gdk_save_png (GdkTexture *texture)
 
   if (sigsetjmp (png_jmpbuf (png), 1))
     {
-      g_free (data);
+      g_object_unref (memtex);
       g_free (io.data);
       png_destroy_read_struct (&png, &info, NULL);
       return NULL;
     }
 
+  memtex = gdk_memory_texture_from_texture (texture, format);
+
   png_set_write_fn (png, &io, png_write_func, png_flush_func);
 
   png_set_IHDR (png, info, width, height, depth,
@@ -478,14 +409,16 @@ gdk_save_png (GdkTexture *texture)
   png_set_swap (png);
 #endif
 
-  for (y = 0, row = data; y < height; y++, row += stride)
-    png_write_rows (png, &row, 1);
+  data = gdk_memory_texture_get_data (memtex);
+  stride = gdk_memory_texture_get_stride (memtex);
+  for (y = 0; y < height; y++)
+    png_write_row (png, data + y * stride);
 
   png_write_end (png, info);
 
   png_destroy_write_struct (&png, &info);
 
-  g_free (data);
+  g_object_unref (memtex);
 
   return g_bytes_new_take (io.data, io.size);
 }


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