diff --git a/src/modules/image/Makefile.src b/src/modules/image/Makefile.src index d8c5f3ca9e5c09e43cec2c78035a13b7e38e555f..5e719c90641b52a407033483bcf47a6cf9cc4e8c 100644 --- a/src/modules/image/Makefile.src +++ b/src/modules/image/Makefile.src @@ -3,7 +3,8 @@ VPATH=@srcdir@:@srcdir@/../..:../.. PREFLAGS=$(DEFINES) -I$(SRCDIR) -I$(SRCDIR)/../.. -I../.. CFLAGS=$(PREFLAGS) $(OTHERFLAGS) @DEFS@ -FILES=image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o +FILES = image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o \ + pattern.o image.a: $(FILES) -rm -f image.a diff --git a/src/modules/image/blit.c b/src/modules/image/blit.c index 6c2988a3a8ed5a11656c762766485675179b6905..9d33009f0bd19e5bfa80be78c4a0c49d23ef1060 100644 --- a/src/modules/image/blit.c +++ b/src/modules/image/blit.c @@ -49,6 +49,8 @@ void chrono(char *x) /***************** internals ***********************************/ +#define testrange(x) max(min((x),255),0) + #define apply_alpha(x,y,alpha) \ ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L)) @@ -427,3 +429,5 @@ void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2) img_box_nocheck(max(x1,0),max(y1,0),min(x2,THIS->xsize-1),min(y2,THIS->ysize-1)); } + + diff --git a/src/modules/image/image.c b/src/modules/image/image.c index f9229b05d6033af77c2545b28527a217f31c31a4..09ceeff7a9534bd5a14e2725f7a7509df34e45e4 100644 --- a/src/modules/image/image.c +++ b/src/modules/image/image.c @@ -390,59 +390,6 @@ void image_clear(INT32 args) push_object(o); } - -void image_fromgif(INT32 args) -{ - if (sp[-args].type!=T_STRING) - error("Illegal argument to image->fromgif()\n"); - - if (THIS->img) free(THIS->img); - THIS->img=NULL; - - image_decode_gif(THIS,NULL,sp[-args].u.string->str,sp[-args].u.string->len); - - pop_n_elems(args); - THISOBJ->refs++; - push_object(THISOBJ); -} - -void image_togif(INT32 args) -{ - rgb_group *transparent=NULL; - struct colortable *ct; - - if (args>=3) - { - getrgb(THIS,0,args,"image->togif() (transparency)"); - transparent=&(THIS->rgb); - } - - pop_n_elems(args); - if (!THIS->img) { error("no image\n"); return; } - ct=colortable_quant(THIS,256); - push_string( image_encode_gif( THIS,ct, transparent, 0) ); - colortable_free(ct); -} - -void image_togif_fs(INT32 args) -{ - rgb_group *transparent=NULL; - struct colortable *ct; - - if (args>=3) - { - getrgb(THIS,0,args,"image->togif_fs() (transparency)"); - transparent=&(THIS->rgb); - } - - pop_n_elems(args); - if (!THIS->img) { error("no image\n"); return; } - ct=colortable_quant(THIS,256); - push_string( image_encode_gif( THIS,ct, transparent, 1) ); - colortable_free(ct); -} - - void image_copy(INT32 args) { struct object *o; @@ -881,9 +828,12 @@ void image_color(INT32 args) if (!THIS->img) error("no image\n"); if (args<3) { - rgb.r=255; - rgb.g=255; - rgb.b=255; + if (args>0 && sp[-args].type==T_INT) + rgb.r=rgb.b=rgb.g=sp[-args].u.integer; + else + rgb.r=THIS->rgb.r, + rgb.g=THIS->rgb.g, + rgb.b=THIS->rgb.b; } else getrgbl(&rgb,0,args,"image->color()"); @@ -1483,6 +1433,8 @@ void init_image_programs() { int i; + image_noise_init(); + start_new_program(); add_storage(sizeof(struct image)); @@ -1506,6 +1458,17 @@ void init_image_programs() "function(:string)",0); add_function("togif_fs",image_togif_fs, "function(:string)",0); + add_function("gif_begin",image_gif_begin, + "function(int:string)",0); + add_function("gif_add",image_gif_add, + "function(int|void,int|void:string)",0); + add_function("gif_add_fs",image_gif_add_fs, + "function(int|void,int|void:string)",0); + add_function("gif_end",image_gif_end, + "function(:string)",0); + add_function("gif_netscape_loop",image_gif_netscape_loop, + "function(:string)",0); + add_function("copy",image_copy, "function(void|int,void|int,void|int,void|int,"RGB_TYPE":object)",0); add_function("autocrop",image_autocrop, @@ -1588,6 +1551,11 @@ void init_image_programs() "function(:object)",0); add_function("select_colors",image_select_colors, "function(int:array(array(int)))",0); + + add_function("noise",image_noise, + "function(array(float|int|array(int)),float|void,float|void,float|void,float|void:object)",0); + add_function("turbulence",image_turbulence, + "function(array(float|int|array(int)),int|void,float|void,float|void,float|void,float|void:object)",0); set_init_callback(init_image_struct); set_exit_callback(exit_image_struct); diff --git a/src/modules/image/image.h b/src/modules/image/image.h index c577f5d54762a20b65519234542a7c186f5d1cf2..67245c199f030d0268b0f88b712d5cfb777a32a8 100644 --- a/src/modules/image/image.h +++ b/src/modules/image/image.h @@ -72,6 +72,15 @@ void image_floyd_steinberg(rgb_group *rgb,int xsize, int image_decode_gif(struct image *dest,struct image *dest_alpha, unsigned char *src,unsigned long len); +void image_togif(INT32 args); +void image_togif_fs(INT32 args); +void image_fromgif(INT32 args); +void image_gif_begin(INT32 args); +void image_gif_add(INT32 args); +void image_gif_add_fs(INT32 args); +void image_gif_end(INT32 args); +void image_gif_netscape_loop(INT32 args); + /* blit.c */ void img_clear(rgb_group *dest,rgb_group rgb,INT32 size); @@ -108,3 +117,9 @@ void image_mirrory(INT32 args); void image_toppm(INT32 args); void image_frompnm(INT32 args); + +/* pattern.c */ + +void image_noise(INT32 args); +void image_turbulence(INT32 args); +void image_noise_init(void); diff --git a/src/modules/image/togif.c b/src/modules/image/togif.c index 185430022b125004fd0f2bc66d6dff767155915c..e5c93e1b1ca1f3aa5d2904bb979e3126308fb52e 100644 --- a/src/modules/image/togif.c +++ b/src/modules/image/togif.c @@ -6,11 +6,21 @@ Pontus Hagland, law@infovav.se */ -#include <stdlib.h> +#include "global.h" + +#include <math.h> +#include <ctype.h> #include "stralloc.h" #include "global.h" #include "types.h" +#include "macros.h" +#include "object.h" +#include "constants.h" +#include "interpret.h" +#include "svalue.h" +#include "array.h" +#include "error.h" #include "dynamic_buffer.h" #include "image.h" @@ -18,6 +28,9 @@ Pontus Hagland, law@infovav.se #define INITIAL_BUF_LEN 8192 +#define THIS ((struct image *)(fp->current_storage)) +#define THISOBJ (fp->current_object) + #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)<(b)?(b):(a)) @@ -378,3 +391,246 @@ int image_decode_gif(struct image *dest,struct image *dest_alpha, return 1; /* ok */ } + + +void image_fromgif(INT32 args) +{ + if (sp[-args].type!=T_STRING) + error("Illegal argument to image->fromgif()\n"); + + if (THIS->img) free(THIS->img); + THIS->img=NULL; + + image_decode_gif(THIS,NULL,sp[-args].u.string->str,sp[-args].u.string->len); + + pop_n_elems(args); + THISOBJ->refs++; + push_object(THISOBJ); +} + +static INLINE void getrgb(struct image *img, + INT32 args_start,INT32 args,char *name) +{ + INT32 i; + if (args-args_start<3) return; + for (i=0; i<3; i++) + if (sp[-args+i+args_start].type!=T_INT) + error("Illegal r,g,b argument to %s\n",name); + img->rgb.r=(unsigned char)sp[-args+args_start].u.integer; + img->rgb.g=(unsigned char)sp[1-args+args_start].u.integer; + img->rgb.b=(unsigned char)sp[2-args+args_start].u.integer; + if (args-args_start>=4) + if (sp[3-args+args_start].type!=T_INT) + error("Illegal alpha argument to %s\n",name); + else + img->alpha=sp[3-args+args_start].u.integer; + else + img->alpha=0; +} + +void image_togif(INT32 args) +{ + rgb_group *transparent=NULL; + struct colortable *ct; + + if (args>=3) + { + getrgb(THIS,0,args,"image->togif() (transparency)"); + transparent=&(THIS->rgb); + } + + pop_n_elems(args); + if (!THIS->img) { error("no image\n"); return; } + ct=colortable_quant(THIS,256); + push_string( image_encode_gif( THIS,ct, transparent, 0) ); + colortable_free(ct); +} + +void image_togif_fs(INT32 args) +{ + rgb_group *transparent=NULL; + struct colortable *ct; + + if (args>=3) + { + getrgb(THIS,0,args,"image->togif_fs() (transparency)"); + transparent=&(THIS->rgb); + } + + pop_n_elems(args); + if (!THIS->img) { error("no image\n"); return; } + ct=colortable_quant(THIS,256); + push_string( image_encode_gif( THIS,ct, transparent, 1) ); + colortable_free(ct); +} + +void image_gif_begin(INT32 args) +{ + dynamic_buffer buf; + long i; + + pop_n_elems(args); + + buf.s.str=NULL; + low_init_buf(&buf); + + low_my_binary_strcat("GIF89a",6,&buf); + buf_word((unsigned short)THIS->xsize,&buf); + buf_word((unsigned short)THIS->ysize,&buf); + low_my_putchar( (char)(0x77), &buf); + /* 7 is bpp - 1 7 is "no" global colormap + resolution (??!) */ + + low_my_putchar( 0, &buf ); /* background color */ + low_my_putchar( 0, &buf ); /* just zero */ + + push_string(low_free_buf(&buf)); +} + +void image_gif_end(INT32 args) +{ + pop_n_elems(args); + push_string(make_shared_binary_string(";",1)); +} + +void image_gif_netscape_loop(INT32 args) +{ + unsigned short loops; + char buf[30]; + if (args) + if (sp[-args].type!=T_INT) + error("Illegal argument to image->gif_netscape_loop()\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&255,(loops>>8)&255,0); + + push_string(make_shared_binary_string(buf,19)); +} + +static void img_gif_add(INT32 args,int fs) +{ + INT32 x,y,i; + struct lzw lzw; + rgb_group *rgb; + struct colortable *ct; + dynamic_buffer buf; + + buf.s.str=NULL; + low_init_buf(&buf); + + if (args==0) x=y=0; + else if (sp[-args].type!=T_INT + || sp[1-args].type!=T_INT) + error("Illegal argument(s) to image->gif_add()\n"); + else + { + x=sp[-args].u.integer; + y=sp[1-args].u.integer; + } + + if (args>2) + { + unsigned short delay; + if (sp[2-args].type==T_INT) + delay=sp[2-args].u.integer; + else if (sp[2-args].type==T_FLOAT) + delay=(unsigned short)(sp[2-args].u.float_number*100); + else + error("Illegal argument 3 to image->gif_add()\n"); + + low_my_putchar( '!', &buf ); /* extension block */ + low_my_putchar( 0xf9, &buf ); /* graphics control */ + low_my_putchar( 4, &buf ); /* block size */ + low_my_putchar( 0, &buf ); /* disposal, transparency, blabla */ + buf_word( delay, &buf ); /* delay in centiseconds */ + low_my_putchar( 0, &buf ); /* (transparency index) */ + low_my_putchar( 0, &buf ); /* terminate block */ + } + + ct=colortable_quant(THIS,256); + + low_my_putchar( ',', &buf ); /* image separator */ + + buf_word(x,&buf); /* leftofs */ + buf_word(y,&buf); /* topofs */ + buf_word(THIS->xsize,&buf); /* width */ + buf_word(THIS->ysize,&buf); /* height */ + + low_my_putchar(0x80|7, &buf); + /* not interlaced (interlaced == 0x40) */ + /* local colormap ( == 0x80) */ + /* 8 bpp in map ( == 0x07) */ + + for (i=0; i<256; 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); + } + + low_my_putchar( 8, &buf ); /* bits per pixel , or min 2 */ + + i=THIS->xsize*THIS->ysize; + rgb=THIS->img; + + lzw_init(&lzw,8); + 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)*THIS->xsize); + cres=(int*)xalloc(sizeof(int)*THIS->xsize); + for (i=0; i<THIS->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=THIS->ysize; + while (i--) + { + image_floyd_steinberg(rgb,THIS->xsize,errb,w=!w,cres,ct); + for (j=0; j<THIS->xsize; j++) + lzw_add(&lzw,cres[j]); + rgb+=THIS->xsize; + } + + free(errb); + free(cres); + } + + lzw_write_last(&lzw); + + 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 */ + + lzw_quit(&lzw); + + pop_n_elems(args); + push_string(low_free_buf(&buf)); +} + +void image_gif_add(INT32 args) +{ + img_gif_add(args,0); +} + +void image_gif_add_fs(INT32 args) +{ + img_gif_add(args,1); +} + diff --git a/src/pike_types.c b/src/pike_types.c index cbfcee4a0dfd9f6d5c6e300348e436592aafabd3..83af7551098d67e63d90a84974b06b90b95b6862 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -70,6 +70,7 @@ void init_types() static int type_length(char *t) { char *q=t; + switch(EXTRACT_UCHAR(t++)) { default: @@ -1027,6 +1028,11 @@ struct pike_string *get_type_of_svalue(struct svalue *s) push_type(T_MAPPING); return pop_type(); + case T_OBJECT: + push_type_int(0); + push_type(T_OBJECT); + return pop_type(); + default: push_type(s->type); return pop_type();