bc73c61999-04-11Per Hedbor #include "global.h"
7ae4b21999-04-11Per Hedbor RCSID("$Id: xcf.c,v 1.2 1999/04/11 05:48:51 per Exp $");
bc73c61999-04-11Per Hedbor  #include "config.h" #include "pike_macros.h" #include "object.h" #include "constants.h" #include "module_support.h" #include "interpret.h" #include "object.h" #include "svalue.h" #include "threads.h" #include "array.h" #include "interpret.h" #include "svalue.h" #include "mapping.h" #include "error.h" #include "stralloc.h" #include "builtin_functions.h" #include "operators.h" #include "dynamic_buffer.h" #include "image.h" #include "colortable.h" extern struct program *image_colortable_program; extern struct program *image_program; /* **! module Image **! submodule XCF **! */ #define STRING(X) static struct pike_string *s_##X; #include "xcf_constant_strings.h" #undef STRING struct buffer { unsigned int len; unsigned char *str; }; 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 } property_type; typedef enum { RGB = 0, GRAY = 1, INDEXED = 2, } image_type; typedef enum { Red, Green, Blue, Gray, Indexed, Auxillary } channel_type; typedef enum { RGB_GIMAGE, RGBA_GIMAGE, GRAY_GIMAGE, GRAYA_GIMAGE, INDEXED_GIMAGE, INDEXEDA_GIMAGE } layer_type; typedef enum { COMPRESS_NONE = 0, COMPRESS_RLE = 1, COMPRESS_ZLIB = 2, COMPRESS_FRACTAL = 3, } compression_type; struct property { int type; struct buffer data; struct property *next; }; static unsigned int read_uint( struct buffer *from ) { unsigned int res; if(from->len < 4) error("Not enough space for 4 bytes (uint32)\n"); res = from->str[0]<<24|from->str[1]<<16|from->str[2]<<8|from->str[3]; from->str += 4; from->len -= 4; return res; } static int read_int( struct buffer *from ) { return (int)read_uint( from ); } static char *read_data( struct buffer * from, unsigned int len ) { char *res; if( from->len < len ) error("Not enough space for %ud bytes\n", len); res = from->str; from->str += len; from->len -= len; return res; } static struct buffer read_string( struct buffer *data ) { struct buffer res; res.len = read_int( data ); res.str = read_data( data, res.len ); if(res.len > 0) res.len--; /* len includes ending \0 */ if(!res.str) error("String read failed\n"); return res; } static struct property read_property( struct buffer * data ) { int i; struct property res; res.type = read_uint( data ); if(res.type == PROP_COLORMAP) { unsigned int foo; read_uint(data); /* bogus 'len'... */ foo = read_uint( data ); res.data.len = foo*3; res.data.str = read_data( data,foo*3 ); } else { res.data.len = read_uint( data ); res.data.str = read_data( data,res.data.len ); } res.next = NULL; return res; } struct tile { struct tile *next; struct buffer data; }; struct level { unsigned int width; unsigned int height; struct tile *first_tile; }; struct hierarchy { unsigned int width; unsigned int height; unsigned int bpp; struct level level; }; struct channel { struct channel *next; unsigned int width; unsigned int height; struct buffer name; struct hierarchy image_data; struct property *first_property; }; struct layer_mask { unsigned int width; unsigned int height; struct buffer name; struct hierarchy image_data; struct property *first_property; }; struct layer { struct layer *next; unsigned int width; unsigned int height; int type; struct buffer name; struct hierarchy image_data; struct property *first_property; struct layer_mask *mask; }; struct gimp_image { unsigned int width; unsigned int height; int type; struct property *first_property; struct layer *first_layer; /* OBS: In reverse order! */ struct channel *first_channel; /* OBS: In reverse order! */ }; static void free_level( struct level *l ) { struct tile *t; while( (t = l->first_tile) ) { struct tile *n; n = t->next; free(t); l->first_tile = n; } } static void free_layer_mask( struct layer_mask *l ) { struct property *p; while( (p = l->first_property) ) { struct property *n; n = p->next; free(p); l->first_property = n; } free_level( &l->image_data.level ); } static void free_layer( struct layer *l ) { struct property *p; while( (p = l->first_property) ) { struct property *n; n = p->next; free(p); l->first_property = n; } if(l->mask) { free_layer_mask( l->mask ); free( l->mask ); } free_level( &l->image_data.level ); } static void free_channel( struct channel *l ) { struct property *p; while( (p = l->first_property) ) { struct property *n; n = p->next; free(p); l->first_property = n; } free_level( &l->image_data.level ); } static void free_image( struct gimp_image *i ) { struct property *p; struct layer *l; while( (p = i->first_property) ) { struct property *n; n = p->next; free(p); i->first_property = n; } while( (l = i->first_layer) ) { struct layer *n; n = l->next; free_layer( l ); free( l ); i->first_layer = n; } } static struct level read_level( struct buffer *buff, struct buffer *initial ) { struct level res; ONERROR err; int offset; struct tile *last_tile = NULL; int all_tiles_eq = 0; MEMSET(&res, 0, sizeof(res)); res.width = read_uint( buff ); res.height = read_uint( buff ); SET_ONERROR( err, free_level, &res ); offset = read_uint( buff ); while(offset) { struct buffer ob = *initial; int offset2 = read_uint( buff ); struct tile *tile = (struct tile *)xalloc(sizeof(struct tile)); read_data( &ob, offset ); if(last_tile) last_tile->next = tile; last_tile = tile; if(!res.first_tile) { res.first_tile = tile; if(offset2) all_tiles_eq = offset2-offset; } if(all_tiles_eq && offset2 && offset2-offset != all_tiles_eq) all_tiles_eq = 0; if(all_tiles_eq) ob.len = all_tiles_eq; else if(offset2) ob.len = offset2-offset; tile->data = ob; tile->next = NULL; /* fprintf(stderr, "tile, o=%d; o2=%d; l=%d\n", offset, offset2,ob.len); */ offset = offset2; } UNSET_ONERROR( err ); return res; } static struct hierarchy read_hierarchy( struct buffer *buff, struct buffer *initial ) { struct hierarchy res; unsigned int offset; struct buffer ob; MEMSET(&res, 0, sizeof(res)); res.width = read_uint( buff ); res.height = read_uint( buff ); res.bpp = read_uint( buff ); offset = read_uint( buff ); ob = *initial; read_data( &ob, offset ); res.level = read_level( &ob, initial ); return res; } static struct layer_mask read_layer_mask( struct buffer *buff, struct buffer *initial ) { struct layer_mask res; ONERROR err; int offset; struct property tmp; struct buffer ob; MEMSET(&res, 0, sizeof(res)); res.width = read_uint( buff ); res.height = read_uint( buff ); res.name = read_string( buff ); SET_ONERROR( err, free_layer_mask, &res ); do { tmp = read_property( buff ); if(tmp.type) { struct property *s = (struct property *)xalloc(sizeof(struct property)); *s = tmp; s->next = res.first_property; res.first_property = s; } } while(tmp.type); offset = read_uint( buff ); if(offset) { struct buffer ob = *initial; read_data( &ob, offset ); res.image_data = read_hierarchy( &ob, initial ); } UNSET_ONERROR( err ); return res; } static struct channel read_channel( struct buffer *buff, struct buffer *initial ) { struct channel res; ONERROR err; int offset; struct property tmp; struct buffer ob; MEMSET(&res, 0, sizeof(res)); res.width = read_uint( buff ); res.height = read_uint( buff ); res.name = read_string( buff ); SET_ONERROR( err, free_channel, &res ); do { tmp = read_property( buff ); if(tmp.type) { struct property *s =(struct property *)xalloc( sizeof(struct property )); *s = tmp; s->next = res.first_property; res.first_property = s; } } while( tmp.type ); offset = read_uint( buff ); if(offset) { struct buffer ob = *initial; read_data( &ob, offset ); res.image_data = read_hierarchy( &ob, initial ); } UNSET_ONERROR( err ); return res; } static struct layer read_layer( struct buffer *buff, struct buffer *initial ) { struct layer res; struct property tmp; int lm_offset; int h_offset; ONERROR err; MEMSET(&res, 0, sizeof(res)); SET_ONERROR( err, free_layer, &res ); res.width = read_uint( buff ); res.height = read_uint( buff ); res.type = read_int( buff ); res.name = read_string( buff ); do { tmp = read_property( buff ); if(tmp.type) { struct property *s=(struct property *)xalloc( sizeof(struct property )); *s = tmp; s->next = res.first_property; res.first_property = s; } } while( tmp.type ); h_offset = read_int( buff ); lm_offset = read_int( buff ); if(lm_offset) { struct buffer loffset = *initial; struct layer_mask *m=(struct layer_mask *)xalloc(sizeof(struct layer_mask)); res.mask = m; read_data( &loffset, lm_offset ); MEMSET(m, 0, sizeof( struct layer_mask )); *m = read_layer_mask( &loffset, initial ); } if(h_offset) { struct buffer loffset = *initial; read_data( &loffset, h_offset ); res.image_data = read_hierarchy( &loffset, initial ); } UNSET_ONERROR( err ); return res; } static struct gimp_image read_image( struct buffer * data ) { struct gimp_image res; struct property tmp; struct buffer initial; unsigned int offset; ONERROR err; MEMSET(&res, 0, sizeof(res)); initial = *data; if(data->len < 34) error("This is not an xcf file (to little data)\n"); if(!(data->str[0] == 'g' && data->str[1] == 'i' && data->str[2] == 'm' && data->str[3] == 'p' && data->str[4] == ' ')) { if(strlen(data->str) == 13) error("This is not an xcf file (%s)\n", data->str); else error("This is not an xcf file\n"); } data->str+=14; data->len-=14; res.width = read_uint( data ); res.height = read_uint( data ); res.type = read_int( data ); SET_ONERROR( err, free_image, &res ); do { tmp = read_property( data ); if(tmp.type) { struct property *s= (struct property *)xalloc( sizeof(struct property )); *s = tmp; s->next = res.first_property; res.first_property = s; } } while( tmp.type ); while( (offset = read_uint( data )) ) { struct buffer layer_data = initial; struct layer tmp; read_data( &layer_data, offset ); tmp = read_layer( &layer_data, &initial ); if( tmp.width && tmp.height ) { struct layer *s = (struct layer *)xalloc( sizeof(struct layer)); *s = tmp; s->next = res.first_layer; res.first_layer = s; } } while( (offset = read_uint( data )) ) { struct buffer channel_data = initial; struct channel tmp; read_data( &channel_data, offset ); tmp = read_channel( &channel_data, &initial ); if( tmp.width && tmp.height ) { struct channel *s = (struct channel *)xalloc( sizeof(struct channel)); *s = tmp; s->next = res.first_channel; res.first_channel = s; } } UNSET_ONERROR( err ); return res; } static void push_buffer( struct buffer *b ) { push_string( make_shared_binary_string( b->str, b->len ) ); } static void push_properties( struct property *p ) { struct svalue *osp = sp; while(p) { ref_push_string( s_type ); push_int( p->type ); ref_push_string( s_data ); push_buffer( &p->data ); f_aggregate_mapping( 4 ); p = p->next; } f_aggregate( sp-osp ); } static void push_tile( struct tile *t ) { push_buffer( &t->data ); } static void push_hierarchy( struct hierarchy * h ) { struct tile *t = h->level.first_tile; struct svalue *osp = sp, *tsp; if(h->level.width != h->width || h->level.height != h->height) error("Illegal hierarchy level sizes!\n"); ref_push_string( s_width ); push_int( h->width ); ref_push_string( s_height ); push_int( h->height ); ref_push_string( s_bpp ); push_int( h->bpp ); ref_push_string( s_tiles ); tsp = sp; while(t) { push_tile( t ); t=t->next; } f_aggregate( sp-tsp ); f_aggregate_mapping( sp-osp ); } static void push_layer_mask(struct layer_mask *i) { struct svalue *osp = sp; ref_push_string( s_width ); push_int( i->width ); ref_push_string( s_height ); push_int( i->height ); ref_push_string( s_properties ); push_properties( i->first_property ); ref_push_string( s_name ); push_buffer( &i->name ); ref_push_string( s_image_data ); push_hierarchy( &i->image_data ); f_aggregate_mapping( sp-osp ); } static void push_channel(struct channel *i) { struct svalue *osp = sp; ref_push_string( s_width ); push_int( i->width ); ref_push_string( s_height ); push_int( i->height ); ref_push_string( s_properties ); push_properties( i->first_property ); ref_push_string( s_name ); push_buffer( &i->name ); ref_push_string( s_image_data ); push_hierarchy( &i->image_data ); f_aggregate_mapping( sp-osp ); } static void push_layer(struct layer *i) { struct svalue *osp = sp; ref_push_string( s_width ); push_int( i->width ); ref_push_string( s_height ); push_int( i->height ); ref_push_string( s_type ); push_int( i->type ); ref_push_string( s_properties ); push_properties( i->first_property ); ref_push_string( s_name ); push_buffer( &i->name ); ref_push_string( s_image_data ); push_hierarchy( &i->image_data ); if( i->mask ) { ref_push_string( s_mask ); push_layer_mask( i->mask ); } f_aggregate_mapping( sp-osp ); } static void push_image( struct gimp_image *i ) { struct layer *l; struct channel *c; int nitems = 0; struct svalue *osp = sp; ref_push_string( s_width ); push_int( i->width ); ref_push_string( s_height ); push_int( i->height ); ref_push_string( s_type ); push_int( i->type ); ref_push_string( s_properties ); push_properties( i->first_property ); ref_push_string( s_layers ); l = i->first_layer; while(l) { nitems++; push_layer( l ); l = l->next; } f_aggregate( nitems ); f_reverse(1); ref_push_string( s_channels ); nitems=0; c = i->first_channel; while(c) { nitems++; push_channel( c ); c = c->next; } f_aggregate( nitems ); f_reverse(1); f_aggregate_mapping( sp-osp ); } static void image_xcf____decode( INT32 args ) { struct pike_string *s; struct buffer b; struct gimp_image res; ONERROR err; get_all_args( "___decode", args, "%S", &s ); if(args > 1) error("Too many arguments to Image.XCF.___decode()\n"); b.str = s->str; b.len = s->len; res = read_image( &b ); SET_ONERROR( err, free_image, &res ); push_image( &res ); UNSET_ONERROR( err ); free_image( &res ); stack_swap(); pop_stack(); } #define TILE_WIDTH 64 #define TILE_HEIGHT 64 unsigned char read_char( struct buffer *from ) { unsigned char res = 0; if(from->len) { res = from->str[0]; from->str++; from->len--; } return res; } void image_xcf_f__rle_decode( INT32 args ) { struct pike_string *t; struct buffer s; struct buffer od, d; int bpp, xsize, ysize, i; get_all_args( "_rle_decode", args, "%S%d%d%d", &t, &bpp, &xsize, &ysize); s.len = t->len; s.str = t->str; od.len = xsize*ysize*bpp; od.str = xalloc( xsize*ysize*bpp ); /* Max and only size, really */ d = od; for(i=0; i<bpp; i++) { int nelems = xsize*ysize; int length; while(nelems) { unsigned char val = read_char( &s ); if(!s.len) { break; /* Hm. This is actually rather fatal */ } length = val; if( length >= 128 ) { length = 255-(length-1); if (length == 128) length = (read_char( &s )<<8) + read_char( &s ); nelems -= length; while(length--) { if(d.len < 1) break; d.str[0] = read_char( &s ); d.str++; d.len--; } } else { length++; if(length == 128) length = (read_char( &s )<<8) + read_char( &s ); nelems -= length; val = read_char( &s ); while(length--) { if(d.len < 1) break; d.str[0] = val; d.str++; d.len--; } } } } pop_n_elems(args); /* fprintf(stderr, "%d bytes of source data used out of %d bytes\n" */ /* "%d bytes decoded data generated\n", */ /* t->len-s.len,t->len,od.len); */ push_string(make_shared_binary_string(od.str,od.len)); free(od.str); } /* **! method object decode(string data) **! Decodes a XCF image to a single image object. **! **! note **! Throws upon error in data, you will loose quite a lot of **! information by doing this. See Image.XCF._decode and Image.XCF.__decode */ /* **! method mapping _decode(string|object data) **! Decodes a XCF image to a mapping, with at least an **! 'image' and an 'alpha' object. Data is either a XCF image, or **! a XCF.GimpImage object structure (as received from __decode) **! **! note **! Throws upon error in data. For more information, see Image.XCF.__decode */ /* **! method object __decode(string|mapping data) **! Decodes a XCF image to a Image.XCF.GimpImage object. **! **! <pre>Structure reference **! **! class GimpImage **! { **! int width; **! int height; **! int compression; **! int type; **! int tattoo_state; **! float xres = 72.0; **! float yres = 72.0; **! int res_unit; **! Image.colortable colormap; **! Image.colortable meta_colormap; **! array(Layer) layers = ({}); **! array(Channel) channels = ({}); **! array(Guide) guides = ({}); **! array(Parasite) parasites = ({}); **! array(Path) paths = ({}); **! **! Layer active_layer; **! Channel active_channel; **! Channel selection; **! } **! **! class Layer **! { **! string name; **! int opacity; **! int type; **! int mode; **! int tattoo; **! mapping flags = ([]); **! int width, height; **! int xoffset, yoffset; **! array (Parasite) parasites; **! LayerMask mask; **! Hierarchy image; **! } **! **! class Channel **! { **! string name; **! int width; **! int height; **! int opacity; **! int r, g, b; **! int tattoo; **! Hierarchy image_data; **! object parent; **! mapping flags = ([]); **! array (Parasite) parasites; **! } **! **! class Hierarchy **! { **! Image.image img; **! Image.image alpha; **! int width; **! int height; **! int bpp; **! } **! **! class Parasite **! { **! string name; **! int flags; **! string data; **! } **! **! **! class Guide **! { **! int pos; **! int vertical; **! } **! **! class Path **! { **! string name; **! int ptype; **! int tattoo; **! int closed; **! int state; **! int locked; **! array (PathPoint) points = ({}); **! } **! **! class PathPoint **! { **! int type; **! float x; **! float y; **! } **! **! </pre> */ /* **! method object ___decode(string|mapping data) **! Decodes a XCF image to a mapping. **! **! <pre>Structure reference **! **! ([ **! "width":int, **! "height":int, **! "type":int, **! "properties":({ **! ([ **! "type":int, **! "data":string, **! ]), **! ... **! }), **! "layers":({ **! ([ **! "name":string, **! "width":int, **! "height":int, **! "type":type, **! "properties":({ **! ([ **! "type":int, **! "data":string, **! ]), **! ... **! }), **! "mask":0 || ([ **! "name":string, **! "width":int, **! "height":int, **! "properties":({ **! ([ **! "type":int, **! "data":string, **! ]), **! ... **! }), **! "image_data":([ **! "bpp":int, **! "width":int, **! "height":int, **! "tiles":({ **! string, **! ... **! }), **! ]), **! ]), **! "image_data":([ **! "bpp":int, **! "width":int, **! "height":int, **! "tiles":({ **! string, **! ... **! }), **! ]), **! ]), **! ... **! }), **! "channels":({ **! "name":string, **! "width":int, **! "height":int, **! "properties":({ **! ([ **! "type":int, **! "data":string, **! ]), **! ... **! }), **! "image_data":([ **! "bpp":int, **! "width":int, **! "height":int, **! "tiles":({ **! string, **! ... **! }), **! ]), **! }), **! ]) **!</pre> */ #define MIN(X,Y) ((X)<(Y)?(X):(Y)) void image_xcf_f__decode_tiles( INT32 args ) {
7ae4b21999-04-11Per Hedbor  extern void check_signals();
bc73c61999-04-11Per Hedbor  struct object *io,*ao, *cmapo; struct array *tiles; struct image *i, *a; struct neo_colortable *cmap = NULL; rgb_group *colortable=NULL; int rle, bpp, span; unsigned int l, x=0, y=0, cx, cy; get_all_args( "_decode_tiles", args, "%o%o%a%i%i%O", &io, &ao, &tiles, &rle, &bpp, &cmapo); if( !(i = (struct image *)get_storage( io, image_program ))) error("Wrong type object argument 1 (image)\n"); if( !(a = (struct image *)get_storage( ao, image_program ))) error("Wrong type object argument 2 (image)\n"); if( cmapo && !(cmap=(struct neo_colortable *)get_storage(cmapo, image_colortable_program))) error("Wrong type object argument 4 (colortable)\n"); for(l=0; l<(unsigned int)tiles->size; l++) if(tiles->item[l].type != T_STRING) error("Wrong type array argument 3 (tiles)\n"); if(i->xsize != a->xsize ||i->ysize != a->ysize) error("Image and alpha objects are not identically sized.\n"); if(cmap) { colortable = malloc(sizeof(rgb_group)*image_colortable_size( cmap )); image_colortable_write_rgb( cmap, (unsigned char *)colortable ); } x=y=0; for(l=0; l<(unsigned)tiles->size; l++) { struct pike_string *tile = tiles->item[l].u.string; unsigned int eheight, ewidth; unsigned char *s; ewidth = MIN(TILE_WIDTH, i->xsize-x); eheight = MIN(TILE_HEIGHT, i->ysize-y); tile->refs++;
7ae4b21999-04-11Per Hedbor /* fprintf(stderr, " tile %d/%d [%dx%d] %dbpp \n", */ /* l+1, tiles->size, ewidth, eheight,bpp); */
bc73c61999-04-11Per Hedbor  if(rle) { push_string( tile ); push_int( bpp ); push_int( ewidth ); push_int( eheight ); image_xcf_f__rle_decode( 4 ); tile = sp[-1].u.string; if(sp[-1].type != T_STRING) fatal("Internal disaster in XCF module\n"); sp--; } if( (unsigned)(tile->len) < (unsigned)(eheight * ewidth * bpp )) error("Too small tile, was %d bytes, I really need %d\n", tile->len, eheight*ewidth * bpp); s = tile->str; check_signals(); /* Allow ^C */ for(cy=0; cy<eheight; cy++) { for(cx=0; cx<ewidth; cx++) { rgb_group pix; rgb_group apix = {255,255,255}; int ind = (cx+cy*ewidth); if(rle) span = ewidth*eheight; else span = 1;
7ae4b21999-04-11Per Hedbor  if(cx+x > (unsigned)i->xsize) continue; if(cy+y > (unsigned)i->ysize) continue;
bc73c61999-04-11Per Hedbor  switch( bpp ) { case 1: /* indexed or grey */ if(colortable) pix = colortable[s[ind]]; else pix.r = pix.g = pix.b = s[ind]; break; case 2: /* indexed or grey with alpha */ if(colortable) pix = colortable[s[ind]]; else pix.r = pix.g = pix.b = s[ind]; apix.r = apix.g = apix.b = s[ind+span]; break; case 3: /* rgb */ pix.r = s[ind]; pix.g = s[ind+span]; pix.b = s[ind+span*2]; break; case 4: /* rgb with alpha */ pix.r = s[ind]; pix.g = s[ind+span*1]; pix.b = s[ind+span*2]; apix.r = apix.g = apix.b = s[ind+span*3]; break; } ind = i->xsize*(cy+y)+(cx+x); i->img[ind] = pix; a->img[ind] = apix; } } x += TILE_WIDTH; if( x >= (unsigned)i->xsize ) { x = 0; y += TILE_HEIGHT; } if(y>=(unsigned)i->ysize) { free_string(tile); if(colortable) free( colortable ); return; } free_string(tile); } if(colortable) free( colortable ); pop_n_elems(args); push_int(0); } static struct program *image_encoding_xcf_program=NULL; void init_image_xcf() { start_new_program(); add_function( "___decode", image_xcf____decode, "function(string:mapping)", 0); add_function( "_decode_tiles", image_xcf_f__decode_tiles, "mixed", 0); add_integer_constant( "PROP_END", PROP_END,0 ); add_integer_constant( "PROP_COLORMAP", PROP_COLORMAP, 0 ); add_integer_constant( "PROP_ACTIVE_LAYER", PROP_ACTIVE_LAYER, 0 ); add_integer_constant( "PROP_ACTIVE_CHANNEL", PROP_ACTIVE_CHANNEL, 0 ); add_integer_constant( "PROP_SELECTION", PROP_SELECTION, 0 ); add_integer_constant( "PROP_FLOATING_SELECTION", PROP_FLOATING_SELECTION, 0 ); add_integer_constant( "PROP_OPACITY", PROP_OPACITY, 0 ); add_integer_constant( "PROP_MODE", PROP_MODE, 0 ); add_integer_constant( "PROP_VISIBLE", PROP_VISIBLE, 0 ); add_integer_constant( "PROP_LINKED", PROP_LINKED, 0 ); add_integer_constant( "PROP_PRESERVE_TRANSPARENCY", PROP_PRESERVE_TRANSPARENCY, 0); add_integer_constant( "PROP_APPLY_MASK", PROP_APPLY_MASK, 0 ); add_integer_constant( "PROP_EDIT_MASK", PROP_EDIT_MASK, 0 ); add_integer_constant( "PROP_SHOW_MASK", PROP_SHOW_MASK, 0 ); add_integer_constant( "PROP_SHOW_MASKED", PROP_SHOW_MASKED, 0 ); add_integer_constant( "PROP_OFFSETS", PROP_OFFSETS, 0 ); add_integer_constant( "PROP_COLOR", PROP_COLOR, 0 ); add_integer_constant( "PROP_COMPRESSION", PROP_COMPRESSION, 0 ); add_integer_constant( "PROP_GUIDES", PROP_GUIDES, 0 ); add_integer_constant( "PROP_RESOLUTION", PROP_RESOLUTION, 0 ); add_integer_constant( "PROP_TATTOO", PROP_TATTOO, 0 ); add_integer_constant( "PROP_PARASITES", PROP_PARASITES, 0 ); add_integer_constant( "PROP_UNIT", PROP_UNIT, 0 ); add_integer_constant( "PROP_PATHS", PROP_PATHS, 0 ); add_integer_constant( "PROP_USER_UNIT", PROP_USER_UNIT, 0 ); add_integer_constant( "RGB", RGB, 0 ); add_integer_constant( "GRAY", GRAY, 0 ); add_integer_constant( "INDEXED", INDEXED, 0 ); add_integer_constant( "COMPRESS_NONE", COMPRESS_NONE, 0 ); add_integer_constant( "COMPRESS_RLE", COMPRESS_RLE, 0 ); add_integer_constant( "COMPRESS_ZLIB", COMPRESS_ZLIB, 0 ); add_integer_constant( "COMPRESS_FRACTAL", COMPRESS_FRACTAL, 0 ); add_integer_constant( "Red", Red, 0 ); add_integer_constant( "Green", Green, 0 ); add_integer_constant( "Blue", Blue, 0 ); add_integer_constant( "Gray", Gray, 0 ); add_integer_constant( "Indexed", Indexed, 0 ); add_integer_constant( "Auxillary", Auxillary, 0 ); add_integer_constant( "RGB_GIMAGE", RGB_GIMAGE, 0 ); add_integer_constant( "RGBA_GIMAGE", RGBA_GIMAGE, 0 ); add_integer_constant( "GRAY_GIMAGE", GRAY_GIMAGE, 0 ); add_integer_constant( "GRAYA_GIMAGE", GRAYA_GIMAGE, 0 ); add_integer_constant( "INDEXED_GIMAGE", INDEXED_GIMAGE, 0 ); add_integer_constant( "INDEXEDA_GIMAGE", INDEXEDA_GIMAGE, 0 ); image_encoding_xcf_program=end_program(); push_object(clone_object(image_encoding_xcf_program,0)); { struct pike_string *s=make_shared_string("_XCF"); add_constant(s,sp-1,0); free_string(s); } #define STRING(X) s_##X = make_shared_binary_string(#X,sizeof( #X )-sizeof("")); #include "xcf_constant_strings.h" #undef STRING } void exit_image_xcf() { if(image_encoding_xcf_program) { free_program(image_encoding_xcf_program); image_encoding_xcf_program=0; #define STRING(X) free_string(s_##X) #include "xcf_constant_strings.h" #undef STRING } }