[gimp] Bug 735026: Enable zlib compression in XCF for GIMP 2.10
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Bug 735026: Enable zlib compression in XCF for GIMP 2.10
- Date: Tue, 16 Sep 2014 21:54:20 +0000 (UTC)
commit 128baab2b601c5001c174100dd572a838daac8a1
Author: Jehan <jehan girinstud io>
Date: Mon Sep 15 15:33:22 2014 +0200
Bug 735026: Enable zlib compression in XCF for GIMP 2.10
XCF file format bumped to version 8 when compressing with zlib.
app/xcf/xcf-load.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++-
app/xcf/xcf-save.c | 81 +++++++++++++++++++++++++++++++++++++++++-
app/xcf/xcf.c | 5 ++-
3 files changed, 181 insertions(+), 5 deletions(-)
---
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index ffe9f69..b36b240 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -18,6 +18,7 @@
#include "config.h"
#include <string.h>
+#include <zlib.h>
#include <cairo.h>
#include <gegl.h>
@@ -114,6 +115,11 @@ static gboolean xcf_load_tile_rle (XcfInfo *info,
GeglRectangle *tile_rect,
const Babl *format,
gint data_length);
+static gboolean xcf_load_tile_zlib (XcfInfo *info,
+ GeglBuffer *buffer,
+ GeglRectangle *tile_rect,
+ const Babl *format,
+ gint data_length);
static GimpParasite * xcf_load_parasite (XcfInfo *info);
static gboolean xcf_load_old_paths (XcfInfo *info,
GimpImage *image);
@@ -1780,8 +1786,9 @@ xcf_load_level (XcfInfo *info,
fail = TRUE;
break;
case COMPRESS_ZLIB:
- g_warning ("xcf: zlib compression unimplemented");
- fail = TRUE;
+ if (!xcf_load_tile_zlib (info, buffer, &rect, format,
+ offset2 - offset))
+ fail = TRUE;
break;
case COMPRESS_FRACTAL:
g_warning ("xcf: fractal compression unimplemented");
@@ -1975,6 +1982,95 @@ xcf_load_tile_rle (XcfInfo *info,
return FALSE;
}
+static gboolean
+xcf_load_tile_zlib (XcfInfo *info,
+ GeglBuffer *buffer,
+ GeglRectangle *tile_rect,
+ const Babl *format,
+ gint data_length)
+{
+ z_stream strm;
+ int action;
+ int status;
+ gint bpp = babl_format_get_bytes_per_pixel (format);
+ gint tile_size = bpp * tile_rect->width * tile_rect->height;
+ guchar *tile_data = g_alloca (tile_size);
+ gsize bytes_read;
+ guchar *xcfdata;
+
+ /* Workaround for bug #357809: avoid crashing on g_malloc() and skip
+ * this tile (return TRUE without storing data) as if it did not
+ * contain any data. It is better than returning FALSE, which would
+ * skip the whole hierarchy while there may still be some valid
+ * tiles in the file.
+ */
+ if (data_length <= 0)
+ return TRUE;
+
+ xcfdata = g_alloca (data_length);
+
+ /* we have to read directly instead of xcf_read_* because we may be
+ * reading past the end of the file here
+ */
+ g_input_stream_read_all (info->input, xcfdata, data_length,
+ &bytes_read, NULL, NULL);
+
+ if (bytes_read == 0)
+ return TRUE;
+
+ info->cp += bytes_read;
+
+ strm.next_out = tile_data;
+ strm.avail_out = tile_size;
+
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.next_in = xcfdata;
+ strm.avail_in = bytes_read;
+
+ /* Initialize the stream decompression. */
+ status = inflateInit (&strm);
+ if (status != Z_OK)
+ return FALSE;
+
+ action = Z_NO_FLUSH;
+
+ while (status == Z_OK)
+ {
+ if (strm.avail_in == 0)
+ {
+ action = Z_FINISH;
+ }
+
+ status = inflate (&strm, action);
+
+ if (status == Z_STREAM_END)
+ {
+ /* All the data was successfully decoded. */
+ break;
+ }
+ else if (status == Z_BUF_ERROR)
+ {
+ g_printerr ("xcf: decompressed tile bigger than the expected size.");
+ inflateEnd (&strm);
+ return FALSE;
+ }
+ else if (status != Z_OK)
+ {
+ g_printerr ("xcf: tile decompression failed: %s", zError (status));
+ inflateEnd (&strm);
+ return FALSE;
+ }
+ }
+
+ gegl_buffer_set (buffer, tile_rect, 0, format, tile_data,
+ GEGL_AUTO_ROWSTRIDE);
+
+ inflateEnd (&strm);
+ return TRUE;
+}
+
static GimpParasite *
xcf_load_parasite (XcfInfo *info)
{
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index 7fe9df7..5a6de8a 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -18,6 +18,7 @@
#include "config.h"
#include <string.h>
+#include <zlib.h>
#include <cairo.h>
#include <gegl.h>
@@ -109,6 +110,11 @@ static gboolean xcf_save_tile_rle (XcfInfo *info,
const Babl *format,
guchar *rlebuf,
GError **error);
+static gboolean xcf_save_tile_zlib (XcfInfo *info,
+ GeglBuffer *buffer,
+ GeglRectangle *tile_rect,
+ const Babl *format,
+ GError **error);
static gboolean xcf_save_parasite (XcfInfo *info,
GimpParasite *parasite,
GError **error);
@@ -223,6 +229,10 @@ xcf_save_choose_format (XcfInfo *info,
if (gimp_image_get_precision (image) != GIMP_PRECISION_U8_GAMMA)
save_version = MAX (7, save_version);
+ /* need version 8 for zlib compression */
+ if (info->compression == COMPRESS_ZLIB)
+ save_version = MAX (8, save_version);
+
info->file_version = save_version;
}
@@ -1506,7 +1516,8 @@ xcf_save_level (XcfInfo *info,
rlebuf, error));
break;
case COMPRESS_ZLIB:
- g_error ("xcf: zlib compression unimplemented");
+ xcf_check_error (xcf_save_tile_zlib (info, buffer, &rect, format,
+ error));
break;
case COMPRESS_FRACTAL:
g_error ("xcf: fractal compression unimplemented");
@@ -1681,6 +1692,74 @@ xcf_save_tile_rle (XcfInfo *info,
}
static gboolean
+xcf_save_tile_zlib (XcfInfo *info,
+ GeglBuffer *buffer,
+ GeglRectangle *tile_rect,
+ const Babl *format,
+ GError **error)
+{
+ gint bpp = babl_format_get_bytes_per_pixel (format);
+ gint tile_size = bpp * tile_rect->width * tile_rect->height;
+ guchar *tile_data = g_alloca (tile_size);
+ /* The buffer for compressed data. */
+ guchar *buf = g_alloca (tile_size);
+ GError *tmp_error = NULL;
+ z_stream strm;
+ int action;
+ int status;
+
+ gegl_buffer_get (buffer, tile_rect, 1.0, format, tile_data,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ /* allocate deflate state */
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+
+ status = deflateInit (&strm, Z_DEFAULT_COMPRESSION);
+ if (status != Z_OK)
+ return FALSE;
+
+ strm.next_in = tile_data;
+ strm.avail_in = tile_size;
+ strm.next_out = buf;
+ strm.avail_out = tile_size;
+
+ action = Z_NO_FLUSH;
+
+ while (status == Z_OK || status == Z_BUF_ERROR)
+ {
+ if (strm.avail_in == 0)
+ {
+ /* Finish the encoding. */
+ action = Z_FINISH;
+ }
+
+ status = deflate (&strm, action);
+
+ if (status == Z_STREAM_END || status == Z_BUF_ERROR)
+ {
+ size_t write_size = tile_size - strm.avail_out;
+
+ xcf_write_int8_check_error (info, buf, write_size);
+
+ /* Reset next_out and avail_out. */
+ strm.next_out = buf;
+ strm.avail_out = tile_size;
+ }
+ else if (status != Z_OK)
+ {
+ g_printerr ("xcf: tile compression failed: %s", zError (status));
+ deflateEnd (&strm);
+ return FALSE;
+ }
+ }
+
+ deflateEnd (&strm);
+ return TRUE;
+}
+
+static gboolean
xcf_save_parasite (XcfInfo *info,
GimpParasite *parasite,
GError **error)
diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c
index c675a86..110be91 100644
--- a/app/xcf/xcf.c
+++ b/app/xcf/xcf.c
@@ -74,7 +74,8 @@ static GimpXcfLoaderFunc * const xcf_loaders[] =
xcf_load_image, /* version 4 */
xcf_load_image, /* version 5 */
xcf_load_image, /* version 6 */
- xcf_load_image /* version 7 */
+ xcf_load_image, /* version 7 */
+ xcf_load_image /* version 8 */
};
@@ -390,7 +391,7 @@ xcf_save_invoker (GimpProcedure *procedure,
info.seekable = G_SEEKABLE (info.output);
info.progress = progress;
info.filename = filename;
- info.compression = COMPRESS_RLE;
+ info.compression = COMPRESS_ZLIB;
if (progress)
gimp_progress_start (progress, FALSE, _("Saving '%s'"), filename);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]