bc73c61999-04-11Per Hedbor inherit Image._XCF;
fb14c42000-09-06Per Hedbor #define SIGNED(X) if(X>=(1<<31)) X=-((1<<32)-X)
bc73c61999-04-11Per Hedbor class PathPoint { int type; float x; float y; } class Path { string name; int ptype; int tattoo; int closed; int state; int locked; array (PathPoint) points = ({}); } class Guide { int pos; int vertical; void create(string data) {
79757c1999-04-12Per Hedbor  sscanf(data, "%4c%c", pos,vertical);vertical--;
fb14c42000-09-06Per Hedbor  SIGNED(pos);
bc73c61999-04-11Per Hedbor  } } class Parasite { string name; int flags; string data; void create( string _n, int _f, string _d ) { name = _n; data = _d; flags = _f; } } array(Parasite) decode_parasites( string data ) { array res = ({}); while(strlen(data)) { int slen, flags; string value, name; sscanf(data, "%4c", slen); name = data[..slen-2]; data = data[slen..]; sscanf(data, "%4c%4c", flags, slen);
e6c0c42000-02-08Per Hedbor  res += ({ Parasite( name,flags,data[8..slen+8-1] ) });
bc73c61999-04-11Per Hedbor  data = data[slen+8..]; } 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;
fb14c42000-09-06Per Hedbor #define SINT(X,Y) case PROP_##X: sscanf(p->data, "%4c", Y); SIGNED(Y); break;
bc73c61999-04-11Per Hedbor  class Hierarchy { Image.image img; Image.image alpha; int width; int height; int bpp;
e6c0c42000-02-08Per Hedbor 
0e02e91999-04-11Per Hedbor  Hierarchy set_image( int x, int y, int bp, array tiles, int compression, Image.colortable cmap)
bc73c61999-04-11Per Hedbor  { width = x; height = y; bpp = bp; img = Image.image( x, y, 0,0,0 );
79757c1999-04-12Per Hedbor  if(!(bp & 1 )) alpha = Image.image( x, y, 255,255,255 );
bc73c61999-04-11Per Hedbor  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"); }
0e02e91999-04-11Per Hedbor  return this_object();
bc73c61999-04-11Per Hedbor  }
0e02e91999-04-11Per Hedbor  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(); } Hierarchy copy() {
79757c1999-04-12Per Hedbor  return Hierarchy()->qsi( img,alpha,width,height,bpp );
0e02e91999-04-11Per Hedbor  } Hierarchy get_opaqued( int opaque_value ) { Hierarchy res = copy(); if(opaque_value != 255)
79757c1999-04-12Per Hedbor  { if(res->alpha) res->alpha *= opaque_value/255.0; else res->alpha = Image.image(width,height, opaque_value,opaque_value,opaque_value); }
0e02e91999-04-11Per Hedbor  return res; }
bc73c61999-04-11Per Hedbor } int iid; Hierarchy decode_image_data( mapping what, object i ) {
e6c0c42000-02-08Per Hedbor  Hierarchy h =
0e02e91999-04-11Per Hedbor  Hierarchy( )->set_image(what->width, what->height, what->bpp, what->tiles, i->compression, i->colormap );
bc73c61999-04-11Per Hedbor  return h; } 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; void decode_properties( array properties ) { foreach(properties, mapping p) { switch(p->type) { case PROP_ACTIVE_CHANNEL: parent->active_channel = this_object(); break; case PROP_SELECTION: parent->selection = this_object(); break; INT(OPACITY,opacity); FLAG(VISIBLE,visible); FLAG(LINKED,linked); FLAG(PRESERVE_TRANSPARENCY,preserve_transparency); FLAG(EDIT_MASK,edit_mask); FLAG(SHOW_MASKED,show_masked); INT(TATTOO,tattoo); case PROP_COLOR: sscanf( p->data, "%c%c%c", r, g, b); break;
e6c0c42000-02-08Per Hedbor 
bc73c61999-04-11Per Hedbor  case PROP_PARASITES: parasites = decode_parasites( p->data ); break; } } } void create( mapping d, object p ) { parent = p; name = d->name; width = d->width; height = d->height; image_data = decode_image_data( d->image_data, parent ); if(d->properties) decode_properties( d->properties ); } } class LayerMask { inherit Channel; } 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; object parent; void decode_properties( array properties ) { foreach( properties, mapping p) { switch(p->type) { case PROP_ACTIVE_LAYER: parent->active_layer = this_object(); break; case PROP_SELECTION: parent->selection = this_object(); break;
0e02e91999-04-11Per Hedbor  case PROP_OFFSETS: sscanf(p->data, "%4c%4c", xoffset, yoffset);
fb14c42000-09-06Per Hedbor  SIGNED(xoffset); SIGNED(yoffset);
0e02e91999-04-11Per Hedbor  break;
bc73c61999-04-11Per Hedbor  INT(OPACITY,opacity); FLAG(VISIBLE,visible);
0e02e91999-04-11Per Hedbor  FLAG(LINKED,linked); FLAG(PRESERVE_TRANSPARENCY,preserve_transparency); FLAG(APPLY_MASK,apply_mask); FLAG(EDIT_MASK,edit_mask); FLAG(SHOW_MASK,show_mask); INT(MODE,mode);
bc73c61999-04-11Per Hedbor  INT(TATTOO,tattoo); case PROP_PARASITES: parasites = decode_parasites( p->data ); break; } } } void create( mapping data, object pa ) { parent = pa; name = data->name; type = data->type; width = data->width; height = data->height; decode_properties( data->properties ); image = decode_image_data( data->image_data, pa ); if(data->mask) mask = LayerMask( data->mask, pa ); } } 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;
79757c1999-04-12Per Hedbor  array(Layer) layers = ({}); // bottom-to-top array(Channel) channels = ({}); // unspecified order, really
bc73c61999-04-11Per Hedbor  array(Guide) guides = ({}); array(Parasite) parasites = ({}); array(Path) paths = ({}); Layer active_layer; Channel active_channel; Channel selection; static string read_point_bz1( string data, Path path ) { object p = PathPoint( ); int x, y; sscanf(data, "%4c%4c%4c%s", p->type, x, y);
fb14c42000-09-06Per Hedbor  SIGNED(x); SIGNED(y);
bc73c61999-04-11Per Hedbor  p->x = (float)x; p->y = (float)y; return data; } static string read_point_bz2( string data, Path path ) { object p = PathPoint( ); sscanf(data, "%4c%4F%4F%s", p->type, p->x, p->y); return data; } static string decode_one_path( string data, Path path ) { int nlen, version, num_points; sscanf(data, "%4c", nlen ); path->name = data[..nlen-2]; data = data[nlen..]; sscanf(data, "%4c%4c%4c%4c%4c", path->locked, path->state, path->closed, num_points, version); switch(version) { case 1: while(num_points--) data = read_point_bz1( data, path ); break; case 2: sscanf(data, "%4c%s", path->ptype, data ); while(num_points--) data = read_point_bz2( data, path ); break; case 3: sscanf(data, "%4%4cc%s", path->ptype, path->tattoo, data ); while(num_points--) data = read_point_bz2( data, path ); break; default: data =""; } return data; } array(Path) decode_paths( string data ) { int last_selected_row; int num_paths; array res = ({}); sscanf( data, "%4c%4c%s", last_selected_row, num_paths, data ); while(num_paths--) { Path path = Path(); data = decode_one_path( data, path ); res += ({ path }); } return res; } void decode_properties(array props) { foreach( props, mapping p) { switch(p->type) { case PROP_COLORMAP: if(type == INDEXED)
e6c0c42000-02-08Per Hedbor  meta_colormap = colormap = Image.colortable( p->data );
bc73c61999-04-11Per Hedbor  else meta_colormap = Image.colortable( p->data ); break;
79757c1999-04-12Per Hedbor  case PROP_COMPRESSION: compression = p->data[0]; break;
bc73c61999-04-11Per Hedbor  case PROP_GUIDES: guides = Array.map(p->data/5,Guide); break; case PROP_RESOLUTION: sscanf( p->data, "%4f%4f", xres,yres); if (xres < 1e-5 || xres> 1e+5 || yres<1e-5 || yres>1e+5) xres = yres = 72.0; break;
e6c0c42000-02-08Per Hedbor  case PROP_TATTOO: sscanf(p->data, "%4c", tattoo_state );
bc73c61999-04-11Per Hedbor  break; case PROP_PARASITES: parasites = decode_parasites( p->data ); break; case PROP_UNIT:
e6c0c42000-02-08Per Hedbor  sscanf(p->data, "%4c", res_unit );
bc73c61999-04-11Per Hedbor  break; case PROP_PATHS: paths = decode_paths( p->data ); break; case PROP_USER_UNIT: /* NYI */ break; } } } void create( mapping data ) { type = data->type; decode_properties( data->properties ); width = data->width; height = data->height; foreach(data->layers, mapping l ) layers += ({ Layer( l, this_object() ) }); foreach(data->channels, mapping c ) channels += ({ Channel( c, this_object() ) }); } } GimpImage __decode( string|mapping what ) {
79757c1999-04-12Per Hedbor  if(stringp(what)) what = ___decode( what );
bc73c61999-04-11Per Hedbor  return GimpImage(what); }
c1be651999-07-01Per Hedbor string translate_mode( int mode ) { switch( mode ) { case NORMAL_MODE: return "normal"; case MULTIPLY_MODE: return "multiply"; case ADDITION_MODE: return "add"; case DIFFERENCE_MODE: return "difference"; case SUBTRACT_MODE: return "subtract"; case DIVIDE_MODE: return "divide"; case DISSOLVE_MODE: return "dissolve"; case DARKEN_ONLY_MODE: return "min"; case LIGHTEN_ONLY_MODE:return "max"; case HUE_MODE: return "hue"; case SATURATION_MODE: return "saturation"; case COLOR_MODE: return "color"; case VALUE_MODE: return "value"; case SCREEN_MODE: return "screen"; case OVERLAY_MODE: return "overlay"; default: werror("WARNING: XCF: Unsupported mode: "+mode+"\n"); return "normal"; } }
79757c1999-04-12Per Hedbor 
9b68cc1999-07-16Per Hedbor array decode_layers( string|object|mapping what, mapping|void opts )
bc73c61999-04-11Per Hedbor {
0e02e91999-04-11Per Hedbor  if(!opts) opts = ([]);
79757c1999-04-12Per Hedbor 
9b68cc1999-07-16Per Hedbor  if(!objectp( what ) ) what = __decode( what );
e6c0c42000-02-08Per Hedbor 
c1be651999-07-01Per Hedbor  mapping lopts = ([ "tiled":1, ]);
e6c0c42000-02-08Per Hedbor  array layers = ({});
c1be651999-07-01Per Hedbor  if( opts->background ) { lopts->image = Image.Image( 32, 32, opts->background );
9b68cc1999-07-16Per Hedbor  lopts->alpha = Image.Image( 32, 32, Image.Color.white );
c1be651999-07-01Per Hedbor  lopts->alpha_value = 1.0;
e6c0c42000-02-08Per Hedbor  layers = ({ Image.Layer( lopts ) });
c1be651999-07-01Per Hedbor  }
0e02e91999-04-11Per Hedbor 
9b68cc1999-07-16Per Hedbor  foreach(what->layers, object l)
0e02e91999-04-11Per Hedbor  {
79757c1999-04-12Per Hedbor  if(l->flags->visible || opts->draw_all_layers)
0e02e91999-04-11Per Hedbor  {
c1be651999-07-01Per Hedbor  Hierarchy h = l->image; Image.Layer lay = Image.Layer( h->img, h->alpha, translate_mode( l->mode ) );
e6c0c42000-02-08Per Hedbor  /* 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 );
c1be651999-07-01Per Hedbor  h->img = 0; h->alpha = 0;
79757c1999-04-12Per Hedbor 
c1be651999-07-01Per Hedbor  lay->set_alpha_value( l->opacity / 255.0 ); lay->set_offset( l->xoffset, l->yoffset );
79757c1999-04-12Per Hedbor 
c1be651999-07-01Per Hedbor  if(l->mask && l->flags->apply_mask)
0e02e91999-04-11Per Hedbor  {
c1be651999-07-01Per Hedbor  l->mask = 0; object a = l->alpha(); if(a) a *= l->mask->image; else a = l->mask->image; if( a->xsize() != l->image->img->xsize() || a->ysize() != l->image->img->ysize() )
e6c0c42000-02-08Per Hedbor  a = a->copy( 0,0, l->image->image->xsize(),
c1be651999-07-01Per Hedbor  l->image->image->ysize(), 255,255,255 ); lay->set_alpha( a );
0e02e91999-04-11Per Hedbor  }
c1be651999-07-01Per Hedbor  layers += ({ lay });
0e02e91999-04-11Per Hedbor  } }
9b68cc1999-07-16Per Hedbor  return layers; }
0e02e91999-04-11Per Hedbor 
9b68cc1999-07-16Per Hedbor mapping _decode( string|mapping what, mapping|void opts ) { if(!opts) opts = ([]); GimpImage data = __decode( what ); what = 0;
e6c0c42000-02-08Per Hedbor 
9b68cc1999-07-16Per Hedbor  Image.Layer res = Image.lay(decode_layers( data, opts ), 0,0,data->width,data->height );
c1be651999-07-01Per Hedbor  Image.Image img = res->image(); Image.Image alpha = res->alpha(); res = 0;
79757c1999-04-12Per Hedbor  if(opts->draw_guides) foreach( data->guides, Guide g ) if(g->vertical)
c1be651999-07-01Per Hedbor  {
79757c1999-04-12Per Hedbor  img->line( g->pos, 0, g->pos, img->ysize(), 0,155,0 );
c1be651999-07-01Per Hedbor  if( alpha ) alpha->line( g->pos, 0, g->pos, img->ysize(), 255,255,255 ); }
79757c1999-04-12Per Hedbor  else
c1be651999-07-01Per Hedbor  { img->line( 0,g->pos, img->xsize(), g->pos, 0,155,0 ); if( alpha ) alpha->line( 0,g->pos, img->xsize(),g->pos, 255,255,255 ); }
79757c1999-04-12Per Hedbor  if(opts->draw_selection) if(data->selection) img->paste_alpha_color( data->selection->image_data->img*0.25,
c1be651999-07-01Per Hedbor  data->selection->r, data->selection->g,
79757c1999-04-12Per Hedbor  data->selection->b ); if(opts->mark_layers) { foreach(data->layers, Layer l) { 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;
9642201999-11-24Per Hedbor  img->setcolor(0,0,255);
79757c1999-04-12Per Hedbor  img->line( x1,y1,x2,y1 ); img->line( x2,y1,x2,y2 ); img->line( x2,y2,x1,y2 ); img->line( x1,y2,x1,y1 );
e6c0c42000-02-08Per Hedbor  if(alpha)
c1be651999-07-01Per Hedbor  {
9642201999-11-24Per Hedbor  alpha->setcolor(0,0,255);
c1be651999-07-01Per Hedbor  alpha->line( x1,y1,x2,y1 ); alpha->line( x2,y1,x2,y2 ); alpha->line( x2,y2,x1,y2 ); alpha->line( x1,y2,x1,y1 ); }
79757c1999-04-12Per Hedbor  } } }
e6c0c42000-02-08Per Hedbor 
79757c1999-04-12Per Hedbor  if(opts->mark_layer_names) { foreach(data->layers, Layer l) { if(l->flags->visible || opts->draw_all_layers) {
c1be651999-07-01Per Hedbor  int x, y;
79757c1999-04-12Per Hedbor  int x1 = l->xoffset; int y1 = l->yoffset+3;
c1be651999-07-01Per Hedbor  object a = opts->mark_layer_names->write( l->name ); for( x=-1; x<2; x++ ) for( y=-1; y<2; y++ ) { img->paste_alpha_color( a, 0,0,0, x1+x, y1+y ); if(alpha) alpha->paste_alpha_color(a,255,255,255, x1+x,y1+y ); } img->paste_alpha_color( a, 255,255,255, x1, y1 );
79757c1999-04-12Per Hedbor  } } } if(opts->mark_active_layer) { 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; img->setcolor(255,0,0); img->line( x1,y1,x2,y1 ); img->line( x2,y1,x2,y2 ); img->line( x2,y2,x1,y2 ); img->line( x1,y2,x1,y1 );
e6c0c42000-02-08Per Hedbor  if(alpha)
c1be651999-07-01Per Hedbor  {
9642201999-11-24Per Hedbor  alpha->setcolor(0,0,255);
c1be651999-07-01Per Hedbor  alpha->line( x1,y1,x2,y1 ); alpha->line( x2,y1,x2,y2 ); alpha->line( x2,y2,x1,y2 ); alpha->line( x1,y2,x1,y1 ); }
79757c1999-04-12Per Hedbor  } }
c1be651999-07-01Per Hedbor 
d15a431999-11-25Henrik Grubbström (Grubba)  Array.map( data->layers, lambda(object o) { destruct(o); } );
c1be651999-07-01Per Hedbor  destruct( data );
e6c0c42000-02-08Per Hedbor  return
c1be651999-07-01Per Hedbor  ([
0e02e91999-04-11Per Hedbor  "image":img, "alpha":alpha, ]);
bc73c61999-04-11Per Hedbor }
0e02e91999-04-11Per Hedbor object decode( string what,mapping|void opts )
bc73c61999-04-11Per Hedbor {
0e02e91999-04-11Per Hedbor  return _decode( what,opts )->image;
bc73c61999-04-11Per Hedbor }