diff --git a/src/modules/Image/togif.c b/src/modules/Image/togif.c index 8b29db174839729a182fcd84eda22f9e1b15a5ac..89b9d8890a9051b9ec548a7f52c96eafc91ab90c 100644 --- a/src/modules/Image/togif.c +++ b/src/modules/Image/togif.c @@ -4,7 +4,7 @@ togif Pontus Hagland, law@infovav.se -$Id: togif.c,v 1.12 1997/05/28 19:41:33 mirar Exp $ +$Id: togif.c,v 1.13 1997/05/28 21:00:48 mirar Exp $ */ @@ -21,6 +21,7 @@ $Id: togif.c,v 1.12 1997/05/28 19:41:33 mirar Exp $ #include "stralloc.h" #include "global.h" #include "threads.h" +#include "types.h" #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -184,6 +185,138 @@ void image_floyd_steinberg(rgb_group *rgb,int xsize, } } + +struct pike_string * + image_encode_gif(struct image *img,struct colortable *ct, + rgb_group *transparent,int fs,int closest) +{ + dynamic_buffer buf; + long i; + rgb_group *rgb; + struct lzw lzw; + int colors,bpp; + +CHRONO("image_encode_gif begin"); + + buf.s.str=NULL; + initialize_buf(&buf); + + colors=4; bpp=2; + while (colors<ct->numcol) { colors<<=1; bpp++; } + + low_my_binary_strcat(transparent?"GIF89a":"GIF87a",6,&buf); + buf_word((unsigned short)img->xsize,&buf); + buf_word((unsigned short)img->ysize,&buf); + low_my_putchar( (char)(0xf0|(bpp-1)), &buf); + /* | global colormap | 3 bits color res | sort | 3 bits bpp */ + /* color res is'nt cared of */ + + low_my_putchar( 0, &buf ); /* background color */ + low_my_putchar( 0, &buf ); /* just zero */ + + for (i=0; i<ct->numcol; i++) + { + low_my_putchar(ct->clut[i].r,&buf); + low_my_putchar(ct->clut[i].g,&buf); + low_my_putchar(ct->clut[i].b,&buf); + } + + for (; i<colors; i++) + { + low_my_putchar(0,&buf); + low_my_putchar(0,&buf); + low_my_putchar(0,&buf); + } + + if (transparent) + { + i=colortable_rgb(ct,*transparent); + + low_my_putchar( '!', &buf ); /* extras */ + low_my_putchar( 0xf9, &buf ); /* transparency */ + low_my_putchar( 4, &buf ); + low_my_putchar( 1, &buf ); + low_my_putchar( 0, &buf ); + low_my_putchar( 0, &buf ); + low_my_putchar( i, &buf ); + low_my_putchar( 0, &buf ); + } + + + low_my_putchar( ',', &buf ); /* image separator */ + + buf_word(0,&buf); /* leftofs */ + buf_word(0,&buf); /* topofs */ + buf_word(img->xsize,&buf); /* width */ + buf_word(img->ysize,&buf); /* height */ + + low_my_putchar(0x00, &buf); + /* not interlaced (interlaced == 0x40) */ + /* no local colormap ( == 0x80) */ + + low_my_putchar( bpp, &buf ); /* bits per pixel , or min 2 */ + + i=img->xsize*img->ysize; + rgb=img->img; + +CHRONO("image_encode_gif header done"); + +THREADS_ALLOW(); + lzw_init(&lzw,bpp); + if (!fs) + while (i--) lzw_add(&lzw,colortable_rgb(ct,*(rgb++))); + else + { + rgbl_group *errb; + rgb_group corgb; + int w,*cres,j; + errb=(rgbl_group*)xalloc(sizeof(rgbl_group)*img->xsize); + cres=(int*)xalloc(sizeof(int)*img->xsize); + for (i=0; i<img->xsize; i++) + errb[i].r=(rand()%(FS_SCALE*2+1))-FS_SCALE, + errb[i].g=(rand()%(FS_SCALE*2+1))-FS_SCALE, + errb[i].b=(rand()%(FS_SCALE*2+1))-FS_SCALE; + + w=0; + i=img->ysize; + while (i--) + { + image_floyd_steinberg(rgb,img->xsize,errb,w=!w,cres,ct,closest); + for (j=0; j<img->xsize; j++) + lzw_add(&lzw,cres[j]); + rgb+=img->xsize; + } + + free(errb); + free(cres); + } + + lzw_write_last(&lzw); + +CHRONO("lzw done"); + + for (i=0; i<(int)lzw.outpos; i+=254) + { + int wr; + if (i+254>(int)lzw.outpos) wr=lzw.outpos-i; + else wr=254; + low_my_putchar( (unsigned char)wr, &buf ); /* bytes in chunk */ + low_my_binary_strcat( (char *) lzw.out+i, wr, &buf ); + } + low_my_putchar( 0, &buf ); /* terminate stream */ + +CHRONO("image_encode_gif wrote ok"); + + lzw_quit(&lzw); + + low_my_putchar( ';', &buf ); /* end gif file */ + +CHRONO("image_encode_gif done"); +THREADS_DISALLOW(); + + return low_free_buf(&buf); +} + #define STD_ARENA_SIZE 16384 int image_decode_gif(struct image *dest,struct image *dest_alpha, @@ -341,9 +474,7 @@ void image_fromgif(INT32 args) if (THIS->img) free(THIS->img); THIS->img=NULL; - image_decode_gif(THIS,NULL, - (unsigned char*)sp[-args].u.string->str, - sp[-args].u.string->len); + image_decode_gif(THIS,NULL,sp[-args].u.string->str,sp[-args].u.string->len); pop_n_elems(args); THISOBJ->refs++; @@ -398,64 +529,58 @@ static INLINE void getrgb(struct image *img, **! see also: togif_begin, togif_add, togif_end, toppm, fromgif */ - -static void img_encode_gif(rgb_group *transparent,int fs,INT32 args) -{ - struct colortable *ct; - image_gif_begin(0); - ct=img_gif_add(args,fs,1); - if (transparent) - { - struct svalue sv; - push_int(colortable_rgb(ct,*transparent)); - image_gif_transparency(1); - sv=sp[-1]; sp[-1]=sp[-2]; sp[-2]=sv; - } - colortable_free(ct); - image_gif_end(0); - - /* on stack is now: - - gif beginning - - eventual transparency chunk - - image with local palette - - gif end chunk */ - - f_sum(4); -} - void image_togif(INT32 args) { rgb_group *transparent=NULL; + struct colortable *ct=NULL; + + if (args>0 && sp[-args].type==T_ARRAY) + ct=colortable_from_array(sp[-args].u.array,"image->togif()\n"); + else if (args>0 && args!=3 && sp[-args].type==T_INT) + ct=colortable_quant(THIS,min(256,max(2,sp[-args].u.integer))); - if (args>3) + if (args>=3+!!ct) { - getrgb(THIS,1,args,"image->togif() (transparency)"); + getrgb(THIS,!!ct,args,"image->togif() (transparency)"); transparent=&(THIS->rgb); } - if (args) pop_n_elems(args-1); + pop_n_elems(args); if (!THIS->img) { error("no image\n"); return; } if (!ct) ct=colortable_quant(THIS,256); - img_encode_gif(transparent, 0,!!args); + push_string( image_encode_gif( THIS,ct, transparent, 0, 0) ); + colortable_free(ct); } void image_togif_fs(INT32 args) { rgb_group *transparent=NULL; + struct colortable *ct=NULL; + int closest=0; + + if (args>0 && sp[-args].type==T_ARRAY) + { + ct=colortable_from_array(sp[-args].u.array,"image->togif_fs()\n"); + closest=1; + } + else if (args>0 && args!=3 && sp[-args].type==T_INT) + ct=colortable_quant(THIS,min(256,max(2,sp[-args].u.integer))); - if (args>3) + if (args>=3+!!ct) { - getrgb(THIS,1,args,"image->togif() (transparency)"); + getrgb(THIS,!!ct,args,"image->togif() (transparency)"); transparent=&(THIS->rgb); } - if (args) pop_n_elems(args-1); + pop_n_elems(args); if (!THIS->img) { error("no image\n"); return; } - if (!ct) ct=colortable_quant(THIS,256); - img_encode_gif(transparent, 0); + if (!ct) + ct=colortable_quant(THIS,256); + push_string( image_encode_gif( THIS,ct, transparent, 1, closest) ); + colortable_free(ct); } /* @@ -572,38 +697,7 @@ void image_gif_netscape_loop(INT32 args) push_string(make_shared_binary_string(buf,19)); } -/* -**! method string gif_transparency(int color) -**! -**! returns a gif chunk that transparent a color in the next image chunk -**! -**! arg int color -**! index of color in the palette -**! note -**! Yes - i know this function is too hard to use. :/ -**! The palette _is_ unknown mostly... -**! see also: gif_add, gif_begin, gif_end -*/ - -void image_gif_transparency(INT32 args) -{ - unsigned short i=0; - char buf[30]; - if (args) - if (sp[-args].type!=T_INT) - error("Illegal argument to image->gif_transparency()\n"); - else - loops=sp[-args].u.integer; - else - error("Too few arguments to image->gif_transparency()\n"); - pop_n_elems(args); - - sprintf(buf,"%c%c%c%c%c%c%c%c",33,0xf9,4,1,0,0,i,0); - - push_string(make_shared_binary_string(buf,19)); -} - -static struct colortable *img_gif_add(INT32 args,int fs,int lm) +static void img_gif_add(INT32 args,int fs,int lm) { INT32 x=0,y=0,i; struct lzw lzw; @@ -745,14 +839,13 @@ CHRONO("end pack"); lzw_quit(&lzw); + colortable_free(ct); THREADS_DISALLOW(); CHRONO("done"); pop_n_elems(args); push_string(low_free_buf(&buf)); - - return ct; } /* @@ -827,21 +920,21 @@ CHRONO("done"); void image_gif_add(INT32 args) { - colortable_free(img_gif_add(args,0,1)); + img_gif_add(args,0,1); } void image_gif_add_fs(INT32 args) { - colortable_free(img_gif_add(args,1,1)); + img_gif_add(args,1,1); } void image_gif_add_nomap(INT32 args) { - colortable_free(img_gif_add(args,0,0)); + img_gif_add(args,0,0); } void image_gif_add_fs_nomap(INT32 args) { - colortable_free(img_gif_add(args,1,0)); + img_gif_add(args,1,0); }