From 2767d58eaa53ab054ddbc26c71a905e1ac06349b Mon Sep 17 00:00:00 2001 From: Per Hedbor <ph@opera.com> Date: Sat, 17 Apr 1999 03:25:48 +0200 Subject: [PATCH] Now actually works with almost all photoshop images Rev: lib/modules/_Image_PSD.pmod:1.3 Rev: src/modules/Image/encodings/psd.c:1.5 --- lib/modules/_Image_PSD.pmod | 84 +++++++++--- src/modules/Image/encodings/psd.c | 205 +++++++++++++++++++++++------- 2 files changed, 228 insertions(+), 61 deletions(-) diff --git a/lib/modules/_Image_PSD.pmod b/lib/modules/_Image_PSD.pmod index e5c5865188..70388180bd 100644 --- a/lib/modules/_Image_PSD.pmod +++ b/lib/modules/_Image_PSD.pmod @@ -11,6 +11,10 @@ class Layer int xoffset, yoffset; int width, height; + int mask_flags; + int mask_xoffset, mask_yoffset; + int mask_width, mask_height; + Layer copy() { @@ -56,7 +60,18 @@ Layer decode_layer(mapping layer, mapping i) l->mode = layer->mode; l->flags = layer->flags; + l->mask_width = layer->mask_right-layer->mask_left; + l->mask_height = layer->mask_bottom-layer->mask_top; + l->mask_xoffset = layer->mask_left; + l->mask_yoffset = layer->mask_top; + + if( !(l->mask_flags & 1 ) ) // pos relative to layer + { + l->mask_xoffset -= l->xoffset; + l->mask_yoffset -= l->yoffset; + } array colors; + int inverted; switch(i->mode) { case Greyscale: @@ -70,35 +85,67 @@ Layer decode_layer(mapping layer, mapping i) ({0,0,255,}), }) + ({ 255,255,255 }) * 24; break; + case CMYK: + inverted = 1; + colors = ({ ({255,0,0,}), + ({0,255,0,}), + ({0,0,255,}), + }) + ({ 255,255,255 }) * 24; + break; case Indexed: use_cmap = 1; - error("Tell per to fix colormap support\n"); break; default: werror("Unsupported mode (for now), using greyscale\n"); - colors = ({ - 255,255,255 - })*24; + colors = ({ 255,255,255 })*24; break; } foreach(layer->channels, mapping c) { - object tmp =___decode_image_channel(l->width,l->height,c->data); - + object tmp; + if( c->id != -2) + tmp = ___decode_image_channel(l->width, l->height, c->data); + else + tmp = ___decode_image_channel(l->mask_width,l->mask_height,c->data); + switch(c->id) { default: - l->image->paste_alpha_color( tmp, @colors[c->id%24] ); + if(!use_cmap) + { + if(inverted) + l->image -= tmp*colors[c->id%sizeof(colors)]; + else + l->image += tmp*colors[c->id%sizeof(colors)]; + } else { + __apply_cmap( tmp, i->color_data ); + l->image = tmp; + } break; case -1: /* alpha */ - l->alpha = tmp; - break; - case -2: /* user mask */ if(!l->alpha) l->alpha = tmp; else l->alpha *= tmp; break; + case -2: /* user mask */ + if(!(l->mask_flags & 2 )) /* layer mask disabled */ + { + array pad_color = ({255,255,255}); + if( (l->mask_flags & 4 ) ) /* invert mask */ + tmp = tmp->invert(); + + tmp = tmp->copy( -l->mask_xoffset, -l->mask_yoffset, + l->image->xsize()-1, l->image->ysize()-1, + @pad_color ) + ->copy(0,0,l->image->xsize()-1,l->image->ysize()-1, + @pad_color); + if(!l->alpha) + l->alpha = tmp; + else + l->alpha *= tmp; + break; + } } } return l; @@ -137,11 +184,12 @@ array(object) decode_background( mapping data, array bg ) object img, alpha; if( !bg ) alpha = Image.image(data->width, data->height); - -// if( data->image_data ) -// img = ___decode_image_data(data->width, data->height, -// data->channels, data->image_data); -// else + if( data->image_data ) + img = ___decode_image_data(data->width, data->height, + data->channels, data->mode, + data->compression, data->image_data, + data->color_data); + else img = Image.image( data->width, data->height, @((bg&&(array)bg)||({255,255,255}))); return ({ img, alpha }); @@ -150,6 +198,7 @@ array(object) decode_background( mapping data, array bg ) mapping _decode( string|mapping what, mapping|void opts ) { mapping data; +mixed e =catch{ if(!opts) opts = ([]); if(mappingp(what)) data = what; @@ -162,7 +211,7 @@ mapping _decode( string|mapping what, mapping|void opts ) foreach(reverse(data->layers), object l) { -// if((l->flags & LAYER_FLAG_VISIBLE)|| opts->draw_all_layers) + if((l->flags & LAYER_FLAG_VISIBLE) || opts->draw_all_layers) { Layer h = l->get_opaqued( l->opacity ); @@ -172,7 +221,6 @@ mapping _decode( string|mapping what, mapping|void opts ) PASTE_ALPHA(h->image,h->alpha); break; - case "mul ": object oi = IMG_SLICE(l,h); oi *= h->image; @@ -208,4 +256,6 @@ mapping _decode( string|mapping what, mapping|void opts ) "image":img, "alpha":alpha, ]); +}; + werror(describe_backtrace(e)); } diff --git a/src/modules/Image/encodings/psd.c b/src/modules/Image/encodings/psd.c index ab309081f4..61fb371982 100644 --- a/src/modules/Image/encodings/psd.c +++ b/src/modules/Image/encodings/psd.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: psd.c,v 1.4 1999/04/15 20:31:49 per Exp $"); +RCSID("$Id: psd.c,v 1.5 1999/04/17 01:25:48 per Exp $"); #include "config.h" @@ -162,6 +162,14 @@ struct layer unsigned int left; unsigned int right; unsigned int bottom; + + unsigned int mask_top; + unsigned int mask_left; + unsigned int mask_right; + unsigned int mask_bottom; + unsigned int mask_default_color; + unsigned int mask_flags; + unsigned int opacity; unsigned int num_channels; unsigned int clipping; @@ -220,6 +228,21 @@ static void decode_layers_and_masks( struct psd_image *dst, layer->flags = read_uchar( src ); read_uchar( src ); layer->extra_data = read_string( src ); + if(layer->extra_data.len) + { + struct buffer tmp = layer->extra_data; + struct buffer tmp2; + tmp2 = read_string( &tmp ); + if( tmp2.len ) + { + layer->mask_top = read_int( &tmp2 ); + layer->mask_left = read_int( &tmp2 ); + layer->mask_bottom = read_int( &tmp2 ); + layer->mask_right = read_int( &tmp2 ); + layer->mask_default_color = read_uchar( &tmp2 ); + layer->mask_flags = read_uchar( &tmp2 ); + } + } } while(layer->next) layer = layer->next; @@ -284,25 +307,37 @@ packbitsdecode(struct buffer src, static void f_decode_packbits_encoded(INT32 args) { - struct pike_string *src = sp[-3].u.string; - int nelems = sp[-2].u.integer; - int width = sp[-1].u.integer; + struct pike_string *src = sp[-args].u.string; + int nelems = sp[-args+1].u.integer; + int width = sp[-args+2].u.integer; struct pike_string *dest; + int compression = 0; struct buffer b, ob, d; - if(args != 3) - error("internal argument error 2"); - if(sp[-3].type != T_STRING) + if(sp[-args].type != T_STRING) error("internal argument error"); - pop_n_elems(2); - if( src->str[0] ) - error("Impossible compression (%d)!\n", (src->str[0]<<8|src->str[1]) ); - b.str = src->str+2; - b.len = src->len-2; + + if(args == 5) + { + nelems *= sp[-args+3].u.integer; + compression = sp[-args+4].u.integer; + b.str = src->str; + b.len = src->len; + pop_n_elems(4); + } else if(args == 3) { + if( src->str[0] ) + error("Impossible compression (%d)!\n", (src->str[0]<<8|src->str[1]) ); + compression = src->str[1]; + b.str = src->str+2; + b.len = src->len-2; + pop_n_elems(2); + } + ob = b; ob.str += nelems*2; ob.len -= nelems*2; - switch(src->str[1]) + + switch(compression) { case 1: push_text(""); @@ -316,8 +351,7 @@ static void f_decode_packbits_encoded(INT32 args) } break; case 0: - push_string( make_shared_binary_string(((char *)src->str)+2, - src->len-2 ) ); + push_string( make_shared_binary_string(b.str,b.len)); break; default: error("Impossible compression (%d)!\n", src->str[1]); @@ -359,34 +393,84 @@ static void f_decode_image_channel( INT32 args ) -/* static void f_decode_image_data( INT32 args ) */ -/* { */ -/* INT32 w, h, c, d; */ -/* int y; */ -/* struct pike_string *s; */ -/* struct object *io; */ -/* unsigned char *source; */ -/* rgb_group *dst; */ -/* get_all_args( "_decode_image_channel",args, "%d%d%S", &w,&h,&s); */ +static void f_decode_image_data( INT32 args ) +{ + INT32 w, h, c, d, m; + int y; + struct pike_string *s, *ct; + struct object *io; + unsigned char *source, *source2, *source3, *source4; + rgb_group *dst; + get_all_args( "_decode_image_data",args, "%d%d%d%d%d%S%S", + &w,&h,&d,&m,&c,&s,&ct); -/* ref_push_string( s ); */ -/* push_int( h ); */ -/* push_int( w ); */ -/* f_decode_packbits_encoded( 3 ); */ -/* s = sp[-1].u.string; */ -/* stack_swap(); */ -/* pop_stack(); */ -/* if(s->len < w*h) */ -/* error("Not enough data in string for this channel\n"); */ -/* source = s->str; */ -/* push_int( w ); push_int( h ); */ -/* io = clone_object( image_program, 2 ); */ -/* dst = ((struct image *)get_storage(io,image_program))->img; */ -/* for(y=0; y<w*h; y++) */ -/* dst->r = dst->g = (dst++)->b = *(source++); */ -/* pop_n_elems(args); */ -/* push_object( io ); */ -/* } */ + if(!ct->len) ct = NULL; + + ref_push_string( s ); + push_int( h ); + push_int( w ); + push_int( d ); + push_int( c ); + f_decode_packbits_encoded( 5 ); + s = sp[-1].u.string; + stack_swap(); + pop_stack(); + if(s->len < w*h*d) + error("Not enough data in string for this channel\n"); + source = s->str; + source2 = s->str+w*h; + source3 = s->str+w*h*2; + source4 = s->str+w*h*3; + push_int( w ); push_int( h ); + io = clone_object( image_program, 2 ); + dst = ((struct image *)get_storage(io,image_program))->img; + for(y=0; y<w*h; y++) + { + switch( d ) + { + case 4: + /* cmyk.. */ + dst->r = dst->g = dst->b = 255; + dst->r -= *(source++); + dst->g -= *(source2++); + dst->b -= *(source3++); + if(dst->r > *source4) + dst->r -= *source4; + else + dst->r = 0; + if(dst->g > *source4) + dst->g -= *source4; + else + dst->g = 0; + if(dst->b > *source4) + dst->b -= *source4; + else + dst->b = 0; + source4++; + break; + case 3: + dst->r = *(source++); + dst->g = *(source2++); + (dst++)->b = *(source3++); + break; + case 2: + case 1: + if(ct) + { + dst->r = ct->str[*source]; + dst->g = ct->str[*source+256]; + dst->b = ct->str[*source+256*2]; + *source++; + *dst++; + } + else + dst->r = dst->g = (dst++)->b = *(source++); + break; + } + } + pop_n_elems(args); + push_object( io ); +} @@ -437,6 +521,11 @@ void push_layer( struct layer *l) ref_push_string( s_left ); push_int( l->left ); ref_push_string( s_right ); push_int( l->right ); ref_push_string( s_bottom ); push_int( l->bottom ); + ref_push_string( s_mask_top ); push_int( l->mask_top ); + ref_push_string( s_mask_left ); push_int( l->mask_left ); + ref_push_string( s_mask_right ); push_int( l->mask_right ); + ref_push_string( s_mask_bottom ); push_int( l->mask_bottom ); + ref_push_string( s_mask_flags ); push_int( l->mask_flags ); ref_push_string( s_opacity ); push_int( l->opacity ); ref_push_string( s_clipping ); push_int( l->clipping ); ref_push_string( s_flags ); push_int( l->flags ); @@ -509,6 +598,33 @@ static void image_f_psd___decode( INT32 args ) } } +static void f_apply_cmap( INT32 args ) +{ + struct object *io; + struct image *i; + rgb_group *d; + struct pike_string *cmap; + int n; + get_all_args( "apply_cmap", args, "%o%S", &io, &cmap ); + if(cmap->len < 256*3) + error("Invalid colormap resource\n"); + if(!(i = (struct image *)get_storage( io, image_program ))) + error("Invalid image object\n"); + n = i->xsize * i->ysize; + d = i->img; + THREADS_ALLOW(); + while(n--) + { + int i = d->g; + d->r = cmap->str[i]; + d->g = cmap->str[i+256]; + d->b = cmap->str[i+512]; + } + THREADS_DISALLOW(); + pop_n_elems(args); + push_int(0); +} + static struct program *image_encoding_psd_program=NULL; void init_image_psd() { @@ -517,8 +633,9 @@ void init_image_psd() "function(string:mapping)", 0); add_function( "___decode_image_channel", f_decode_image_channel, "mixed", 0); -/* add_function( "___decode_image_data", f_decode_image_data, */ -/* "mixed", 0); */ + add_function( "___decode_image_data", f_decode_image_data, + "mixed", 0); + add_function( "__apply_cmap", f_apply_cmap, "mixed", 0); add_integer_constant("Bitmap" , Bitmap, 0 ); add_integer_constant("Greyscale" , Greyscale, 0 ); -- GitLab