[gthumb] xcf loader: simplified the code removing the use of cairo to draw layers
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] xcf loader: simplified the code removing the use of cairo to draw layers
- Date: Sat, 16 Mar 2013 16:43:55 +0000 (UTC)
commit f071f7d250bede84656db5a7046d41407fe42c5e
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sat Mar 16 17:38:58 2013 +0100
xcf loader: simplified the code removing the use of cairo to draw layers
implemented all the layer modes instead of using cairo operations
for some modes, this allows to remove some time-consuming functions
such as gimp_layer_apply_mask and _cairo_surface_data_post_production,
and allows to avoid some alpha channel multiplications.
extensions/cairo_io/cairo-image-surface-xcf.c | 1073 ++++++++++++-------------
1 files changed, 493 insertions(+), 580 deletions(-)
---
diff --git a/extensions/cairo_io/cairo-image-surface-xcf.c b/extensions/cairo_io/cairo-image-surface-xcf.c
index 77f80b3..1038a7d 100644
--- a/extensions/cairo_io/cairo-image-surface-xcf.c
+++ b/extensions/cairo_io/cairo-image-surface-xcf.c
@@ -26,18 +26,38 @@
#include "cairo-image-surface-xcf.h"
-#define TILE_WIDTH 64
-#define MAX_TILE_SIZE (TILE_WIDTH * TILE_WIDTH * 4 * 1.5)
-#define MIN3(x,y,z) ((y) <= (z) ? MIN ((x), (y)) : MIN ((x), (z)))
-#define MAX3(x,y,z) ((y) >= (z) ? MAX ((x), (y)) : MAX ((x), (z)))
-#define DISSOLVE_SEED 737893334
-#define CLAMP_TEMP(x, min, max) (temp = (x), CLAMP (temp, min, max))
-#define CLAMP_PIXEL(x) CLAMP_TEMP(x, 0, 255)
-#define GIMP_OP_NORMAL(xaA, xaB, aA) (CLAMP_PIXEL (xaA + (double) xaB * (1.0 - aA)))
-#define GIMP_OP_SUBTRACT(xaA, xaB) (CLAMP_PIXEL (xaB - xaA))
-#define GIMP_OP_DIVIDE(xaA, xaB, aA) (CLAMP_PIXEL ((xaA > 0) ? (double) (xaB / xaA) * aA * 255.0 :
xaB))
-#define GIMP_OP_GRAIN_EXTRACT(xaA, xaB, aA) (CLAMP_PIXEL (xaB - xaA + (127.0 * aA)))
-#define GIMP_OP_GRAIN_MERGE(xaA, xaB, aA) (CLAMP_PIXEL (xaB + xaA - (127.0 * aA)))
+/* Optimizations taken from xcftools 1.0.7 written by Henning Makholm
+ *
+ * xL : Layer color
+ * xI : Image color
+ * aL : Layer alpha
+ * */
+
+
+#define TILE_WIDTH 64
+#define MAX_TILE_SIZE (TILE_WIDTH * TILE_WIDTH * 4 * 1.5)
+#define ADD_ALPHA(v, a) (add_alpha_table[v][a])
+#define MIN3(x,y,z) ((y) <= (z) ? MIN ((x), (y)) : MIN ((x), (z)))
+#define MAX3(x,y,z) ((y) >= (z) ? MAX ((x), (y)) : MAX ((x), (z)))
+#define DISSOLVE_SEED 737893334
+#define CLAMP_TEMP(x, min, max) (temp = (x), CLAMP (temp, min, max))
+#define ABS_TEMP2(x) (temp2 = (x), (temp2 < 0) ? -temp2: temp2)
+#define CLAMP_PIXEL(x) CLAMP_TEMP (x, 0, 255)
+#define GIMP_OP_NORMAL(xL, xI, aL) CLAMP_PIXEL (ADD_ALPHA (xL, aL) + ADD_ALPHA (xI, 255 - aL))
+#define GIMP_OP_LIGHTEN_ONLY(xL, xI) MAX (xI, xL)
+#define GIMP_OP_SCREEN(xL, xI) CLAMP_PIXEL (255 ^ ADD_ALPHA (255 - xI, 255 - xL))
+#define GIMP_OP_DODGE(xL, xI) GIMP_OP_DIVIDE (255-xL, xI)
+#define GIMP_OP_ADDITION(xL, xI) CLAMP_PIXEL (xI + xL)
+#define GIMP_OP_DARKEN_ONLY(xL, xI) MIN (xI, xL)
+#define GIMP_OP_MULTIPLY(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xL, xI))
+#define GIMP_OP_BURN(xL, xI) CLAMP_PIXEL (255 - GIMP_OP_DIVIDE (xL, 255 - xI))
+#define GIMP_OP_SOFT_LIGHT(xL, xI) CLAMP_PIXEL (ADD_ALPHA (xI, xI) + 2 * ADD_ALPHA (xL, ADD_ALPHA (xI,
255 - xI)))
+#define GIMP_OP_HARD_LIGHT(xL, xI) CLAMP_PIXEL (xL > 128 ? 255 ^ ADD_ALPHA (255 - xI, 2 * (255 - xL)) :
ADD_ALPHA (xI, 2 * xL))
+#define GIMP_OP_DIFFERENCE(xL, xI) CLAMP_PIXEL (ABS_TEMP2 (xI - xL))
+#define GIMP_OP_SUBTRACT(xL, xI) CLAMP_PIXEL (xI - xL)
+#define GIMP_OP_GRAIN_EXTRACT(xL, xI) CLAMP_PIXEL ((int) xI - xL + 128)
+#define GIMP_OP_GRAIN_MERGE(xL, xI) CLAMP_PIXEL ((int) xI + xL - 128)
+#define GIMP_OP_DIVIDE(xL, xI) CLAMP_PIXEL ((int) (xI) * 256 / (1 + (xL)))
typedef enum {
@@ -92,28 +112,30 @@ typedef enum {
typedef struct {
- guint width;
- guint height;
- GimpImageType type;
- char *name;
- guint32 opacity;
- gboolean visible;
- gboolean floating_selection;
- GimpLayerMode mode;
- gboolean apply_mask;
- gint32 h_offset;
- gint32 v_offset;
- cairo_surface_t *image;
- cairo_surface_t *mask;
+ int n;
+ guint width;
+ guint height;
+ GimpImageType type;
+ char *name;
+ guint32 opacity;
+ gboolean visible;
+ gboolean floating_selection;
+ GimpLayerMode mode;
+ gboolean apply_mask;
+ gint32 h_offset;
+ gint32 v_offset;
+ int stride;
+ guchar *pixels;
+ guchar *alpha_mask;
+ int bpp;
struct {
- gboolean dirty;
- int rows;
- int columns;
- int n_tiles;
- int last_row_height;
- int last_col_width;
+ gboolean dirty;
+ int rows;
+ int columns;
+ int n_tiles;
+ int last_row_height;
+ int last_col_width;
} tiles;
- int stride;
} GimpLayer;
@@ -124,9 +146,34 @@ typedef struct {
} GimpColormap;
-static int cairo_rgba[4] = { CAIRO_RED, CAIRO_GREEN, CAIRO_BLUE, CAIRO_ALPHA };
-static int cairo_graya[2] = { CAIRO_RED, CAIRO_ALPHA };
+static int cairo_rgba[4] = { CAIRO_RED, CAIRO_GREEN, CAIRO_BLUE, CAIRO_ALPHA };
+static int cairo_graya[2] = { 0, CAIRO_ALPHA };
static int cairo_indexed[2] = { 0, CAIRO_ALPHA };
+static guchar add_alpha_table[256][256];
+static GOnce xcf_init_once = G_ONCE_INIT;
+
+
+static gpointer
+xcf_init (gpointer data)
+{
+ int v;
+ int a;
+ int r;
+
+ /* add_alpha_table[v][a] = v * a / 255 */
+
+ for (v = 0; v < 128; v++) {
+ for (a = 0; a <= v; a++) {
+ r = (v * a + 127) / 255;
+ add_alpha_table[v][a] = add_alpha_table[a][v] = r;
+ add_alpha_table[255-v][a] = add_alpha_table[a][255-v] = a - r;
+ add_alpha_table[v][255-a] = add_alpha_table[255-a][v] = v - r;
+ add_alpha_table[255-v][255-a] = add_alpha_table[255-a][255-v] = (255 - a) - (v - r);
+ }
+ }
+
+ return NULL;
+}
/* -- GDataInputStream functions -- */
@@ -169,11 +216,12 @@ _g_data_input_stream_read_xcf_string (GDataInputStream *stream,
static GimpLayer *
-gimp_layer_new (void)
+gimp_layer_new (int n)
{
GimpLayer *layer;
layer = g_new0 (GimpLayer, 1);
+ layer->n = n;
layer->width = 0;
layer->height = 0;
layer->type = GIMP_RGBA_IMAGE;
@@ -185,9 +233,10 @@ gimp_layer_new (void)
layer->apply_mask = FALSE;
layer->h_offset = 0;
layer->v_offset = 0;
- layer->image = NULL;
- layer->mask = NULL;
layer->tiles.dirty = TRUE;
+ layer->tiles.n_tiles = 0;
+ layer->pixels = NULL;
+ layer->alpha_mask = NULL;
return layer;
}
@@ -196,6 +245,7 @@ gimp_layer_new (void)
static gboolean
gimp_layer_get_tile_size (GimpLayer *layer,
int n_tile,
+ int bpp,
goffset *offset,
int *width,
int *height)
@@ -222,7 +272,7 @@ gimp_layer_get_tile_size (GimpLayer *layer,
layer->tiles.n_tiles = layer->tiles.columns * layer->tiles.rows;
layer->tiles.dirty = FALSE;
- layer->stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, layer->width);
+ layer->stride = layer->width * bpp;
}
if ((n_tile < 0) || (n_tile >= layer->tiles.n_tiles))
@@ -240,7 +290,7 @@ gimp_layer_get_tile_size (GimpLayer *layer,
else
tile_height = TILE_WIDTH;
- *offset = ((tile_row * TILE_WIDTH) * layer->stride) + (tile_column * TILE_WIDTH * 4);
+ *offset = ((tile_row * TILE_WIDTH) * layer->stride) + (tile_column * TILE_WIDTH * bpp);
*width = tile_width;
*height = tile_height;
@@ -249,62 +299,12 @@ gimp_layer_get_tile_size (GimpLayer *layer,
static void
-gimp_layer_apply_mask (GimpLayer *layer)
-{
- int width;
- int height;
- int row_stride;
- guchar *image_row;
- guchar *mask_row;
- guchar *image_pixel;
- guchar *mask_pixel;
- int i, j;
-
- if ((layer->image == NULL) || (layer->mask == NULL))
- return;
-
- cairo_surface_flush (layer->image);
-
- width = cairo_image_surface_get_width (layer->image);
- height = cairo_image_surface_get_height (layer->image);
- row_stride = cairo_image_surface_get_stride (layer->image);
- image_row = cairo_image_surface_get_data (layer->image);
- mask_row = cairo_image_surface_get_data (layer->mask);
-
- for (i = 0; i < height; i++) {
- image_pixel = image_row;
- mask_pixel = mask_row;
-
- for (j = 0; j < width; j++) {
-
- if (mask_pixel[0] != 0xff) {
- double factor = (double) mask_pixel[0] / 0xff;
- image_pixel[CAIRO_RED] *= factor;
- image_pixel[CAIRO_GREEN] *= factor;
- image_pixel[CAIRO_BLUE] *= factor;
- image_pixel[CAIRO_ALPHA] *= factor;
- }
-
- image_pixel += 4;
- mask_pixel += 4;
- }
- image_row += row_stride;
- mask_row += row_stride;
- }
-
- cairo_surface_mark_dirty (layer->image);
-}
-
-
-static void
gimp_layer_free (GimpLayer *layer)
{
if (layer == NULL)
return;
- if (layer->image != NULL)
- cairo_surface_destroy (layer->image);
- if (layer->mask != NULL)
- cairo_surface_destroy (layer->mask);
+ g_free (layer->pixels);
+ g_free (layer->alpha_mask);
g_free (layer->name);
g_free (layer);
}
@@ -313,6 +313,9 @@ gimp_layer_free (GimpLayer *layer)
/* -- _cairo_image_surface_create_from_xcf -- */
+/* RGB <-> HSV */
+
+
static void
gimp_rgb_to_hsv (guchar red,
guchar green,
@@ -338,7 +341,9 @@ gimp_rgb_to_hsv (guchar red,
return;
}
- if (max == red)
+ if (max == min)
+ *hue = 0;
+ else if (max == red)
*hue = 0 + 43 * (green - blue) / (max - min);
else if (max == green)
*hue = 85 + 43 * (blue - red) / (max - min);
@@ -351,9 +356,9 @@ static void
gimp_hsv_to_rgb (guchar hue,
guchar sat,
guchar val,
- double *red,
- double *green,
- double *blue)
+ guchar *red,
+ guchar *green,
+ guchar *blue)
{
guchar region, remainder, p, q, t;
@@ -404,6 +409,104 @@ gimp_hsv_to_rgb (guchar hue,
}
+/* RGB <-> HSL */
+
+
+static void
+gimp_rgb_to_hsl (guchar red,
+ guchar green,
+ guchar blue,
+ guchar *hue,
+ guchar *sat,
+ guchar *lum)
+{
+ guchar min, max;
+
+ min = MIN3 (red, green, blue);
+ max = MAX3 (red, green, blue);
+
+ *lum = (max + min) / 2;
+
+ if (max == min) {
+ *hue = *sat = 0;
+ return;
+ }
+
+ if (*lum < 128)
+ *sat = 255 * (long) (max - min) / (max + min);
+ else
+ *sat = 255 * (long) (max - min) / (512 - max - min);
+
+ if (max == min)
+ *hue = 0;
+ else if (max == red)
+ *hue = 0 + 43 * (green - blue) / (max - min);
+ else if (max == green)
+ *hue = 85 + 43 * (blue - red) / (max - min);
+ else if (max == blue)
+ *hue = 171 + 43 * (red - green) / (max - min);
+}
+
+
+static inline gint
+gimp_hsl_value (gdouble n1,
+ gdouble n2,
+ gdouble hue)
+{
+ gdouble value;
+
+ if (hue > 255)
+ hue -= 255;
+ else if (hue < 0)
+ hue += 255;
+
+ if (hue < 42.5)
+ value = n1 + (n2 - n1) * (hue / 42.5);
+ else if (hue < 127.5)
+ value = n2;
+ else if (hue < 170)
+ value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
+ else
+ value = n1;
+
+ return value * 255.0;
+}
+
+
+static void
+gimp_hsl_to_rgb (guchar hue,
+ guchar sat,
+ guchar lum,
+ guchar *red,
+ guchar *green,
+ guchar *blue)
+{
+ if (sat == 0) {
+ *red = lum;
+ *green = lum;
+ *blue = lum;
+ }
+ else {
+ gdouble h, s, l, m1, m2;
+
+ h = hue;
+ s = sat;
+ l = lum;
+
+ if (l < 128)
+ m2 = (l * (255 + s)) / 65025.0;
+ else
+ m2 = (l + s - (l * s) / 255.0) / 255.0;
+
+ m1 = (l / 127.5) - m2;
+
+ *red = gimp_hsl_value (m1, m2, h + 85);
+ *green = gimp_hsl_value (m1, m2, h);
+ *blue = gimp_hsl_value (m1, m2, h - 85);
+ }
+}
+
+
static void
_cairo_image_surface_paint_layer (cairo_surface_t *image,
GimpLayer *layer)
@@ -416,16 +519,19 @@ _cairo_image_surface_paint_layer (cairo_surface_t *image,
int layer_height;
int layer_row_stride;
guchar *layer_row;
+ guchar *mask_row;
int x, y, width, height;
guchar *image_pixel;
guchar *layer_pixel;
+ guchar *mask_pixel;
GRand *rand_gen;
int i, j;
- double layer_opacity, layer_a, r, g, b, a, temp;
- guchar image_hue, image_sat, image_val;
- guchar layer_hue, layer_sat, layer_val;
+ guchar r, g, b, a;
+ int temp, temp2;
+ guchar image_hue, image_sat, image_val, image_lum;
+ guchar layer_hue, layer_sat, layer_val, layer_lum;
- if ((image == NULL) || (layer->image == NULL))
+ if ((image == NULL) || (layer->pixels == NULL))
return;
cairo_surface_flush (image);
@@ -434,9 +540,9 @@ _cairo_image_surface_paint_layer (cairo_surface_t *image,
image_height = cairo_image_surface_get_height (image);
image_row_stride = cairo_image_surface_get_stride (image);
- layer_width = cairo_image_surface_get_width (layer->image);
- layer_height = cairo_image_surface_get_height (layer->image);
- layer_row_stride = cairo_image_surface_get_stride (layer->image);
+ layer_width = layer->width;
+ layer_height = layer->height;
+ layer_row_stride = layer->width * 4;
/* compute the layer <-> image intersection */
@@ -469,13 +575,11 @@ _cairo_image_surface_paint_layer (cairo_surface_t *image,
image_row = cairo_image_surface_get_data (image) + (y * image_row_stride) + (x * 4);
- /*g_print ("image: (%d, %d) [%d, %d]\n", x, y, width, height);*/
-
x = (layer->h_offset < 0) ? -layer->h_offset : 0;
y = (layer->v_offset < 0) ? -layer->v_offset : 0;
- layer_row = cairo_image_surface_get_data (layer->image) + (y * layer_row_stride) + (x * 4);
+ layer_row = layer->pixels + (y * layer_row_stride) + (x * 4);
- /*g_print ("layer: (%d, %d) [%d, %d]\n", x, y, width, height);*/
+ mask_row = layer->alpha_mask + (y * layer_width) + x;
if (layer->mode == GIMP_LAYER_MODE_DISSOLVE)
rand_gen = g_rand_new_with_seed (DISSOLVE_SEED);
@@ -483,139 +587,204 @@ _cairo_image_surface_paint_layer (cairo_surface_t *image,
for (i = 0; i < height; i++) {
image_pixel = image_row;
layer_pixel = layer_row;
+ mask_pixel = mask_row;
for (j = 0; j < width; j++) {
- layer_opacity = (double) layer->opacity / 255.0;
+ a = ((layer->bpp == 2) || (layer->bpp == 4)) ? layer_pixel[CAIRO_ALPHA] : 255;
- r = layer_opacity * layer_pixel[CAIRO_RED];
- g = layer_opacity * layer_pixel[CAIRO_GREEN];
- b = layer_opacity * layer_pixel[CAIRO_BLUE];
- a = layer_opacity * layer_pixel[CAIRO_ALPHA];
+ a = ADD_ALPHA (a, layer->opacity);
+ if (layer->alpha_mask && (layer->alpha_mask != NULL))
+ a = ADD_ALPHA (a, mask_pixel[0]);
- layer_a = a / 255.0;
+ if (a == 0)
+ goto next_pixel;
switch (layer->mode) {
+ case GIMP_LAYER_MODE_NORMAL:
+ default:
+ r = layer_pixel[CAIRO_RED];
+ g = layer_pixel[CAIRO_GREEN];
+ b = layer_pixel[CAIRO_BLUE];
+ break;
+
case GIMP_LAYER_MODE_DISSOLVE:
- if ((g_rand_double (rand_gen) <= layer_a) && (layer_a > 0)) {
- image_pixel[CAIRO_RED] = CLAMP_PIXEL (r / layer_a);
- image_pixel[CAIRO_GREEN] = CLAMP_PIXEL (g / layer_a);
- image_pixel[CAIRO_BLUE] = CLAMP_PIXEL (b / layer_a);
- image_pixel[CAIRO_ALPHA] = 0xff;
- }
+ if (g_rand_int_range (rand_gen, 0, 256) > a)
+ goto next_pixel;
+ r = layer_pixel[CAIRO_RED];
+ g = layer_pixel[CAIRO_GREEN];
+ b = layer_pixel[CAIRO_BLUE];
+ a = 255;
break;
- case GIMP_LAYER_MODE_SUBTRACT:
- if (layer_a > 0.0) {
- r = layer_a * GIMP_OP_SUBTRACT (r / layer_a, image_pixel[CAIRO_RED]);
- g = layer_a * GIMP_OP_SUBTRACT (g / layer_a,
image_pixel[CAIRO_GREEN]);
- b = layer_a * GIMP_OP_SUBTRACT (b / layer_a, image_pixel[CAIRO_BLUE]);
-
- image_pixel[CAIRO_RED] = GIMP_OP_NORMAL (r, image_pixel[CAIRO_RED],
layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_NORMAL (g,
image_pixel[CAIRO_GREEN], layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_NORMAL (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a,
image_pixel[CAIRO_ALPHA], layer_a);
- }
+ case GIMP_LAYER_MODE_LIGHTEN_ONLY:
+ r = GIMP_OP_LIGHTEN_ONLY (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_LIGHTEN_ONLY (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_LIGHTEN_ONLY (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
break;
- case GIMP_LAYER_MODE_DIVIDE:
- if (layer_a > 0.0) {
- r = layer_a * GIMP_OP_DIVIDE (r, image_pixel[CAIRO_RED], layer_a);
- g = layer_a * GIMP_OP_DIVIDE (g, image_pixel[CAIRO_GREEN], layer_a);
- b = layer_a * GIMP_OP_DIVIDE (b, image_pixel[CAIRO_BLUE], layer_a);
-
- image_pixel[CAIRO_RED] = GIMP_OP_NORMAL (r, image_pixel[CAIRO_RED],
layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_NORMAL (g,
image_pixel[CAIRO_GREEN], layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_NORMAL (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a,
image_pixel[CAIRO_ALPHA], layer_a);
- }
+ case GIMP_LAYER_MODE_SCREEN:
+ r = GIMP_OP_SCREEN (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_SCREEN (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_SCREEN (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
break;
- case GIMP_LAYER_MODE_HUE:
- case GIMP_LAYER_MODE_SATURATION:
- case GIMP_LAYER_MODE_VALUE:
- if (layer_a > 0.0) {
- gimp_rgb_to_hsv (image_pixel[CAIRO_RED],
- image_pixel[CAIRO_GREEN],
- image_pixel[CAIRO_BLUE],
- &image_hue,
- &image_sat,
- &image_val);
- gimp_rgb_to_hsv (r / layer_a,
- g / layer_a,
- b / layer_a,
- &layer_hue,
- &layer_sat,
- &layer_val);
-
- switch (layer->mode) {
- case GIMP_LAYER_MODE_HUE:
- gimp_hsv_to_rgb (layer_hue,
- image_sat,
- image_val,
- &r,
- &g,
- &b);
- break;
- case GIMP_LAYER_MODE_SATURATION:
- gimp_hsv_to_rgb (image_hue,
- layer_sat,
- image_val,
- &r,
- &g,
- &b);
- break;
- case GIMP_LAYER_MODE_VALUE:
- gimp_hsv_to_rgb (image_hue,
- image_sat,
- layer_val,
- &r,
- &g,
- &b);
- break;
- default:
- break;
- }
+ case GIMP_LAYER_MODE_DODGE:
+ r = GIMP_OP_DODGE (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_DODGE (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_DODGE (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
- r *= layer_a;
- g *= layer_a;
- b *= layer_a;
+ case GIMP_LAYER_MODE_ADDITION:
+ r = GIMP_OP_ADDITION (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_ADDITION (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_ADDITION (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
- image_pixel[CAIRO_RED] = GIMP_OP_NORMAL (r, image_pixel[CAIRO_RED],
layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_NORMAL (g,
image_pixel[CAIRO_GREEN], layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_NORMAL (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a,
image_pixel[CAIRO_ALPHA], layer_a);
- }
+ case GIMP_LAYER_MODE_DARKEN_ONLY:
+ r = GIMP_OP_DARKEN_ONLY (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_DARKEN_ONLY (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_DARKEN_ONLY (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_MULTIPLY:
+ r = GIMP_OP_MULTIPLY (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_MULTIPLY (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_MULTIPLY (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_BURN:
+ r = GIMP_OP_BURN (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_BURN (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_BURN (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_OVERLAY:
+ case GIMP_LAYER_MODE_SOFT_LIGHT:
+ r = GIMP_OP_SOFT_LIGHT (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_SOFT_LIGHT (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_SOFT_LIGHT (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_HARD_LIGHT:
+ r = GIMP_OP_HARD_LIGHT (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_HARD_LIGHT (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_HARD_LIGHT (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_DIFFERENCE:
+ r = GIMP_OP_DIFFERENCE (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_DIFFERENCE (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_DIFFERENCE (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_SUBTRACT:
+ r = GIMP_OP_SUBTRACT (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_SUBTRACT (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_SUBTRACT (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
break;
case GIMP_LAYER_MODE_GRAIN_EXTRACT:
- image_pixel[CAIRO_RED] = GIMP_OP_GRAIN_EXTRACT (r, image_pixel[CAIRO_RED],
layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_GRAIN_EXTRACT (g,
image_pixel[CAIRO_GREEN], layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_GRAIN_EXTRACT (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a, image_pixel[CAIRO_ALPHA],
layer_a);
+ r = GIMP_OP_GRAIN_EXTRACT (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_GRAIN_EXTRACT (layer_pixel[CAIRO_GREEN],
image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_GRAIN_EXTRACT (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
break;
case GIMP_LAYER_MODE_GRAIN_MERGE:
- image_pixel[CAIRO_RED] = GIMP_OP_GRAIN_MERGE (r, image_pixel[CAIRO_RED],
layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_GRAIN_MERGE (g, image_pixel[CAIRO_GREEN],
layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_GRAIN_MERGE (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a, image_pixel[CAIRO_ALPHA],
layer_a);
+ r = GIMP_OP_GRAIN_MERGE (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_GRAIN_MERGE (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_GRAIN_MERGE (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
break;
- case GIMP_LAYER_MODE_NORMAL:
- default:
- image_pixel[CAIRO_RED] = GIMP_OP_NORMAL (r, image_pixel[CAIRO_RED], layer_a);
- image_pixel[CAIRO_GREEN] = GIMP_OP_NORMAL (g, image_pixel[CAIRO_GREEN],
layer_a);
- image_pixel[CAIRO_BLUE] = GIMP_OP_NORMAL (b, image_pixel[CAIRO_BLUE],
layer_a);
- image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (a, image_pixel[CAIRO_ALPHA],
layer_a);
+ case GIMP_LAYER_MODE_DIVIDE:
+ r = GIMP_OP_DIVIDE (layer_pixel[CAIRO_RED], image_pixel[CAIRO_RED]);
+ g = GIMP_OP_DIVIDE (layer_pixel[CAIRO_GREEN], image_pixel[CAIRO_GREEN]);
+ b = GIMP_OP_DIVIDE (layer_pixel[CAIRO_BLUE], image_pixel[CAIRO_BLUE]);
+ break;
+
+ case GIMP_LAYER_MODE_HUE:
+ case GIMP_LAYER_MODE_SATURATION:
+ case GIMP_LAYER_MODE_VALUE:
+ gimp_rgb_to_hsv (image_pixel[CAIRO_RED],
+ image_pixel[CAIRO_GREEN],
+ image_pixel[CAIRO_BLUE],
+ &image_hue,
+ &image_sat,
+ &image_val);
+ gimp_rgb_to_hsv (layer_pixel[CAIRO_RED],
+ layer_pixel[CAIRO_GREEN],
+ layer_pixel[CAIRO_BLUE],
+ &layer_hue,
+ &layer_sat,
+ &layer_val);
+
+ switch (layer->mode) {
+ case GIMP_LAYER_MODE_HUE:
+ gimp_hsv_to_rgb (layer_hue,
+ image_sat,
+ image_val,
+ &r,
+ &g,
+ &b);
+ break;
+ case GIMP_LAYER_MODE_SATURATION:
+ gimp_hsv_to_rgb (image_hue,
+ layer_sat,
+ image_val,
+ &r,
+ &g,
+ &b);
+ break;
+ case GIMP_LAYER_MODE_VALUE:
+ gimp_hsv_to_rgb (image_hue,
+ image_sat,
+ layer_val,
+ &r,
+ &g,
+ &b);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ case GIMP_LAYER_MODE_COLOR:
+ gimp_rgb_to_hsl (image_pixel[CAIRO_RED],
+ image_pixel[CAIRO_GREEN],
+ image_pixel[CAIRO_BLUE],
+ &image_hue,
+ &image_sat,
+ &image_lum);
+ gimp_rgb_to_hsl (layer_pixel[CAIRO_RED],
+ layer_pixel[CAIRO_GREEN],
+ layer_pixel[CAIRO_BLUE],
+ &layer_hue,
+ &layer_sat,
+ &layer_lum);
+ gimp_hsl_to_rgb (layer_hue,
+ layer_sat,
+ image_lum,
+ &r,
+ &g,
+ &b);
break;
}
+ image_pixel[CAIRO_RED] = GIMP_OP_NORMAL (r, image_pixel[CAIRO_RED], a);
+ image_pixel[CAIRO_GREEN] = GIMP_OP_NORMAL (g, image_pixel[CAIRO_GREEN], a);
+ image_pixel[CAIRO_BLUE] = GIMP_OP_NORMAL (b, image_pixel[CAIRO_BLUE], a);
+ image_pixel[CAIRO_ALPHA] = GIMP_OP_NORMAL (255, image_pixel[CAIRO_ALPHA], a);
+
+next_pixel:
+
image_pixel += 4;
layer_pixel += 4;
+ mask_pixel += 1;
}
image_row += image_row_stride;
layer_row += layer_row_stride;
+ mask_row += layer_width;
}
if (layer->mode == GIMP_LAYER_MODE_DISSOLVE)
@@ -637,15 +806,11 @@ _cairo_image_surface_create_from_layers (int canvas_width,
image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, canvas_width, canvas_height);
for (scan = layers; scan; scan = scan->next) {
- GimpLayer *layer = scan->data;
- cairo_operator_t op = -1;
+ GimpLayer *layer = scan->data;
- if (layer->image == NULL)
+ if (layer->pixels == NULL)
continue;
- if ((layer->mask != NULL) && layer->apply_mask)
- gimp_layer_apply_mask (layer);
-
/* the bottommost layer only supports NORMAL and DISSOLVE */
if ((scan == layers) && (layer->mode != GIMP_LAYER_MODE_DISSOLVE))
@@ -668,162 +833,38 @@ _cairo_image_surface_create_from_layers (int canvas_width,
}
}
- /* find the cairo operation equivalent to the layer mode */
+ _cairo_image_surface_paint_layer (image, layer);
- switch (layer->mode) {
- case GIMP_LAYER_MODE_NORMAL:
- op = CAIRO_OPERATOR_OVER;
- break;
- case GIMP_LAYER_MODE_DISSOLVE:
- break;
- case GIMP_LAYER_MODE_BEHIND:
- break;
- case GIMP_LAYER_MODE_MULTIPLY:
- op = CAIRO_OPERATOR_MULTIPLY;
- break;
- case GIMP_LAYER_MODE_SCREEN:
- op = CAIRO_OPERATOR_SCREEN;
- break;
- case GIMP_LAYER_MODE_OVERLAY:
- /* In Gimp OVERLAY and SOFT_LIGHT are identical */
- op = CAIRO_OPERATOR_SOFT_LIGHT;
- break;
- case GIMP_LAYER_MODE_DIFFERENCE:
- op = CAIRO_OPERATOR_DIFFERENCE;
- break;
- case GIMP_LAYER_MODE_ADDITION:
- op = CAIRO_OPERATOR_ADD;
- break;
- case GIMP_LAYER_MODE_SUBTRACT:
- break;
- case GIMP_LAYER_MODE_DARKEN_ONLY:
- op = CAIRO_OPERATOR_DARKEN;
- break;
- case GIMP_LAYER_MODE_LIGHTEN_ONLY:
- op = CAIRO_OPERATOR_LIGHTEN;
- break;
- case GIMP_LAYER_MODE_HUE:
- break;
- case GIMP_LAYER_MODE_SATURATION:
- break;
- case GIMP_LAYER_MODE_COLOR:
- op = CAIRO_OPERATOR_HSL_COLOR;
- break;
- case GIMP_LAYER_MODE_VALUE:
- break;
- case GIMP_LAYER_MODE_DIVIDE:
- break;
- case GIMP_LAYER_MODE_DODGE:
- op = CAIRO_OPERATOR_COLOR_DODGE;
- break;
- case GIMP_LAYER_MODE_BURN:
- op = CAIRO_OPERATOR_COLOR_BURN;
- break;
- case GIMP_LAYER_MODE_HARD_LIGHT:
- op = CAIRO_OPERATOR_HARD_LIGHT;
- break;
- case GIMP_LAYER_MODE_SOFT_LIGHT:
- op = CAIRO_OPERATOR_SOFT_LIGHT;
- break;
- case GIMP_LAYER_MODE_GRAIN_EXTRACT:
- break;
- case GIMP_LAYER_MODE_GRAIN_MERGE:
- break;
- }
-
- if (op != -1) {
-
- /* layer mode supported directly by cairo */
-
- cairo_t *cr;
-
- cr = cairo_create (image);
- cairo_set_source_surface (cr, layer->image, layer->h_offset, layer->v_offset);
- cairo_set_operator (cr, op);
- cairo_rectangle (cr, 0, 0, canvas_width, canvas_height);
- cairo_paint_with_alpha (cr, (double) layer->opacity / 255.0);
-
- cairo_destroy (cr);
- }
- else
- _cairo_image_surface_paint_layer (image, layer);
+ performance (DEBUG_INFO, "end paint layer %d, mode %d", layer->n, layer->mode);
}
return image;
}
-static void
-_cairo_surface_data_post_production (guchar *image_pixels,
- int row_stride,
- int width,
- int height,
- int bpp,
- GimpImageBaseType base_type)
+static guchar *
+read_pixels_from_hierarchy (GDataInputStream *data_stream,
+ guint32 hierarchy_offset,
+ GimpLayer *layer,
+ GimpColormap *colormap,
+ GimpImageBaseType base_type,
+ GimpCompression compression,
+ gboolean is_gimp_channel,
+ GCancellable *cancellable,
+ GError **error)
{
- int i, j;
- guchar *row, *pixel;
-
- row = image_pixels;
- for (i = 0; i < height; i++) {
- pixel = row;
- for (j = 0; j < width; j++) {
-
- if ((bpp <= 2) && (base_type != GIMP_INDEXED)) {
-
- /* copy the red channel value to the green and blue channels */
-
- pixel[CAIRO_GREEN] = pixel[CAIRO_RED];
- pixel[CAIRO_BLUE] = pixel[CAIRO_RED];
- }
-
- if ((bpp == 4) || (bpp == 2)) {
-
- /* multiply for the alpha channel */
-
- if (pixel[CAIRO_ALPHA] < 0xff) {
- double factor = (double) pixel[CAIRO_ALPHA] / 0xff;
- pixel[CAIRO_RED] *= factor;
- pixel[CAIRO_GREEN] *= factor;
- pixel[CAIRO_BLUE] *= factor;
- }
- }
- else if ((bpp == 3) || (bpp == 1)) {
-
- /* set the alpha channel to opaque */
-
- pixel[CAIRO_ALPHA] = 0xff;
- }
-
- pixel += 4;
- }
- row += row_stride;
- }
-}
-
-
-static cairo_surface_t *
-_cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
- guint32 hierarchy_offset,
- GimpLayer *layer,
- GimpColormap *colormap,
- GimpImageBaseType base_type,
- GimpCompression compression,
- GCancellable *cancellable,
- GError **error)
-{
- cairo_surface_t *image = NULL;
- guint32 width;
- guint32 height;
- guint32 bpp;
- guint32 level_offset;
- GArray *tile_offsets = NULL;
- guint32 tile_offset;
- guint32 last_tile_offset;
- int n_tiles;
- int t;
- guchar *image_pixels;
- int row_stride;
+ guchar *image_pixels = NULL;
+ guint32 width;
+ guint32 height;
+ guint32 in_bpp;
+ guint32 out_bpp;
+ int row_stride;
+ guint32 level_offset;
+ GArray *tile_offsets = NULL;
+ guint32 tile_offset;
+ guint32 last_tile_offset;
+ int n_tiles;
+ int t;
/* read the hierarchy structure */
@@ -844,7 +885,7 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
if (*error != NULL)
goto read_error;
- bpp = g_data_input_stream_read_uint32 (data_stream, cancellable, error);
+ in_bpp = g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto read_error;
@@ -852,12 +893,13 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
if (*error != NULL)
goto read_error;
- /*
- g_print (" hierarchy width: %" G_GUINT32_FORMAT "\n", width);
- g_print (" hierarchy height: %" G_GUINT32_FORMAT "\n", height);
- g_print (" hierarchy bpp: %" G_GUINT32_FORMAT "\n", bpp);
- g_print (" level offset: %" G_GUINT32_FORMAT "\n", level_offset);
- */
+ if (is_gimp_channel)
+ g_assert (in_bpp == 1);
+
+ if (! is_gimp_channel)
+ layer->bpp = in_bpp;
+
+ layer->tiles.dirty = TRUE;
/* read the level structure */
@@ -878,17 +920,11 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
if (*error != NULL)
goto read_error;
- /*
- g_print (" level width: %" G_GUINT32_FORMAT "\n", width);
- g_print (" level height: %" G_GUINT32_FORMAT "\n", height);
- */
-
/* tiles */
- image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
- cairo_surface_flush (image);
- image_pixels = cairo_image_surface_get_data (image);
- row_stride = cairo_image_surface_get_stride (image);
+ out_bpp = is_gimp_channel ? 1 : 4;
+ row_stride = width * out_bpp;
+ image_pixels = g_new (guchar, row_stride * height);
tile_offsets = g_array_new (FALSE, FALSE, sizeof (guint32));;
n_tiles = 0;
@@ -897,7 +933,6 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
n_tiles += 1;
last_tile_offset = tile_offset;
g_array_append_val (tile_offsets, tile_offset);
- /*g_print (" tile %d: %" G_GUINT32_FORMAT "\n", n_tiles, tile_offset);*/
}
tile_offset = last_tile_offset + MAX_TILE_SIZE;
g_array_append_val (tile_offsets, tile_offset);
@@ -906,11 +941,11 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
goto read_error;
if (compression == GIMP_COMPRESSION_RLE) {
+ guchar *tile_data = NULL;
/* go to the first tile */
tile_offset = g_array_index (tile_offsets, guint32, 0);
- /*g_print (" <seek: %" G_GUINT32_FORMAT ">\n", tile_offset);*/
if (! g_seekable_seek (G_SEEKABLE (data_stream),
tile_offset,
G_SEEK_SET,
@@ -922,9 +957,10 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
/* decompress the tile data */
+ tile_data = g_malloc (MAX_TILE_SIZE);
+
for (t = 0; t < n_tiles; t++) {
goffset tile_data_size;
- guchar *tile_data;
guchar *tile_data_p;
guchar *tile_data_limit;
gsize data_read;
@@ -937,27 +973,22 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
/* read the tile data */
tile_data_size = g_array_index (tile_offsets, guint32, t + 1) - g_array_index
(tile_offsets, guint32, t);
- if (tile_data_size <= 0) {
- /*g_print ("<tile %d: size error %" G_GUINT32_FORMAT " = %" G_GUINT32_FORMAT
" - %" G_GUINT32_FORMAT ">", t, tile_data_size, g_array_index (tile_offsets, guint32, t + 1), g_array_index
(tile_offsets, guint32, t));*/
+ if (tile_data_size <= 0)
continue;
- }
- tile_data = g_malloc (tile_data_size);
data_read = g_input_stream_read (G_INPUT_STREAM (data_stream), tile_data,
tile_data_size, cancellable, error);
if (*error != NULL)
goto rle_error;
- /*g_print (" tile size %d: %" G_GSIZE_FORMAT " (%" G_GSIZE_FORMAT ")\n", t,
data_read, tile_data_size);*/
-
/* decompress the channel streams */
if (! gimp_layer_get_tile_size (layer,
t,
+ out_bpp,
&tile_pixels_offset,
&tile_width,
&tile_height))
{
- /*g_print ("<tile %d: error>", t);*/
goto rle_error;
}
@@ -965,47 +996,51 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
tile_data_p = tile_data;
tile_data_limit = tile_data + data_read - 1;
- for (c = 0; c < bpp; c++) {
+ for (c = 0; c < in_bpp; c++) {
int channel_offset;
guchar *pixels_row;
- guchar *pixels;
+ guchar *pixel;
int size;
int n, p, q, v;
int tile_column;
- if (base_type == GIMP_INDEXED)
+ if (is_gimp_channel)
+ channel_offset = 0;
+ else if (base_type == GIMP_INDEXED)
channel_offset = cairo_indexed[c];
- else if (bpp >= 3)
+ else if (in_bpp >= 3)
channel_offset = cairo_rgba[c];
- else if (bpp <= 2)
- /* save the value in the red channel,
- * it will be copied to the other channels in
- * _cairo_surface_data_post_production */
+ else if (in_bpp <= 2)
channel_offset = cairo_graya[c];
else
channel_offset = 0;
pixels_row = image_pixels + tile_pixels_offset + channel_offset;
- pixels = pixels_row;
+ pixel = pixels_row;
size = tile_pixels_size;
tile_column = 0;
-#define SET_PIXEL(v) { \
- tile_column++; \
- if (tile_column > tile_width) { \
- pixels_row += row_stride; \
- pixels = pixels_row; \
- tile_column = 1; \
- } \
- if ((base_type == GIMP_INDEXED) && (c == 0)) { \
- guchar *color = (guchar *) (colormap + (v)); \
- pixels[CAIRO_RED] = color[0]; \
- pixels[CAIRO_GREEN] = color[1]; \
- pixels[CAIRO_BLUE] = color[2]; \
- } \
- else \
- *pixels = (v); \
- pixels += 4; \
+#define SET_PIXEL(v) { \
+ tile_column++; \
+ if (tile_column > tile_width) { \
+ pixels_row += row_stride; \
+ pixel = pixels_row; \
+ tile_column = 1; \
+ } \
+ if ((base_type == GIMP_INDEXED) && (c == 0)) { \
+ guchar *color = (guchar *) (colormap + (v)); \
+ pixel[CAIRO_RED] = color[0]; \
+ pixel[CAIRO_GREEN] = color[1]; \
+ pixel[CAIRO_BLUE] = color[2]; \
+ } \
+ else if (! is_gimp_channel && (in_bpp <= 2) && (c == 0)) { \
+ pixel[CAIRO_RED] = (v); \
+ pixel[CAIRO_GREEN] = (v); \
+ pixel[CAIRO_BLUE] = (v); \
+ } \
+ else \
+ *pixel = (v); \
+ pixel += out_bpp; \
}
while (size > 0) {
@@ -1073,151 +1108,56 @@ _cairo_image_surface_create_from_hierarchy (GDataInputStream *data_stream,
if (size < 0)
goto rle_error;
- while (n-- > 0)
- SET_PIXEL (*tile_data_p++);
+ while (n-- > 0) {
+ v = *tile_data_p++;
+ SET_PIXEL (v);
+ }
}
}
}
-#undef SET_PIXEL
+ }
rle_error:
- g_free (tile_data);
- if (*error != NULL)
- goto read_error;
- }
+ g_free (tile_data);
}
else if (compression == GIMP_COMPRESSION_NONE) {
- /* This is untested because Gimp doesn't save in uncompressed
- * mode any more. */
-
- /* go to the first tile */
-
- tile_offset = g_array_index (tile_offsets, guint32, 0);
- /*g_print (" <seek: %" G_GUINT32_FORMAT ">\n", tile_offset);*/
- if (! g_seekable_seek (G_SEEKABLE (data_stream),
- tile_offset,
- G_SEEK_SET,
- cancellable,
- error))
- {
- goto read_error;
- }
-
- /* decompress the tile data */
-
- for (t = 0; t < n_tiles; t++) {
- goffset tile_data_size;
- guchar *tile_data;
- guchar *tile_data_p;
- gsize data_read;
- goffset tile_pixels_offset;
- int tile_width;
- int tile_height;
- guchar *pixels_row;
- guchar *pixels;
- int i, j;
+ /* Gimp doesn't save in uncompressed mode. */
- /* get the tile size and position */
-
- if (! gimp_layer_get_tile_size (layer,
- t,
- &tile_pixels_offset,
- &tile_width,
- &tile_height))
- {
- /*g_print ("<tile %d: error>", t);*/
- continue;
- }
-
- /* read the tile data */
-
- tile_data_size = tile_width * tile_height * bpp;
- if (tile_data_size <= 0) {
- /*g_print ("<tile %d: size error %" G_GUINT32_FORMAT " = %" G_GUINT32_FORMAT
" - %" G_GUINT32_FORMAT ">", t, tile_data_size, g_array_index (tile_offsets, guint32, t + 1), g_array_index
(tile_offsets, guint32, t));*/
- continue;
- }
-
- tile_data = g_malloc (tile_data_size);
- data_read = g_input_stream_read (G_INPUT_STREAM (data_stream), tile_data,
tile_data_size, cancellable, error);
- if (*error != NULL) {
- g_free (tile_data);
- goto read_error;
- }
-
- if (data_read != tile_data_size) {
- /*g_print (" tile size %d: %" G_GSIZE_FORMAT " (%" G_GSIZE_FORMAT ")\n",
t, data_read, tile_data_size);*/
- g_free (tile_data);
- continue;
- }
-
- tile_data_p = tile_data;
- pixels_row = image_pixels + tile_pixels_offset;
-
- for (i = 0; i < tile_height; i++) {
- pixels = pixels_row;
-
- for (j = 0; j < tile_width; j++) {
- if (base_type == GIMP_INDEXED) {
- guchar *color = (guchar *) (colormap + (*tile_data_p++));
- pixels[CAIRO_RED] = color[0];
- pixels[CAIRO_GREEN] = color[1];
- pixels[CAIRO_BLUE] = color[2];
- }
- else if (bpp >= 3) {
- pixels[CAIRO_RED] = *tile_data_p++;
- pixels[CAIRO_GREEN] = *tile_data_p++;
- pixels[CAIRO_BLUE] = *tile_data_p++;
-
- }
- else if (bpp <= 2)
- pixels[CAIRO_RED] = *tile_data_p++;
-
- if ((bpp == 2) || (bpp == 4))
- pixels[CAIRO_ALPHA] = *tile_data_p++;
-
- pixels += 4;
- }
-
- pixels_row += row_stride;
- }
-
- g_free (tile_data);
- }
}
- _cairo_surface_data_post_production (image_pixels, row_stride, width, height, bpp, base_type);
- cairo_surface_mark_dirty (image);
+ performance (DEBUG_INFO, "end read hierarchy");
g_array_free (tile_offsets, TRUE);
- return image;
+ return image_pixels;
read_error:
- if (image != NULL)
- cairo_surface_destroy (image);
- if (tile_offsets != NULL)
- g_array_free (tile_offsets, TRUE);
+ g_free (image_pixels);
+ g_array_free (tile_offsets, TRUE);
return NULL;
}
+#undef SET_PIXEL
+
+
GthImage *
_cairo_image_surface_create_from_xcf (GInputStream *istream,
- GthFileData *file_data,
- int requested_size,
- int *original_width,
- int *original_height,
- gpointer user_data,
- GCancellable *cancellable,
- GError **error)
+ GthFileData *file_data,
+ int requested_size,
+ int *original_width,
+ int *original_height,
+ gpointer user_data,
+ GCancellable *cancellable,
+ GError **error)
{
GthImage *image = NULL;
- cairo_surface_t *surface = NULL;
+ cairo_surface_t *surface;
GDataInputStream *data_stream;
char *file_type;
char *version;
@@ -1227,18 +1167,24 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
guint32 property_type;
guint32 payload_length;
GimpCompression compression;
- GList *layers = NULL;
+ GList *layers;
guint32 n_colors;
- GimpColormap *colormap = NULL;
+ GimpColormap *colormap;
guint n_properties;
gboolean read_properties;
- GArray *layer_offsets = NULL;
+ GArray *layer_offsets;
guint32 layer_offset;
guint n_layers;
guint32 channel_offset;
guint n_channels;
int i;
+ performance (DEBUG_INFO, "start loading");
+
+ g_once (&xcf_init_once, xcf_init, NULL);
+
+ performance (DEBUG_INFO, "end init");
+
data_stream = g_data_input_stream_new (istream);
g_data_input_stream_set_byte_order (data_stream, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN);
@@ -1250,8 +1196,7 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (g_strcmp0 (file_type, "gimp xcf ") != 0) {
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid format");
- g_free (file_type);
- goto out;
+ return NULL;
}
g_free (file_type);
@@ -1260,8 +1205,6 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
version = _g_data_input_stream_read_c_string (data_stream, 5, cancellable, error);
if (*error != NULL)
goto out;
-
- /*g_print ("version: %s\n", version);*/
g_free (version);
/* canvas size */
@@ -1274,16 +1217,12 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (*error != NULL)
goto out;
- /*g_print ("canvas size: %" G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT "\n", canvas_width,
canvas_height);*/
-
/* base type */
base_type = g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto out;
- /*g_print ("base type: %d\n", base_type);*/
-
/* properties */
compression = GIMP_COMPRESSION_RLE;
@@ -1346,19 +1285,15 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
compression = g_data_input_stream_read_byte (data_stream, cancellable, error);
if (*error != NULL)
goto out;
-
- /*g_print ("compression: %d\n", compression);*/
break;
default:
g_input_stream_skip (G_INPUT_STREAM (data_stream), payload_length, cancellable,
error);
if (*error != NULL)
goto out;
-
break;
}
}
- /*g_print ("properties: %d\n", n_properties);*/
/* layers */
@@ -1367,25 +1302,21 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
while ((layer_offset = g_data_input_stream_read_uint32 (data_stream, cancellable, error)) != 0) {
n_layers += 1;
g_array_append_val (layer_offsets, layer_offset);
- /*g_print ("layer %d: %" G_GUINT32_FORMAT "\n", n_layers, layer_offset);*/
}
- if (*error != NULL)
- goto out;
-
/* channels */
n_channels = 0;
- while ((channel_offset = g_data_input_stream_read_uint32 (data_stream, cancellable, error)) != 0) {
+ while ((channel_offset = g_data_input_stream_read_uint32 (data_stream, cancellable, error)) != 0)
n_channels += 1;
- /*g_print ("channel %d: %" G_GUINT32_FORMAT "\n", n_channels, channel_offset);*/
- }
if (*error != NULL)
goto out;
/* read the layers */
+ performance (DEBUG_INFO, "start read layers");
+
for (i = 0; i < n_layers; i++) {
GimpLayer *layer;
guint32 hierarchy_offset;
@@ -1393,7 +1324,6 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
char *mask_name;
layer_offset = g_array_index (layer_offsets, guint32, i);
- /*g_print ("layer %d: %" G_GUINT32_FORMAT "\n", i, layer_offset);*/
if (! g_seekable_seek (G_SEEKABLE (data_stream),
layer_offset,
@@ -1404,7 +1334,7 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
goto out;
}
- layer = gimp_layer_new ();
+ layer = gimp_layer_new (i);
layers = g_list_prepend (layers, layer);
/* size */
@@ -1417,24 +1347,18 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (*error != NULL)
goto out;
- /*g_print (" size: %" G_GUINT32_FORMAT " x %" G_GUINT32_FORMAT "\n", layer->width,
layer->height);*/
-
/* type */
layer->type = g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto out;
- /*g_print (" type: %d\n", layer->type);*/
-
/* name */
layer->name = _g_data_input_stream_read_xcf_string (data_stream, cancellable, error);
if (*error != NULL)
goto out;
- /*g_print (" name: %s\n", layer->name);*/
-
/* properties */
read_properties = TRUE;
@@ -1462,22 +1386,18 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
case 6: /* PROP_OPACITY */
layer->opacity = g_data_input_stream_read_uint32 (data_stream, cancellable,
error);
- /*g_print (" opacity: %d\n", layer->opacity);*/
break;
case 7: /* PROP_MODE */
layer->mode = g_data_input_stream_read_uint32 (data_stream, cancellable,
error);
- /*g_print (" mode: %d\n", layer->mode);*/
break;
case 8: /* PROP_VISIBLE */
layer->visible = g_data_input_stream_read_uint32 (data_stream, cancellable,
error);
- /*g_print (" visible: %d\n", layer->visible);*/
break;
case 11: /* PROP_APPLY_MASK */
layer->apply_mask = (g_data_input_stream_read_uint32 (data_stream,
cancellable, error) == 1);
- /*g_print (" apply mask: %d\n", layer->apply_mask);*/
break;
case 15: /* PROP_OFFSETS */
@@ -1486,7 +1406,6 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
goto out;
layer->v_offset = g_data_input_stream_read_uint32 (data_stream, cancellable,
error);
- /*g_print (" coordinates: %d, %d\n", layer->h_offset, layer->v_offset);*/
break;
default:
@@ -1497,7 +1416,6 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (*error != NULL)
goto out;
}
- /*g_print (" properties: %d\n", n_properties);*/
/* hierarchy structure offset */
@@ -1505,22 +1423,18 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (*error != NULL)
goto out;
- /*g_print (" hierarchy offset: %" G_GUINT32_FORMAT "\n", hierarchy_offset);*/
-
/* layer mask offset */
mask_offset = g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto out;
- /*g_print (" mask offset: %" G_GUINT32_FORMAT "\n", mask_offset);*/
-
/* the layer image */
if (layer->floating_selection || ! layer->visible || (layer->opacity == 0))
continue;
- layer->image = _cairo_image_surface_create_from_hierarchy (data_stream, hierarchy_offset,
layer, colormap, base_type, compression, cancellable, error);
+ layer->pixels = read_pixels_from_hierarchy (data_stream, hierarchy_offset, layer, colormap,
base_type, compression, FALSE, cancellable, error);
if (*error != NULL)
goto out;
@@ -1540,11 +1454,11 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
/* mask width, height and name */
- /* mask_width = */ g_data_input_stream_read_uint32 (data_stream, cancellable, error);
+ /*mask_width = */ g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto out;
- /* mask_height = */ g_data_input_stream_read_uint32 (data_stream, cancellable, error);
+ /*mask_height = */ g_data_input_stream_read_uint32 (data_stream, cancellable, error);
if (*error != NULL)
goto out;
@@ -1581,7 +1495,6 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
break;
}
}
- /*g_print (" mask properties: %d\n", n_properties);*/
/* the mask image */
@@ -1589,25 +1502,25 @@ _cairo_image_surface_create_from_xcf (GInputStream *istream,
if (*error != NULL)
goto out;
- /*g_print (" mask hierarchy offset: %" G_GUINT32_FORMAT "\n", hierarchy_offset);*/
-
- layer->mask = _cairo_image_surface_create_from_hierarchy (data_stream, hierarchy_offset,
layer, colormap, base_type, compression, cancellable, error);
+ layer->alpha_mask = read_pixels_from_hierarchy (data_stream, hierarchy_offset, layer,
colormap, base_type, compression, TRUE, cancellable, error);
if (*error != NULL)
goto out;
}
+ performance (DEBUG_INFO, "end read layers");
+
surface = _cairo_image_surface_create_from_layers (canvas_width, canvas_height, base_type, layers);
image = gth_image_new_for_surface (surface);
cairo_surface_destroy (surface);
+ performance (DEBUG_INFO, "end rendering");
+
out:
- if (layers != NULL)
- g_list_free_full (layers, (GDestroyNotify) gimp_layer_free);
+ g_list_free_full (layers, (GDestroyNotify) gimp_layer_free);
if (layer_offsets != NULL)
g_array_free (layer_offsets, TRUE);
- if (colormap != NULL)
- g_free (colormap);
+ g_free (colormap);
if (data_stream != NULL)
g_object_unref (data_stream);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]