diff --git a/src/modules/Image/encodings/gif.c b/src/modules/Image/encodings/gif.c index 61ded9f443e03e9a7ed76519854fdc41054c1399..1af9fd57a97f6bfa82a2b44e8bc20a6d76742243 100644 --- a/src/modules/Image/encodings/gif.c +++ b/src/modules/Image/encodings/gif.c @@ -1,9 +1,9 @@ -/* $Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $ */ +/* $Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $ */ /* **! module Image **! note -**! $Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $ +**! $Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $ **! submodule GIF **! **! This submodule keep the GIF encode/decode capabilities @@ -31,7 +31,7 @@ #include <ctype.h> #include "stralloc.h" -RCSID("$Id: gif.c,v 1.42 1998/04/16 23:47:54 hubbe Exp $"); +RCSID("$Id: gif.c,v 1.43 1998/04/29 01:27:20 mirar Exp $"); #include "pike_macros.h" #include "object.h" #include "constants.h" @@ -1595,13 +1595,6 @@ static void _gif_decode_lzw(unsigned char *s, { struct neo_colortable *nct; - struct lzwc - { - unsigned short prev; - unsigned short len; - unsigned short c; - } *c; - rgb_group white={255,255,255},black={0,0,0}; int bit=0,bits=obits+1; @@ -1647,7 +1640,7 @@ fprintf(stderr,"_gif_decode_lzw(%lx,%lu,%d,%lx,%lx,%lx,%lu,%d)\n", bit-=bits; #ifdef GIF_DEBUG - if (debug) fprintf(stderr,"code=%d 0x%x bits=%d\n",n,n,bits); + if (debug) fprintf(stderr,"code=%d 0x%02x bits=%d\n",n,n,bits); #endif if (n==m) @@ -2292,6 +2285,244 @@ void image_gif__encode(INT32 args) f_add(n); /* add the strings */ } +/** lzw stuff ***************************************************/ + +static void image_gif_lzw_encode(INT32 args) +{ + struct gif_lzw lzw; + + if (!args || sp[-args].type!=T_STRING) + error("Image.GIF.lzw_encode(): illegal argument\n"); + + image_gif_lzw_init(&lzw,8); + if (lzw.broken) error("out of memory\n"); + + if (args>=2 && !IS_ZERO(sp+1-args)) + lzw.earlychange=1; + + if (args>=3 && !IS_ZERO(sp+2-args)) + lzw.reversebits=1; + + image_gif_lzw_add(&lzw, + (unsigned char *)sp[-args].u.string->str, + sp[-args].u.string->len); + + image_gif_lzw_finish(&lzw); + + if (lzw.broken) error("out of memory\n"); + + pop_n_elems(args); + push_string(make_shared_binary_string((char*)lzw.out,lzw.outpos)); +} + +static void image_gif_lzw_decode(INT32 args) +{ + unsigned char *s,*dest0,*dest; + int earlychange=0; + unsigned long len,n; + signed long clearcode,endcode,last,q,bit,m,dlen,dlen0; + unsigned int mask; + struct lzwc *c; + signed long bits,obits=8; + signed long maxcode; + int reversebits=0; + + if (!args || sp[-args].type!=T_STRING) + error("Image.GIF.lzw_encode(): illegal argument\n"); + + s=(unsigned char*)sp[-args].u.string->str; + len=(unsigned long)sp[-args].u.string->len; + + if (args>=2 && !IS_ZERO(sp+1-args)) + earlychange=1; + if (args>=3 && !IS_ZERO(sp+2-args)) + reversebits=1; + + if (len<1) + { + pop_n_elems(args); + push_string(make_shared_binary_string("",0)); + return; + } + + clearcode=(1<<obits); + endcode=clearcode+1; + bits=obits+1; + mask=(unsigned short)((1<<bits)-1); + m=endcode; + maxcode=(1<<bits); + + last=clearcode; + + c=(struct lzwc*)xalloc(sizeof(struct lzwc)*MAX_GIF_CODE); + + dest0=(unsigned char*)malloc(dlen0=len*4); + if (!dest0) + { + free(c); + error("Image.GIF.lzw_decode: out of memory\n"); + } + dest=dest0; dlen=dlen0; + + for (n=0; n<clearcode; n++) + c[n].prev=0xffff,c[n].len=1,c[n].c=n; + c[clearcode].len=0; + c[endcode].len=0; + + if (len>1) + { + if (reversebits) q=s[1]|(s[0]<<8); + else q=s[0]|(s[1]<<8); + bit=16; + s+=2; len-=2; + } + else + { + q=s[0]; + bit=8; + s+=1; len-=1; + } + + while (bit>0) + { + /* get next code */ + +#ifdef GIF_DEBUG + fprintf(stderr,"q=0x%04x bit=%2d bits=%2d ... ",q,bit,bits); +#endif + + if (reversebits) + n=(q>>(bit-bits))&mask; + else + { + n=q&mask; + q>>=bits; + } + bit-=bits; + +#ifdef GIF_DEBUG + fprintf(stderr,"code=%3d 0x%02x bits=%d bit=%2d *s=0x%02x len=%d\n",n,n,bits,bit,*s,len); +#endif + + if (n==m) + { + c[n].prev=last; + c[n].c=c[last].c; + c[n].len=c[last].len+1; + } + else if (n>=m) + { +#ifdef GIF_DEBUG + fprintf(stderr,"cancel; illegal code, %d>=%d at %lx\n",n,m,s); +#endif + break; /* illegal code */ + } + if (!c[n].len) + if (n==clearcode) + { + bits=obits+1; + mask=(1<<bits)-1; + m=endcode; + last=clearcode; + maxcode=1<<bits; + } + else + { + /* endcode */ +#ifdef GIF_DEBUG + fprintf(stderr,"endcode at %lx\n",s); +#endif + break; + } + else + { + struct lzwc *myc; + unsigned char *d; + unsigned short lc; + myc=c+n; + + if (myc->len>dlen) + { + signed long p; + p=(dest-dest0); + +#ifdef GIF_DEBUG + fprintf(stderr,"increase at dlen left=%lu p=%ld dlen0=%d\n",dlen,p,dlen0); +#endif + dest=realloc(dest0,dlen0*2); + if (!dest) + { + dest=dest0+p; + break; /* out of memory */ + } + dest0=dest; + dest=dest0+p; + dlen+=dlen0; + dlen0+=dlen0; + +#ifdef GIF_DEBUG + fprintf(stderr,"increase at dlen left=%lu p=%ld dlen0=%d\n",dlen,dest-dest0,dlen0); +#endif + } + + d=(dest+=myc->len); + dlen-=myc->len; + + for (;;) + { + lc=myc->c; + *(--d)=(unsigned char)lc; + if (myc->prev==0xffff) break; + myc=c+myc->prev; + } + + if (last!=clearcode) + { + c[m].prev=last; + c[m].len=c[last].len+1; + c[m].c=lc; + } + last=n; + + m++; + if (m>=maxcode - earlychange) + if (m==MAX_GIF_CODE - earlychange) + { +#ifdef GIF_DEBUG + fprintf(stderr,"too many codes at %lx\n",s); +#endif + m--; + bits=12; + } + else + { + bits++; + mask=(1<<bits)-1; + maxcode<<=1; + if (maxcode>MAX_GIF_CODE) + { +#ifdef GIF_DEBUG + fprintf(stderr,"cancel; gif codes=%ld m=%ld\n",maxcode,m); +#endif + break; /* error! too much codes */ + } + } + } + + if (reversebits) + while (bit<bits && len) + q=(q<<8)|(*s),bit+=8,s++,len--; + else + while (bit<bits && len) + q|=((*s)<<bit),bit+=8,s++,len--; + } + free(c); + + pop_n_elems(args); + push_string(make_shared_binary_string((char*)dest0,dest-dest0)); + free(dest0); +} + /** module *******************************************/ struct program *image_encoding_gif_program=NULL; @@ -2334,6 +2565,11 @@ void init_image_gif(void) add_function("_encode_extension",image_gif__encode_extension, "function(array:string)",0); + add_function("lzw_encode",image_gif_lzw_encode, + "function(string,void|int,void|int:string)",0); + add_function("lzw_decode",image_gif_lzw_decode, + "function(string,void|int,void|int:string)",0); + /** constants **/ add_integer_constant("RENDER",GIF_RENDER,0); diff --git a/src/modules/Image/encodings/gif_lzw.c b/src/modules/Image/encodings/gif_lzw.c index 916e8ef62c0557023322d2bef61bd24b3e85c833..13ffa228307d986ae68acd254c227295851e6f76 100644 --- a/src/modules/Image/encodings/gif_lzw.c +++ b/src/modules/Image/encodings/gif_lzw.c @@ -1,7 +1,7 @@ /* **! module Image **! note -**! $Id: gif_lzw.c,v 1.4 1997/11/05 03:42:50 mirar Exp $ +**! $Id: gif_lzw.c,v 1.5 1998/04/29 01:27:22 mirar Exp $ */ #include "global.h" @@ -12,9 +12,6 @@ static INLINE void lzw_output(struct gif_lzw *lzw,lzwcode_t codeno) { - int bits,bitp; - unsigned char c; - if (lzw->outpos+4>=lzw->outlen) { unsigned char *new; @@ -23,31 +20,60 @@ static INLINE void lzw_output(struct gif_lzw *lzw,lzwcode_t codeno) lzw->out=new; } - bitp=lzw->outbit; - c=lzw->lastout; - bits=lzw->codebits; - if (bits>12) bits=12; - - while (bits) + if (!lzw->reversebits) { - c|=(codeno<<bitp); - if (bits+bitp>=8) + int bits,bitp; + unsigned char c; + + bitp=lzw->outbit; + c=(unsigned char)lzw->lastout; + bits=lzw->codebits; + if (bits>12) bits=12; + + while (bits) { - bits-=8-bitp; - codeno>>=8-bitp; - bitp=0; - lzw->out[lzw->outpos++]=c; - c=0; + c|=(codeno<<bitp); + if (bits+bitp>=8) + { + bits-=8-bitp; + codeno>>=8-bitp; + bitp=0; + lzw->out[lzw->outpos++]=c; + c=0; + } + else + { + lzw->outbit=bitp+bits; + lzw->lastout=c; + return; + } } - else + lzw->lastout=0; + lzw->outbit=0; + } + else + { +#ifdef GIF_DEBUG + fprintf(stderr,"codeno=%x lastout=%x outbit=%d codebits=%d\n", + codeno,lzw->lastout,lzw->outbit,lzw->codebits); +#endif + lzw->lastout=(lzw->lastout<<lzw->codebits)|codeno; + lzw->outbit+=lzw->codebits; +#ifdef GIF_DEBUG + fprintf(stderr,"-> codeno=%x lastout=%x outbit=%d codebits=%d\n", + codeno,lzw->lastout,lzw->outbit,lzw->codebits); +#endif + while (lzw->outbit>8) { - lzw->outbit=bitp+bits; - lzw->lastout=c; - return; + lzw->out[lzw->outpos++] = + (unsigned char)(lzw->lastout>>(lzw->outbit-8)); + lzw->outbit-=8; +#ifdef GIF_DEBUG + fprintf(stderr,"(shiftout) codeno=%x lastout=%x outbit=%d codebits=%d\n", + codeno,lzw->lastout,lzw->outbit,lzw->codebits); +#endif } } - lzw->lastout=0; - lzw->outbit=0; } static INLINE void lzw_add(struct gif_lzw *lzw,int c) @@ -103,7 +129,8 @@ static INLINE void lzw_add(struct gif_lzw *lzw,int c) lzw->code[lzw->current].firstchild=lno2; lzw->codes++; - if (lzw->codes>(unsigned long)(1L<<lzw->codebits)) lzw->codebits++; + if (lzw->codes+lzw->earlychange>(unsigned long)(1L<<lzw->codebits)) + lzw->codebits++; lzw->current=c; } @@ -134,6 +161,8 @@ void image_gif_lzw_init(struct gif_lzw *lzw,int bits) lzw->current=LZWCNULL; lzw->outbit=0; lzw->lastout=0; + lzw->earlychange=0; + lzw->reversebits=0; lzw_output(lzw,1L<<bits); } @@ -143,7 +172,12 @@ void image_gif_lzw_finish(struct gif_lzw *lzw) lzw_output(lzw,lzw->current); lzw_output( lzw, (1L<<lzw->bits)+1 ); /* GIF end code */ if (lzw->outbit) - lzw->out[lzw->outpos++]=lzw->lastout; + { + if (lzw->reversebits) + lzw->out[lzw->outpos++]=lzw->lastout<<(8-lzw->outbit); + else + lzw->out[lzw->outpos++]=lzw->lastout; + } } void image_gif_lzw_free(struct gif_lzw *lzw) diff --git a/src/modules/Image/encodings/gif_lzw.h b/src/modules/Image/encodings/gif_lzw.h index b50e2f3ea3f7c2bed5ff3dc1d4449f95fb584937..7555d1ada98698aad0c3fd5408f470d7628e9c71 100644 --- a/src/modules/Image/encodings/gif_lzw.h +++ b/src/modules/Image/encodings/gif_lzw.h @@ -1,19 +1,29 @@ /* **! module Image **! note -**! $Id: gif_lzw.h,v 1.4 1997/11/02 03:44:51 mirar Exp $ +**! $Id: gif_lzw.h,v 1.5 1998/04/29 01:27:23 mirar Exp $ */ typedef unsigned short lzwcode_t; /* no more than 12 bits used */ #define LZWCNULL ((lzwcode_t)(~0)) +struct lzwc +{ + unsigned short prev; + unsigned short len; + unsigned short c; +} *c; + struct gif_lzw { int broken; /* lzw failed, out of memory */ - unsigned char *out,lastout; - unsigned long outlen; + unsigned char *out; + unsigned long outlen,lastout; + int earlychange; + int reversebits; + unsigned long codes; unsigned long bits; /* initial encoding bits */ unsigned long codebits; /* current encoding bits */