From: Matthias Clasen Date: Tue, 14 Sep 2021 21:40:29 +0000 (-0400) Subject: Add code to save jpegs X-Git-Tag: archive/raspbian/4.6.5+ds-1+rpi1~1^2~19^2~5^2~340^2~12 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=e720f9d35d2ca66936f6d3378839fb3fdb8e1578;p=gtk4.git Add code to save jpegs --- 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) {