mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-10-06 05:22:40 +02:00
Compare commits
3 Commits
wip/Jehan/
...
wip/xcf-de
Author | SHA1 | Date | |
---|---|---|---|
|
3a10fa0b23 | ||
|
0bea993691 | ||
|
abf24a4b49 |
@@ -2468,9 +2468,12 @@ gimp_image_get_xcf_version (GimpImage *image,
|
||||
if (gimp_image_get_precision (image) > GIMP_PRECISION_U8_GAMMA)
|
||||
version = MAX (12, version);
|
||||
|
||||
/* need version 8 for zlib compression */
|
||||
/* need version 8 for zlib compression, and version 14 for delta-encoded
|
||||
* zlib compression; we always use delta encoding when zlib compression is
|
||||
* requested.
|
||||
*/
|
||||
if (zlib_compression)
|
||||
version = MAX (8, version);
|
||||
version = MAX (14, version);
|
||||
|
||||
/* if version is 10 (lots of new layer modes), go to version 11 with
|
||||
* 64 bit offsets right away
|
||||
@@ -2509,6 +2512,7 @@ gimp_image_get_xcf_version (GimpImage *image,
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
if (gimp_version) *gimp_version = 210;
|
||||
if (version_string) *version_string = "GIMP 2.10";
|
||||
break;
|
||||
|
@@ -685,10 +685,11 @@ xcf_load_image_props (XcfInfo *info,
|
||||
|
||||
xcf_read_int8 (info, (guint8 *) &compression, 1);
|
||||
|
||||
if ((compression != COMPRESS_NONE) &&
|
||||
(compression != COMPRESS_RLE) &&
|
||||
(compression != COMPRESS_ZLIB) &&
|
||||
(compression != COMPRESS_FRACTAL))
|
||||
if ((compression != COMPRESS_NONE) &&
|
||||
(compression != COMPRESS_RLE) &&
|
||||
(compression != COMPRESS_ZLIB) &&
|
||||
(compression != COMPRESS_FRACTAL) &&
|
||||
(compression != COMPRESS_ZLIB_DELTA))
|
||||
{
|
||||
gimp_message (info->gimp, G_OBJECT (info->progress),
|
||||
GIMP_MESSAGE_ERROR,
|
||||
@@ -2004,6 +2005,7 @@ xcf_load_level (XcfInfo *info,
|
||||
fail = TRUE;
|
||||
break;
|
||||
case COMPRESS_ZLIB:
|
||||
case COMPRESS_ZLIB_DELTA:
|
||||
if (!xcf_load_tile_zlib (info, buffer, &rect, format,
|
||||
offset2 - offset))
|
||||
fail = TRUE;
|
||||
@@ -2244,6 +2246,7 @@ xcf_load_tile_zlib (XcfInfo *info,
|
||||
guchar *tile_data = g_alloca (tile_size);
|
||||
gsize bytes_read;
|
||||
guchar *xcfdata;
|
||||
guint32 order;
|
||||
|
||||
/* Workaround for bug #357809: avoid crashing on g_malloc() and skip
|
||||
* this tile (return TRUE without storing data) as if it did not
|
||||
@@ -2251,8 +2254,24 @@ xcf_load_tile_zlib (XcfInfo *info,
|
||||
* skip the whole hierarchy while there may still be some valid
|
||||
* tiles in the file.
|
||||
*/
|
||||
if (data_length <= 0)
|
||||
return TRUE;
|
||||
if (data_length <= 0 ||
|
||||
(info->compression == COMPRESS_ZLIB_DELTA && data_length <= 4))
|
||||
{
|
||||
gimp_message_literal (info->gimp, G_OBJECT (info->progress),
|
||||
GIMP_MESSAGE_WARNING,
|
||||
_("Invalid tile data length in XCF file.\n"
|
||||
"Skipping tile."));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (info->compression == COMPRESS_ZLIB_DELTA)
|
||||
{
|
||||
/* read the derivative order of a delta-encoded tile. */
|
||||
xcf_read_int32 (info, &order, 1);
|
||||
|
||||
data_length -= 4;
|
||||
}
|
||||
|
||||
xcfdata = g_alloca (data_length);
|
||||
|
||||
@@ -2298,13 +2317,13 @@ xcf_load_tile_zlib (XcfInfo *info,
|
||||
}
|
||||
else if (status == Z_BUF_ERROR)
|
||||
{
|
||||
g_printerr ("xcf: decompressed tile bigger than the expected size.");
|
||||
g_printerr ("xcf: decompressed tile bigger than the expected size.\n");
|
||||
inflateEnd (&strm);
|
||||
return FALSE;
|
||||
}
|
||||
else if (status != Z_OK)
|
||||
{
|
||||
g_printerr ("xcf: tile decompression failed: %s", zError (status));
|
||||
g_printerr ("xcf: tile decompression failed: %s\n", zError (status));
|
||||
inflateEnd (&strm);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -2320,6 +2339,17 @@ xcf_load_tile_zlib (XcfInfo *info,
|
||||
tile_size / bpp * n_components);
|
||||
}
|
||||
|
||||
if (info->compression == COMPRESS_ZLIB_DELTA)
|
||||
{
|
||||
/* integrate the data, to get the original back. */
|
||||
if (! xcf_data_integrate (tile_data, tile_data, tile_size / bpp, format,
|
||||
order, 0))
|
||||
{
|
||||
g_printerr ("xcf: tile integration failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gegl_buffer_set (buffer, tile_rect, 0, format, tile_data,
|
||||
GEGL_AUTO_ROWSTRIDE);
|
||||
}
|
||||
|
@@ -70,8 +70,9 @@ typedef enum
|
||||
{
|
||||
COMPRESS_NONE = 0,
|
||||
COMPRESS_RLE = 1,
|
||||
COMPRESS_ZLIB = 2, /* unused */
|
||||
COMPRESS_FRACTAL = 3 /* unused */
|
||||
COMPRESS_ZLIB = 2,
|
||||
COMPRESS_FRACTAL = 3, /* unused */
|
||||
COMPRESS_ZLIB_DELTA = 4
|
||||
} XcfCompressionType;
|
||||
|
||||
typedef enum
|
||||
|
@@ -66,11 +66,25 @@
|
||||
#include "xcf-read.h"
|
||||
#include "xcf-save.h"
|
||||
#include "xcf-seek.h"
|
||||
#include "xcf-utils.h"
|
||||
#include "xcf-write.h"
|
||||
|
||||
#include "gimp-log.h"
|
||||
#include "gimp-intl.h"
|
||||
|
||||
|
||||
/* the ratio between the test data size and the tile data size, for delta-
|
||||
* encoded zlib compressed tiles. bigger values result in better and slower
|
||||
* compression. see xcf_save_tile_zlib().
|
||||
*/
|
||||
#define XCF_SAVE_ZLIB_DELTA_TEST_SIZE_RATIO (1.0 / 2.0)
|
||||
|
||||
/* the maximal derivative order that may be used for delta-encoded zlib
|
||||
* compressed tiles. see xcf_save_tile_zlib().
|
||||
*/
|
||||
#define XCF_SAVE_ZLIB_DELTA_MAX_ORDER 2
|
||||
|
||||
|
||||
static gboolean xcf_save_image_props (XcfInfo *info,
|
||||
GimpImage *image,
|
||||
GError **error);
|
||||
@@ -112,6 +126,14 @@ static gboolean xcf_save_tile_rle (XcfInfo *info,
|
||||
const Babl *format,
|
||||
guchar *rlebuf,
|
||||
GError **error);
|
||||
static gboolean xcf_save_data_zlib (XcfInfo *info,
|
||||
const Babl *format,
|
||||
const guchar *data,
|
||||
gint size,
|
||||
gboolean write,
|
||||
gint max_compressed_size,
|
||||
gint *compressed_size,
|
||||
GError **error);
|
||||
static gboolean xcf_save_tile_zlib (XcfInfo *info,
|
||||
GeglBuffer *buffer,
|
||||
GeglRectangle *tile_rect,
|
||||
@@ -1590,6 +1612,7 @@ xcf_save_level (XcfInfo *info,
|
||||
rlebuf, error));
|
||||
break;
|
||||
case COMPRESS_ZLIB:
|
||||
case COMPRESS_ZLIB_DELTA:
|
||||
xcf_check_error (xcf_save_tile_zlib (info, buffer, &rect, format,
|
||||
error));
|
||||
break;
|
||||
@@ -1787,31 +1810,36 @@ xcf_save_tile_rle (XcfInfo *info,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_save_tile_zlib (XcfInfo *info,
|
||||
GeglBuffer *buffer,
|
||||
GeglRectangle *tile_rect,
|
||||
const Babl *format,
|
||||
GError **error)
|
||||
xcf_save_data_zlib (XcfInfo *info,
|
||||
const Babl *format,
|
||||
const guchar *data,
|
||||
gint size,
|
||||
gboolean write,
|
||||
gint max_compressed_size,
|
||||
gint *compressed_size,
|
||||
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;
|
||||
guchar *buf = g_alloca (size);
|
||||
z_stream strm;
|
||||
int action;
|
||||
int status;
|
||||
|
||||
gegl_buffer_get (buffer, tile_rect, 1.0, format, tile_data,
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
gint remaining_size = max_compressed_size;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
if (info->file_version >= 12)
|
||||
{
|
||||
gint n_components = babl_format_get_n_components (format);
|
||||
gint bpp = babl_format_get_bytes_per_pixel (format);
|
||||
gint n_components = babl_format_get_n_components (format);
|
||||
guchar *be_data = g_alloca (size);
|
||||
|
||||
xcf_write_to_be (bpp / n_components, tile_data,
|
||||
tile_size / bpp * n_components);
|
||||
/* don't overwrite 'data'; the caller expects it not to change */
|
||||
memcpy (be_data, data, size);
|
||||
|
||||
xcf_write_to_be (bpp / n_components, be_data,
|
||||
size / bpp * n_components);
|
||||
|
||||
data = be_data;
|
||||
}
|
||||
|
||||
/* allocate deflate state */
|
||||
@@ -1823,14 +1851,17 @@ xcf_save_tile_zlib (XcfInfo *info,
|
||||
if (status != Z_OK)
|
||||
return FALSE;
|
||||
|
||||
strm.next_in = tile_data;
|
||||
strm.avail_in = tile_size;
|
||||
strm.next_in = (guchar *) data;
|
||||
strm.avail_in = size;
|
||||
strm.next_out = buf;
|
||||
strm.avail_out = tile_size;
|
||||
strm.avail_out = size;
|
||||
|
||||
action = Z_NO_FLUSH;
|
||||
|
||||
while (status == Z_OK || status == Z_BUF_ERROR)
|
||||
if (compressed_size)
|
||||
*compressed_size = 0;
|
||||
|
||||
while ((status == Z_OK || status == Z_BUF_ERROR) && remaining_size > 0)
|
||||
{
|
||||
if (strm.avail_in == 0)
|
||||
{
|
||||
@@ -1842,26 +1873,136 @@ xcf_save_tile_zlib (XcfInfo *info,
|
||||
|
||||
if (status == Z_STREAM_END || status == Z_BUF_ERROR)
|
||||
{
|
||||
size_t write_size = tile_size - strm.avail_out;
|
||||
gint write_size = size - strm.avail_out;
|
||||
|
||||
xcf_write_int8_check_error (info, buf, write_size);
|
||||
if (compressed_size)
|
||||
*compressed_size += write_size;
|
||||
|
||||
if (write)
|
||||
xcf_write_int8_check_error (info, buf, write_size);
|
||||
|
||||
/* Reset next_out and avail_out. */
|
||||
strm.next_out = buf;
|
||||
strm.avail_out = tile_size;
|
||||
strm.avail_out = size;
|
||||
|
||||
remaining_size -= write_size;
|
||||
}
|
||||
else if (status != Z_OK)
|
||||
{
|
||||
g_printerr ("xcf: tile compression failed: %s", zError (status));
|
||||
g_printerr ("xcf: tile compression failed: %s\n",
|
||||
zError (status));
|
||||
deflateEnd (&strm);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
deflateEnd (&strm);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
gegl_buffer_get (buffer, tile_rect, 1.0, format, tile_data,
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
|
||||
if (info->compression == COMPRESS_ZLIB_DELTA)
|
||||
{
|
||||
GeglRectangle test_rect;
|
||||
gint test_size;
|
||||
guint32 order;
|
||||
gint prev_compressed_size = G_MAXINT;
|
||||
|
||||
/* we repeatedly differentiate a small portion of the tile data,
|
||||
* referred to as the test data, and compress it, with the intention of
|
||||
* finding the derivative order which minimizes the compressed data size.
|
||||
*/
|
||||
|
||||
test_rect = *tile_rect;
|
||||
test_rect.height *= XCF_SAVE_ZLIB_DELTA_TEST_SIZE_RATIO;
|
||||
test_rect.height = MAX (test_rect.height, 1);
|
||||
|
||||
test_size = bpp * test_rect.width * test_rect.height;
|
||||
|
||||
g_assert (test_size <= tile_size);
|
||||
|
||||
for (order = 0; order <= XCF_SAVE_ZLIB_DELTA_MAX_ORDER; order++)
|
||||
{
|
||||
gint compressed_size;
|
||||
|
||||
/* do a dummy compression, that isn't actually written anywhere, to
|
||||
* find the size of the compressed test data.
|
||||
*/
|
||||
if (! xcf_save_data_zlib (info, format, tile_data, test_size, FALSE,
|
||||
prev_compressed_size, &compressed_size,
|
||||
error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* if the compressed data size has increased, compared to the
|
||||
* previous iteration, stop looking and use the derivative order of
|
||||
* the previous iteration.
|
||||
*/
|
||||
if (compressed_size >= prev_compressed_size)
|
||||
{
|
||||
order--;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* otherwise, try to differentiate the data, so that we compress the
|
||||
* next-order derivative on the next iteration. if this fails, or if
|
||||
* we reached the max order, break and use the current order.
|
||||
*/
|
||||
if (order == XCF_SAVE_ZLIB_DELTA_MAX_ORDER ||
|
||||
! xcf_data_differentiate (tile_data, tile_data, test_size / bpp,
|
||||
format, order, order + 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
prev_compressed_size = compressed_size;
|
||||
}
|
||||
|
||||
/* we've overwritten the first test_size bytes of the tile data; reread
|
||||
* them.
|
||||
*/
|
||||
gegl_buffer_get (buffer, &test_rect, 1.0, format, tile_data,
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
|
||||
/* calculate the derivative of the determined order of the tile data; if
|
||||
* this fails, use the 0-th derivative (i.e., the original data).
|
||||
*/
|
||||
if (! xcf_data_differentiate (tile_data, tile_data, tile_size / bpp,
|
||||
format, 0, order))
|
||||
{
|
||||
order = 0;
|
||||
|
||||
gegl_buffer_get (buffer, tile_rect, 1.0, format, tile_data,
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
}
|
||||
|
||||
/* write the derivative order before the actual data */
|
||||
xcf_write_int32_check_error (info, &order, 1);
|
||||
|
||||
GIMP_LOG (XCF, "delta encoding order: %d", order);
|
||||
}
|
||||
|
||||
return xcf_save_data_zlib (info, format, tile_data, tile_size, TRUE,
|
||||
G_MAXINT, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xcf_save_parasite (XcfInfo *info,
|
||||
GimpParasite *parasite,
|
||||
|
@@ -17,10 +17,19 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libgimpbase/gimpbase.h"
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
|
||||
#include "core/core-types.h"
|
||||
|
||||
#include "gegl/gimp-babl.h"
|
||||
|
||||
#include "xcf-utils.h"
|
||||
|
||||
|
||||
@@ -51,3 +60,205 @@ xcf_data_is_zero (const void *data,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* calculates the (discrete) derivative of a sequence of pixels. the input
|
||||
* sequence, given by `src`, shall be a derivative of order `from_order` of
|
||||
* some original sequence; the output sequence, written to `dest`, is the
|
||||
* derivative of order `to_order`, which shall be greater than or equal to
|
||||
* `from_order`, of the said original sequence.
|
||||
*
|
||||
* `dest` and `src` may be equal, but may not otherwise partially overlap.
|
||||
*
|
||||
* returns TRUE if successful, or FALSE otherwise. upon failure, the contents
|
||||
* of `dest` are unspecified.
|
||||
*/
|
||||
gboolean
|
||||
xcf_data_differentiate (void *dest,
|
||||
const void *src,
|
||||
gint n_pixels,
|
||||
const Babl *format,
|
||||
gint from_order,
|
||||
gint to_order)
|
||||
{
|
||||
gint bpp;
|
||||
gint n_components;
|
||||
gint o;
|
||||
gint i;
|
||||
gint c;
|
||||
|
||||
g_return_val_if_fail (dest != NULL, FALSE);
|
||||
g_return_val_if_fail (src != NULL, FALSE);
|
||||
g_return_val_if_fail (n_pixels >= 0, FALSE);
|
||||
g_return_val_if_fail (format != NULL, FALSE);
|
||||
g_return_val_if_fail (from_order >= 0 && from_order <= to_order, FALSE);
|
||||
|
||||
if (to_order == 0 && n_pixels == 0)
|
||||
return TRUE;
|
||||
else if (to_order >= n_pixels)
|
||||
return FALSE;
|
||||
|
||||
bpp = babl_format_get_bytes_per_pixel (format);
|
||||
n_components = babl_format_get_n_components (format);
|
||||
|
||||
if (from_order == to_order)
|
||||
{
|
||||
if (dest != src)
|
||||
memcpy (dest, src, n_pixels * bpp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define XCF_DATA_DIFFERENTIATE(type) \
|
||||
do \
|
||||
{ \
|
||||
type *d = dest; \
|
||||
const type *s = src; \
|
||||
\
|
||||
if (dest != src) \
|
||||
memcpy (dest, src, (from_order + 1) * bpp); \
|
||||
\
|
||||
for (o = from_order; o < to_order; o++) \
|
||||
{ \
|
||||
for (i = n_pixels - 1; i > o; i--) \
|
||||
{ \
|
||||
for (c = 0; c < n_components; c++) \
|
||||
{ \
|
||||
d[n_components * i + c] = s[n_components * i + c] - \
|
||||
s[n_components * (i - 1) + c]; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
s = d; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
switch (gimp_babl_format_get_component_type (format))
|
||||
{
|
||||
case GIMP_COMPONENT_TYPE_U8:
|
||||
XCF_DATA_DIFFERENTIATE (guint8);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_U16:
|
||||
case GIMP_COMPONENT_TYPE_HALF:
|
||||
XCF_DATA_DIFFERENTIATE (guint16);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_U32:
|
||||
case GIMP_COMPONENT_TYPE_FLOAT:
|
||||
XCF_DATA_DIFFERENTIATE (guint32);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_DOUBLE:
|
||||
XCF_DATA_DIFFERENTIATE (guint64);
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#undef XCF_DATA_DIFFERENTIATE
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* calculates the (discrete) integral of a sequence of pixels. the input
|
||||
* sequence, given by `src`, shall be a derivative of order `from_order` of
|
||||
* some original sequence; the output sequence, written to `dest`, is the
|
||||
* derivative of order `to_order`, which shall be less than or equal to
|
||||
* `from_order`, of the said original sequence.
|
||||
*
|
||||
* `dest` and `src` may be equal, but may not otherwise partially overlap.
|
||||
*
|
||||
* returns TRUE if successful, or FALSE otherwise. upon failure, the contents
|
||||
* of `dest` are unspecified.
|
||||
*/
|
||||
gboolean
|
||||
xcf_data_integrate (void *dest,
|
||||
const void *src,
|
||||
gint n_pixels,
|
||||
const Babl *format,
|
||||
gint from_order,
|
||||
gint to_order)
|
||||
{
|
||||
gint bpp;
|
||||
gint n_components;
|
||||
gint o;
|
||||
gint i;
|
||||
gint c;
|
||||
|
||||
g_return_val_if_fail (dest != NULL, FALSE);
|
||||
g_return_val_if_fail (src != NULL, FALSE);
|
||||
g_return_val_if_fail (n_pixels >= 0, FALSE);
|
||||
g_return_val_if_fail (format != NULL, FALSE);
|
||||
g_return_val_if_fail (to_order >= 0 && to_order <= from_order, FALSE);
|
||||
|
||||
if (from_order == 0 && n_pixels == 0)
|
||||
return TRUE;
|
||||
else if (from_order >= n_pixels)
|
||||
return FALSE;
|
||||
|
||||
bpp = babl_format_get_bytes_per_pixel (format);
|
||||
n_components = babl_format_get_n_components (format);
|
||||
|
||||
if (from_order == to_order)
|
||||
{
|
||||
if (dest != src)
|
||||
memcpy (dest, src, n_pixels * bpp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define XCF_DATA_INTEGRATE(type) \
|
||||
do \
|
||||
{ \
|
||||
type *d = dest; \
|
||||
const type *s = src; \
|
||||
\
|
||||
if (dest != src) \
|
||||
memcpy (dest, src, from_order * bpp); \
|
||||
\
|
||||
for (o = from_order; o > to_order; o--) \
|
||||
{ \
|
||||
for (i = o; i < n_pixels; i++) \
|
||||
{ \
|
||||
for (c = 0; c < n_components; c++) \
|
||||
{ \
|
||||
d[n_components * i + c] = s[n_components * i + c] + \
|
||||
d[n_components * (i - 1) + c]; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
s = d; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
switch (gimp_babl_format_get_component_type (format))
|
||||
{
|
||||
case GIMP_COMPONENT_TYPE_U8:
|
||||
XCF_DATA_INTEGRATE (guint8);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_U16:
|
||||
case GIMP_COMPONENT_TYPE_HALF:
|
||||
XCF_DATA_INTEGRATE (guint16);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_U32:
|
||||
case GIMP_COMPONENT_TYPE_FLOAT:
|
||||
XCF_DATA_INTEGRATE (guint32);
|
||||
break;
|
||||
|
||||
case GIMP_COMPONENT_TYPE_DOUBLE:
|
||||
XCF_DATA_INTEGRATE (guint64);
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#undef XCF_DATA_INTEGRATE
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@@ -19,8 +19,21 @@
|
||||
#define __XCF_UTILS_H__
|
||||
|
||||
|
||||
gboolean xcf_data_is_zero (const void *data,
|
||||
gint size);
|
||||
gboolean xcf_data_is_zero (const void *data,
|
||||
gint size);
|
||||
|
||||
gboolean xcf_data_differentiate (void *dest,
|
||||
const void *src,
|
||||
gint n_pixels,
|
||||
const Babl *format,
|
||||
gint from_order,
|
||||
gint to_order);
|
||||
gboolean xcf_data_integrate (void *dest,
|
||||
const void *src,
|
||||
gint n_pixels,
|
||||
const Babl *format,
|
||||
gint from_order,
|
||||
gint to_order);
|
||||
|
||||
|
||||
#endif /* __XCF_UTILS_H__ */
|
||||
|
@@ -80,7 +80,8 @@ static GimpXcfLoaderFunc * const xcf_loaders[] =
|
||||
xcf_load_image, /* version 10 */
|
||||
xcf_load_image, /* version 11 */
|
||||
xcf_load_image, /* version 12 */
|
||||
xcf_load_image /* version 13 */
|
||||
xcf_load_image, /* version 13 */
|
||||
xcf_load_image /* version 14 */
|
||||
};
|
||||
|
||||
|
||||
@@ -346,6 +347,7 @@ xcf_save_stream (Gimp *gimp,
|
||||
const gchar *filename;
|
||||
gboolean success = FALSE;
|
||||
GError *my_error = NULL;
|
||||
gboolean zlib_compression;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
|
||||
@@ -366,14 +368,21 @@ xcf_save_stream (Gimp *gimp,
|
||||
info.progress = progress;
|
||||
info.file = output_file;
|
||||
|
||||
if (gimp_image_get_xcf_compression (image))
|
||||
info.compression = COMPRESS_ZLIB;
|
||||
else
|
||||
info.compression = COMPRESS_RLE;
|
||||
zlib_compression = gimp_image_get_xcf_compression (image);
|
||||
|
||||
info.file_version = gimp_image_get_xcf_version (image,
|
||||
info.compression ==
|
||||
COMPRESS_ZLIB,
|
||||
if (zlib_compression)
|
||||
{
|
||||
if (g_getenv ("GIMP_XCF_NO_DELTA_COMPRESSION"))
|
||||
info.compression = COMPRESS_ZLIB;
|
||||
else
|
||||
info.compression = COMPRESS_ZLIB_DELTA;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.compression = COMPRESS_RLE;
|
||||
}
|
||||
|
||||
info.file_version = gimp_image_get_xcf_version (image, zlib_compression,
|
||||
NULL, NULL);
|
||||
|
||||
if (info.file_version >= 11)
|
||||
|
@@ -714,8 +714,9 @@ PROP_COMPRESSION (essential)
|
||||
byte comp Compression indicator; one of
|
||||
0: No compression
|
||||
1: RLE encoding
|
||||
2: (Never used, but reserved for zlib compression)
|
||||
2: zlib compression
|
||||
3: (Never used, but reserved for some fractal compression)
|
||||
4: Delta-encoded zlib compression
|
||||
|
||||
PROP_COMPRESSION defines the encoding of pixels in tile data blocks in the
|
||||
entire XCF file. See chapter 7 for details.
|
||||
@@ -724,11 +725,9 @@ PROP_COMPRESSION (essential)
|
||||
small integer, PROP_COMPRESSION does _not_ pad the value to a full
|
||||
32-bit integer.
|
||||
|
||||
Contemporary GIMP versions always write files with comp=1. It is unknown to
|
||||
Contemporary GIMP versions always write files with comp>=1. It is unknown to
|
||||
the author of this document whether versions that wrote completely
|
||||
uncompressed (comp=0) files ever existed.
|
||||
TODO: Why do we use zlib compression to compress only the whole file (.xcf.gz)
|
||||
if it is a built-in feature?
|
||||
|
||||
PROP_GUIDES (editing state)
|
||||
uint32 18 Type identification
|
||||
@@ -1229,8 +1228,8 @@ Ceil(x) is the smallest integer not smaller than x.
|
||||
The format of the data blocks pointed to by the tile pointers in the
|
||||
level structure of hierarchy differs according to the value of the
|
||||
PROP_COMPRESSION property of the main image structure. Current
|
||||
GIMP versions always use RLE compression, but readers should nevertheless
|
||||
be prepared to meet the older uncompressed format.
|
||||
GIMP versions always use at least RLE compression, but readers should
|
||||
nevertheless be prepared to meet the older uncompressed format.
|
||||
|
||||
Both formats assume the width, height and byte depth of the tile are
|
||||
known from the context (namely, they are stored explicitly in the
|
||||
@@ -1289,8 +1288,7 @@ The RLE encoding can cause degenerated encodings in which the original
|
||||
data stream may double in size (or grow to arbitrarily large sizes if
|
||||
(128,0,0) operations are inserted). Such encodings must be avoided, as
|
||||
GIMP's XCF reader expects that the size of an encoded tile is
|
||||
never more than 24 KB, which is only 1.5 times the unencoded size of a
|
||||
64x64 RGBA tile.
|
||||
never more than 1.5 times the unencoded size of a 64x64 RGBA tile.
|
||||
|
||||
A simple way for an XCF creator to avoid overflow is
|
||||
a) never using opcode 0 (but instead opcode 255)
|
||||
@@ -1298,9 +1296,37 @@ A simple way for an XCF creator to avoid overflow is
|
||||
c) never emitting two "different bytes" opcodes next to each other
|
||||
in the encoding of a single stream.
|
||||
|
||||
TODO: If each tile has a maximum of 64 pixels (resulting in a maximum of 64
|
||||
bytes for each color in this tile), do values>64 and long runs apply at all?
|
||||
zlib compressed tile data
|
||||
-------------------------
|
||||
|
||||
In the zlib compressed format the raw tile data is compressed using the
|
||||
DEFLATE algorithm.
|
||||
|
||||
Delta-encoded zlib compressed tile data
|
||||
---------------------------------------
|
||||
|
||||
In the delta-encoded zlib compressed format the tile data is delta-encoded,
|
||||
and the result is compressed using the DEFLATE algorithm.
|
||||
|
||||
The tile data is a sequence of pixels, manipulated arithmetically
|
||||
componentwise, as unsigned integers; in particular, for floating-point
|
||||
formats, the raw value representation is manipulated using integer
|
||||
arithmeic. Delta encoding stores the sequence using its n-th-order
|
||||
(discrete) derivative, rather than the original sequence (unless n = 0).
|
||||
The n-th derivative of a sequence A of length m is defined as follows:
|
||||
|
||||
- if n = 0, the derivative is A;
|
||||
|
||||
- if n > 0, the derivative is [B[0], ..., B[n-1], B[n] - B[n-1], ...,
|
||||
B[m-1] - B[m-2]], where B is the (n-1)-th derivative of A.
|
||||
|
||||
A delta-encoded zlib compressed tile begins with a (noncompressed) field
|
||||
specifying the order of the derivative:
|
||||
|
||||
uint32 order Order of the tile-data derivative
|
||||
|
||||
Following this field is the actual derivative of the tile data. The
|
||||
derivative is compressed using the DEFLATE algorithm.
|
||||
|
||||
8. MISCELLANEOUS
|
||||
================
|
||||
|
Reference in New Issue
Block a user