diff --git a/loaders/Makefile.am b/loaders/Makefile.am index 34265a9..a175617 100644 --- a/loaders/Makefile.am +++ b/loaders/Makefile.am @@ -12,7 +12,7 @@ INCLUDES = -I/usr/local/BerkeleyDB/include -I/usr/X11R6/include -I$(top_src -I$(top_srcdir)/loaders pkgdir = $(libdir)/loaders/image -pkg_LTLIBRARIES = png.la jpeg.la gif.la pnm.la argb.la tiff.la bmp.la xpm.la tga.la db.la xcf.la +pkg_LTLIBRARIES = png.la jpeg.la gif.la pnm.la argb.la tiff.la bmp.la xpm.la tga.la db.la #xcf.la png_la_SOURCES = loader_png.c png_la_LDFLAGS = -no-undefined -module -avoid-version @@ -54,6 +54,6 @@ db_la_SOURCES = loader_db.c db_la_LDFLAGS = -no-undefined -module -avoid-version db_la_LIBADD = -ldb -lz -xcf_la_SOURCES = loader_xcf.c loader_xcf_pixelfuncs.c -xcf_la_LDFLAGS = -no-undefined -module -avoid-version -xcf_la_LIBADD = +#xcf_la_SOURCES = loader_xcf.c loader_xcf_pixelfuncs.c +#xcf_la_LDFLAGS = -no-undefined -module -avoid-version +#xcf_la_LIBADD = diff --git a/loaders/loader_xcf.c b/loaders/loader_xcf.c deleted file mode 100644 index 6c9acd7..0000000 --- a/loaders/loader_xcf.c +++ /dev/null @@ -1,1704 +0,0 @@ -/* - - ----------------------------------[ XCF Loader ]---------------------------------- - - There's a quick overview of the XCF file structure in Gimp's source tree, in - docs/xcf.doc. However it's brief, so here's a more verbose overview. All image - characteristics are defined in "properties". In the data stream properties are - defined through a 4 bit index number (see enum below), followed by a 4 byte length. - The property data directly follows this information. A list of properties ends - when PROP_END is encountered. There is a properties block at the beginning of - the file, as well as at the beginning of each layer and channel. Layers and - channels are read at offsets in the file, the list of layers (resp. channels) is - exhausted when the next offset read in is zero. - - The actual image data is stored in tiles, which are by default 64x64 in size, - likely with smaller ones on the right and bottom edges. - - The position of the tiles on the image is left->right, row by row. The actual - DATA8* data is contained in a "level" which is contained in a "hierarchy". I've - not really understood the purpose of the hierarchy, as it seems to always contain - only one level anyway. - - Layer masks are stored as channels (basically grayscale layers with a single - color definition. For the purpose of this loader I replaced the concept of a - channel with a layer, since it doesn't really matter. - - Ok, hope this helps with understanding docs/xcf.c. --cK. - -*/ - - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "image.h" -#include "Imlib2.h" -#include "colormod.h" -#include "blend.h" - -/* #define XCF_DBG */ - -#ifdef XCF_DBG -#define D(s) \ - { \ - printf s; \ - } -#else -#define D(s) -#endif - -#define TILE_WIDTH 64 -#define TILE_HEIGHT 64 - -/* --------------------------------------------------------------------------- typedefs ------------ */ - -typedef struct _Layer Layer; -typedef struct _Tile Tile; - -/* ------------------------------------------------------------------------------ enums ------------ */ - - -/* These are all the properties that a layer or channel can have. - Only some of them are actually used. */ -typedef enum -{ - PROP_END = 0, - PROP_COLORMAP = 1, - PROP_ACTIVE_LAYER = 2, - PROP_ACTIVE_CHANNEL = 3, - PROP_SELECTION = 4, - PROP_FLOATING_SELECTION = 5, - PROP_OPACITY = 6, - PROP_MODE = 7, - PROP_VISIBLE = 8, - PROP_LINKED = 9, - PROP_PRESERVE_TRANSPARENCY = 10, - PROP_APPLY_MASK = 11, - PROP_EDIT_MASK = 12, - PROP_SHOW_MASK = 13, - PROP_SHOW_MASKED = 14, - PROP_OFFSETS = 15, - PROP_COLOR = 16, - PROP_COMPRESSION = 17, - PROP_GUIDES = 18, - PROP_RESOLUTION = 19, - PROP_TATTOO = 20, - PROP_PARASITES = 21, - PROP_UNIT = 22, - PROP_PATHS = 23, - PROP_USER_UNIT = 24 -} -PropType; - -/* The tiles can be stored in an encrypted fashion, defined as follows: */ -typedef enum -{ - COMPRESS_NONE = 0, - COMPRESS_RLE = 1, - COMPRESS_ZLIB = 2, - COMPRESS_FRACTAL = 3 /* Unused. */ -} CompressionType; - -/* Layer modes (*SIGH*) */ -typedef enum -{ - NORMAL_MODE, - DISSOLVE_MODE, - BEHIND_MODE, - MULTIPLY_MODE, - SCREEN_MODE, - OVERLAY_MODE, - DIFFERENCE_MODE, - ADDITION_MODE, - SUBTRACT_MODE, - DARKEN_ONLY_MODE, - LIGHTEN_ONLY_MODE, - HUE_MODE, - SATURATION_MODE, - COLOR_MODE, - VALUE_MODE, - DIVIDE_MODE, - ERASE_MODE, /*< skip >*/ - REPLACE_MODE, /*< skip >*/ - ANTI_ERASE_MODE /*< skip >*/ -} -LayerModeEffects; - -/* Base image types */ -typedef enum -{ - RGB, - GRAY, - INDEXED -} GimpImageBaseType; - -/* Image types */ -typedef enum -{ - RGB_GIMAGE, - RGBA_GIMAGE, - GRAY_GIMAGE, - GRAYA_GIMAGE, - INDEXED_GIMAGE, - INDEXEDA_GIMAGE -} GimpImageType; - -/* ---------------------------------------------------------------------------- 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 - from the Gimp drawable superclass. This one also serves as a - Channel, e.g. for use as a layer mask. - --cK. -*/ -struct _Layer -{ - char visible; /* controls visibility */ - int width, height; /* size of drawable */ - int bpp; /* depth */ - int offset_x, offset_y; /* offset of layer in image */ - - int ID; /* provides a unique ID */ - GimpImageType type; /* type of drawable */ - char has_alpha; /* drawable has alpha */ - - int preserve_trans; /* preserve transparency */ - - Layer *mask; /* possible layer mask */ - - int opacity; /* layer opacity */ - LayerModeEffects mode; /* layer combination mode */ - - - /* XCF stores the actual image data as tiles. A Layer is covered with - tiles, the tiles on the right and bottom will (usually) be a bit - smaller. num_rows and num_cols gives the number of tile rows and - columns. - */ - - Tile* tiles; /* tiles for drawable data */ - int num_rows; - int num_cols; - - /* After the tiles are read in, they're serialized int an array - of DATA8's, that will always contain 4 bpp data. Not optimal, - I know, but makes life easier - */ - - DATA8* data; - - /* Layers are stored as a linked list. */ - struct _Layer* next; - struct _Layer* prev; -}; - - -/* The tile structure: -*/ -struct _Tile -{ - unsigned char bpp; /* the bytes per pixel (1, 2, 3 or 4) */ - unsigned short ewidth; /* the effective width of the tile */ - unsigned short eheight; /* the effective height of the tile */ - - /* a tile's effective width and height may be smaller - * (but not larger) than TILE_WIDTH and TILE_HEIGHT. - * This is to handle edge tiles of a drawable. - */ - - DATA8 *data; -}; - - -/* This struct simply contains everything that didn't fit elsewhere, - based on GimpImage :) -*/ -struct _GimpImage -{ - FILE* fp; - char* filename; - int cp; /* file stream pointer */ - int compression; /* file compression mode */ - int file_version; - - int width, height; /* width and height attributes */ - GimpImageBaseType base_type; /* base gimp_image type */ - - DATA32 floating_sel_offset; - - DATA8* cmap; /* colormap--for indexed */ - int num_cols; /* number of colors in map */ - - /* If a layer number was passed to the loader, it goes here: */ - int single_layer_index; - - /* Tadaa -- the final image data. Layers get pasted - onto this one, bottom-up. - */ - DATA8* data; - - Layer* layers; - Layer* last_layer; - Layer* floating_sel; -} -_image; - -/* ------------------------------------------------------------------------- prototypes ------------ */ - -char load(ImlibImage *im, ImlibProgressFunction progress,char progress_granularity, char immediate_load); -char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity); -void formats(ImlibLoader *l); - -/* 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_rows, int num_cols, int width, int height, int bpp, DATA8** data); -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); - -/* Stuff for pixel merging: -*/ -extern void blend_pixels (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); -/* ... */ - - -/* ---------------------------------------------------------------------------- globals ------------ */ - -/* This makes using the Gimp sources easier */ -struct _GimpImage * image = &_image; - -/* ------------------------------------------------------------------------------- code ------------ */ - -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_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_float (FILE *fp, - float *data, - int count) -{ - return (xcf_read_int32(fp, (DATA32 *)((void *)data), count)); -} - -static int -xcf_read_int8 (FILE *fp, - DATA8 *data, - int count) -{ - int total; - int bytes; - - total = count; - while (count > 0) - { - bytes = fread ((char*) data, sizeof (char), count, fp); - if (bytes <= 0) /* something bad happened */ - break; - count -= bytes; - data += bytes; - } - - return total; -} - -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 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; -} - - -static char -xcf_load_image_props (void) -{ - 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 image properties.\n")); - return 1; - } - case PROP_COLORMAP: - { - if (image->file_version == 0) - { - 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 = (DATA8*) malloc (sizeof(DATA8) * image->num_cols * 3); - xcf_seek_pos (image->cp + image->num_cols); - for (i = 0; inum_cols; i++) - { - image->cmap[i*3+0] = i; - image->cmap[i*3+1] = i; - image->cmap[i*3+2] = i; - } - } - else - { - 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: - { - char compression; - - image->cp += xcf_read_int8 (image->fp, (char*) &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: - { - 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; - } - } - - return 0; -} - - -static void -xcf_load_image (void) -{ - 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)); - - /* read the image properties */ - if (!xcf_load_image_props ()) - goto hard_error; - - while (1) - { - /* read in the offset of the next layer */ - image->cp += xcf_read_int32 (image->fp, &offset, 1); - - /* if the offset is 0 then we are at the end - * of the layer list. - */ - if (offset == 0) - break; - - /* save the current position as it is where the - * next layer offset is stored. - */ - saved_pos = image->cp; - - /* seek to the layer offset */ - xcf_seek_pos (offset); - - /* read in the layer */ - layer = xcf_load_layer(); - if (!layer) - goto error; - - num_successful_elements++; - - /* add the layer to the image if its not the floating selection */ - if (layer != image->floating_sel && 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. - */ - xcf_seek_pos (saved_pos); - - } - - /* If we were a Gimp we would now load the user-defined channels here ... */ - - /* Flat-o-rama now :) */ - flatten_image(); - - return; - - error: - if (num_successful_elements == 0) - goto hard_error; - - fprintf(stderr, "XCF: This file is corrupt! I have loaded as much\nof it as I can, but it is incomplete.\n"); - - return; - - hard_error: - fprintf(stderr, "XCF: This file is corrupt! I could not even\nsalvage any partial image data from it.\n"); - return; -} - - -static char -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: - image->floating_sel = layer; - image->cp += xcf_read_int32 (image->fp, (DATA32*) &image->floating_sel_offset, 1); - break; - 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_PRESERVE_TRANSPARENCY: - image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->preserve_trans, 1); - break; - case PROP_OFFSETS: - image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->offset_x, 1); - image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->offset_y, 1); - break; - case PROP_MODE: - image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->mode, 1); - break; - - /* I threw out all of the following: --cK */ - case PROP_LINKED: - case PROP_ACTIVE_LAYER: - case PROP_TATTOO: - case PROP_APPLY_MASK: - case PROP_EDIT_MASK: - 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); - } - } - break; - } - } - - 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_rows, layer->num_cols, - layer->width, layer->height, layer->bpp, &(layer->data)); - 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_rows, int num_cols, - int width, int height, int bpp, DATA8** data_p) -{ - int b, tile_x, tile_y, k, x, y, offset_x, offset_y; - DATA8* data; - DATA8* ptr; - DATA8* ptr2; - Tile* t; - - if (tiles) - { - if (*data_p) - free(*data_p); - - /* Always allocate the data as 4 bytes per pixel */ - data = (*data_p) = (DATA8*) malloc (sizeof(DATA32) * width * height); - - ptr = data; - - for (y = 0; y < height; y++) - { - 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; - - t = &tiles[tile_y * num_cols + tile_x]; - ptr2 = &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]); - - switch (bpp) - { - case 1: - { - /* use colormap if the image has one */ - if (image->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) - { - 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 - { - fprintf (stderr, "There's nothing to see here. 2 bpp without colormap not implemented yet.\n"); - } - break; - } - case 3: - { - if (image->cmap) - { - 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; - } - } - ptr += 4; - } - } - } -} - - -static Layer* -xcf_load_channel (void) -{ - Layer *layer; - DATA32 hierarchy_offset; - int width; - int height; - int add_floating_sel; - 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); - - /* 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_rows, layer->num_cols, - layer->width, layer->height, layer->bpp, &(layer->data)); - free_tiles(layer->tiles, layer->num_rows * layer->num_cols); - layer->tiles = NULL; - - D(("Channel loaded successfully.\n")); - - return layer; - -error: - free_layer(layer); - return NULL; -} - - -static char -xcf_load_channel_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 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; - } - } - - return 0; -} - - -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; - - 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); - - image->cp += xcf_read_int32 (image->fp, &offset, 1); /* top level */ - - D(("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp)); - - /* discard offsets for layers below first, if any. - */ - do - { - image->cp += xcf_read_int32 (image->fp, &junk, 1); - } - while (junk != 0); - - /* save the current position as it is where the - * next level offset is stored. - */ - saved_pos = image->cp; - - /* seek to the level offset */ - xcf_seek_pos (offset); - - /* read in the level */ - if (!xcf_load_level (tiles, width, height, *bpp, num_rows, num_cols)) - return 0; - - /* restore the saved position so we'll be ready to - * read the next offset. - */ - xcf_seek_pos (saved_pos); - - D(("Loaded hierarchy successfully.\n")); - - return 1; -} - - -static char -xcf_load_level (Tile** tiles_p, int hierarchy_width, int hierarchy_height, int bpp, int* num_rows, int* num_cols) -{ - DATA32 saved_pos; - DATA32 offset, offset2; - int ntiles; - int width; - int height; - int i; - int fail; - - Tile* tiles; - Tile* current_tile; - - image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); - image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); - - if ((width != hierarchy_width) || - (height != hierarchy_height)) - return 0; - - D(("Loading level of size %ix%i.\n", width, height)); - (*tiles_p) = allocate_tiles(width, height, bpp, num_rows, num_cols); - tiles = (*tiles_p); - - image->cp += xcf_read_int32 (image->fp, &offset, 1); - if (offset == 0) - return 1; - - ntiles = (*num_rows) * (*num_cols); - for (i = 0; i < ntiles; i++) - { - current_tile = &(tiles[i]); - fail = 0; - - if (offset == 0) - { - D(("Not enough tiles found in level\n")); - return 0; - } - - /* save the current position as it is where the - * next tile offset is stored. - */ - saved_pos = image->cp; - - /* read in the offset of the next tile so we can calculate the amount - of data needed for this tile*/ - image->cp += xcf_read_int32 (image->fp, &offset2, 1); - - /* if the offset is 0 then we need to read in the maximum possible - allowing for negative compression */ - if (offset2 == 0) - offset2 = offset + TILE_WIDTH*TILE_WIDTH*4*1.5; /* 1.5 is probably more - than we need to allow */ - - /* seek to the tile offset */ - xcf_seek_pos (offset); - - /* read in the current_tile */ - switch (image->compression) - { - case COMPRESS_NONE: - if (!xcf_load_tile (current_tile)) - fail = 1; - break; - case COMPRESS_RLE: - if (!xcf_load_tile_rle (current_tile, offset2 - offset)) - fail = 1; - break; - case COMPRESS_ZLIB: - fprintf (stderr, "xcf: zlib compression unimplemented\n"); - fail = 1; - break; - case COMPRESS_FRACTAL: - fprintf (stderr, "xcf: fractal compression unimplemented\n"); - fail = 1; - break; - } - - if (fail) - { - D(("Couldn't load tiles.\n")); - free_tiles(tiles, (*num_rows) * (*num_cols)); - return 0; - } - - /* restore the saved position so we'll be ready to - * read the next offset. - */ - xcf_seek_pos (saved_pos); - - /* read in the offset of the next tile */ - image->cp += xcf_read_int32 (image->fp, &offset, 1); - } - - if (offset != 0) - { - D(("encountered garbage after reading level: %d\n", offset)); - return 0; - } - - D(("Loaded level successfully.\n")); - - 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) -{ - DATA8 *data; - DATA8 val; - int size; - int count; - int length; - int bpp; - int i, j; - int nmemb_read_successfully; - DATA8 *xcfdata, *xcfodata, *xcfdatalimit, *dump; - - 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]; - - for (i = 0; i < bpp; i++) - { - data = (tile->data) + i; - size = tile->ewidth * tile->eheight; - count = 0; - - while (size > 0) - { - if (xcfdata > xcfdatalimit) - { - goto bogus_rle; - } - - val = *xcfdata++; - - length = val; - if (length >= 128) - { - length = 255 - (length - 1); - if (length == 128) - { - if (xcfdata >= xcfdatalimit) - { - goto bogus_rle; - } - - length = (*xcfdata << 8) + xcfdata[1]; - xcfdata += 2; - } - - count += length; - size -= length; - - if (size < 0) - { - goto bogus_rle; - } - - if (&xcfdata[length-1] > xcfdatalimit) - { - goto bogus_rle; - } - - while (length-- > 0) - { - *data = *xcfdata++; - data += bpp; - } - } - else - { - length += 1; - if (length == 128) - { - if (xcfdata >= xcfdatalimit) - { - goto bogus_rle; - } - - length = (*xcfdata << 8) + xcfdata[1]; - xcfdata += 2; - } - - count += length; - size -= length; - - if (size < 0) - { - goto bogus_rle; - } - - 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"); - if (xcfodata) - free (xcfodata); - return 0; -} - - -static Layer* -new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode) -{ - Layer* layer; - - layer = (Layer*) malloc(sizeof(Layer)); - if (!layer) - { - D(("Couldn't allocate layer.\n")); - return NULL; - } - - bzero(layer, sizeof(Layer)); - - layer->width = width; - layer->height = height; - layer->type = type; - layer->opacity = opacity; - layer->mode = mode; - - layer->tiles = NULL; - layer->next = NULL; - layer->mask = NULL; - - return layer; -} - - -static void -free_layer(Layer* layer) -{ - if (layer) - { - if (layer->tiles) - free_tiles(layer->tiles, layer->num_rows * layer->num_cols); - - if (layer->mask) - free_layer(layer->mask); - - free(layer); - } -} - - -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; - - (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT; - (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH; - - tiles = (Tile*) malloc(sizeof(Tile) * (*num_rows) * (*num_cols)); - if (!tiles) - { - D(("Couldn't allocate tiles.\n")); - return NULL; - } - - right_tile = width - (((*num_cols) - 1) * TILE_WIDTH); - bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT); - - for (i = 0, k = 0; i < (*num_rows); i++) - { - 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(("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows))); - - return tiles; -} - - -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 = (DATA8*) malloc (sizeof(DATA8) * width * height * bpp); - if (!tile->data) - { - D(("Couldn't allocate tile.\n")); - } - } -} - - -static void -free_tiles(Tile* tiles, int num_tiles) -{ - int i; - - for (i=0; ilast_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; - } -} - - -static void -set_layer_opacity(Layer* layer) -{ - int i; - DATA8* ptr; - - 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; - } - } - } -} - -static void -apply_layer_mask(Layer* layer) -{ - DATA8* ptr1; - DATA8* ptr2; - int i; - - D(("Applying layer mask.\n")); - - if (layer) - { - if (layer->mask) - { - ptr1 = layer->data; - ptr2 = layer->mask->data; - - for (i = 0; i < layer->width*layer->height; i++) - { - *(ptr1+3) = (*(ptr1+3) * *(ptr2)) >> 8; - ptr1 += 4; - ptr2 += 4; - } - } - } -} - - -static void -flatten_image(void) -{ - Layer* l = image->last_layer; - Layer* lp; - int layer_index; - DATA8* ptr; - - image->data = (DATA8*) 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. The code that's commented - out is directly from Gimp. Right now fall through all of these - and simply combine the layers. - --cK. - */ - if (image->single_layer_index < 0 || layer_index == image->single_layer_index) - { - switch (l->mode) - { - case DISSOLVE_MODE: - /* - if (! has_alpha2) - add_alpha_pixels (src2, *dest, length, bytes2); - - dissolve_pixels (src2, *dest, x, y, opacity, length, bytes2, - ((has_alpha2) ? bytes2 : bytes2 + 1), has_alpha2); - combine = (has_alpha1) ? COMBINE_INTEN_A_INTEN_A : COMBINE_INTEN_INTEN_A; - break; - */ - case MULTIPLY_MODE: - /* - multiply_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case DIVIDE_MODE: - /* - divide_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case SCREEN_MODE: - /* - screen_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case OVERLAY_MODE: - /* - overlay_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case DIFFERENCE_MODE: - /* - difference_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case ADDITION_MODE: - /* - add_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case SUBTRACT_MODE: - /* - subtract_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case DARKEN_ONLY_MODE: - /* - darken_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case LIGHTEN_ONLY_MODE: - /* - lighten_pixels (src1, src2, *dest, length, bytes1, bytes2, has_alpha1, has_alpha2); - break; - */ - case HUE_MODE: case SATURATION_MODE: case VALUE_MODE: - /* - if (bytes1 > 2) - hsv_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2); - else - *dest = src2; - break; - */ - case COLOR_MODE: - /* - if (bytes1 > 2) - color_only_pixels (src1, src2, *dest, mode, length, bytes1, bytes2, has_alpha1, has_alpha2); - else - *dest = src2; - break; - */ - case BEHIND_MODE: - /* - *dest = src2; - if (has_alpha1) - combine = BEHIND_INTEN; - else - combine = NO_COMBINATION; - break; - */ - case REPLACE_MODE: - /* - *dest = src2; - combine = REPLACE_INTEN; - break; - */ - case ERASE_MODE: - /* - *dest = src2; - combine = ERASE_INTEN; - break; - */ - case ANTI_ERASE_MODE: - /* - *dest = src2; - combine = ANTI_ERASE_INTEN; - break; - */ - case NORMAL_MODE: - combine_pixels(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", lp->mode)); - } - } - - 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; -} - - -static char -xcf_file_init(char* filename) -{ - char success = 1; - char id[14]; - char* suffix = NULL; - - image->single_layer_index = -1; - if ((suffix = strchr(filename, ':'))) - { - *suffix = '\0'; - image->single_layer_index = atoi(suffix+1); - D(("Loading only XCF layer %i.\n", image->single_layer_index)); - } - - image->fp = fopen (filename, "r"); - if (!image->fp) - return 0; - - image->filename = filename; - image->layers = NULL; - image->last_layer = NULL; - image->cmap = NULL; - image->num_cols = 0; - image->data = NULL; - - image->cp = 0; - - image->cp += xcf_read_int8 (image->fp, (DATA8*) id, 14); - if (strncmp (id, "gimp xcf ", 9) != 0) - success = 0; - else if (strcmp (id+9, "file") == 0) - { - image->file_version = 0; - } - else if (id[9] == 'v') - { - image->file_version = atoi(id + 10); - } - else - success = 0; - - return success; -} - - -static void -xcf_cleanup(void) -{ - Layer* l; - Layer* lp; - - fclose(image->fp); - - l = image->last_layer; - while (l) - { - lp = l->prev; - free_layer(l); - l = lp; - } -} - -static void -xcf_to_imlib(ImlibImage *im) -{ - im->w = image->width; - im->h = image->height; - SET_FLAG(im->flags, F_HAS_ALPHA); - - im->data = (DATA32*)image->data; -} - - -char -load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) -{ - /* if immediate_load is 1, then dont delay image laoding as below, or */ - /* already data in this image - dont load it again */ - - if (im->data) - return 0; - - /* initialize */ - if (!xcf_file_init(im->file)) - return 0; - - /* set the format string member to the lower-case full extension */ - /* name for the format - so example names would be: */ - /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ - if (!im->loader) - im->format = strdup("xcf"); - - /* do it! */ - xcf_load_image(); - - /* Now paste stuff into Imlib image */ - xcf_to_imlib(im); - - /* I want to ignore this for now, am I doing this right? --cK */ - if (progress) - { - progress(im, 100, 0, 0, im->w, im->h); - } - - /* cleanup */ - xcf_cleanup(); - - return 1; -} - -char -save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity) -{ - return 0; - im = NULL; - progress = NULL; - progress_granularity = 0; -} - -/* fills the ImlibLoader struct with a strign array of format file */ -/* extensions this loader can load. eg: */ -/* loader->formats = { "jpeg", "jpg"}; */ -/* giving permutations is a good idea. case sensitivity is irrelevant */ -/* your laoder CAN load more than one format if it likes - like: */ -/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ -/* if it can load those formats. */ -void -formats (ImlibLoader *l) -{ - /* this is the only bit you have to change... */ - char *list_formats[] = - { "xcf" }; - - /* don't bother changing any of this - it just reads this in and sets */ - /* the struct values and makes copies */ - { - int i; - - l->num_formats = (sizeof(list_formats) / sizeof (char *)); - l->formats = malloc(sizeof(char *) * l->num_formats); - for (i = 0; i < l->num_formats; i++) - l->formats[i] = strdup(list_formats[i]); - } -} - diff --git a/loaders/loader_xcf_pixelfuncs.c b/loaders/loader_xcf_pixelfuncs.c deleted file mode 100644 index aa36110..0000000 --- a/loaders/loader_xcf_pixelfuncs.c +++ /dev/null @@ -1,115 +0,0 @@ - -/* These are the tons of different functions for merging layers. - All of them assume merging of src2 ONTO src1. Heavily adapted - from gimp's paint_funcs.c. - --cK. -*/ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "image.h" -#include "Imlib2.h" - -#include "colormod.h" -#include "blend.h" - -#define STD_BUF_SIZE 1021 -#define MAXDIFF 195076 -#define HASH_TABLE_SIZE 1021 -#define RANDOM_TABLE_SIZE 4096 -#define RANDOM_SEED 314159265 -#define EPSILON 0.0001 - -#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8)) - -#define LINEAR(x,y,w) ((w*y + x)*4) - -#define alphify(src_alpha,new_alpha) \ - b = 3; \ - if (new_alpha != 0) \ - { \ - ratio = (float) src_alpha / new_alpha; \ - compl_ratio = 1.0 - ratio; \ - \ - do { b--; \ - dest[d_idx + b] = \ - (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPSILON); \ - } while (b); \ - } - - -void -combine_pixels (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) -{ - int x, y, s_idx, d_idx, dest_col; - int src_tl_x = 0, src_tl_y = 0; - int src_br_x = src_w, src_br_y = src_h; - - int a, red, green, blue; - - int alpha, b; - unsigned char src_alpha; - unsigned char new_alpha; - float ratio, compl_ratio; - long tmp; - int length; - - /*printf ("Blending %ix%i onto %ix%i at %i, %i -->", src_w, src_h, dest_w, dest_h, dest_x, dest_y);*/ - - /* translate negative destinations */ - if (dest_x + src_br_x >= dest_w) - src_br_x -= (dest_x + src_br_x) - dest_w; - - if (dest_y + src_br_y >= dest_h) - src_br_y -= (dest_y + src_br_y) - dest_h; - - if (dest_x < 0) - { - src_tl_x = -dest_x; - dest_x = 0; - } - if (dest_y < 0) - { - src_tl_y = -dest_y; - dest_y = 0; - } - - for (y = src_tl_y; y < src_br_y; y++) - { - for (x = src_tl_x; x < src_br_x; x++) - { - d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); - s_idx = LINEAR(x, y, src_w); - - src_alpha = A_VAL(src + s_idx); - - if (src_alpha != 0) - { - if (src_alpha == 255) - { - new_alpha = src_alpha; - alphify (src_alpha, new_alpha); - A_VAL(dest + d_idx) = new_alpha; - } - else - { - new_alpha = A_VAL(dest + d_idx) + INT_MULT((255 - A_VAL(dest + d_idx)), src_alpha, tmp); - alphify (src_alpha, new_alpha); - A_VAL(dest + d_idx) = new_alpha; - } - } - } - } -}