[gtk/gamma-shenanigans] Save pngs using libpng
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/gamma-shenanigans] Save pngs using libpng
- Date: Mon, 6 Sep 2021 03:56:36 +0000 (UTC)
commit b49fd4e2eb1acad078820a544c77cbe9ff8f244c
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Sep 5 23:18:59 2021 -0400
Save pngs using libpng
If we have a texture with 16bit data, lets save
it as such when gdk_texture_save_to_png is called.
libpng lets us do this.
This replaces the cairo saving code with an
implementation using libpng's png_image.
gdk/gdkgltexture.c | 31 ++++++++++++++++++++++++++
gdk/gdkmemorytexture.c | 12 ++++++++++
gdk/gdktexture.c | 59 +++++++++++++++++++++++++++++++++++--------------
gdk/gdktextureprivate.h | 3 +++
4 files changed, 89 insertions(+), 16 deletions(-)
---
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index caf3e7ab6b..974545f576 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -22,6 +22,7 @@
#include "gdkcairo.h"
#include "gdktextureprivate.h"
+#include "gdkinternals.h"
#include <epoxy/gl.h>
@@ -110,6 +111,35 @@ gdk_gl_texture_download (GdkTexture *texture,
cairo_surface_destroy (surface);
}
+static GBytes *
+gdk_gl_texture_download_16bit (GdkTexture *texture)
+{
+ GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+ GdkSurface *surface;
+ GdkGLContext *context;
+ int format = 0;
+ gpointer data;
+ gsize size;
+
+ surface = gdk_gl_context_get_surface (self->context);
+ context = gdk_surface_get_paint_gl_context (surface, NULL);
+
+ gdk_gl_context_make_current (context);
+ glBindTexture (GL_TEXTURE_2D, self->id);
+ glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
+
+ if (format != GL_RGBA16)
+ return NULL;
+
+ size = texture->width * texture->height * 4 * sizeof (guint16);
+ data = malloc (size);
+
+ glReadPixels (0, 0, texture->width, texture->height,
+ GL_RGBA16, GL_UNSIGNED_SHORT, data);
+
+ return g_bytes_new_take (data, size);
+}
+
static void
gdk_gl_texture_class_init (GdkGLTextureClass *klass)
{
@@ -117,6 +147,7 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
texture_class->download = gdk_gl_texture_download;
+ texture_class->download_16bit = gdk_gl_texture_download_16bit;
gobject_class->dispose = gdk_gl_texture_dispose;
}
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index fbb77851d9..69d0e0317e 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -100,6 +100,17 @@ gdk_memory_texture_download (GdkTexture *texture,
area->width, area->height);
}
+static GBytes *
+gdk_memory_texture_download_16bit (GdkTexture *texture)
+{
+ GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
+
+ if (self->format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
+ return g_bytes_ref (self->bytes);
+
+ return NULL;
+}
+
static void
gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
{
@@ -107,6 +118,7 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
texture_class->download = gdk_memory_texture_download;
+ texture_class->download_16bit = gdk_memory_texture_download_16bit;
gobject_class->dispose = gdk_memory_texture_dispose;
}
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 112707e300..8792c95663 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -125,6 +125,12 @@ gdk_texture_real_download (GdkTexture *self,
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download);
}
+static GBytes *
+gdk_texture_real_download_16bit (GdkTexture *self)
+{
+ return NULL;
+}
+
static void
gdk_texture_set_property (GObject *gobject,
guint prop_id,
@@ -189,6 +195,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->download = gdk_texture_real_download;
+ klass->download_16bit = gdk_texture_real_download_16bit;
gobject_class->set_property = gdk_texture_set_property;
gobject_class->get_property = gdk_texture_get_property;
@@ -564,6 +571,12 @@ gdk_texture_download (GdkTexture *texture,
stride);
}
+GBytes *
+gdk_texture_download_16bit (GdkTexture *texture)
+{
+ return GDK_TEXTURE_GET_CLASS (texture)->download_16bit (texture);
+}
+
gboolean
gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
@@ -610,6 +623,9 @@ gdk_texture_get_render_data (GdkTexture *self,
*
* Store the given @texture to the @filename as a PNG file.
*
+ * If the texture contains 16bit data, the generated PNG file
+ * will have linear 16bit data, otherwise it will contain SRGB.
+ *
* This is a utility function intended for debugging and testing.
* If you want more control over formats, proper error handling or
* want to store to a `GFile` or other location, you might want to
@@ -621,30 +637,41 @@ gboolean
gdk_texture_save_to_png (GdkTexture *texture,
const char *filename)
{
- cairo_surface_t *surface;
- cairo_status_t status;
+ png_image image = { NULL, PNG_IMAGE_VERSION, 0, };
+ GBytes *bytes;
gboolean result;
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
- surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- gdk_texture_get_width (texture),
- gdk_texture_get_height (texture));
- gdk_texture_download (texture,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_stride (surface));
- cairo_surface_mark_dirty (surface);
-
- status = cairo_surface_write_to_png (surface, filename);
+ image.width = gdk_texture_get_width (texture);
+ image.height = gdk_texture_get_height (texture);
- if (status != CAIRO_STATUS_SUCCESS ||
- cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
- result = FALSE;
+ bytes = gdk_texture_download_16bit (texture);
+ if (bytes)
+ {
+ image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
+ }
else
- result = TRUE;
+ {
+ int stride = image.width * 4;
+ gpointer data;
+
+ data = malloc (image.height * stride);
+
+ gdk_texture_download (texture, data, stride);
- cairo_surface_destroy (surface);
+ bytes = g_bytes_new_take (data, image.height * stride);
+
+ image.format = PNG_FORMAT_RGBA;
+ }
+
+ result = png_image_write_to_file (&image, filename, FALSE,
+ g_bytes_get_data (bytes, NULL),
+ 0, NULL);
+ g_bytes_unref (bytes);
+
+ png_image_free (&image);
return result;
}
diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h
index 3e2e9f3a49..e0b7b842a6 100644
--- a/gdk/gdktextureprivate.h
+++ b/gdk/gdktextureprivate.h
@@ -28,6 +28,7 @@ struct _GdkTextureClass {
const GdkRectangle *area,
guchar *data,
gsize stride);
+ GBytes * (* download_16bit) (GdkTexture *texture);
};
gpointer gdk_texture_new (const GdkTextureClass *klass,
@@ -48,6 +49,8 @@ void gdk_texture_clear_render_data (GdkTexture
gpointer gdk_texture_get_render_data (GdkTexture *self,
gpointer key);
+GBytes * gdk_texture_download_16bit (GdkTexture *texture);
+
G_END_DECLS
#endif /* __GDK_TEXTURE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]