diff --git a/lib/modules/_Image_XCF.pmod b/lib/modules/_Image_XCF.pmod index da10bee5cc3a0fa3d295659047154c8c627e1a44..38f9bcdad27e4a51a929edf60179afb642d26dc4 100644 --- a/lib/modules/_Image_XCF.pmod +++ b/lib/modules/_Image_XCF.pmod @@ -33,23 +33,12 @@ class Guide } } -class Parasite -{ - string name; - int flags; - string data; - - void create( string _n, int _f, string _d ) - { - name = _n; - data = _d; - flags = _f; - } -} +class Parasite( string name, int flags, string data ) { } -array(Parasite) decode_parasites( string data ) +array(Parasite) decode_parasites( mixed data ) { array res = ({}); + data = (string)data; while(strlen(data)) { int slen, flags; @@ -64,66 +53,25 @@ array(Parasite) decode_parasites( string data ) return res; } -#define FLAG(X,Y) case PROP_##X: sscanf(p->data, "%4c", flags->Y); break; -#define INT(X,Y) case PROP_##X: sscanf(p->data, "%4c", Y); break; -#define SINT(X,Y) case PROP_##X: sscanf(p->data, "%4c", Y); SIGNED(Y); break; - -class Hierarchy -{ - Image.image img; - Image.image alpha; - int width; - int height; - int bpp; - - Hierarchy set_image( int x, int y, int bp, array tiles, int compression, - Image.colortable cmap) - { - width = x; - height = y; - bpp = bp; - img = Image.image( x, y, 0,0,0 ); - if(!(bp & 1 )) - alpha = Image.image( x, y, 255,255,255 ); - switch(compression) - { - case COMPRESS_NONE: - case COMPRESS_RLE: - _decode_tiles( img,alpha,tiles,compression,bpp,cmap ); - break; - default: - error("Image tile compression type not supported\n"); - } - return this_object(); - } - - Hierarchy qsi(object _i, object _a, int _w, int _h,int _b) - { - img = _i; - alpha = _a; - width = _w; - height = _h; - bpp = _b; - return this_object(); - } +#define FLAG(X,Y) case PROP_##X: flags->Y=p->data->get_int(0); break; +#define INT(X,Y) case PROP_##X: Y = p->data->get_uint( 0 ); break; +#define SINT(X,Y) case PROP_##X: Y = p->data->get_int( 0 ); break; - Hierarchy copy() - { - return Hierarchy()->qsi( img,alpha,width,height,bpp ); - } +int id; - Hierarchy get_opaqued( int opaque_value ) +class Hierarchy( int width, int height, int bpp, array tiles, + int compression, Image.Colortable ct ) +{ + Image.Layer get_layer( int|void shrink ) { - Hierarchy res = copy(); - if(opaque_value != 255) - { - if(res->alpha) - res->alpha *= opaque_value/255.0; - else - res->alpha = Image.image(width,height, - opaque_value,opaque_value,opaque_value); - } - return res; + Image.Image img, alpha; + if(!shrink) + shrink = 1; + img = Image.Image( width/shrink, height/shrink ); + if( !(bpp & 1 ) ) + alpha = Image.Image( width/shrink, height/shrink ); + _decode_tiles( img,alpha,tiles,compression,bpp,ct, shrink,width,height ); + return Image.Layer( img, alpha ); } } @@ -131,8 +79,8 @@ int iid; Hierarchy decode_image_data( mapping what, object i ) { Hierarchy h = - Hierarchy( )->set_image(what->width, what->height, what->bpp, - what->tiles, i->compression, i->colormap ); + Hierarchy( what->width, what->height, what->bpp, + what->tiles, i->compression, i->colormap ); return h; } @@ -169,11 +117,11 @@ class Channel FLAG(SHOW_MASKED,show_masked); INT(TATTOO,tattoo); case PROP_COLOR: - sscanf( p->data, "%c%c%c", r, g, b); + sscanf( (string)p->data, "%c%c%c", r, g, b); break; case PROP_PARASITES: - parasites = decode_parasites( p->data ); + parasites = decode_parasites( (string)p->data ); break; } } @@ -184,7 +132,7 @@ class Channel { parent = p; - name = d->name; + name = (string)d->name; width = d->width; height = d->height; image_data = decode_image_data( d->image_data, parent ); @@ -227,9 +175,8 @@ class Layer parent->selection = this_object(); break; case PROP_OFFSETS: - sscanf(p->data, "%4c%4c", xoffset, yoffset); - SIGNED(xoffset); - SIGNED(yoffset); + xoffset = p->data->get_int( 0 ); + yoffset = p->data->get_int( 1 ); break; INT(OPACITY,opacity); FLAG(VISIBLE,visible); @@ -241,7 +188,7 @@ class Layer INT(MODE,mode); INT(TATTOO,tattoo); case PROP_PARASITES: - parasites = decode_parasites( p->data ); + parasites = decode_parasites( (string)p->data ); break; } } @@ -250,7 +197,7 @@ class Layer void create( mapping data, object pa ) { parent = pa; - name = data->name; + name = (string)data->name; type = data->type; width = data->width; height = data->height; @@ -271,8 +218,8 @@ class GimpImage float xres = 72.0; float yres = 72.0; int res_unit; - Image.colortable colormap; - Image.colortable meta_colormap; + Image.Colortable colormap; + Image.Colortable meta_colormap; array(Layer) layers = ({}); // bottom-to-top array(Channel) channels = ({}); // unspecified order, really array(Guide) guides = ({}); @@ -358,29 +305,29 @@ class GimpImage { case PROP_COLORMAP: if(type == INDEXED) - meta_colormap = colormap = Image.colortable( p->data ); + meta_colormap = colormap = Image.Colortable( (string)p->data ); else - meta_colormap = Image.colortable( p->data ); + meta_colormap = Image.Colortable( (string)p->data ); break; case PROP_COMPRESSION: - compression = p->data[0]; + compression = ((string)p->data)[0]; break; case PROP_GUIDES: - guides = Array.map(p->data/5,Guide); + guides = Array.map(((string)p->data)/5,Guide); break; case PROP_RESOLUTION: - sscanf( p->data, "%4f%4f", xres,yres); + sscanf( (string)p->data, "%4F%4F", xres,yres); if (xres < 1e-5 || xres> 1e+5 || yres<1e-5 || yres>1e+5) xres = yres = 72.0; break; case PROP_TATTOO: - sscanf(p->data, "%4c", tattoo_state ); + tattoo_state = p->data->get_int( 0 ); break; case PROP_PARASITES: - parasites = decode_parasites( p->data ); + parasites = decode_parasites( (string)p->data ); break; case PROP_UNIT: - sscanf(p->data, "%4c", res_unit ); + res_unit = p->data->get_int( 0 ); break; case PROP_PATHS: paths = decode_paths( p->data ); @@ -413,6 +360,20 @@ GimpImage __decode( string|mapping what ) return GimpImage(what); } +mapping decode_header( string|mapping|object(GimpImage) data ) +{ + if( !objectp(data) ) + { + if( stringp( data ) ) data = ___decode( data ); + data = GimpImage( data ); + } + return ([ + "type":"image/x-gimp-image", + "xsize":data->width, + "ysize":data->height, + ]); +} + string translate_mode( int mode ) { @@ -440,17 +401,19 @@ string translate_mode( int mode ) } } -array decode_layers( string|object|mapping what, mapping|void opts ) +array decode_layers( string|object|mapping what, mapping|void opts, + int|void concat ) { + int shrink = (opts->shrink_fact||1); if(!opts) opts = ([]); if(!objectp( what ) ) what = __decode( what ); - mapping lopts = ([ "tiled":1, ]); array layers = ({}); if( opts->background ) { + mapping lopts = ([ "tiled":1, ]); lopts->image = Image.Image( 32, 32, opts->background ); lopts->alpha = Image.Image( 32, 32, Image.Color.white ); lopts->alpha_value = 1.0; @@ -458,64 +421,68 @@ array decode_layers( string|object|mapping what, mapping|void opts ) } foreach(what->layers, object l) - { - if(l->flags->visible || opts->draw_all_layers) + if((l->flags->visible || opts->draw_all_layers) && l->opacity > 0) { - Hierarchy h = l->image; - Image.Layer lay = Image.Layer( h->img, - h->alpha, - translate_mode( l->mode ) ); - - - /* Not really layer related */ - lay->set_misc_value( "image_xres", l->parent->xres ); - lay->set_misc_value( "image_yres", l->parent->yres ); - lay->set_misc_value( "image_colormap", l->parent->colormap ); - lay->set_misc_value( "image_guides", l->parent->guides ); - lay->set_misc_value( "image_parasites", l->parent->parasites ); - - /* But these are. :) */ - lay->set_misc_value( "name", l->name ); - lay->set_misc_value( "tattoo", l->tattoo ); - lay->set_misc_value( "parasites", l->parasites ); - lay->set_misc_value( "visible", l->flags->visible ); - if( l == l->parent->active_layer ) - lay->set_misc_value( "active", 1 ); - - h->img = 0; h->alpha = 0; - - lay->set_alpha_value( l->opacity / 255.0 ); - lay->set_offset( l->xoffset, l->yoffset ); + Image.Layer lay = l->image->get_layer( shrink ); + lay->set_mode( translate_mode( l->mode ) ); + if( l->opacity != 255 ) + lay->set_alpha_value( l->opacity / 255.0 ); + lay->set_offset( l->xoffset/shrink, l->yoffset/shrink ); if(l->mask && l->flags->apply_mask) { - l->mask = 0; - object a = l->alpha(); + object a = lay->alpha(); + object a2 =l->mask->image_data->get_layer(shrink)->image(); + int x = lay->image()->xsize( ); + int y = lay->image()->ysize( ); + if( a2->xsize() != x || a2->ysize() != y ) + a2 = a2->copy( 0,0, x, y, 255,255,255 ); + if(a) - a *= l->mask->image; + a *= l->mask->image_data->get_layer(shrink)->image(); else - a = l->mask->image; - if( a->xsize() != l->image->img->xsize() || - a->ysize() != l->image->img->ysize() ) - a = a->copy( 0,0, l->image->image->xsize(), - l->image->image->ysize(), 255,255,255 ); + a = a2; lay->set_alpha( a ); } layers += ({ lay }); + + + if(!concat) /* No reason to set these flags if they are just + going to be ignored. */ + { + /* Not really layer related */ + lay->set_misc_value( "image_xres", l->parent->xres/shrink ); + lay->set_misc_value( "image_yres", l->parent->yres/shrink ); + lay->set_misc_value( "image_colormap", l->parent->colormap ); + lay->set_misc_value( "image_guides", l->parent->guides ); + lay->set_misc_value( "image_parasites", l->parent->parasites ); + + /* But these are. :) */ + lay->set_misc_value( "name", l->name ); + lay->set_misc_value( "tattoo", l->tattoo ); + lay->set_misc_value( "parasites", l->parasites ); + lay->set_misc_value( "visible", l->flags->visible ); + if( l == l->parent->active_layer ) + lay->set_misc_value( "active", 1 ); + } } - } + return layers; } -mapping _decode( string|mapping what, mapping|void opts ) +mapping _decode( string|mapping|object(GimpImage) what, mapping|void opts ) { if(!opts) opts = ([]); - - GimpImage data = __decode( what ); + GimpImage data; + if( objectp( what ) ) + data = what; + else + data = __decode( what ); what = 0; - Image.Layer res = Image.lay(decode_layers( data, opts ), - 0,0,data->width,data->height ); + int shrink = (opts->shrink_fact||1); + Image.Layer res = Image.lay(decode_layers( data, opts, 1 ), + 0,0,data->width/shrink,data->height/shrink ); Image.Image img = res->image(); Image.Image alpha = res->alpha(); res = 0; @@ -524,22 +491,22 @@ mapping _decode( string|mapping what, mapping|void opts ) foreach( data->guides, Guide g ) if(g->vertical) { - img->line( g->pos, 0, g->pos, img->ysize(), 0,155,0 ); + img->line( g->pos/shrink, 0, g->pos/shrink, img->ysize(), 0,155,0 ); if( alpha ) - alpha->line( g->pos, 0, g->pos, img->ysize(), 255,255,255 ); + alpha->line( g->pos/shrink,0,g->pos/shrink,img->ysize(), 255,255,255 ); } else { - img->line( 0,g->pos, img->xsize(), g->pos, 0,155,0 ); + img->line( 0,g->pos/shrink, img->xsize(), g->pos/shrink, 0,155,0 ); if( alpha ) - alpha->line( 0,g->pos, img->xsize(),g->pos, 255,255,255 ); + alpha->line( 0,g->pos/shrink, img->xsize(),g->pos/shrink, 255,255,255 ); } - if(opts->draw_selection) - if(data->selection) - img->paste_alpha_color( data->selection->image_data->img*0.25, - data->selection->r, data->selection->g, - data->selection->b ); +// if(opts->draw_selection) +// if(data->selection) +// img->paste_alpha_color( data->selection->image_data->img*0.25, +// data->selection->r, data->selection->g, +// data->selection->b ); if(opts->mark_layers) { @@ -547,10 +514,10 @@ mapping _decode( string|mapping what, mapping|void opts ) { if(l->flags->visible || opts->draw_all_layers) { - int x1 = l->xoffset; - int x2 = l->xoffset+l->width; - int y1 = l->yoffset; - int y2 = l->yoffset+l->height; + int x1 = l->xoffset/shrink; + int x2 = (l->xoffset+l->width)/shrink; + int y1 = (l->yoffset)/shrink; + int y2 = (l->yoffset+l->height)/shrink; img->setcolor(0,0,255); img->line( x1,y1,x2,y1 ); img->line( x2,y1,x2,y2 ); @@ -575,8 +542,8 @@ mapping _decode( string|mapping what, mapping|void opts ) if(l->flags->visible || opts->draw_all_layers) { int x, y; - int x1 = l->xoffset; - int y1 = l->yoffset+3; + int x1 = l->xoffset/shrink; + int y1 = (l->yoffset+3)/shrink; object a = opts->mark_layer_names->write( l->name ); for( x=-1; x<2; x++ ) for( y=-1; y<2; y++ ) @@ -594,10 +561,10 @@ mapping _decode( string|mapping what, mapping|void opts ) { if(data->active_layer) { - int x1 = data->active_layer->xoffset; - int x2 = data->active_layer->xoffset+data->active_layer->width; - int y1 = data->active_layer->yoffset; - int y2 = data->active_layer->yoffset+data->active_layer->height; + int x1 = data->active_layer->xoffset/shrink; + int x2 = (data->active_layer->xoffset+data->active_layer->width)/shrink; + int y1 = data->active_layer->yoffset/shrink; + int y2 = (data->active_layer->yoffset+data->active_layer->height)/shrink; img->setcolor(255,0,0); img->line( x1,y1,x2,y1 ); img->line( x2,y1,x2,y2 ); @@ -613,9 +580,8 @@ mapping _decode( string|mapping what, mapping|void opts ) } } } - - Array.map( data->layers, lambda(object o) { destruct(o); } ); - destruct( data ); +// Array.map( data->layers, lambda(object o) { destruct(o); } ); +// destruct( data ); return ([ "image":img, diff --git a/src/modules/Image/encodings/xcf.c b/src/modules/Image/encodings/xcf.c index e12caf542b1a3acfb73a56bffbff7f8c42e5f4f3..6a30262f38e2f76ea672c4a5bb4e9a85ca68c9c1 100644 --- a/src/modules/Image/encodings/xcf.c +++ b/src/modules/Image/encodings/xcf.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: xcf.c,v 1.21 2000/08/16 19:54:51 grubba Exp $"); +RCSID("$Id: xcf.c,v 1.22 2000/10/08 21:12:45 per Exp $"); #include "image_machine.h" @@ -21,6 +21,7 @@ RCSID("$Id: xcf.c,v 1.21 2000/08/16 19:54:51 grubba Exp $"); #include "operators.h" #include "dynamic_buffer.h" #include "signal_handler.h" +#include "bignum.h" #include "image.h" #include "colortable.h" @@ -48,10 +49,157 @@ extern struct program *image_program; struct buffer { + struct pike_string *s; + int base_offset; + int base_len; + size_t len; unsigned char *str; }; +struct substring +{ + struct pike_string *s; + int offset; + int len; +}; + +static struct program *substring_program; +#define SS(X) ((struct substring*)X->storage) + +static void f_substring_cast( INT32 args ) +{ + /* FIXME: assumes string */ + struct substring *s = SS(fp->current_object); + pop_n_elems( args ); + push_string( make_shared_binary_string( (((char *)s->s->str)+s->offset), + s->len ) ); +} + +static void f_substring_index( INT32 args ) +{ + int i = sp[-1].u.integer; + struct substring *s = SS(fp->current_object); + pop_n_elems( args ); + + if( i < 0 ) i = s->len + i; + if( i >= s->len ) error("Index out of bounds, %d > %d\n", i, s->len-1 ); + push_int( ((unsigned char *)s->s->str)[s->offset+i] ); +} + +static void f_substring__sprintf( INT32 args ) +{ + int x; + struct substring *s = SS(fp->current_object); + extern void f_sprintf( INT32 args ); + + if (args != 2 ) + SIMPLE_TOO_FEW_ARGS_ERROR("_sprintf",2); + if (sp[-2].type!=T_INT) + SIMPLE_BAD_ARG_ERROR("_sprintf",0,"integer"); + if (sp[-1].type!=T_MAPPING) + SIMPLE_BAD_ARG_ERROR("_sprintf",1,"mapping"); + x = sp[-2].u.integer; + pop_n_elems( args ); + + switch( x ) + { + case 't': + push_constant_text("SubString"); + return; + case 'O': + push_constant_text("SubString( %O /* [+%d .. %d] */ )" ); + push_text("string"); f_substring_cast( 1 ); + + push_int( s->len ); + push_int( s->offset ); + f_sprintf( 4 ); + return; + default: + push_int(0); + return; + } +} + +static void f_substring_get_int( INT32 args ) +{ + struct substring *s = SS(fp->current_object); + int res; + unsigned char *p; + int x = sp[-1].u.integer; + if( x > s->len>>2 ) + error("Index %d out of range", x ); + + p = s->s->str + s->offset + x*4; + res = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; + push_int( res ); +} + + +static void f_substring_get_uint( INT32 args ) +{ + struct substring *s = SS(fp->current_object); + unsigned int res; + unsigned char *p; + int x = sp[-1].u.integer; + if( x > s->len>>2 ) + error("Index %d out of range", x ); + + p = s->s->str + s->offset + x*4; + res = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; + push_int64( res ); +} + +static void f_substring_get_ushort( INT32 args ) +{ + struct substring *s = SS(fp->current_object); + unsigned short res; + unsigned char *p; + int x = sp[-1].u.integer; + if( x > s->len>>1 ) + error("Index %d out of range", x ); + + p = s->s->str + s->offset + x*2; + res = (p[2]<<8) | p[3]; + push_int( res ); +} + +static void f_substring_get_short( INT32 args ) +{ + struct substring *s = SS(fp->current_object); + short res; + unsigned char *p; + int x = sp[-1].u.integer; + if( x > s->len>>1 ) + error("Index %d out of range", x ); + + p = s->s->str + s->offset + x*2; + res = (p[2]<<8) | p[3]; + push_int( res ); +} + +static void push_substring( struct pike_string *s, + int offset, + int len ) +{ + struct object *o = clone_object( substring_program, 0 ); + struct substring *ss = SS(o); + ss->s = s; + s->refs++; + ss->offset = offset; + ss->len = len; + push_object( o ); +} + +static void free_substring( ) +{ + if( SS(fp->current_object)->s ) + { + free_string( SS(fp->current_object)->s ); + SS(fp->current_object)->s = 0; + } +} + typedef enum { @@ -153,7 +301,7 @@ 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]; + res = (from->str[0]<<24)|(from->str[1]<<16)|(from->str[2]<<8)|from->str[3]; from->str += 4; from->len -= 4; return res; @@ -164,7 +312,7 @@ static int xcf_read_int( struct buffer *from ) return (int)read_uint( from ); } -static char *read_data( struct buffer * from, size_t len ) +static char *read_data( struct buffer *from, size_t len ) { char *res; if( from->len < len ) @@ -178,8 +326,10 @@ static char *read_data( struct buffer * from, size_t len ) static struct buffer read_string( struct buffer *data ) { - struct buffer res; + struct buffer res = *data; res.len = xcf_read_int( data ); + res.base_len = res.len; + res.base_offset = data->base_offset+(data->base_len-data->len); res.str = (unsigned char *)read_data( data, res.len ); if(res.len > 0) res.len--; /* len includes ending \0 */ if(!res.str) @@ -198,10 +348,16 @@ static struct property read_property( struct buffer * data ) read_uint(data); /* bogus 'len'... */ foo = read_uint( data ); res.data.len = foo*3; + res.data.base_offset = data->base_offset+(data->base_len-data->len); + res.data.base_len = res.data.len; res.data.str = (unsigned char *)read_data( data,foo*3 ); + res.data.s = data->s; } else { res.data.len = read_uint( data ); + res.data.base_offset = data->base_offset+(data->base_len-data->len); + res.data.base_len = res.data.len; res.data.str = (unsigned char *)read_data( data,res.data.len ); + res.data.s = data->s; } res.next = NULL; return res; @@ -358,7 +514,7 @@ static struct level read_level( struct buffer *buff, ONERROR err; int offset; struct tile *last_tile = NULL; - int all_tiles_eq = 0; +/* int all_tiles_eq = 0; */ MEMSET(&res, 0, sizeof(res)); res.width = read_uint( buff ); res.height = read_uint( buff ); @@ -375,22 +531,9 @@ static struct level read_level( struct buffer *buff, 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; - else - ob.len = MINIMUM((TILE_WIDTH*TILE_HEIGHT*5),ob.len); 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 ); @@ -622,7 +765,8 @@ static struct gimp_image read_image( struct buffer * data ) static void push_buffer( struct buffer *b ) { - push_string( make_shared_binary_string( (char *)b->str, b->len ) ); + push_substring( b->s, b->base_offset+(b->base_len-b->len), b->len ); +/* push_string( make_shared_binary_string( (char *)b->str, b->len ) );*/ } static void push_properties( struct property *p ) @@ -757,7 +901,12 @@ static void image_xcf____decode( INT32 args ) if(args > 1) error("Too many arguments to Image.XCF.___decode()\n"); - b.str = (unsigned char *)s->str; b.len = s->len; + b.s = s; + b.base_offset = 0; + b.base_len = s->len; + b.len = s->len; + b.str = (unsigned char *)s->str; + res = read_image( &b ); SET_ONERROR( err, free_image, &res ); push_image( &res ); @@ -768,7 +917,7 @@ static void image_xcf____decode( INT32 args ) } -unsigned char read_char( struct buffer *from ) +static unsigned char read_char( struct buffer *from ) { unsigned char res = 0; if(from->len) @@ -780,72 +929,6 @@ unsigned char read_char( struct buffer *from ) return res; } - -void image_xcf_f__rle_decode( INT32 args ) -{ - struct pike_string *t; - struct buffer s; - struct buffer od, d; - INT_TYPE bpp, xsize, ysize, i; - get_all_args( "_rle_decode", args, "%S%d%d%d", &t, &bpp, &xsize, &ysize); - - s.len = t->len; - s.str = (unsigned char *)t->str; - od.len = xsize*ysize*bpp; /* Max and only size, really */ - od.str = (unsigned char *)xalloc( xsize*ysize*bpp ); - 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((char *)od.str,od.len)); - free(od.str); -} - /* **! method array(object) decode_layers( string data ) **! Decodes a XCF image to an array of Image.Layer objects @@ -1096,25 +1179,32 @@ void image_xcf_f__decode_tiles( INT32 args ) { struct object *io,*ao, *cmapo; struct array *tiles; - struct image *i, *a=NULL; + struct image *i=NULL, *a=NULL; struct neo_colortable *cmap = NULL; + int rxs, rys; rgb_group *colortable=NULL; - INT_TYPE rle, bpp, span; + INT_TYPE rle, bpp, span, shrink; 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); + get_all_args( "_decode_tiles", args, "%o%O%a%i%i%O%d%d%d", + &io, &ao, &tiles, &rle, &bpp, &cmapo, &shrink, &rxs, &rys); + + if( !(i = (struct image *)get_storage( io, image_program ))) error("Wrong type object argument 1 (image)\n"); + if(ao && !(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) + if(tiles->item[l].type != T_OBJECT) error("Wrong type array argument 3 (tiles)\n"); - if(a && (i->xsize != a->xsize ||i->ysize != a->ysize)) + + if(a && ((i->xsize != a->xsize) || (i->ysize != a->ysize))) error("Image and alpha objects are not identically sized.\n"); if(cmap) @@ -1123,117 +1213,185 @@ void image_xcf_f__decode_tiles( INT32 args ) image_colortable_write_rgb( cmap, (unsigned char *)colortable ); } - -/* switch(bpp) */ -/* { */ -/* case 1: */ -/* case 3: */ -/* if(ao) */ -/* { */ -/* destruct( ao ); */ -/* a=0; */ -/* ao=0; */ -/* } */ -/* break; */ -/* } */ - x=y=0; + + THREADS_ALLOW(); for(l=0; l<(unsigned)tiles->size; l++) { - struct pike_string *tile = tiles->item[l].u.string; + struct object *to = tiles->item[l].u.object; + struct substring *tile_ss = SS(to); + struct buffer tile; + char *df = 0; unsigned int eheight, ewidth; unsigned char *s; - ewidth = MINIMUM(TILE_WIDTH, i->xsize-x); - eheight = MINIMUM(TILE_HEIGHT, i->ysize-y); - add_ref(tile); -/* fprintf(stderr, " tile %d/%d [%dx%d] %dbpp \n", */ -/* l+1, tiles->size, ewidth, eheight,bpp); */ + if(!tile_ss) + continue; + + tile.str = (tile_ss->s->str + tile_ss->offset); + tile.len = tile_ss->len; + + ewidth = MINIMUM(TILE_WIDTH, (rxs-x)); + eheight = MINIMUM(TILE_HEIGHT, (rys-y)); if(rle) { - push_string( tile ); - push_int( bpp ); - push_int( ewidth ); - push_int( eheight ); - image_xcf_f__rle_decode( 4 ); - tile = (struct pike_string *)debug_malloc_pass(sp[-1].u.string); - if(sp[-1].type != T_STRING) - fatal("Internal disaster in XCF module\n"); - sp--; + struct buffer s = tile, od, d; + int i; + od.len = eheight*ewidth*bpp; /* Max and only size, really */ + df = od.str = (unsigned char *)xalloc( eheight*ewidth*bpp+1 ); + d = od; + + for(i=0; i<bpp; i++) + { + int nelems = ewidth*eheight; + 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--; + } + } + } + } + tile = od; } - if( (size_t)(tile->len) < (size_t)(eheight * ewidth * bpp )) - error("Too small tile, was %ld bytes, I really need %d\n", - DO_NOT_WARN((long)tile->len), - eheight*ewidth * bpp); +/* fprintf(stderr, "%d,%d + %d,%d <%d,%d * %d>\n", x, y, */ +/* ewidth, eheight, i->xsize, i->ysize, shrink ); */ - s = (unsigned char *)tile->str; + if( (size_t)(tile.len) < (size_t)(eheight * ewidth * bpp )) + { + if( df ) free( df ); df=0; + continue; + } + s = (unsigned char *)tile.str; + + +#define LOOP_INIT() {\ + int ix, iy=y/shrink; \ + for(cy=0; cy<eheight; cy+=shrink,iy=((cy+y)/shrink)) \ + { \ + int ind=cy*ewidth, bi=(i->xsize*iy); \ + int ds = 0; \ + if(iy >= i->ysize) continue; \ + ix= x/shrink; \ + for(cx=0; cx<ewidth; cx+=shrink,ind+=shrink,ix++) \ + { \ + rgb_group pix; \ + rgb_group apix; \ + if(ix >= i->xsize) continue + +#define LOOP_EXIT() \ + i->img[ix+bi] = pix; \ + if(a) a->img[ix+bi] = apix; \ + } \ + }} - check_signals(0,0,0); /* Allow ^C */ + if(rle) + span = ewidth*eheight; + else + span = 1; - for(cy=0; cy<eheight; cy++) + switch( bpp ) { - for(cx=0; cx<ewidth; cx++) - { - rgb_group pix; - rgb_group apix; - int ind = (cx+cy*ewidth); - - if(rle) - span = ewidth*eheight; - else - span = 1; - if(cx+x > (unsigned)i->xsize) continue; - if(cy+y > (unsigned)i->ysize) continue; - - 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; - if(a) a->img[ind] = apix; - } + case 1: /* indexed or grey */ + if(colortable) + { + LOOP_INIT(); + pix = colortable[s[ind]]; + LOOP_EXIT(); + } + else + { + LOOP_INIT(); + pix.r = pix.g = pix.b = s[ind]; + LOOP_EXIT(); + } + break; + case 2: /* indexed or grey with alpha */ + if(colortable) + { + LOOP_INIT(); + pix = colortable[s[ind]]; + apix.r = apix.g = apix.b = s[ind+span]; + LOOP_EXIT(); + } + else + { + LOOP_INIT(); + pix.r = pix.g = pix.b = s[ind]; + apix.r = apix.g = apix.b = s[ind+span]; + LOOP_EXIT(); + } + break; + case 3: /* rgb */ + LOOP_INIT(); + pix.r = s[ind]; + pix.g = s[ind+span]; + pix.b = s[ind+span*2]; + LOOP_EXIT(); + break; + case 4: /* rgb */ + LOOP_INIT(); + pix.r = s[ind]; + pix.g = s[ind+span]; + pix.b = s[ind+span*2]; + apix.r = apix.b = apix.g = s[ind+span*3]; + LOOP_EXIT(); + break; + } + + if( df ) + { + free(df); + df=0; } x += TILE_WIDTH; - if( x >= (unsigned)i->xsize ) + + if( x >= rxs ) { x = 0; y += TILE_HEIGHT; } - if(y>=(unsigned)i->ysize) - { - free_string(tile); - if(colortable) free( colortable ); - return; - } - free_string(tile); + /* Not exactly likely to happen, and the test consumes some CPU */ + /* if(y>=(unsigned)(i->ysize*shrink)) */ + /* break; */ } - if(colortable) free( colortable ); + THREADS_DISALLOW(); + if(colortable) + free( colortable ); pop_n_elems(args); push_int(0); @@ -1322,6 +1480,20 @@ void init_image_xcf() #define STRING(X) s_##X = make_shared_binary_string(#X,sizeof( #X )-sizeof("")) #include "xcf_constant_strings.h" #undef STRING + + start_new_program(); + ADD_STORAGE( struct substring ); + add_function("cast", f_substring_cast, "function(string:mixed)",0); + add_function("`[]", f_substring_index, "function(int:int)",0); + add_function("get_short", f_substring_get_short, "function(int:int)", 0 ); + add_function("get_ushort", f_substring_get_ushort, "function(int:int)", 0 ); + add_function("get_int", f_substring_get_int, "function(int:int)", 0 ); + add_function("get_uint", f_substring_get_uint, "function(int:int)", 0 ); + add_function("_sprintf",f_substring__sprintf, + "function(int,mapping:mixed)", 0); +/* set_init_callback(init_substring); */ + set_exit_callback(free_substring); + substring_program = end_program(); } @@ -1330,4 +1502,5 @@ void exit_image_xcf() #define STRING(X) free_string(s_##X) #include "xcf_constant_strings.h" #undef STRING + free_program( substring_program ); }