diff --git a/src/modules/Image/encodings/gif.c b/src/modules/Image/encodings/gif.c index 8208f8e9556237e3d7e24c33a3cf0ecd6e0f799a..5f07139747fc37f1f59d67521ba88dc8d5589275 100644 --- a/src/modules/Image/encodings/gif.c +++ b/src/modules/Image/encodings/gif.c @@ -1,9 +1,9 @@ -/* $Id: gif.c,v 1.7 1997/11/02 18:50:30 grubba Exp $ */ +/* $Id: gif.c,v 1.8 1997/11/03 01:39:36 mirar Exp $ */ /* **! module Image **! note -**! $Id: gif.c,v 1.7 1997/11/02 18:50:30 grubba Exp $ +**! $Id: gif.c,v 1.8 1997/11/03 01:39:36 mirar Exp $ **! submodule GIF **! **! This submodule keep the GIF encode/decode capabilities @@ -21,7 +21,7 @@ #include "stralloc.h" #include "global.h" -RCSID("$Id: gif.c,v 1.7 1997/11/02 18:50:30 grubba Exp $"); +RCSID("$Id: gif.c,v 1.8 1997/11/03 01:39:36 mirar Exp $"); #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -47,25 +47,6 @@ extern void f_add(INT32 args); goal: -string encode(object img); -string encode(object img,int colors); -string encode(object img,object colortable); - Simply make a complete GIF file. - -string encode_transparent(object img,object alpha); -string encode_transparent(object img,object alpha,int r,int g,int b); -string encode_transparent(object img,int colors,int r,int g,int b); -string encode_transparent(object img,int colors,object alpha,int r,int g,int b); -string encode_transparent(object img,object colortable,object alpha); -string encode_transparent(object img,object colortable,object alpha,int r,int g,int b); -string encode_transparent(object img,object colortable,int transp_index); - Simply make a complete GIF file with transparency; - Transparency is taken from the given alpha mask - (black=transparent), the color closest(!) to the given, or - by the given index in the colortable. The following r,g,b - values gives the possibility of setting the transparent color - (some decoders ignore the transparency). - object decode(string data); Decode GIF data to one (!) image object. @@ -75,18 +56,8 @@ object decode_alpha(string data); advanced: -string header_block(int xsize,int ysize,int numcolors); -string header_block(int xsize,int ysize,object colortable); -string header_block(int xsize,int ysize,object colortable,int background_color_index); -string end_block(); -string transparency_block(int no); -string delay_block(int centiseconds); string netscape_loop_block(void|int number_of_loops); -string image_block(int x,int y,object img,object colortable,int nolocalpalette,int transp_index); -string image_block(int x,int y,object img,object colortable,object|int alpha,int nolocalpalette); -string image_block(int x,int y,object img,object colortable,object|int alpha,int nolocalpalette,int r,int g,int b); - string _function_block(int function,string data); array _decode(string data); @@ -154,7 +125,7 @@ void image_gif_header_block(INT32 args) struct neo_colortable *nct=NULL; int globalpalette; int numcolors; - int bpp=0; + int bpp=1; char buf[20]; struct pike_string *ps; rgb_group alphacolor={0,0,0}; @@ -321,7 +292,7 @@ void image_gif_end_block(INT32 args) **! Most decoders just ignore some or all of these parameters. */ -void image_gif__gce_block(INT32 args) +static void image_gif__gce_block(INT32 args) { char buf[20]; if (args<5) @@ -382,7 +353,7 @@ void image_gif__gce_block(INT32 args) **! please read about how GIFs file works. */ -void image_gif__render_block(INT32 args) +static void image_gif__render_block(INT32 args) { int xpos,ypos,xs,ys,bpp,interlace; int localpalette=0; @@ -468,7 +439,7 @@ void image_gif__render_block(INT32 args) push_string(make_shared_binary_string(buf,1)); numstrings++; - image_gif_lzw_init(&lzw,bpp); + image_gif_lzw_init(&lzw,(bpp<2)?2:bpp); if (lzw.broken) error("out of memory\n"); THREADS_ALLOW(); @@ -663,14 +634,14 @@ void image_gif_render_block(INT32 args) n=6; } else if (sp[5-args].type==T_OBJECT && - (alpha=(struct image*)get_storage(sp[-args].u.object,image_program))) + (alpha=(struct image*)get_storage(sp[5-args].u.object,image_program))) { if (!alpha->img) error("Image.GIF.render_block(): given alpha channel has no image\n"); else if (alpha->xsize != img->xsize || alpha->ysize != img->ysize) error("Image.GIF.render_block(): given alpha channel differ in size from given image\n"); - alphaidx=0; + alphaidx=numcolors; n=9; alphacolor.r=alphacolor.g=alphacolor.b=0; @@ -684,7 +655,6 @@ void image_gif_render_block(INT32 args) alphacolor.g=(unsigned char)(sp[7-args].u.integer); alphacolor.b=(unsigned char)(sp[8-args].u.integer); - alphaidx=numcolors; /* note: same as transparent color index in image_gif_header_block */ alphaentry=1; @@ -728,7 +698,6 @@ void image_gif_render_block(INT32 args) bpp=1; while ((1<<bpp)<numcolors+alphaentry) bpp++; - if (alphaentry) alphaidx=(1<<bpp)-1; /*** write GCE if needed */ @@ -751,12 +720,12 @@ void image_gif_render_block(INT32 args) if (alpha) { rgb_group *a=alpha->img; - int n=img->xsize*img->ysize; + int n2=img->xsize*img->ysize; unsigned char *d=(unsigned char *)ps->str; - while (n--) + while (n2--) { - if (a->r||a->g||a->b) - *d=alphaidx; + if (!(a->r||a->g||a->b)) + *d=(unsigned char)alphaidx; d++; a++; } @@ -772,8 +741,6 @@ void image_gif_render_block(INT32 args) push_string(ps); if (localpalette) { - int numcolors=image_colortable_size(nct); - ps=begin_shared_string((1<<bpp)*3); image_colortable_write_rgb(nct,(unsigned char *)ps->str); MEMSET(ps->str+(numcolors+alphaentry)*3,0,((1<<bpp)-numcolors)*3); @@ -803,6 +770,301 @@ void image_gif_render_block(INT32 args) push_string(ps); } +/* +**! method string encode(object img); +**! method string encode(object img,int colors); +**! method string encode(object img,object colortable); +**! +**! method string encode_trans(object img,object alpha); +**! method string encode_trans(object img,int tr_r,int tr_g,int tr_b); +**! method string encode_trans(object img,int colors,object alpha); +**! method string encode_trans(object img,int colors,int tr_r,int tr_g,int tr_b); +**! method string encode_trans(object img,int colors,object alpha,int tr_r,int tr_g,int tr_b); +**! method string encode_trans(object img,object colortable,object alpha); +**! method string encode_trans(object img,object colortable,int tr_r,int tr_g,int tr_b); +**! method string encode_trans(object img,object colortable,object alpha,int a_r,int a_g,int a_b); +**! method string encode_trans(object img,object colortable,int transp_index); +**! Create a complete GIF file. +**! +**! The latter (<ref>encode_trans</ref>) functions +**! adds transparency capabilities. +**! +**! arg object img +**! The image which to encode. +**! arg int colors +**! arg object colortable +**! These arguments decides what colors the image should +**! be encoded with. If a number is given, a colortable +**! with be created with (at most) that amount of colors. +**! Default is '256' (GIF maximum amount of colors). +**! arg object alpha +**! Alpha channel image (defining what is transparent); black +**! color indicates transparency. GIF has only transparent +**! or nontransparent (no real alpha channel). +**! You can always dither a transparency channel: +**! <tt>Image.colortable(my_alpha, ({({0,0,0}),({255,255,255})}))-> +**! ->full() ->floyd_steinberg() ->map(my_alpha)</tt> +**! arg int tr_r +**! arg int tr_g +**! arg int tr_b +**! Use this (or the color closest to this) color as transparent +**! pixels. +**! arg int a_r +**! arg int a_g +**! arg int a_b +**! Encode transparent pixels (given by alpha channel image) +**! to have this color. This option is for making GIFs for +**! the decoders that doesn't support transparency. +**! arg int transp_index +**! Use this color no in the colortable as transparent color. +**! +**! note +**! For advanced users: +**! <pre>Image.GIF.encode_trans(img,colortable,alpha);</pre> +**! is equivalent of using +**! <pre>Image.GIF.header_block(img->xsize(),img->ysize(),colortable)+ +**! Image.GIF.render_block(img,colortable,0,0,0,alpha)+ +**! Image.GIF.end_block();</pre> +**! and is actually implemented that way. +*/ + +static void _image_gif_encode(INT32 args,int fs) +{ + struct image *img=NULL; + struct object *imgobj=NULL; + + struct object *nctobj=NULL; + struct neo_colortable *nct=NULL; + + struct object *alphaobj=NULL; + struct image *alpha=NULL; + + rgbl_group ac={0,0,0}; + int alphaentry=0; + int trans=0; + int tridx=0; + + int n=0; + int arg=2; + + if (args<1) + error("Image.GIF.encode(): Too few arguments\n"); + + if (sp[-args].type!=T_OBJECT || + !(img=(struct image*)get_storage(imgobj=sp[-args].u.object, + image_program))) + error("Image.GIF.encode(): Illegal argument 1 (expected image object)\n"); + imgobj->refs++; + + if (args>=2) + if (sp[1-args].type==T_INT) + { + n=sp[1-args].u.integer; + if (n>256) n=256; if (n<2) n=2; + + imgobj->refs++; + push_object(imgobj); + if (alpha) push_int(n); + nctobj=clone_object(image_colortable_program,2); + nct=(struct neo_colortable*) + get_storage(nctobj,image_colortable_program); + if (!nct) + error("Image.GIF.encode(): Internal error; colortable isn't colortable\n"); + } + else if (sp[1-args].type!=T_OBJECT) + error("Image.GIF.encode(): Illegal argument 2 (expected image or colortable object or int)\n"); + else if ((nct=(struct neo_colortable*) + get_storage(nctobj=sp[1-args].u.object,image_colortable_program))) + { + nctobj->refs++; + } + else + { + nctobj=NULL; + arg=1; + } + + /* check transparency arguments */ + if (args-arg>0) + if (sp[arg-args].type==T_OBJECT && + (alpha=(struct image*) + get_storage(alphaobj=sp[arg-args].u.object,image_program))) + { + alphaobj->refs++; + if (args-arg>1) + if (args-arg<4 || + sp[1+arg-args].type!=T_INT || + sp[2+arg-args].type!=T_INT || + sp[3+arg-args].type!=T_INT) + error("Image.GIF.encode: Illegal arguments %d..%d (expected int)\n",arg+2,arg+4); + else + { + ac.r=sp[1+arg-args].u.integer; + ac.g=sp[2+arg-args].u.integer; + ac.b=sp[3+arg-args].u.integer; + alphaentry=1; + } + trans=1; + if (!nct) tridx=255; + else tridx=image_colortable_size(nct); + } + else if (args-arg<3 || + sp[arg-args].type!=T_INT || + sp[1+arg-args].type!=T_INT || + sp[2+arg-args].type!=T_INT) + { + if (arg==2 && + sp[arg-args].type==T_INT) + tridx=sp[arg-args].u.integer; + else + error("Image.GIF.encode(): Illegal argument %d or %d..%d\n", + arg+1,arg+1,arg+3); + trans=1; + } + else + { + rgb_group tr; + unsigned char trd; + + /* make a colortable if we don't have one */ + if (!nct) + { + imgobj->refs++; + push_object(imgobj); + push_int(256); + nctobj=clone_object(image_colortable_program,2); + nct=(struct neo_colortable*) + get_storage(nctobj,image_colortable_program); + if (!nct) + error("Image.GIF.encode(): Internal error; colortable isn't colortable\n"); + } + + + tr.r=(unsigned char)sp[arg-args].u.integer; + tr.g=(unsigned char)sp[1+arg-args].u.integer; + tr.b=(unsigned char)sp[2+arg-args].u.integer; + + image_colortable_index_8bit_image(nct,&tr,&trd,1,1); + + tridx=trd; + trans=2; + } + + /* make a colortable if we don't have one */ + if (!nct) + { + imgobj->refs++; + push_object(imgobj); + if (alpha) push_int(255); else push_int(256); + nctobj=clone_object(image_colortable_program,2); + nct=(struct neo_colortable*) + get_storage(nctobj,image_colortable_program); + if (!nct) + error("Image.GIF.encode(): Internal error; colortable isn't colortable\n"); + } + + if (fs) image_colortable_internal_floyd_steinberg(nct); + + pop_n_elems(args); + + /* build header */ + + push_int(img->xsize); + push_int(img->ysize); + nctobj->refs++; + push_object(nctobj); + if (!trans) + image_gif_header_block(3); + else if (trans==1) + { + push_int(tridx); + push_int(0); + push_int(0); + push_int(0); + push_int(ac.r); + push_int(ac.g); + push_int(ac.b); + image_gif_header_block(10); + } + else + { + push_int(tridx); + image_gif_header_block(4); + } + + /* build renderblock */ + + push_object(imgobj); + push_object(nctobj); + push_int(0); + push_int(0); + push_int(0); + if (!trans) + image_gif_render_block(5); + else + if (alpha) + { + push_object(alphaobj); + push_int(ac.r); + push_int(ac.g); + push_int(ac.b); + image_gif_render_block(9); + } + else + { + push_int(tridx); + image_gif_render_block(6); + } + + /* build trailer */ + + image_gif_end_block(0); + + /* add them and return */ + + f_add(3); +} + +void image_gif_encode(INT32 args) +{ + _image_gif_encode(args,0); +} + +void image_gif_encode_fs(INT32 args) +{ + _image_gif_encode(args,1); +} + +/* +**! method string netscape_loop_block(); +**! method string netscape_loop_block(int number_of_loops); +**! Creates a application-specific extention block; +**! this block makes netscape and compatible browsers +**! loop the animation a certain amount of times. +**! arg int number_of_loops +**! Number of loops. Max and default is 65535. +*/ + +void image_gif_netscape_loop_block(INT32 args) +{ + unsigned short loops=0; + char buf[30]; + if (args) + if (sp[-args].type!=T_INT) + error("Image.GIF.netscape_loop_block: illegal argument (exected int)\n"); + else + loops=sp[-args].u.integer; + else + loops=65535; + pop_n_elems(args); + + sprintf(buf,"%c%c%cNETSCAPE2.0%c%c%c%c%c", + 33,255,11,3,1,(loops>>8)&255,loops&255,0); + + push_string(make_shared_binary_string(buf,19)); +} + + struct program *image_gif_module_program=NULL; void init_image_gif(void) @@ -820,6 +1082,12 @@ void init_image_gif(void) "function(int,int,int|object,void|int,void|int,void|int,void|int,void|int,void|int,void|int:string)",0); add_function("end_block",image_gif_end_block, "function(:string)",0); + add_function("encode",image_gif_encode, + "function(object,mixed...:string)",0); + add_function("encode_fs",image_gif_encode_fs, + "function(object,mixed...:string)",0); + add_function("netscape_loop_block",image_gif_netscape_loop_block, + "function(int|void:string)",0); image_gif_module_program=end_program(); push_object(clone_object(image_gif_module_program,0));