[gtk/image-loading: 63/70] Add code to save jpegs
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/image-loading: 63/70] Add code to save jpegs
- Date: Thu, 16 Sep 2021 01:12:48 +0000 (UTC)
commit b7050dd7d21f1dd402a52bc2c1b73a84595ef14d
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Sep 14 17:40:29 2021 -0400
Add code to save jpegs
gdk/loaders/gdkjpeg.c | 205 ++++++++++++++++++++++++++++++++++++++++---
gdk/loaders/gdkjpegprivate.h | 2 +
2 files changed, 196 insertions(+), 11 deletions(-)
---
diff --git a/gdk/loaders/gdkjpeg.c b/gdk/loaders/gdkjpeg.c
index 74a1c9623a..506a278aaa 100644
--- a/gdk/loaders/gdkjpeg.c
+++ b/gdk/loaders/gdkjpeg.c
@@ -70,7 +70,97 @@ output_message_handler (j_common_ptr cinfo)
}
/* }}} */
- /* {{{ Public API */
+/* {{{ Format conversion */
+
+static void
+convert_rgba_to_rgb (guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ gsize x, y;
+ guchar *src, *dest;
+
+ for (y = 0; y < height; y++)
+ {
+ src = data;
+ dest = data;
+
+ for (x = 0; x < width; x++)
+ {
+ guint32 pixel;
+
+ memcpy (&pixel, src, sizeof (guint32));
+
+ dest[0] = (pixel & 0x00ff0000) >> 16;
+ dest[1] = (pixel & 0x0000ff00) >> 8;
+ dest[2] = (pixel & 0x000000ff) >> 0;
+
+ dest += 3;
+ src += 4;
+ }
+
+ data += stride;
+ }
+}
+
+static void
+convert_grayscale_to_rgb (guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ gsize x, y;
+ guchar *dest, *src;
+
+ for (y = 0; y < height; y++)
+ {
+ src = data + width;
+ dest = data + 3 * width;
+ for (x = 0; x < width; x++)
+ {
+ dest -= 3;
+ src -= 1;
+ dest[0] = *src;
+ dest[1] = *src;
+ dest[2] = *src;
+ }
+ data += stride;
+ }
+}
+
+static void
+convert_cmyk_to_rgba (guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ gsize x, r;
+ guchar *dest;
+
+ for (r = 0; r < height; r++)
+ {
+ dest = data;
+ for (x = 0; x < width; x++)
+ {
+ int c, m, y, k;
+
+ c = dest[0];
+ m = dest[1];
+ y = dest[2];
+ k = dest[3];
+ dest[0] = k * c / 255;
+ dest[1] = k * m / 255;
+ dest[2] = k * y / 255;
+ dest[3] = 255;
+ dest += 4;
+ }
+ data += stride;
+ }
+}
+
+ /* }}} */
+/* {{{ Public API */
GdkTexture *
gdk_load_jpeg (GBytes *input_bytes,
@@ -78,13 +168,12 @@ gdk_load_jpeg (GBytes *input_bytes,
{
struct jpeg_decompress_struct info;
struct error_handler_data jerr;
- struct jpeg_error_mgr err;
- int width, height;
- int size;
+ guint width, height, stride;
unsigned char *data;
unsigned char *row[1];
GBytes *bytes;
GdkTexture *texture;
+ GdkMemoryFormat format;
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
@@ -97,7 +186,6 @@ gdk_load_jpeg (GBytes *input_bytes,
return NULL;
}
- info.err = jpeg_std_error (&err);
jpeg_create_decompress (&info);
jpeg_mem_src (&info,
@@ -110,8 +198,27 @@ gdk_load_jpeg (GBytes *input_bytes,
width = info.output_width;
height = info.output_height;
- size = width * height * 3;
- data = g_try_malloc_n (width * 3, height);
+ switch ((int)info.out_color_space)
+ {
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ stride = 3 * width;
+ data = g_try_malloc_n (stride, height);
+ format = GDK_MEMORY_R8G8B8;
+ break;
+ case JCS_CMYK:
+ stride = 4 * width;
+ data = g_try_malloc_n (stride, height);
+ format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+ break;
+ default:
+ g_set_error (error,
+ GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED,
+ "Unsupported colorspace in jpeg (%d)", info.out_color_space);
+ jpeg_destroy_decompress (&info);
+ return NULL;
+ }
+
if (!data)
{
g_set_error_literal (error,
@@ -123,24 +230,100 @@ gdk_load_jpeg (GBytes *input_bytes,
while (info.output_scanline < info.output_height)
{
- row[0] = (unsigned char *)(&data[3 *info.output_width * info.output_scanline]);
+ row[0] = (unsigned char *)(&data[stride * info.output_scanline]);
jpeg_read_scanlines (&info, row, 1);
}
+ switch ((int)info.out_color_space)
+ {
+ case JCS_GRAYSCALE:
+ convert_grayscale_to_rgb (data, width, height, stride);
+ format = GDK_MEMORY_R8G8B8;
+ break;
+ case JCS_RGB:
+ break;
+ case JCS_CMYK:
+ convert_cmyk_to_rgba (data, width, height, stride);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
- bytes = g_bytes_new_take (data, size);
+ bytes = g_bytes_new_take (data, stride * height);
texture = gdk_memory_texture_new (width, height,
- GDK_MEMORY_R8G8B8,
- bytes, width * 3);
+ format,
+ bytes, stride);
g_bytes_unref (bytes);
return texture;
}
+GBytes *
+gdk_save_jpeg (GdkTexture *texture)
+{
+ struct jpeg_compress_struct info;
+ struct error_handler_data jerr;
+ struct jpeg_error_mgr err;
+ guchar *data = NULL;
+ gulong size = 0;
+ guchar *input = NULL;
+ guchar *row;
+ int width, height, stride;
+
+ width = gdk_texture_get_width (texture);
+ height = gdk_texture_get_height (texture);
+
+ info.err = jpeg_std_error (&jerr.pub);
+ jerr.pub.error_exit = fatal_error_handler;
+ jerr.pub.output_message = output_message_handler;
+ jerr.error = NULL;
+
+ if (sigsetjmp (jerr.setjmp_buffer, 1))
+ {
+ free (data);
+ g_free (input);
+ jpeg_destroy_compress (&info);
+ return NULL;
+ }
+
+ info.err = jpeg_std_error (&err);
+ jpeg_create_compress (&info);
+ info.image_width = width;
+ info.image_height = height;
+ info.input_components = 3;
+ info.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults (&info);
+ jpeg_set_quality (&info, 75, TRUE);
+
+ jpeg_mem_dest (&info, &data, &size);
+
+ stride = width * 4;
+ input = g_malloc (stride * height);
+ gdk_texture_download (texture, input, stride);
+ convert_rgba_to_rgb (data, width, height, stride);
+
+ jpeg_start_compress (&info, TRUE);
+
+ while (info.next_scanline < info.image_height)
+ {
+ row = &input[info.next_scanline * stride];
+ jpeg_write_scanlines (&info, &row, 1);
+ }
+
+ jpeg_finish_compress (&info);
+
+ g_free (input);
+ jpeg_destroy_compress (&info);
+
+ return g_bytes_new_with_free_func (data, size, (GDestroyNotify) free, NULL);
+}
+
/* }}} */
/* vim:set foldmethod=marker expandtab: */
diff --git a/gdk/loaders/gdkjpegprivate.h b/gdk/loaders/gdkjpegprivate.h
index 4dcccbaf8d..28e7b90f28 100644
--- a/gdk/loaders/gdkjpegprivate.h
+++ b/gdk/loaders/gdkjpegprivate.h
@@ -26,6 +26,8 @@
GdkTexture *gdk_load_jpeg (GBytes *bytes,
GError **error);
+GBytes *gdk_save_jpeg (GdkTexture *texture);
+
static inline gboolean
gdk_is_jpeg (GBytes *bytes)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]