kwo pushed a commit to branch master. http://git.enlightenment.org/legacy/imlib2_loaders.git/commit/?id=a4bcffe55adbf1492bf399f57bf4faa289445bb7
commit a4bcffe55adbf1492bf399f57bf4faa289445bb7 Author: Kim Woelders <k...@woelders.dk> Date: Sun Nov 17 12:52:07 2019 +0100 XCF loader: Cosmetic rearrangements --- src/modules/loaders/loader_xcf.c | 1908 ++++++++++++++++++-------------------- 1 file changed, 919 insertions(+), 989 deletions(-) diff --git a/src/modules/loaders/loader_xcf.c b/src/modules/loaders/loader_xcf.c index 86bdf9c..7ca745d 100644 --- a/src/modules/loaders/loader_xcf.c +++ b/src/modules/loaders/loader_xcf.c @@ -59,29 +59,22 @@ #include "loader_common.h" #include "loader_xcf.h" -/* #define XCF_DBG */ - -#define FREE(X) { free(X); X = NULL; } - -#ifdef XCF_DBG -#define D(fmt, args...) \ -{ \ - printf("Imlib2 XCF loader: "); \ - printf(fmt, ## args); \ -} +#define XCF_DBG 0 +#if XCF_DBG +#define D(fmt...) printf("Imlib2 XCF loader: " fmt) #else -#define D(fmt, args...) +#define D(fmt...) #endif #define TILE_WIDTH 64 #define TILE_HEIGHT 64 -/* --------------------------------------------------------------------------- typedefs ------------ */ +/* ------------ typedefs ------------ */ typedef struct _Layer Layer; typedef struct _Tile Tile; -/* ------------------------------------------------------------------------------ enums ------------ */ +/* ------------ enums ------------ */ /* These are all the properties that a layer or channel can have. Only some of them are actually used. */ @@ -161,7 +154,7 @@ typedef enum { INDEXEDA_GIMAGE } GimpImageType; -/* ---------------------------------------------------------------------------- structs ------------ */ +/* ------------ structs ------------ */ /* Ok, this is what's left of Gimp's layer abstraction. I kicked out all the stuff that's unnecessary and added the necessary stuff @@ -254,361 +247,548 @@ struct _GimpImage { Layer *floating_sel; } _image; -/* ------------------------------------------------------------------------- prototypes ------------ */ - -/* stuff that was adapted from xcf.c */ - -static void xcf_seek_pos(int pos); -static int xcf_read_int32(FILE * fp, DATA32 * data, int count); - -/*static int xcf_read_float (FILE *fp, float *data, int count);*/ -static int xcf_read_int8(FILE * fp, DATA8 * data, int count); -static int xcf_read_string(FILE * fp, char **data, int count); -static char xcf_load_prop(PropType * prop_type, DATA32 * prop_size); -static void xcf_load_image(void); -static char xcf_load_image_props(void); - -static Layer *xcf_load_channel(void); -static char xcf_load_channel_props(Layer * layer); -static Layer *xcf_load_layer(void); -static char xcf_load_layer_props(Layer * layer); -static char xcf_load_hierarchy(Tile ** tiles, - int *num_rows, int *num_cols, int *bpp); -static char xcf_load_level(Tile ** tiles, int hierarchy_width, - int hierarchy_height, int bpp, - int *num_rows, int *num_cols); -static char xcf_load_tile(Tile * tile); -static char xcf_load_tile_rle(Tile * tile, int data_length); - -/* new stuff :) */ - -static Tile *allocate_tiles(int width, int height, int bpp, - int *num_rows, int *num_cols); -static void free_tiles(Tile * tiles, int num_tiles); -static void init_tile(Tile * tile, int width, int height, int bpp); -static Layer *new_layer(int width, int height, GimpImageType type, - int opacity, LayerModeEffects mode); -static void free_layer(Layer * layer); -static void add_layer_to_image(Layer * layer); -static void read_tiles_into_data(Tile * tiles, int num_cols, int width, - int height, int bpp, DATA8 ** data, - int use_cmap); -static void apply_layer_mask(Layer * layer); -static void set_layer_opacity(Layer * layer); -static void flatten_image(void); - -static char xcf_file_init(char *filename); -static void xcf_cleanup(void); -static void xcf_to_imlib(ImlibImage * im); - -/* ---------------------------------------------------------------------------- globals ------------ */ +/* ------------ globals ------------ */ /* This makes using the Gimp sources easier */ struct _GimpImage *image = &_image; -/* ------------------------------------------------------------------------------- code ------------ */ +/* ------------ prototypes ------------ */ + +/* new stuff :) */ static void -xcf_seek_pos(int pos) +free_tiles(Tile * tiles, int num_tiles) { - if (image->cp != pos) - { - image->cp = pos; - fseek(image->fp, image->cp, SEEK_SET); - } -} + int i; -static int -xcf_read_int32(FILE * fp, DATA32 * data, int count) -{ - int total; + D("%s: tiles=%p num=%d\n", __func__, tiles, num_tiles); - total = count; - if (count > 0) + for (i = 0; i < num_tiles; i++) { - xcf_read_int8(fp, (DATA8 *) data, count * 4); - - while (count--) + if (tiles[i].data) { - *data = (DATA32) ntohl(*data); - data++; + free(tiles[i].data); + tiles[i].data = NULL; } } - - return total * 4; + free(tiles); } -/* -static int -xcf_read_float (FILE *fp, - float *data, - int count) +static void +init_tile(Tile * tile, int width, int height, int bpp) { - return (xcf_read_int32(fp, (DATA32 *)((void *)data), count)); + D("%s: tile=%p\n", __func__, tile); + + if (!tile) + return; + + tile->bpp = bpp; + tile->ewidth = width; + tile->eheight = height; + tile->data = malloc(sizeof(DATA8) * width * height * bpp); + if (!tile->data) + { + D("Couldn't allocate tile.\n"); + } } -*/ -static int -xcf_read_int8(FILE * fp, DATA8 * data, int count) +static Tile * +allocate_tiles(int width, int height, int bpp, int *num_rows, int *num_cols) { - int total; - int bytes; + Tile *tiles; + int i, j, k, right_tile, bottom_tile; + int tile_width, tile_height; - total = count; - while (count > 0) + (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT; + (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH; + + tiles = calloc((*num_rows) * (*num_cols), sizeof(Tile)); + if (!tiles) { - bytes = fread((char *)data, sizeof(char), count, fp); - if (bytes <= 0) /* something bad happened */ - break; - count -= bytes; - data += bytes; + D("Couldn't allocate tiles.\n"); + return NULL; } - return total; -} + D("%s: tiles=%p %dx%d\n", __func__, tiles, *num_cols, *num_rows); -static int -xcf_read_string(FILE * fp, char **data, int count) -{ - DATA32 tmp; - int total; - int i; + right_tile = width - (((*num_cols) - 1) * TILE_WIDTH); + bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT); - total = 0; - for (i = 0; i < count; i++) + for (i = 0, k = 0; i < (*num_rows); i++) { - total += xcf_read_int32(fp, &tmp, 1); - if (tmp > 0) - { - data[i] = malloc(sizeof(DATA8) * tmp); - total += xcf_read_int8(fp, (DATA8 *) data[i], tmp); - } - else + for (j = 0; j < (*num_cols); j++, k++) { - data[i] = NULL; + tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH); + tile_height = ((i == (*num_rows) - 1) ? bottom_tile : TILE_HEIGHT); + init_tile(&(tiles[k]), tile_width, tile_height, bpp); } } - return total; -} + D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows)); -static char -xcf_load_prop(PropType * prop_type, DATA32 * prop_size) -{ - image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_type, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_size, 1); - return 1; + return tiles; } -static char -xcf_load_image_props(void) +static Layer * +new_layer(int width, int height, GimpImageType type, int opacity, + LayerModeEffects mode) { - PropType prop_type; - DATA32 prop_size; + Layer *layer; - while (1) + layer = calloc(1, sizeof(Layer)); + if (!layer) { - if (!xcf_load_prop(&prop_type, &prop_size)) - return 0; - - switch (prop_type) - { - case PROP_END: - { - D("Finished reading image properties.\n"); - return 1; - } - case PROP_COLORMAP: - { - if (image->file_version == 0) - { - unsigned int i; - - fprintf(stderr, - "XCF warning: version 0 of XCF file format\n" - "did not save indexed colormaps correctly.\n" - "Substituting grayscale map.\n"); - image->cp += - xcf_read_int32(image->fp, &image->num_cols, 1); - image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3); - xcf_seek_pos(image->cp + image->num_cols); - for (i = 0; i < image->num_cols; i++) - { - image->cmap[i * 3 + 0] = i; - image->cmap[i * 3 + 1] = i; - image->cmap[i * 3 + 2] = i; - } - } - else - { - D("Loading colormap.\n"); - image->cp += - xcf_read_int32(image->fp, &image->num_cols, 1); - image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3); - image->cp += - xcf_read_int8(image->fp, (DATA8 *) image->cmap, - image->num_cols * 3); - } - } - break; - - case PROP_COMPRESSION: - { - DATA8 compression; - - image->cp += xcf_read_int8(image->fp, &compression, 1); - - if ((compression != COMPRESS_NONE) && - (compression != COMPRESS_RLE) && - (compression != COMPRESS_ZLIB) && - (compression != COMPRESS_FRACTAL)) - { - fprintf(stderr, "unknown xcf compression type: %d\n", - (int)compression); - return 0; - } - - D("Image compression type: %i\n", compression); + D("Couldn't allocate layer.\n"); + return NULL; + } - image->compression = compression; - } - break; + D("%s: layer=%p\n", __func__, layer); - /* I threw out all of the following: --cK */ - case PROP_TATTOO: - case PROP_PARASITES: - case PROP_UNIT: - case PROP_PATHS: - case PROP_USER_UNIT: - case PROP_GUIDES: - case PROP_RESOLUTION: - default: - { - DATA8 buf[16]; - int amount; - - D("Skipping unexpected/unknown image property: %d\n", - prop_type); - - while (prop_size > 0) - { - amount = (16 < prop_size ? 16 : prop_size); - image->cp += xcf_read_int8(image->fp, buf, amount); - prop_size -= (16 < amount ? 16 : amount); - } - } - break; - } - } + layer->width = width; + layer->height = height; + layer->type = type; + layer->opacity = opacity; + layer->mode = mode; - return 0; + return layer; } static void -xcf_load_image(void) +free_layer(Layer * layer) { - Layer *layer; - DATA32 saved_pos; - DATA32 offset; - int width; - int height; - int image_type; - int num_successful_elements = 0; - - /* read in the image width, height and type */ - image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & image_type, 1); - - image->width = width; - image->height = height; - image->base_type = image_type; - - D("Loading %ix%i image.\n", width, height); + D("%s: layer=%p\n", __func__, layer); - /* read the image properties */ - if (!xcf_load_image_props()) - goto hard_error; + if (!layer) + return; - while (1) + if (layer->tiles) { - /* read in the offset of the next layer */ - image->cp += xcf_read_int32(image->fp, &offset, 1); + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + layer->tiles = NULL; + } - /* if the offset is 0 then we are at the end - * of the layer list. - */ - if (offset == 0) - break; + if (layer->mask) + { + free_layer(layer->mask); + layer->mask = NULL; + } - /* save the current position as it is where the - * next layer offset is stored. - */ - saved_pos = image->cp; + if (layer->data) + free(layer->data); - /* seek to the layer offset */ - xcf_seek_pos(offset); + free(layer); +} - /* read in the layer */ - layer = xcf_load_layer(); - if (!layer) - goto error; +static void +add_layer_to_image(Layer * layer) +{ + if (!layer) + return; - num_successful_elements++; + if (image->last_layer) + { + image->last_layer->next = layer; + layer->prev = image->last_layer; + } + else + { + image->layers = layer; + layer->prev = NULL; + } + layer->next = NULL; + image->last_layer = layer; +} - /* add the layer to the image if it's visible */ - if (layer->visible) - add_layer_to_image(layer); - else - free_layer(layer); +static void +set_layer_opacity(Layer * layer) +{ + int i; + DATA8 *ptr; - /* restore the saved position so we'll be ready to - * read the next offset. - */ - xcf_seek_pos(saved_pos); + if (!layer) + return; + if (layer->opacity != 255) + { + for (i = 0, ptr = layer->data; i < layer->width * layer->height; + i++, ptr += 4) + { + *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8; + } } +} - /* If we were a Gimp we would now load the user-defined channels here ... */ +static void +apply_layer_mask(Layer * layer) +{ + DATA8 *ptr1; + DATA8 *ptr2; + int i, tmp; - /* Flat-o-rama now :) */ - flatten_image(); + D("Applying layer mask.\n"); - return; + if (!layer) + return; - error: - if (num_successful_elements == 0) - goto hard_error; + if (!layer->mask) + return; - fprintf(stderr, - "XCF: This file is corrupt! I have loaded as much\nof it as I can, but it is incomplete.\n"); + ptr1 = layer->data; + ptr2 = layer->mask->data; - return; + for (i = 0; i < layer->width * layer->height; i++) + { + tmp = (*(ptr1 + 3) * *(ptr2)) / 256; + if (tmp > 255) + tmp = 255; - hard_error: - fprintf(stderr, - "XCF: This file is corrupt! I could not even\nsalvage any partial image data from it.\n"); - return; + *(ptr1 + 3) = (DATA8) tmp; + ptr1 += 4; + ptr2 += 4; + } } -static char -xcf_load_layer_props(Layer * layer) +static void +flatten_image(void) { - PropType prop_type; - DATA32 prop_size; + Layer *l = image->last_layer; + Layer *lp; + int layer_index; - while (1) - { - if (!xcf_load_prop(&prop_type, &prop_size)) - return 0; + image->data = calloc(image->width * image->height, sizeof(DATA32)); + layer_index = 0; + + while (l) + { + /* Ok, paste each layer on top of the image, using the mode's merging type. + * We're moving upward through the layer stack. + * --cK. + */ + if (image->single_layer_index < 0 + || layer_index == image->single_layer_index) + { + switch (l->mode) + { + case MULTIPLY_MODE: + D("MULTIPLY\n"); + combine_pixels_mult(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DIVIDE_MODE: + D("DIVIDE\n"); + combine_pixels_div(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SCREEN_MODE: + D("SCREEN\n"); + combine_pixels_screen(l->data, l->width, l->height, + image->data, image->width, + image->height, l->offset_x, + l->offset_y); + break; + case OVERLAY_MODE: + D("OVERLAY\n"); + combine_pixels_overlay(l->data, l->width, l->height, + image->data, image->width, + image->height, l->offset_x, + l->offset_y); + break; + case DIFFERENCE_MODE: + D("DIFF\n"); + combine_pixels_diff(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case ADDITION_MODE: + D("ADD\n"); + combine_pixels_add(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SUBTRACT_MODE: + D("SUB\n"); + combine_pixels_sub(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DARKEN_ONLY_MODE: + D("DARKEN\n"); + combine_pixels_darken(l->data, l->width, l->height, + image->data, image->width, + image->height, l->offset_x, + l->offset_y); + break; + case LIGHTEN_ONLY_MODE: + D("LIGHTEN\n"); + combine_pixels_lighten(l->data, l->width, l->height, + image->data, image->width, + image->height, l->offset_x, + l->offset_y); + break; + + case HUE_MODE: + D("HUE\n"); + combine_pixels_hue(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SATURATION_MODE: + D("SATURATION\n"); + combine_pixels_sat(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case VALUE_MODE: + D("VALUE\n"); + combine_pixels_val(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case COLOR_MODE: + D("COLOR\n"); + combine_pixels_col(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DISSOLVE_MODE: + D("DISSOLVE\n"); + combine_pixels_diss(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + + /* None of the following is actually valid for layer blending, fall through: */ + case BEHIND_MODE: + case REPLACE_MODE: + case ERASE_MODE: + case ANTI_ERASE_MODE: + D("EEEEEK -- this mode shouldn't be here\n"); + /* FALLTHROUGH */ + + case NORMAL_MODE: + D("NORMAL\n"); + combine_pixels_normal(l->data, l->width, l->height, + image->data, image->width, + image->height, l->offset_x, + l->offset_y); + break; + + default: + D("Unknown layer mode: %i. Skipping.\n", l->mode); + break; + } + } + + lp = l->prev; + /* free the layer now, since it's not needed anymore */ + free_layer(l); + + l = lp; + layer_index++; + } + + /* We've used up all the layers now, so set them to NULL in the image: */ + image->layers = NULL; + image->last_layer = NULL; +} + +/* ------------ code ------------ */ + +/* stuff that was adapted from xcf.c */ + +static void +xcf_seek_pos(int pos) +{ + if (image->cp != pos) + { + image->cp = pos; + fseek(image->fp, image->cp, SEEK_SET); + } +} + +static int +xcf_read_int8(FILE * fp, DATA8 * data, int count) +{ + int total; + int bytes; + + total = count; + while (count > 0) + { + bytes = fread(data, 1, count, fp); + if (bytes <= 0) /* something bad happened */ + break; + count -= bytes; + data += bytes; + } + + return total; +} + +static int +xcf_read_int32(FILE * fp, DATA32 * data, int count) +{ + int total; + + total = count; + if (count > 0) + { + xcf_read_int8(fp, (DATA8 *) data, count * 4); + + while (count--) + { + *data = (DATA32) ntohl(*data); + data++; + } + } + + return total * 4; +} + +static int +xcf_read_string(FILE * fp, char **data, int count) +{ + DATA32 tmp; + int total; + int i; + + total = 0; + for (i = 0; i < count; i++) + { + total += xcf_read_int32(fp, &tmp, 1); + if (tmp > 0) + { + data[i] = malloc(sizeof(DATA8) * tmp); + total += xcf_read_int8(fp, (DATA8 *) data[i], tmp); + } + else + { + data[i] = NULL; + } + } + + return total; +} + +static int +xcf_load_prop(PropType * prop_type, DATA32 * prop_size) +{ + image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_type, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) prop_size, 1); + return 1; +} + +static int +xcf_load_image_props(void) +{ + PropType prop_type; + DATA32 prop_size; + DATA8 compression; + + while (1) + { + if (!xcf_load_prop(&prop_type, &prop_size)) + return 0; switch (prop_type) { case PROP_END: - { - D("Finished reading layer properties.\n"); - return 1; - } + D("Finished reading image properties.\n"); + return 1; + + case PROP_COLORMAP: + if (image->file_version == 0) + { + unsigned int i; + + fprintf(stderr, + "XCF warning: version 0 of XCF file format\n" + "did not save indexed colormaps correctly.\n" + "Substituting grayscale map.\n"); + image->cp += xcf_read_int32(image->fp, &image->num_cols, 1); + image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3); + xcf_seek_pos(image->cp + image->num_cols); + for (i = 0; i < image->num_cols; i++) + { + image->cmap[i * 3 + 0] = i; + image->cmap[i * 3 + 1] = i; + image->cmap[i * 3 + 2] = i; + } + } + else + { + D("Loading colormap.\n"); + image->cp += xcf_read_int32(image->fp, &image->num_cols, 1); + image->cmap = malloc(sizeof(DATA8) * image->num_cols * 3); + image->cp += + xcf_read_int8(image->fp, (DATA8 *) image->cmap, + image->num_cols * 3); + } + break; + + case PROP_COMPRESSION: + image->cp += xcf_read_int8(image->fp, &compression, 1); + + if ((compression != COMPRESS_NONE) && + (compression != COMPRESS_RLE) && + (compression != COMPRESS_ZLIB) && + (compression != COMPRESS_FRACTAL)) + { + fprintf(stderr, "unknown xcf compression type: %d\n", + (int)compression); + return 0; + } + + D("Image compression type: %i\n", compression); + + image->compression = compression; + break; + + /* I threw out all of the following: --cK */ + case PROP_TATTOO: + case PROP_PARASITES: + case PROP_UNIT: + case PROP_PATHS: + case PROP_USER_UNIT: + case PROP_GUIDES: + case PROP_RESOLUTION: + default: + D("Skipping unexpected/unknown image property: %d\n", prop_type); + + while (prop_size > 0) + { + DATA8 buf[16]; + int amount; + + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8(image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); + } + break; + } + } + + return 0; +} + +static int +xcf_load_layer_props(Layer * layer) +{ + PropType prop_type; + DATA32 prop_size; + + while (1) + { + if (!xcf_load_prop(&prop_type, &prop_size)) + return 0; + + switch (prop_type) + { + case PROP_END: + D("Finished reading layer properties.\n"); + return 1; case PROP_FLOATING_SELECTION: D("Loading floating selection.\n"); image->floating_sel = layer; @@ -649,20 +829,18 @@ xcf_load_layer_props(Layer * layer) case PROP_SHOW_MASK: case PROP_PARASITES: default: - { - DATA8 buf[16]; - int amount; - - D("Skipping unexpected/unknown/unneeded channel property: %d\n", - prop_type); - - while (prop_size > 0) - { - amount = (16 < prop_size ? 16 : prop_size); - image->cp += xcf_read_int8(image->fp, buf, amount); - prop_size -= (16 < amount ? 16 : amount); - } - } + D("Skipping unexpected/unknown/unneeded channel property: %d\n", + prop_type); + + while (prop_size > 0) + { + DATA8 buf[16]; + int amount; + + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8(image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); + } break; } } @@ -670,87 +848,6 @@ xcf_load_layer_props(Layer * layer) return 0; } -static Layer * -xcf_load_layer(void) -{ - Layer *layer; - Layer *layer_mask; - DATA32 hierarchy_offset; - DATA32 layer_mask_offset; - int width; - int height; - int type; - char *name; - - D("Loading one layer ...\n"); - - /* read in the layer width, height and type */ - image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & type, 1); - image->cp += xcf_read_string(image->fp, &name, 1); - - /* ugly, I know */ - FREE(name); - - /* create a new layer */ - layer = new_layer(width, height, type, 255, NORMAL_MODE); - if (!layer) - return NULL; - - /* read in the layer properties */ - if (!xcf_load_layer_props(layer)) - goto error; - - D("Loading opacity: %i \n", layer->opacity); - - if (!layer->visible) - return layer; - - /* read the hierarchy and layer mask offsets */ - image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1); - image->cp += xcf_read_int32(image->fp, &layer_mask_offset, 1); - - /* read in the hierarchy */ - xcf_seek_pos(hierarchy_offset); - if (!xcf_load_hierarchy - (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) - goto error; - - /* read in the layer mask */ - if (layer_mask_offset != 0) - { - D("Loading layer mask.\n"); - xcf_seek_pos(layer_mask_offset); - - layer_mask = xcf_load_channel(); - if (!layer_mask) - goto error; - - /* set the offsets of the layer_mask */ - layer_mask->offset_x = layer->offset_x; - layer_mask->offset_y = layer->offset_y; - layer->mask = layer_mask; - } - - read_tiles_into_data(layer->tiles, layer->num_cols, - layer->width, layer->height, - layer->bpp, &(layer->data), 1); - free_tiles(layer->tiles, layer->num_rows * layer->num_cols); - layer->tiles = NULL; - - set_layer_opacity(layer); - - if (layer->mask) - apply_layer_mask(layer); - - return layer; - - error: - free_layer(layer); - return NULL; -} - static void read_tiles_into_data(Tile * tiles, int num_cols, int width, int height, int bpp, DATA8 ** data_p, int use_cmap) @@ -762,258 +859,229 @@ read_tiles_into_data(Tile * tiles, int num_cols, int width, Tile *t; int warned = 0; - if (tiles) - { - if (*data_p) - FREE(*data_p); + if (!tiles) + return; - /* Always allocate the data as 4 bytes per pixel */ - data = (*data_p) = malloc(sizeof(DATA32) * width * height); + if (*data_p) + free(*data_p); - ptr = data; + /* Always allocate the data as 4 bytes per pixel */ + data = (*data_p) = malloc(sizeof(DATA32) * width * height); - for (y = 0; y < height; y++) + ptr = data; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) { - for (x = 0; x < width; x++) - { - tile_x = x / TILE_WIDTH; - tile_y = y / TILE_HEIGHT; - offset_x = x % TILE_WIDTH; - offset_y = y % TILE_HEIGHT; + tile_x = x / TILE_WIDTH; + tile_y = y / TILE_HEIGHT; + offset_x = x % TILE_WIDTH; + offset_y = y % TILE_HEIGHT; - t = &tiles[tile_y * num_cols + tile_x]; - ptr2 = - &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]); + t = &tiles[tile_y * num_cols + tile_x]; + ptr2 = &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]); - switch (bpp) + switch (bpp) + { + case 1: + /* use colormap if the image has one */ + if (image->cmap && use_cmap) + { + R_VAL(ptr) = image->cmap[*(ptr2) * 3]; + G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; + B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; + A_VAL(ptr) = 255; + } + /* else use colors themselves */ + else + { + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2); + B_VAL(ptr) = *(ptr2); + A_VAL(ptr) = 255; + } + break; + case 2: + /* use colormap if the image has one */ + if (image->cmap && use_cmap) + { + R_VAL(ptr) = image->cmap[*(ptr2) * 3]; + G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; + B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; + A_VAL(ptr) = *(ptr2 + 1); + } + /* else use colors themselves */ + else if (warned == 0) + { + warned++; + fprintf(stderr, + "There's nothing to see here. 2 bpp without colormap not implemented yet.\n"); + } + break; + case 3: + if (image->cmap) + { + if (warned == 0) + { + warned++; + fprintf(stderr, + "There's nothing to see here. 3 bpp with colormap not implemented yet.\n"); + } + } + else { - case 1: - { - /* use colormap if the image has one */ - if (image->cmap && use_cmap) - { - R_VAL(ptr) = image->cmap[*(ptr2) * 3]; - G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; - B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; - A_VAL(ptr) = 255; - } - /* else use colors themselves */ - else - { - R_VAL(ptr) = *(ptr2); - G_VAL(ptr) = *(ptr2); - B_VAL(ptr) = *(ptr2); - A_VAL(ptr) = 255; - } - break; - } - case 2: - { - /* use colormap if the image has one */ - if (image->cmap && use_cmap) - { - R_VAL(ptr) = image->cmap[*(ptr2) * 3]; - G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; - B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; - A_VAL(ptr) = *(ptr2 + 1); - } - /* else use colors themselves */ - else if (warned == 0) - { - warned++; - fprintf(stderr, - "There's nothing to see here. 2 bpp without colormap not implemented yet.\n"); - } - break; - } - case 3: - { - if (image->cmap) - { - if (warned == 0) - { - warned++; - fprintf(stderr, - "There's nothing to see here. 3 bpp with colormap not implemented yet.\n"); - } - } - else - { - R_VAL(ptr) = *(ptr2); - G_VAL(ptr) = *(ptr2 + 1); - B_VAL(ptr) = *(ptr2 + 2); - A_VAL(ptr) = 255; - } - break; - } - default: - { - R_VAL(ptr) = *(ptr2); - G_VAL(ptr) = *(ptr2 + 1); - B_VAL(ptr) = *(ptr2 + 2); - A_VAL(ptr) = *(ptr2 + 3); - break; - } + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2 + 1); + B_VAL(ptr) = *(ptr2 + 2); + A_VAL(ptr) = 255; } - ptr += 4; + break; + default: + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2 + 1); + B_VAL(ptr) = *(ptr2 + 2); + A_VAL(ptr) = *(ptr2 + 3); + break; } + ptr += 4; } } } -static Layer * -xcf_load_channel(void) +static int +xcf_load_tile(Tile * tile) { - Layer *layer; - DATA32 hierarchy_offset; - int width; - int height; - char *name; - - D("Loading channel ...\n"); - - /* read in the layer width, height and name */ - image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); - image->cp += xcf_read_string(image->fp, &name, 1); - - /* Yeah, still ugly :) */ - FREE(name); - - /* create a new channel */ - layer = new_layer(width, height, GRAY, 255, NORMAL_MODE); - if (!layer) - return NULL; - - /* read in the channel properties */ - if (!xcf_load_channel_props(layer)) - goto error; - - /* read the hierarchy and layer mask offsets */ - image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1); + image->cp += + xcf_read_int8(image->fp, tile->data, + tile->ewidth * tile->eheight * tile->bpp); + return 1; +} - /* read in the hierarchy */ - xcf_seek_pos(hierarchy_offset); - if (!xcf_load_hierarchy - (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) - goto error; +static int +xcf_load_tile_rle(Tile * tile, int data_length) +{ + DATA8 *data; + DATA8 val; + int size; + int count; + int length; + int bpp; + int i, j; + int nmemb_read_successfully; + DATA8 *xcfdata, *xcfodata, *xcfdatalimit; - read_tiles_into_data(layer->tiles, layer->num_cols, layer->width, - layer->height, layer->bpp, &(layer->data), 0); - free_tiles(layer->tiles, layer->num_rows * layer->num_cols); - layer->tiles = NULL; + data = tile->data; + bpp = tile->bpp; - D("Channel loaded successfully.\n"); + /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", tile->ewidth, tile->eheight, tile->bpp, data_length); */ - return layer; + xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length); - error: - free_layer(layer); - return NULL; -} + /* we have to use fread instead of xcf_read_* because we may be + * reading past the end of the file here */ + nmemb_read_successfully = fread(xcfdata, 1, data_length, image->fp); + image->cp += nmemb_read_successfully; -static char -xcf_load_channel_props(Layer * layer) -{ - PropType prop_type; - DATA32 prop_size; + xcfdatalimit = &xcfodata[nmemb_read_successfully - 1]; - while (1) + for (i = 0; i < bpp; i++) { - if (!xcf_load_prop(&prop_type, &prop_size)) - return 0; + data = (tile->data) + i; + size = tile->ewidth * tile->eheight; + count = 0; - switch (prop_type) + while (size > 0) { - case PROP_END: - { - D("Finished loading channel props.\n"); - return 1; - } - case PROP_OPACITY: - image->cp += - xcf_read_int32(image->fp, (DATA32 *) & layer->opacity, 1); - break; - case PROP_VISIBLE: - image->cp += - xcf_read_int32(image->fp, (DATA32 *) & layer->visible, 1); - break; - case PROP_ACTIVE_CHANNEL: - case PROP_SHOW_MASKED: - case PROP_SELECTION: - case PROP_COLOR: - case PROP_TATTOO: - case PROP_PARASITES: - default: - { - DATA8 buf[16]; - int amount; - - D("Skipping unexpected/unknown/unneeded channel property: %d\n", - prop_type); - - while (prop_size > 0) - { - amount = (16 < prop_size ? 16 : prop_size); - image->cp += xcf_read_int8(image->fp, buf, amount); - prop_size -= (16 < amount ? 16 : amount); - } - } - break; - } - } + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } - return 0; -} + val = *xcfdata++; -static char -xcf_load_hierarchy(Tile ** tiles, int *num_rows, int *num_cols, int *bpp) -{ - DATA32 saved_pos; - DATA32 offset; - DATA32 junk; - int width; - int height; + length = val; + if (length >= 128) + { + length = 255 - (length - 1); + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } - image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); - image->cp += xcf_read_int32(image->fp, (DATA32 *) bpp, 1); + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } - image->cp += xcf_read_int32(image->fp, &offset, 1); /* top level */ + count += length; + size -= length; - D("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp); + if (size < 0) + { + goto bogus_rle; + } - /* discard offsets for layers below first, if any. - */ - do - { - image->cp += xcf_read_int32(image->fp, &junk, 1); - } - while (junk != 0); + if (&xcfdata[length - 1] > xcfdatalimit) + { + goto bogus_rle; + } - /* save the current position as it is where the - * next level offset is stored. - */ - saved_pos = image->cp; + while (length-- > 0) + { + *data = *xcfdata++; + data += bpp; + } + } + else + { + length += 1; + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } - /* seek to the level offset */ - xcf_seek_pos(offset); + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } - /* read in the level */ - if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols)) - return 0; + count += length; + size -= length; - /* restore the saved position so we'll be ready to - * read the next offset. - */ - xcf_seek_pos(saved_pos); + if (size < 0) + { + goto bogus_rle; + } - D("Loaded hierarchy successfully.\n"); + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } + val = *xcfdata++; + + for (j = 0; j < length; j++) + { + *data = val; + data += bpp; + } + } + } + } + free(xcfodata); return 1; + + bogus_rle: + fprintf(stderr, + "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) \n"); + free(xcfodata); + return 0; } -static char +static int xcf_load_level(Tile ** tiles_p, int hierarchy_width, int hierarchy_height, int bpp, int *num_rows, int *num_cols) { @@ -1120,464 +1188,323 @@ xcf_load_level(Tile ** tiles_p, int hierarchy_width, int hierarchy_height, return 1; } -static char -xcf_load_tile(Tile * tile) -{ - image->cp += - xcf_read_int8(image->fp, tile->data, - tile->ewidth * tile->eheight * tile->bpp); - return 1; -} - -static char -xcf_load_tile_rle(Tile * tile, int data_length) +static int +xcf_load_hierarchy(Tile ** tiles, int *num_rows, int *num_cols, int *bpp) { - DATA8 *data; - DATA8 val; - int size; - int count; - int length; - int bpp; - int i, j; - int nmemb_read_successfully; - DATA8 *xcfdata, *xcfodata, *xcfdatalimit; - - data = tile->data; - bpp = tile->bpp; - - /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", tile->ewidth, tile->eheight, tile->bpp, data_length); */ - - xcfdata = xcfodata = malloc(sizeof(DATA8) * data_length); - - /* we have to use fread instead of xcf_read_* because we may be - * reading past the end of the file here */ - nmemb_read_successfully = fread((char *)xcfdata, sizeof(char), - data_length, image->fp); - image->cp += nmemb_read_successfully; - - xcfdatalimit = &xcfodata[nmemb_read_successfully - 1]; + DATA32 saved_pos; + DATA32 offset; + DATA32 junk; + int width; + int height; - for (i = 0; i < bpp; i++) - { - data = (tile->data) + i; - size = tile->ewidth * tile->eheight; - count = 0; + image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) bpp, 1); - while (size > 0) - { - if (xcfdata > xcfdatalimit) - { - goto bogus_rle; - } + image->cp += xcf_read_int32(image->fp, &offset, 1); /* top level */ - val = *xcfdata++; + D("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp); - length = val; - if (length >= 128) - { - length = 255 - (length - 1); - if (length == 128) - { - if (xcfdata >= xcfdatalimit) - { - goto bogus_rle; - } + /* discard offsets for layers below first, if any. + */ + do + { + image->cp += xcf_read_int32(image->fp, &junk, 1); + } + while (junk != 0); - length = (*xcfdata << 8) + xcfdata[1]; - xcfdata += 2; - } + /* save the current position as it is where the + * next level offset is stored. + */ + saved_pos = image->cp; - count += length; - size -= length; + /* seek to the level offset */ + xcf_seek_pos(offset); - if (size < 0) - { - goto bogus_rle; - } + /* read in the level */ + if (!xcf_load_level(tiles, width, height, *bpp, num_rows, num_cols)) + return 0; - if (&xcfdata[length - 1] > xcfdatalimit) - { - goto bogus_rle; - } + /* restore the saved position so we'll be ready to + * read the next offset. + */ + xcf_seek_pos(saved_pos); - while (length-- > 0) - { - *data = *xcfdata++; - data += bpp; - } - } - else - { - length += 1; - if (length == 128) - { - if (xcfdata >= xcfdatalimit) - { - goto bogus_rle; - } + D("Loaded hierarchy successfully.\n"); - length = (*xcfdata << 8) + xcfdata[1]; - xcfdata += 2; - } + return 1; +} - count += length; - size -= length; +static int +xcf_load_channel_props(Layer * layer) +{ + PropType prop_type; + DATA32 prop_size; - if (size < 0) - { - goto bogus_rle; - } + while (1) + { + if (!xcf_load_prop(&prop_type, &prop_size)) + return 0; - if (xcfdata > xcfdatalimit) - { - goto bogus_rle; - } + switch (prop_type) + { + case PROP_END: + D("Finished loading channel props.\n"); + return 1; + case PROP_OPACITY: + image->cp += + xcf_read_int32(image->fp, (DATA32 *) & layer->opacity, 1); + break; + case PROP_VISIBLE: + image->cp += + xcf_read_int32(image->fp, (DATA32 *) & layer->visible, 1); + break; + case PROP_ACTIVE_CHANNEL: + case PROP_SHOW_MASKED: + case PROP_SELECTION: + case PROP_COLOR: + case PROP_TATTOO: + case PROP_PARASITES: + default: + D("Skipping unexpected/unknown/unneeded channel property: %d\n", + prop_type); - val = *xcfdata++; + while (prop_size > 0) + { + DATA8 buf[16]; + int amount; - for (j = 0; j < length; j++) - { - *data = val; - data += bpp; - } + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8(image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); } + break; } } - FREE(xcfodata); - return 1; - bogus_rle: - fprintf(stderr, - "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) \n"); - if (xcfodata) - FREE(xcfodata); return 0; } static Layer * -new_layer(int width, int height, GimpImageType type, int opacity, - LayerModeEffects mode) +xcf_load_channel(void) { Layer *layer; + DATA32 hierarchy_offset; + int width; + int height; + char *name; + + D("Loading channel ...\n"); + + /* read in the layer width, height and name */ + image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); + image->cp += xcf_read_string(image->fp, &name, 1); + + /* Yeah, still ugly :) */ + free(name); - layer = malloc(sizeof(Layer)); + /* create a new channel */ + layer = new_layer(width, height, GRAY, 255, NORMAL_MODE); if (!layer) - { - D("Couldn't allocate layer.\n"); - return NULL; - } + return NULL; - bzero(layer, sizeof(Layer)); + /* read in the channel properties */ + if (!xcf_load_channel_props(layer)) + goto error; - layer->width = width; - layer->height = height; - layer->type = type; - layer->opacity = opacity; - layer->mode = mode; + /* read the hierarchy and layer mask offsets */ + image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1); + + /* read in the hierarchy */ + xcf_seek_pos(hierarchy_offset); + if (!xcf_load_hierarchy + (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) + goto error; + read_tiles_into_data(layer->tiles, layer->num_cols, layer->width, + layer->height, layer->bpp, &(layer->data), 0); + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); layer->tiles = NULL; - layer->next = NULL; - layer->mask = NULL; + + D("Channel loaded successfully.\n"); return layer; + + error: + free_layer(layer); + return NULL; } -static void -free_layer(Layer * layer) +static Layer * +xcf_load_layer(void) { - if (layer) - { - if (layer->tiles) - free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + Layer *layer; + Layer *layer_mask; + DATA32 hierarchy_offset; + DATA32 layer_mask_offset; + int width; + int height; + int type; + char *name; + + D("Loading one layer ...\n"); + + /* read in the layer width, height and type */ + image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & type, 1); + image->cp += xcf_read_string(image->fp, &name, 1); - if (layer->mask) - free_layer(layer->mask); + /* ugly, I know */ + free(name); - if (layer->data) - FREE(layer->data); + /* create a new layer */ + layer = new_layer(width, height, type, 255, NORMAL_MODE); + if (!layer) + return NULL; - FREE(layer); - } -} + /* read in the layer properties */ + if (!xcf_load_layer_props(layer)) + goto error; -static Tile * -allocate_tiles(int width, int height, int bpp, int *num_rows, int *num_cols) -{ - Tile *tiles; - int i, j, k, right_tile, bottom_tile; - int tile_width, tile_height; + D("Loading opacity: %i \n", layer->opacity); - (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT; - (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH; + if (!layer->visible) + return layer; - tiles = malloc(sizeof(Tile) * (*num_rows) * (*num_cols)); - if (!tiles) - { - D("Couldn't allocate tiles.\n"); - return NULL; - } + /* read the hierarchy and layer mask offsets */ + image->cp += xcf_read_int32(image->fp, &hierarchy_offset, 1); + image->cp += xcf_read_int32(image->fp, &layer_mask_offset, 1); - right_tile = width - (((*num_cols) - 1) * TILE_WIDTH); - bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT); + /* read in the hierarchy */ + xcf_seek_pos(hierarchy_offset); + if (!xcf_load_hierarchy + (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) + goto error; - for (i = 0, k = 0; i < (*num_rows); i++) + /* read in the layer mask */ + if (layer_mask_offset != 0) { - for (j = 0; j < (*num_cols); j++, k++) - { - tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH); - tile_height = ((i == (*num_rows) - 1) ? bottom_tile : TILE_HEIGHT); - init_tile(&(tiles[k]), tile_width, tile_height, bpp); - } + D("Loading layer mask.\n"); + xcf_seek_pos(layer_mask_offset); + + layer_mask = xcf_load_channel(); + if (!layer_mask) + goto error; + + /* set the offsets of the layer_mask */ + layer_mask->offset_x = layer->offset_x; + layer_mask->offset_y = layer->offset_y; + layer->mask = layer_mask; } - D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows)); + read_tiles_into_data(layer->tiles, layer->num_cols, + layer->width, layer->height, + layer->bpp, &(layer->data), 1); + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + layer->tiles = NULL; - return tiles; -} + set_layer_opacity(layer); -static void -init_tile(Tile * tile, int width, int height, int bpp) -{ - if (tile) - { - tile->bpp = bpp; - tile->ewidth = width; - tile->eheight = height; - tile->data = malloc(sizeof(DATA8) * width * height * bpp); - if (!tile->data) - { - D("Couldn't allocate tile.\n"); - } - } -} + if (layer->mask) + apply_layer_mask(layer); -static void -free_tiles(Tile * tiles, int num_tiles) -{ - int i; + return layer; - for (i = 0; i < num_tiles; i++) - { - if (tiles[i].data) - FREE(tiles[i].data); - } - FREE(tiles); + error: + free_layer(layer); + return NULL; } static void -add_layer_to_image(Layer * layer) +xcf_load_image(void) { - if (layer) - { - if (image->last_layer) - { - image->last_layer->next = layer; - layer->prev = image->last_layer; - } - else - { - image->layers = layer; - layer->prev = NULL; - } - layer->next = NULL; - image->last_layer = layer; - } -} + Layer *layer; + DATA32 saved_pos; + DATA32 offset; + int width; + int height; + int image_type; + int num_successful_elements = 0; -static void -set_layer_opacity(Layer * layer) -{ - int i; - DATA8 *ptr; + /* read in the image width, height and type */ + image->cp += xcf_read_int32(image->fp, (DATA32 *) & width, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & height, 1); + image->cp += xcf_read_int32(image->fp, (DATA32 *) & image_type, 1); - if (layer) - { - if (layer->opacity != 255) - { - for (i = 0, ptr = layer->data; i < layer->width * layer->height; - i++, ptr += 4) - { - *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8; - } - } - } -} + image->width = width; + image->height = height; + image->base_type = image_type; -static void -apply_layer_mask(Layer * layer) -{ - DATA8 *ptr1; - DATA8 *ptr2; - int i, tmp; + D("Loading %ix%i image.\n", width, height); - D("Applying layer mask.\n"); + /* read the image properties */ + if (!xcf_load_image_props()) + goto hard_error; - if (layer) + while (1) { - if (layer->mask) - { - ptr1 = layer->data; - ptr2 = layer->mask->data; + /* read in the offset of the next layer */ + image->cp += xcf_read_int32(image->fp, &offset, 1); - for (i = 0; i < layer->width * layer->height; i++) - { - tmp = (*(ptr1 + 3) * *(ptr2)) / 256; - if (tmp > 255) - tmp = 255; + /* if the offset is 0 then we are at the end + * of the layer list. + */ + if (offset == 0) + break; - *(ptr1 + 3) = (DATA8) tmp; - ptr1 += 4; - ptr2 += 4; - } - } - } -} + /* save the current position as it is where the + * next layer offset is stored. + */ + saved_pos = image->cp; -static void -flatten_image(void) -{ - Layer *l = image->last_layer; - Layer *lp; - int layer_index; + /* seek to the layer offset */ + xcf_seek_pos(offset); - image->data = calloc(image->width * image->height, sizeof(DATA32)); - layer_index = 0; + /* read in the layer */ + layer = xcf_load_layer(); + if (!layer) + goto error; - while (l) - { - /* Ok, paste each layer on top of the image, using the mode's merging type. - * We're moving upward through the layer stack. - * --cK. + num_successful_elements++; + + /* add the layer to the image if it's visible */ + if (layer->visible) + add_layer_to_image(layer); + else + free_layer(layer); + + /* restore the saved position so we'll be ready to + * read the next offset. */ - if (image->single_layer_index < 0 - || layer_index == image->single_layer_index) - { - switch (l->mode) - { - case MULTIPLY_MODE: - D("MULTIPLY\n"); - combine_pixels_mult(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case DIVIDE_MODE: - D("DIVIDE\n"); - combine_pixels_div(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case SCREEN_MODE: - D("SCREEN\n"); - combine_pixels_screen(l->data, l->width, l->height, - image->data, image->width, - image->height, l->offset_x, - l->offset_y); - break; - case OVERLAY_MODE: - D("OVERLAY\n"); - combine_pixels_overlay(l->data, l->width, l->height, - image->data, image->width, - image->height, l->offset_x, - l->offset_y); - break; - case DIFFERENCE_MODE: - D("DIFF\n"); - combine_pixels_diff(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case ADDITION_MODE: - D("ADD\n"); - combine_pixels_add(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case SUBTRACT_MODE: - D("SUB\n"); - combine_pixels_sub(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case DARKEN_ONLY_MODE: - D("DARKEN\n"); - combine_pixels_darken(l->data, l->width, l->height, - image->data, image->width, - image->height, l->offset_x, - l->offset_y); - break; - case LIGHTEN_ONLY_MODE: - D("LIGHTEN\n"); - combine_pixels_lighten(l->data, l->width, l->height, - image->data, image->width, - image->height, l->offset_x, - l->offset_y); - break; + xcf_seek_pos(saved_pos); - case HUE_MODE: - D("HUE\n"); - combine_pixels_hue(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case SATURATION_MODE: - D("SATURATION\n"); - combine_pixels_sat(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case VALUE_MODE: - D("VALUE\n"); - combine_pixels_val(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case COLOR_MODE: - D("COLOR\n"); - combine_pixels_col(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; - case DISSOLVE_MODE: - D("DISSOLVE\n"); - combine_pixels_diss(l->data, l->width, l->height, - image->data, image->width, image->height, - l->offset_x, l->offset_y); - break; + } - /* None of the following is actually valid for layer blending, fall through: */ - case BEHIND_MODE: - case REPLACE_MODE: - case ERASE_MODE: - case ANTI_ERASE_MODE: - D("EEEEEK -- this mode shouldn't be here\n"); + /* If we were a Gimp we would now load the user-defined channels here ... */ - case NORMAL_MODE: - D("NORMAL\n"); - combine_pixels_normal(l->data, l->width, l->height, - image->data, image->width, - image->height, l->offset_x, - l->offset_y); - break; + /* Flat-o-rama now :) */ + flatten_image(); - default: - D("Unknown layer mode: %i. Skipping.\n", l->mode); - } - } + return; - lp = l->prev; - /* free the layer now, since it's not needed anymore */ - free_layer(l); + error: + if (num_successful_elements == 0) + goto hard_error; - l = lp; - layer_index++; - } + fprintf(stderr, + "XCF: This file is corrupt! I have loaded as much of it as I can, but it is incomplete.\n"); - /* We've used up all the layers now, so set them to NULL in the image: */ - image->layers = NULL; - image->last_layer = NULL; + return; + + hard_error: + fprintf(stderr, + "XCF: This file is corrupt! I could not even salvage any partial image data from it.\n"); + return; } -static char +static int xcf_file_init(char *filename) { char success = 1; @@ -1645,7 +1572,10 @@ xcf_cleanup(void) } if (image->cmap) - FREE(image->cmap); + { + free(image->cmap); + image->cmap = NULL; + } } static void --