diff --git a/src/modules/image/Makefile.src b/src/modules/image/Makefile.src index fe921440b024437f8aebff480b40c0aa9abab1eb..d8c5f3ca9e5c09e43cec2c78035a13b7e38e555f 100644 --- a/src/modules/image/Makefile.src +++ b/src/modules/image/Makefile.src @@ -3,7 +3,7 @@ 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 +FILES=image.o font.o quant.o lzw.o togif.o matrix.o pnm.o blit.o image.a: $(FILES) -rm -f image.a diff --git a/src/modules/image/blit.c b/src/modules/image/blit.c new file mode 100644 index 0000000000000000000000000000000000000000..fbff9cf4cc2c7fd57a1332fe242cca999e0ef3e8 --- /dev/null +++ b/src/modules/image/blit.c @@ -0,0 +1,358 @@ +#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 "image.h" + +struct program *image_program; +#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)) + +/***************** internals ***********************************/ + +#define apply_alpha(x,y,alpha) \ + ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L)) + +#define set_rgb_group_alpha(dest,src,alpha) \ + ((dest).r=apply_alpha((dest).r,(src).r,alpha), \ + (dest).g=apply_alpha((dest).g,(src).g,alpha), \ + (dest).b=apply_alpha((dest).b,(src).b,alpha)) + +#define pixel(_img,x,y) ((_img)->img[(x)+(y)*(_img)->xsize]) + +#define setpixel(x,y) \ + (THIS->alpha? \ + set_rgb_group_alpha(THIS->img[(x)+(y)*THIS->xsize],THIS->rgb,THIS->alpha): \ + ((pixel(THIS,x,y)=THIS->rgb),0)) + +#define setpixel_test(x,y) \ + (((x)<0||(y)<0||(x)>=THIS->xsize||(y)>=THIS->ysize)? \ + 0:(setpixel(x,y),0)) + +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; +} + +/*** end internals ***/ + + +void img_clear(rgb_group *dest,rgb_group rgb,INT32 size) +{ + while (size--) *(dest++)=rgb; +} + +void img_box_nocheck(INT32 x1,INT32 y1,INT32 x2,INT32 y2) +{ + INT32 x,mod; + rgb_group *foo,*end,rgb; + + mod=THIS->xsize-(x2-x1)-1; + foo=THIS->img+x1+y1*THIS->xsize; + end=THIS->img+x2+y2*THIS->xsize; + rgb=THIS->rgb; + + if (!THIS->alpha) + for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++) *(foo++)=rgb; + else + for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++,foo++) + set_rgb_group_alpha(*foo,rgb,THIS->alpha); +} + + +void img_blit(rgb_group *dest,rgb_group *src,INT32 width, + INT32 lines,INT32 moddest,INT32 modsrc) +{ + while (lines--) + { + MEMCPY(dest,src,sizeof(rgb_group)*width); + dest+=moddest; + src+=modsrc; + } +} + +void img_crop(struct image *dest, + struct image *img, + INT32 x1,INT32 y1, + INT32 x2,INT32 y2) +{ + rgb_group *new; + INT32 blitwidth; + INT32 blitheight; + + if (dest->img) { free(dest->img); dest->img=NULL; } + + if (x1==0 && y1==0 && + img->xsize-1==x2 && img->ysize-1==y2) + { + *dest=*img; + new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) + 1); + if (!new) + error("Out of memory.\n"); + MEMCPY(new,img->img,(x2-x1+1)*(y2-y1+1)*sizeof(rgb_group)); + dest->img=new; + return; + } + + if (x1>x2) x1^=x2,x2^=x1,x1^=x2; + if (y1>y2) y1^=y2,y2^=y1,y1^=y2; + + new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) +1); + if (!new) + error("Out of memory.\n"); + + img_clear(new,THIS->rgb,(x2-x1+1)*(y2-y1+1)); + + blitwidth=min(x2,img->xsize-1)-max(x1,0)+1; + blitheight=min(y2,img->ysize-1)-max(y1,0)+1; + + img_blit(new+max(0,-x1)+(x2-x1+1)*max(0,-y1), + img->img+max(0,x1)+(img->xsize)*max(0,y1), + blitwidth, + blitheight, + (x2-x1+1), + img->xsize); + + dest->img=new; + dest->xsize=x2-x1+1; + dest->ysize=y2-y1+1; +} + +void img_clone(struct image *newimg,struct image *img) +{ + if (newimg->img) free(newimg->img); + newimg->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize +1); + if (!newimg->img) error("Out of memory!\n"); + MEMCPY(newimg->img,img->img,sizeof(rgb_group)*img->xsize*img->ysize); + newimg->xsize=img->xsize; + newimg->ysize=img->ysize; + newimg->rgb=img->rgb; +} + +void image_paste(INT32 args) +{ + struct image *img; + INT32 x1,y1,x2,y2,blitwidth,blitheight; + + if (args<1 + || sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || sp[-args].u.object->prog!=image_program) + error("illegal argument 1 to image->paste()\n"); + if (!THIS->img) return; + + img=(struct image*)sp[-args].u.object->storage; + if (!img) return; + + if (args>=3) + { + if (sp[1-args].type!=T_INT + || sp[2-args].type!=T_INT) + error("illegal arguments to image->paste()\n"); + x1=sp[1-args].u.integer; + y1=sp[2-args].u.integer; + } + else x1=y1=0; + pop_n_elems(args-1); + + x2=x1+img->xsize-1; + y2=y1+img->ysize-1; + + blitwidth=min(x2,THIS->xsize-1)-max(x1,0)+1; + blitheight=min(y2,THIS->ysize-1)-max(y1,0)+1; + + img_blit(THIS->img+max(0,x1)+(THIS->xsize)*max(0,y1), + img->img+max(0,-x1)+(x2-x1+1)*max(0,-y1), + blitwidth, + blitheight, + THIS->xsize, + img->xsize); +} + +void image_paste_alpha(INT32 args) +{ + struct image *img; + INT32 x1,y1,x,y; + + if (args<2 + || sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || sp[-args].u.object->prog!=image_program + || sp[1-args].type!=T_INT) + error("illegal arguments to image->paste_alpha()\n"); + if (!THIS->img) return; + + img=(struct image*)sp[-args].u.object->storage; + if (!img) return; + THIS->alpha=(unsigned char)(sp[1-args].u.integer); + + if (args>=4) + { + if (sp[2-args].type!=T_INT + || sp[3-args].type!=T_INT) + error("illegal arguments to image->paste_alpha()\n"); + x1=sp[2-args].u.integer; + y1=sp[3-args].u.integer; + } + else x1=y1=0; + + for (x=0; x<img->xsize; x++) + for (y=0; y<img->ysize; y++) + { + THIS->rgb=pixel(img,x,y); + setpixel_test(x1+x,y1+y); + } + + pop_n_elems(args); + THISOBJ->refs++; + push_object(THISOBJ); +} + +void image_paste_mask(INT32 args) +{ + struct image *img,*mask; + INT32 x1,y1,x,y,x2,y2; + + if (args<2) + error("illegal number of arguments to image->paste_mask()\n"); + if (sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || sp[-args].u.object->prog!=image_program) + error("illegal argument 1 to image->paste_mask()\n"); + if (sp[1-args].type!=T_OBJECT + || !sp[1-args].u.object + || sp[1-args].u.object->prog!=image_program) + error("illegal argument 2 to image->paste_mask()\n"); + if (!THIS->img) return; + + img=(struct image*)sp[-args].u.object->storage; + mask=(struct image*)sp[1-args].u.object->storage; + if ((!img)||(!img->img)) error("argument 1 has no image\n"); + if ((!mask)||(!mask->img)) error("argument 2 (alpha) has no image\n"); + + if (args>=4) + { + if (sp[2-args].type!=T_INT + || sp[3-args].type!=T_INT) + error("illegal coordinate arguments to image->paste_mask()\n"); + x1=sp[2-args].u.integer; + y1=sp[3-args].u.integer; + } + else x1=y1=0; + + x2=min(THIS->xsize-x1,min(img->xsize,mask->xsize)); + y2=min(THIS->ysize-y1,min(img->ysize,mask->ysize)); + + for (x=max(0,-x1); x<x2; x++) + for (y=max(0,-y1); y<y2; y++) + { + pixel(THIS,x+x1,y+y1).r= + (unsigned char)((pixel(THIS,x+x1,y+y1).r*(long)(255-pixel(mask,x,y).r)+ + pixel(img,x,y).r*(long)pixel(mask,x,y).r)/255); + pixel(THIS,x+x1,y+y1).g= + (unsigned char)((pixel(THIS,x+x1,y+y1).g*(long)(255-pixel(mask,x,y).g)+ + pixel(img,x,y).g*(long)pixel(mask,x,y).g)/255); + pixel(THIS,x+x1,y+y1).b= + (unsigned char)((pixel(THIS,x+x1,y+y1).b*(long)(255-pixel(mask,x,y).b)+ + pixel(img,x,y).b*(long)pixel(mask,x,y).b)/255); + } + pop_n_elems(args); + THISOBJ->refs++; + push_object(THISOBJ); +} + +void image_paste_alpha_color(INT32 args) +{ + struct image *img,*mask; + INT32 x1,y1,x,y,x2,y2; + + if (args!=1 && args!=4 && args!=6 && args!=3) + error("illegal number of arguments to image->paste_alpha_color()\n"); + if (sp[-args].type!=T_OBJECT + || !sp[-args].u.object + || sp[-args].u.object->prog!=image_program) + error("illegal argument 1 to image->paste_alpha_color()\n"); + if (!THIS->img) return; + + if (args==6 || args==4) /* colors at arg 2..4 */ + getrgb(THIS,1,args,"image->paste_alpha_color()\n"); + if (args==3) /* coords at 2..3 */ + { + if (sp[1-args].type!=T_INT + || sp[2-args].type!=T_INT) + error("illegal coordinate arguments to image->paste_alpha_color()\n"); + x1=sp[1-args].u.integer; + y1=sp[2-args].u.integer; + } + else if (args==6) /* at 5..6 */ + { + if (sp[4-args].type!=T_INT + || sp[5-args].type!=T_INT) + error("illegal coordinate arguments to image->paste_alpha_color()\n"); + x1=sp[4-args].u.integer; + y1=sp[5-args].u.integer; + } + else x1=y1=0; + + mask=(struct image*)sp[-args].u.object->storage; + if (!mask||!mask->img) error("argument 2 (alpha) has no image\n"); + + x2=min(THIS->xsize-x1,mask->xsize); + y2=min(THIS->ysize-y1,mask->ysize); + + for (x=max(0,-x1); x<x2; x++) + for (y=max(0,-y1); y<y2; y++) + { + pixel(THIS,x+x1,y+y1).r= + (unsigned char)((pixel(THIS,x+x1,y+y1).r*(long)(255-pixel(mask,x,y).r)+ + THIS->rgb.r*(long)pixel(mask,x,y).r)/255); + pixel(THIS,x+x1,y+y1).g= + (unsigned char)((pixel(THIS,x+x1,y+y1).g*(long)(255-pixel(mask,x,y).g)+ + THIS->rgb.g*(long)pixel(mask,x,y).g)/255); + pixel(THIS,x+x1,y+y1).b= + (unsigned char)((pixel(THIS,x+x1,y+y1).b*(long)(255-pixel(mask,x,y).b)+ + THIS->rgb.b*(long)pixel(mask,x,y).b)/255); + } + pop_n_elems(args); + THISOBJ->refs++; + push_object(THISOBJ); +} + +void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2) +{ + if (x1>x2) x1^=x2,x2^=x1,x1^=x2; + if (y1>y2) y1^=y2,y2^=y1,y1^=y2; + if (x2<0||y2<0||x1>=THIS->xsize||y1>=THIS->ysize) return; + 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 a79178bc22b2094d628ac92c356f9ce18bb6671d..f9229b05d6033af77c2545b28527a217f31c31a4 100644 --- a/src/modules/image/image.c +++ b/src/modules/image/image.c @@ -15,6 +15,7 @@ #include "error.h" #include "image.h" +#include "builtin_functions.h" struct program *image_program; #define THIS ((struct image *)(fp->current_storage)) @@ -22,6 +23,7 @@ struct program *image_program; #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)<(b)?(b):(a)) +#define testrange(x) max(min((x),255),0) #define sq(x) ((x)*(x)) @@ -101,97 +103,6 @@ static INLINE void getrgbl(rgbl_group *rgb,INT32 args_start,INT32 args,char *nam rgb->b=sp[2-args+args_start].u.integer; } -static void img_clear(rgb_group *dest,rgb_group rgb,INT32 size) -{ - while (size--) *(dest++)=rgb; -} - -static INLINE void img_box_nocheck(INT32 x1,INT32 y1,INT32 x2,INT32 y2) -{ - INT32 x,mod; - rgb_group *foo,*end,rgb; - - mod=THIS->xsize-(x2-x1)-1; - foo=THIS->img+x1+y1*THIS->xsize; - end=THIS->img+x2+y2*THIS->xsize; - rgb=THIS->rgb; - - if (!THIS->alpha) - for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++) *(foo++)=rgb; - else - for (; foo<end; foo+=mod) for (x=x1; x<=x2; x++,foo++) - set_rgb_group_alpha(*foo,rgb,THIS->alpha); -} - -static INLINE void img_blit(rgb_group *dest,rgb_group *src,INT32 width, - INT32 lines,INT32 moddest,INT32 modsrc) -{ - while (lines--) - { - MEMCPY(dest,src,sizeof(rgb_group)*width); - dest+=moddest; - src+=modsrc; - } -} - -static void img_crop(struct image *dest, - struct image *img, - INT32 x1,INT32 y1, - INT32 x2,INT32 y2) -{ - rgb_group *new; - INT32 blitwidth; - INT32 blitheight; - - if (dest->img) { free(dest->img); dest->img=NULL; } - - if (x1==0 && y1==0 && - img->xsize-1==x2 && img->ysize-1==y2) - { - *dest=*img; - new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) + 1); - if (!new) - error("Out of memory.\n"); - MEMCPY(new,img->img,(x2-x1+1)*(y2-y1+1)*sizeof(rgb_group)); - dest->img=new; - return; - } - - if (x1>x2) x1^=x2,x2^=x1,x1^=x2; - if (y1>y2) y1^=y2,y2^=y1,y1^=y2; - - new=malloc( (x2-x1+1)*(y2-y1+1)*sizeof(rgb_group) +1); - if (!new) - error("Out of memory.\n"); - - img_clear(new,THIS->rgb,(x2-x1+1)*(y2-y1+1)); - - blitwidth=min(x2,img->xsize-1)-max(x1,0)+1; - blitheight=min(y2,img->ysize-1)-max(y1,0)+1; - - img_blit(new+max(0,-x1)+(x2-x1+1)*max(0,-y1), - img->img+max(0,x1)+(img->xsize)*max(0,y1), - blitwidth, - blitheight, - (x2-x1+1), - img->xsize); - - dest->img=new; - dest->xsize=x2-x1+1; - dest->ysize=y2-y1+1; -} - -static INLINE void img_clone(struct image *newimg,struct image *img) -{ - if (newimg->img) free(newimg->img); - newimg->img=malloc(sizeof(rgb_group)*img->xsize*img->ysize +1); - if (!newimg->img) error("Out of memory!\n"); - MEMCPY(newimg->img,img->img,sizeof(rgb_group)*img->xsize*img->ysize); - newimg->xsize=img->xsize; - newimg->ysize=img->ysize; - newimg->rgb=img->rgb; -} - static INLINE void img_line(INT32 x1,INT32 y1,INT32 x2,INT32 y2) { INT32 pixelstep,pos; @@ -241,242 +152,6 @@ static INLINE void img_line(INT32 x1,INT32 y1,INT32 x2,INT32 y2) } } - -static INLINE void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2) -{ - if (x1>x2) x1^=x2,x2^=x1,x1^=x2; - if (y1>y2) y1^=y2,y2^=y1,y1^=y2; - if (x2<0||y2<0||x1>=THIS->xsize||y1>=THIS->ysize) return; - img_box_nocheck(max(x1,0),max(y1,0),min(x2,THIS->xsize-1),min(y2,THIS->ysize-1)); -} - -#define decimals(x) ((x)-(int)(x)) -#define testrange(x) max(min((x),255),0) -#define _scale_add_rgb(dest,src,factor) \ - ((dest).r=testrange((dest).r+(int)((src).r*(factor)+0.5)), \ - (dest).g=testrange((dest).g+(int)((src).g*(factor)+0.5)), \ - (dest).b=testrange((dest).b+(int)((src).b*(factor)+0.5))) -#define scale_add_pixel(dest,dx,dy,dxw,src,sx,sy,sxw,factor) \ - _scale_add_rgb(dest[(dx)+(dy)*(dxw)],src[(sx)+(sy)*(sxw)],factor) - -static INLINE void scale_add_line(rgb_group *new,INT32 yn,INT32 newx, - rgb_group *img,INT32 y,INT32 xsize, - double py,double dx) -{ - INT32 x,xd; - double xn; - for (x=0,xn=0; x<THIS->xsize; x++,xn+=dx) - { - if ((INT32)xn<(INT32)(xn+dx)) - { - scale_add_pixel(new,(INT32)xn,yn,newx,img,x,y,xsize,py*(1.0-decimals(xn))); - if ((xd=(INT32)(xn+dx)-(INT32)(xn))>1) - while (--xd) - scale_add_pixel(new,(INT32)xn+xd,yn,newx,img,x,y,xsize,py); - scale_add_pixel(new,(INT32)(xn+dx),yn,newx,img,x,y,xsize,py*decimals(xn+dx)); - } - else - scale_add_pixel(new,(int)xn,yn,newx,img,x,y,xsize,py*dx); - } -} - -static void img_scale(struct image *dest, - struct image *source, - INT32 newx,INT32 newy) -{ - rgb_group *new; - INT32 y,yd; - double yn,dx,dy; - - if (dest->img) { free(dest->img); dest->img=NULL; } - - if (!THIS->img || newx<=0 || newy<=0) return; /* no way */ - new=malloc(newx*newy*sizeof(rgb_group) +1); - if (!new) error("Out of memory!\n"); - - MEMSET(new,0,newx*newy*sizeof(rgb_group)); - - dx=((double)newx-0.000001)/source->xsize; - dy=((double)newy-0.000001)/source->ysize; - - for (y=0,yn=0; y<source->ysize; y++,yn+=dy) - { - if ((INT32)yn<(INT32)(yn+dy)) - { - scale_add_line(new,(INT32)(yn),newx,source->img,y,source->xsize, - (1.0-decimals(yn)),dx); - if ((yd=(INT32)(yn+dy)-(INT32)(yn))>1) - while (--yd) - scale_add_line(new,(INT32)yn+yd,newx,source->img,y,source->xsize, - 1.0,dx); - scale_add_line(new,(INT32)(yn+dy),newx,source->img,y,source->xsize, - (decimals(yn+dy)),dx); - } - else - scale_add_line(new,(INT32)yn,newx,source->img,y,source->xsize, - dy,dx); - } - - dest->img=new; - dest->xsize=newx; - dest->ysize=newy; -} - -/* Special, faster, case for scale=1/2 */ -static void img_scale2(struct image *dest, struct image *source) -{ - rgb_group *new; - INT32 x, y, newx, newy; - newx = source->xsize >> 1; - newy = source->ysize >> 1; - - if (dest->img) { free(dest->img); dest->img=NULL; } - if (!THIS->img || newx<=0 || newy<=0) return; /* no way */ - new=malloc(newx*newy*sizeof(rgb_group) +1); - if (!new) error("Out of memory\n"); - MEMSET(new,0,newx*newy*sizeof(rgb_group)); - - dest->img=new; - dest->xsize=newx; - dest->ysize=newy; - for (y = 0; y < newy; y++) - for (x = 0; x < newx; x++) { - pixel(dest,x,y).r = (COLOURTYPE) - (((INT32) pixel(source,2*x+0,2*y+0).r+ - (INT32) pixel(source,2*x+1,2*y+0).r+ - (INT32) pixel(source,2*x+0,2*y+1).r+ - (INT32) pixel(source,2*x+1,2*y+1).r) >> 2); - pixel(dest,x,y).g = (COLOURTYPE) - (((INT32) pixel(source,2*x+0,2*y+0).g+ - (INT32) pixel(source,2*x+1,2*y+0).g+ - (INT32) pixel(source,2*x+0,2*y+1).g+ - (INT32) pixel(source,2*x+1,2*y+1).g) >> 2); - pixel(dest,x,y).b = (COLOURTYPE) - (((INT32) pixel(source,2*x+0,2*y+0).b+ - (INT32) pixel(source,2*x+1,2*y+0).b+ - (INT32) pixel(source,2*x+0,2*y+1).b+ - (INT32) pixel(source,2*x+1,2*y+1).b) >> 2); - } -} - -static INLINE unsigned char getnext(struct pike_string *s,INT32 *pos) -{ - if (*pos>=s->len) return 0; - if (s->str[(*pos)]=='#') - for (;*pos<s->len && ISSPACE(s->str[*pos]);(*pos)++); - return s->str[(*pos)++]; -} - -static INLINE void skip_to_eol(struct pike_string *s,INT32 *pos) -{ - for (;*pos<s->len && s->str[*pos]!=10;(*pos)++); -} - -static INLINE unsigned char getnext_skip_comment(struct pike_string *s,INT32 *pos) -{ - unsigned char c; - while ((c=getnext(s,pos))=='#') - skip_to_eol(s,pos); - return c; -} - -static INLINE void skipwhite(struct pike_string *s,INT32 *pos) -{ - while (*pos<s->len && - ( ISSPACE(s->str[*pos]) || - s->str[*pos]=='#')) - getnext_skip_comment(s,pos); -} - -static INLINE INT32 getnextnum(struct pike_string *s,INT32 *pos) -{ - INT32 i; - skipwhite(s,pos); - i=0; - while (*pos<s->len && - s->str[*pos]>='0' && s->str[*pos]<='9') - { - i=(i*10)+s->str[*pos]-'0'; - getnext(s,pos); - } - return i; -} - -static char* img_frompnm(struct pike_string *s) -{ - struct image new; - INT32 type,c=0,maxval=255; - INT32 pos=0,x,y,i; - - skipwhite(s,&pos); - if (getnext(s,&pos)!='P') return "not pnm"; /* not pnm */ - type=getnext(s,&pos); - if (type<'1'||type>'6') return "unknown type"; /* unknown type */ - new.xsize=getnextnum(s,&pos); - new.ysize=getnextnum(s,&pos); - if (new.xsize<=0||new.ysize<=0) return "illegal size"; /* illegal size */ - if (type=='3'||type=='2'||type=='6'||type=='5') - maxval=getnextnum(s,&pos); - new.img=malloc(new.xsize*new.ysize*sizeof(rgb_group)+1); - if (!new.img) error("Out of memory.\n"); - - if (type=='1'||type=='2'||type=='3') - { - skipwhite(s,&pos); - } - else - { - skip_to_eol(s,&pos); - pos++; - } - for (y=0; y<new.ysize; y++) - { - for (i=0,x=0; x<new.xsize; x++) - { - switch (type) - { - case '1': - c=getnextnum(s,&pos); - pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= - (unsigned char)~(c*255); - break; - case '2': - c=getnextnum(s,&pos); - pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= - (unsigned char)((c*255L)/maxval); - break; - case '3': - pixel(&new,x,y).r=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); - pixel(&new,x,y).g=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); - pixel(&new,x,y).b=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); - break; - case '4': - if (!i) c=getnext(s,&pos),i=8; - pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= - (unsigned char)~(((c>>7)&1)*255); - c<<=1; - i--; - break; - case '5': - c=getnext(s,&pos); - pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= - (unsigned char)((c*255L)/maxval); - break; - case '6': - pixel(&new,x,y).r=(unsigned char)((getnext(s,&pos)*255L)/maxval); - pixel(&new,x,y).g=(unsigned char)((getnext(s,&pos)*255L)/maxval); - pixel(&new,x,y).b=(unsigned char)((getnext(s,&pos)*255L)/maxval); - break; - } - } - } - if (THIS->img) free(THIS->img); - THIS->xsize=new.xsize; - THIS->ysize=new.ysize; - THIS->img=new.img; - return NULL; -} - static INLINE rgb_group _pixel_apply_matrix(struct image *img, int x,int y, int width,int height, @@ -524,7 +199,8 @@ static INLINE rgb_group _pixel_apply_matrix(struct image *img, return res; } -static void img_apply_matrix(struct image *dest, + +void img_apply_matrix(struct image *dest, struct image *img, int width,int height, rgbl_group *matrix, @@ -714,21 +390,6 @@ void image_clear(INT32 args) push_object(o); } -void image_toppm(INT32 args) -{ - char buf[80]; - struct pike_string *a,*b; - - pop_n_elems(args); - if (!THIS->img) { error("no image\n"); return; } - sprintf(buf,"P6\n%d %d\n255\n",THIS->xsize,THIS->ysize); - a=make_shared_string(buf); - b=make_shared_binary_string((char*)THIS->img, - THIS->xsize*THIS->ysize*3); - push_string(add_shared_strings(a,b)); - free_string(a); - free_string(b); -} void image_fromgif(INT32 args) { @@ -747,8 +408,6 @@ void image_fromgif(INT32 args) void image_togif(INT32 args) { - char buf[80]; - struct pike_string *a,*b; rgb_group *transparent=NULL; struct colortable *ct; @@ -767,8 +426,6 @@ void image_togif(INT32 args) void image_togif_fs(INT32 args) { - char buf[80]; - struct pike_string *a,*b; rgb_group *transparent=NULL; struct colortable *ct; @@ -785,17 +442,6 @@ void image_togif_fs(INT32 args) colortable_free(ct); } -void image_frompnm(INT32 args) -{ - char *s; - if (args<1|| - sp[-args].type!=T_STRING) - error("Illegal argument to image->frompnm()\n"); - s=img_frompnm(sp[-args].u.string); - pop_n_elems(args); - if (!s) { push_object(THISOBJ); THISOBJ->refs++; } - else push_string(make_shared_string(s)); -} void image_copy(INT32 args) { @@ -914,194 +560,6 @@ void image_autocrop(INT32 args) push_object(o); } -void image_paste(INT32 args) -{ - struct image *img; - INT32 x1,y1,x2,y2,blitwidth,blitheight; - - if (args<1 - || sp[-args].type!=T_OBJECT - || !sp[-args].u.object - || sp[-args].u.object->prog!=image_program) - error("illegal argument 1 to image->paste()\n"); - if (!THIS->img) return; - - img=(struct image*)sp[-args].u.object->storage; - if (!img) return; - - if (args>=3) - { - if (sp[1-args].type!=T_INT - || sp[2-args].type!=T_INT) - error("illegal arguments to image->paste()\n"); - x1=sp[1-args].u.integer; - y1=sp[2-args].u.integer; - } - else x1=y1=0; - pop_n_elems(args-1); - - x2=x1+img->xsize-1; - y2=y1+img->ysize-1; - - blitwidth=min(x2,THIS->xsize-1)-max(x1,0)+1; - blitheight=min(y2,THIS->ysize-1)-max(y1,0)+1; - - img_blit(THIS->img+max(0,x1)+(THIS->xsize)*max(0,y1), - img->img+max(0,-x1)+(x2-x1+1)*max(0,-y1), - blitwidth, - blitheight, - THIS->xsize, - img->xsize); -} - -void image_paste_alpha(INT32 args) -{ - struct image *img; - INT32 x1,y1,x,y; - - if (args<2 - || sp[-args].type!=T_OBJECT - || !sp[-args].u.object - || sp[-args].u.object->prog!=image_program - || sp[1-args].type!=T_INT) - error("illegal arguments to image->paste_alpha()\n"); - if (!THIS->img) return; - - img=(struct image*)sp[-args].u.object->storage; - if (!img) return; - THIS->alpha=(unsigned char)(sp[1-args].u.integer); - - if (args>=4) - { - if (sp[2-args].type!=T_INT - || sp[3-args].type!=T_INT) - error("illegal arguments to image->paste_alpha()\n"); - x1=sp[2-args].u.integer; - y1=sp[3-args].u.integer; - } - else x1=y1=0; - - for (x=0; x<img->xsize; x++) - for (y=0; y<img->ysize; y++) - { - THIS->rgb=pixel(img,x,y); - setpixel_test(x1+x,y1+y); - } - - pop_n_elems(args); - THISOBJ->refs++; - push_object(THISOBJ); -} - -void image_paste_mask(INT32 args) -{ - struct image *img,*mask; - INT32 x1,y1,x,y,x2,y2; - - if (args<2) - error("illegal number of arguments to image->paste_mask()\n"); - if (sp[-args].type!=T_OBJECT - || !sp[-args].u.object - || sp[-args].u.object->prog!=image_program) - error("illegal argument 1 to image->paste_mask()\n"); - if (sp[1-args].type!=T_OBJECT - || !sp[1-args].u.object - || sp[1-args].u.object->prog!=image_program) - error("illegal argument 2 to image->paste_mask()\n"); - if (!THIS->img) return; - - img=(struct image*)sp[-args].u.object->storage; - mask=(struct image*)sp[1-args].u.object->storage; - if ((!img)||(!img->img)) error("argument 1 has no image\n"); - if ((!mask)||(!mask->img)) error("argument 2 (alpha) has no image\n"); - - if (args>=4) - { - if (sp[2-args].type!=T_INT - || sp[3-args].type!=T_INT) - error("illegal coordinate arguments to image->paste_mask()\n"); - x1=sp[2-args].u.integer; - y1=sp[3-args].u.integer; - } - else x1=y1=0; - - x2=min(THIS->xsize-x1,min(img->xsize,mask->xsize)); - y2=min(THIS->ysize-y1,min(img->ysize,mask->ysize)); - - for (x=max(0,-x1); x<x2; x++) - for (y=max(0,-y1); y<y2; y++) - { - pixel(THIS,x+x1,y+y1).r= - (unsigned char)((pixel(THIS,x+x1,y+y1).r*(long)(255-pixel(mask,x,y).r)+ - pixel(img,x,y).r*(long)pixel(mask,x,y).r)/255); - pixel(THIS,x+x1,y+y1).g= - (unsigned char)((pixel(THIS,x+x1,y+y1).g*(long)(255-pixel(mask,x,y).g)+ - pixel(img,x,y).g*(long)pixel(mask,x,y).g)/255); - pixel(THIS,x+x1,y+y1).b= - (unsigned char)((pixel(THIS,x+x1,y+y1).b*(long)(255-pixel(mask,x,y).b)+ - pixel(img,x,y).b*(long)pixel(mask,x,y).b)/255); - } - pop_n_elems(args); - THISOBJ->refs++; - push_object(THISOBJ); -} - -void image_paste_alpha_color(INT32 args) -{ - struct image *img,*mask; - INT32 x1,y1,x,y,x2,y2; - - if (args!=1 && args!=4 && args!=6 && args!=3) - error("illegal number of arguments to image->paste_alpha_color()\n"); - if (sp[-args].type!=T_OBJECT - || !sp[-args].u.object - || sp[-args].u.object->prog!=image_program) - error("illegal argument 1 to image->paste_alpha_color()\n"); - if (!THIS->img) return; - - if (args==6 || args==4) /* colors at arg 2..4 */ - getrgb(THIS,1,args,"image->paste_alpha_color()\n"); - if (args==3) /* coords at 2..3 */ - { - if (sp[1-args].type!=T_INT - || sp[2-args].type!=T_INT) - error("illegal coordinate arguments to image->paste_alpha_color()\n"); - x1=sp[1-args].u.integer; - y1=sp[2-args].u.integer; - } - else if (args==6) /* at 5..6 */ - { - if (sp[4-args].type!=T_INT - || sp[5-args].type!=T_INT) - error("illegal coordinate arguments to image->paste_alpha_color()\n"); - x1=sp[4-args].u.integer; - y1=sp[5-args].u.integer; - } - else x1=y1=0; - - mask=(struct image*)sp[-args].u.object->storage; - if (!mask||!mask->img) error("argument 2 (alpha) has no image\n"); - - x2=min(THIS->xsize-x1,mask->xsize); - y2=min(THIS->ysize-y1,mask->ysize); - - for (x=max(0,-x1); x<x2; x++) - for (y=max(0,-y1); y<y2; y++) - { - pixel(THIS,x+x1,y+y1).r= - (unsigned char)((pixel(THIS,x+x1,y+y1).r*(long)(255-pixel(mask,x,y).r)+ - THIS->rgb.r*(long)pixel(mask,x,y).r)/255); - pixel(THIS,x+x1,y+y1).g= - (unsigned char)((pixel(THIS,x+x1,y+y1).g*(long)(255-pixel(mask,x,y).g)+ - THIS->rgb.g*(long)pixel(mask,x,y).g)/255); - pixel(THIS,x+x1,y+y1).b= - (unsigned char)((pixel(THIS,x+x1,y+y1).b*(long)(255-pixel(mask,x,y).b)+ - THIS->rgb.b*(long)pixel(mask,x,y).b)/255); - } - pop_n_elems(args); - THISOBJ->refs++; - push_object(THISOBJ); -} void image_setcolor(INT32 args) { @@ -1226,62 +684,6 @@ void image_circle(INT32 args) push_object(THISOBJ); } -void image_scale(INT32 args) -{ - float factor; - struct object *o; - struct image *newimg; - - o=clone(image_program,0); - newimg=(struct image*)(o->storage); - - if (args==1 && sp[-args].type==T_FLOAT) { - if (sp[-args].u.float_number == 0.5) - img_scale2(newimg,THIS); - else - img_scale(newimg,THIS, - (INT32)(THIS->xsize*sp[-args].u.float_number), - (INT32)(THIS->ysize*sp[-args].u.float_number)); - } - else if (args>=2 && - sp[-args].type==T_INT && sp[-args].u.integer==0 && - sp[1-args].type==T_INT) - { - factor=((float)sp[1-args].u.integer)/THIS->ysize; - img_scale(newimg,THIS, - (INT32)(THIS->xsize*factor), - sp[1-args].u.integer); - } - else if (args>=2 && - sp[1-args].type==T_INT && sp[1-args].u.integer==0 && - sp[-args].type==T_INT) - { - factor=((float)sp[-args].u.integer)/THIS->xsize; - img_scale(newimg,THIS, - sp[-args].u.integer, - (INT32)(THIS->ysize*factor)); - } - else if (args>=2 && - sp[-args].type==T_FLOAT && - sp[1-args].type==T_FLOAT) - img_scale(newimg,THIS, - (INT32)(THIS->xsize*sp[-args].u.float_number), - (INT32)(THIS->ysize*sp[1-args].u.float_number)); - else if (args>=2 && - sp[-args].type==T_INT && - sp[1-args].type==T_INT) - img_scale(newimg,THIS, - sp[-args].u.integer, - sp[1-args].u.integer); - else - { - free_object(o); - error("illegal arguments to image->scale()\n"); - } - pop_n_elems(args); - push_object(o); -} - static INLINE void get_rgba_group_from_array_index(rgba_group *rgba,struct array *v,INT32 index) { struct svalue s,s2; @@ -1335,7 +737,6 @@ void image_tuned_box(INT32 args) INT32 x1,y1,x2,y2,xw,yw,x,y; rgba_group topleft,topright,bottomleft,bottomright,sum,sumzero={0,0,0,0}; rgb_group *img; - INT32 mod; if (args<5|| sp[-args].type!=T_INT|| @@ -1732,8 +1133,6 @@ fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b void image_select_from(INT32 args) { - INT32 i; - rgb_group rgb; struct object *o; struct image *img; INT32 low_limit; @@ -1985,7 +1384,6 @@ static void image_map_closest(INT32 args) struct colortable *ct; long i; rgb_group *rgb; - int colors; if (!THIS->img) error("no image\n"); if (args<1 @@ -2051,7 +1449,6 @@ static void image_map_fs(INT32 args) void image_select_colors(INT32 args) { - rgb_group *transparent=NULL; struct colortable *ct; int colors,i; @@ -2075,143 +1472,6 @@ void image_select_colors(INT32 args) colortable_free(ct); } -static void image_ccw(INT32 args) -{ - INT32 i,j; - rgb_group *src,*dest; - struct object *o; - struct image *img; - - pop_n_elems(args); - - if (!THIS->img) error("no image\n"); - - o=clone(image_program,0); - img=(struct image*)o->storage; - *img=*THIS; - if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) - { - free_object(o); - error("Out of memory\n"); - } - img->xsize=THIS->ysize; - img->ysize=THIS->xsize; - i=THIS->xsize; - src=THIS->img+THIS->xsize-1; - dest=img->img; - while (i--) - { - j=THIS->ysize; - while (j--) *(dest++)=*(src),src+=THIS->xsize; - src--; - src-=THIS->xsize*THIS->ysize; - } - - push_object(o); -} - -static void image_cw(INT32 args) -{ - INT32 i,j; - rgb_group *src,*dest; - struct object *o; - struct image *img; - - pop_n_elems(args); - - if (!THIS->img) error("no image\n"); - - o=clone(image_program,0); - img=(struct image*)o->storage; - *img=*THIS; - if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) - { - free_object(o); - error("Out of memory\n"); - } - img->xsize=THIS->ysize; - img->ysize=THIS->xsize; - i=THIS->xsize; - src=THIS->img+THIS->xsize-1; - dest=img->img+THIS->xsize*THIS->ysize; - while (i--) - { - j=THIS->ysize; - while (j--) *(--dest)=*(src),src+=THIS->xsize; - src--; - src-=THIS->xsize*THIS->ysize; - } - - push_object(o); -} - -static void image_mirrorx(INT32 args) -{ - rgb_group *src,*dest; - struct object *o; - struct image *img; - INT32 i,j; - - pop_n_elems(args); - - if (!THIS->img) error("no image\n"); - - o=clone(image_program,0); - img=(struct image*)o->storage; - *img=*THIS; - if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) - { - free_object(o); - error("Out of memory\n"); - } - - i=THIS->ysize; - src=THIS->img+THIS->xsize-1; - dest=img->img; - while (i--) - { - j=THIS->xsize; - while (j--) *(dest++)=*(src--); - src+=THIS->xsize*2; - } - - push_object(o); -} - -static void image_mirrory(INT32 args) -{ - rgb_group *src,*dest; - struct object *o; - struct image *img; - INT32 i,j; - - pop_n_elems(args); - - if (!THIS->img) error("no image\n"); - - o=clone(image_program,0); - img=(struct image*)o->storage; - *img=*THIS; - if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) - { - free_object(o); - error("Out of memory\n"); - } - - i=THIS->ysize; - src=THIS->img+THIS->xsize*(THIS->ysize-1); - dest=img->img; - while (i--) - { - j=THIS->xsize; - while (j--) *(dest++)=*(src++); - src-=THIS->xsize*2; - } - - push_object(o); - -} - /***************** global init etc *****************************/ #define RGB_TYPE "int|void,int|void,int|void,int|void" @@ -2303,6 +1563,19 @@ void init_image_programs() "function(:object)",0); add_function("mirrory",image_mirrory, "function(:object)",0); + add_function("skewx",image_skewx, + "function(int|float,"RGB_TYPE":object)",0); + add_function("skewy",image_skewy, + "function(int|float,"RGB_TYPE":object)",0); + add_function("skewx_expand",image_skewx_expand, + "function(int|float,"RGB_TYPE":object)",0); + add_function("skewy_expand",image_skewy_expand, + "function(int|float,"RGB_TYPE":object)",0); + + add_function("rotate",image_rotate, + "function(int|float,"RGB_TYPE":object)",0); + add_function("rotate_expand",image_rotate_expand, + "function(int|float,"RGB_TYPE":object)",0); add_function("xsize",image_xsize, "function(:int)",0); diff --git a/src/modules/image/image.h b/src/modules/image/image.h index 8540e77cead4807e857bff4dfa729b8c18a476d4..c577f5d54762a20b65519234542a7c186f5d1cf2 100644 --- a/src/modules/image/image.h +++ b/src/modules/image/image.h @@ -71,3 +71,40 @@ 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); + +/* blit.c */ + +void img_clear(rgb_group *dest,rgb_group rgb,INT32 size); +void img_box_nocheck(INT32 x1,INT32 y1,INT32 x2,INT32 y2); +void img_box(INT32 x1,INT32 y1,INT32 x2,INT32 y2); +void img_blit(rgb_group *dest,rgb_group *src,INT32 width, + INT32 lines,INT32 moddest,INT32 modsrc); +void img_crop(struct image *dest, + struct image *img, + INT32 x1,INT32 y1, + INT32 x2,INT32 y2); +void img_clone(struct image *newimg,struct image *img); +void image_paste(INT32 args); +void image_paste_alpha(INT32 args); +void image_paste_mask(INT32 args); +void image_paste_alpha_color(INT32 args); + +/* matrix.c */ + +void image_scale(INT32 args); +void image_skewx(INT32 args); +void image_skewy(INT32 args); +void image_skewx_expand(INT32 args); +void image_skewy_expand(INT32 args); +void image_rotate(INT32 args); +void image_rotate_expand(INT32 args); +void image_cw(INT32 args); +void image_ccw(INT32 args); +void image_ccw(INT32 args); +void image_mirrorx(INT32 args); +void image_mirrory(INT32 args); + +/* pnm.c */ + +void image_toppm(INT32 args); +void image_frompnm(INT32 args); diff --git a/src/modules/image/matrix.c b/src/modules/image/matrix.c new file mode 100644 index 0000000000000000000000000000000000000000..2153b3c36bdea8102e4a962647cc4d228f397846 --- /dev/null +++ b/src/modules/image/matrix.c @@ -0,0 +1,759 @@ +#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 "image.h" + +struct program *image_program; +#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)) + +/***************** internals ***********************************/ + +#define apply_alpha(x,y,alpha) \ + ((unsigned char)((y*(255L-(alpha))+x*(alpha))/255L)) + +#define set_rgb_group_alpha(dest,src,alpha) \ + ((dest).r=apply_alpha((dest).r,(src).r,alpha), \ + (dest).g=apply_alpha((dest).g,(src).g,alpha), \ + (dest).b=apply_alpha((dest).b,(src).b,alpha)) + +#define pixel(_img,x,y) ((_img)->img[(x)+(y)*(_img)->xsize]) + +#define setpixel(x,y) \ + (THIS->alpha? \ + set_rgb_group_alpha(THIS->img[(x)+(y)*THIS->xsize],THIS->rgb,THIS->alpha): \ + ((pixel(THIS,x,y)=THIS->rgb),0)) + +#define setpixel_test(x,y) \ + (((x)<0||(y)<0||(x)>=THIS->xsize||(y)>=THIS->ysize)? \ + 0:(setpixel(x,y),0)) + +static INLINE int getrgb(struct image *img, + INT32 args_start,INT32 args,char *name) +{ + INT32 i; + if (args-args_start<3) return 0; + 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; + return 1; +} + +static INLINE int getrgbl(rgbl_group *rgb,INT32 args_start,INT32 args,char *name) +{ + INT32 i; + if (args-args_start<3) return 0; + 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); + rgb->r=sp[-args+args_start].u.integer; + rgb->g=sp[1-args+args_start].u.integer; + rgb->b=sp[2-args+args_start].u.integer; + return 1; +} + +/** end internals **/ + + +#define decimals(x) ((x)-(int)(x)) +#define testrange(x) max(min((x),255),0) +#define _scale_add_rgb(dest,src,factor) \ + ((dest).r=testrange((dest).r+(int)((src).r*(factor)+0.5)), \ + (dest).g=testrange((dest).g+(int)((src).g*(factor)+0.5)), \ + (dest).b=testrange((dest).b+(int)((src).b*(factor)+0.5))) +#define scale_add_pixel(dest,dx,dy,dxw,src,sx,sy,sxw,factor) \ + _scale_add_rgb(dest[(dx)+(dy)*(dxw)],src[(sx)+(sy)*(sxw)],factor) + +static INLINE void scale_add_line(rgb_group *new,INT32 yn,INT32 newx, + rgb_group *img,INT32 y,INT32 xsize, + double py,double dx) +{ + INT32 x,xd; + double xn; + for (x=0,xn=0; x<THIS->xsize; x++,xn+=dx) + { + if ((INT32)xn<(INT32)(xn+dx)) + { + scale_add_pixel(new,(INT32)xn,yn,newx,img,x,y,xsize,py*(1.0-decimals(xn))); + if ((xd=(INT32)(xn+dx)-(INT32)(xn))>1) + while (--xd) + scale_add_pixel(new,(INT32)xn+xd,yn,newx,img,x,y,xsize,py); + scale_add_pixel(new,(INT32)(xn+dx),yn,newx,img,x,y,xsize,py*decimals(xn+dx)); + } + else + scale_add_pixel(new,(int)xn,yn,newx,img,x,y,xsize,py*dx); + } +} + +void img_scale(struct image *dest, + struct image *source, + INT32 newx,INT32 newy) +{ + rgb_group *new; + INT32 y,yd; + double yn,dx,dy; + + if (dest->img) { free(dest->img); dest->img=NULL; } + + if (!THIS->img || newx<=0 || newy<=0) return; /* no way */ + new=malloc(newx*newy*sizeof(rgb_group) +1); + if (!new) error("Out of memory!\n"); + + MEMSET(new,0,newx*newy*sizeof(rgb_group)); + + dx=((double)newx-0.000001)/source->xsize; + dy=((double)newy-0.000001)/source->ysize; + + for (y=0,yn=0; y<source->ysize; y++,yn+=dy) + { + if ((INT32)yn<(INT32)(yn+dy)) + { + scale_add_line(new,(INT32)(yn),newx,source->img,y,source->xsize, + (1.0-decimals(yn)),dx); + if ((yd=(INT32)(yn+dy)-(INT32)(yn))>1) + while (--yd) + scale_add_line(new,(INT32)yn+yd,newx,source->img,y,source->xsize, + 1.0,dx); + scale_add_line(new,(INT32)(yn+dy),newx,source->img,y,source->xsize, + (decimals(yn+dy)),dx); + } + else + scale_add_line(new,(INT32)yn,newx,source->img,y,source->xsize, + dy,dx); + } + + dest->img=new; + dest->xsize=newx; + dest->ysize=newy; +} + +/* Special, faster, case for scale=1/2 */ +void img_scale2(struct image *dest, struct image *source) +{ + rgb_group *new; + INT32 x, y, newx, newy; + newx = source->xsize >> 1; + newy = source->ysize >> 1; + + if (dest->img) { free(dest->img); dest->img=NULL; } + if (!THIS->img || newx<=0 || newy<=0) return; /* no way */ + new=malloc(newx*newy*sizeof(rgb_group) +1); + if (!new) error("Out of memory\n"); + MEMSET(new,0,newx*newy*sizeof(rgb_group)); + + dest->img=new; + dest->xsize=newx; + dest->ysize=newy; + for (y = 0; y < newy; y++) + for (x = 0; x < newx; x++) { + pixel(dest,x,y).r = (COLOURTYPE) + (((INT32) pixel(source,2*x+0,2*y+0).r+ + (INT32) pixel(source,2*x+1,2*y+0).r+ + (INT32) pixel(source,2*x+0,2*y+1).r+ + (INT32) pixel(source,2*x+1,2*y+1).r) >> 2); + pixel(dest,x,y).g = (COLOURTYPE) + (((INT32) pixel(source,2*x+0,2*y+0).g+ + (INT32) pixel(source,2*x+1,2*y+0).g+ + (INT32) pixel(source,2*x+0,2*y+1).g+ + (INT32) pixel(source,2*x+1,2*y+1).g) >> 2); + pixel(dest,x,y).b = (COLOURTYPE) + (((INT32) pixel(source,2*x+0,2*y+0).b+ + (INT32) pixel(source,2*x+1,2*y+0).b+ + (INT32) pixel(source,2*x+0,2*y+1).b+ + (INT32) pixel(source,2*x+1,2*y+1).b) >> 2); + } +} + + + +void image_scale(INT32 args) +{ + float factor; + struct object *o; + struct image *newimg; + + o=clone(image_program,0); + newimg=(struct image*)(o->storage); + + if (args==1 && sp[-args].type==T_FLOAT) { + if (sp[-args].u.float_number == 0.5) + img_scale2(newimg,THIS); + else + img_scale(newimg,THIS, + (INT32)(THIS->xsize*sp[-args].u.float_number), + (INT32)(THIS->ysize*sp[-args].u.float_number)); + } + else if (args>=2 && + sp[-args].type==T_INT && sp[-args].u.integer==0 && + sp[1-args].type==T_INT) + { + factor=((float)sp[1-args].u.integer)/THIS->ysize; + img_scale(newimg,THIS, + (INT32)(THIS->xsize*factor), + sp[1-args].u.integer); + } + else if (args>=2 && + sp[1-args].type==T_INT && sp[1-args].u.integer==0 && + sp[-args].type==T_INT) + { + factor=((float)sp[-args].u.integer)/THIS->xsize; + img_scale(newimg,THIS, + sp[-args].u.integer, + (INT32)(THIS->ysize*factor)); + } + else if (args>=2 && + sp[-args].type==T_FLOAT && + sp[1-args].type==T_FLOAT) + img_scale(newimg,THIS, + (INT32)(THIS->xsize*sp[-args].u.float_number), + (INT32)(THIS->ysize*sp[1-args].u.float_number)); + else if (args>=2 && + sp[-args].type==T_INT && + sp[1-args].type==T_INT) + img_scale(newimg,THIS, + sp[-args].u.integer, + sp[1-args].u.integer); + else + { + free_object(o); + error("illegal arguments to image->scale()\n"); + } + pop_n_elems(args); + push_object(o); +} + +void image_ccw(INT32 args) +{ + INT32 i,j; + rgb_group *src,*dest; + struct object *o; + struct image *img; + + pop_n_elems(args); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + img=(struct image*)o->storage; + *img=*THIS; + if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) + { + free_object(o); + error("Out of memory\n"); + } + img->xsize=THIS->ysize; + img->ysize=THIS->xsize; + i=THIS->xsize; + src=THIS->img+THIS->xsize-1; + dest=img->img; + while (i--) + { + j=THIS->ysize; + while (j--) *(dest++)=*(src),src+=THIS->xsize; + src--; + src-=THIS->xsize*THIS->ysize; + } + + push_object(o); +} + +static void img_cw(struct image *is,struct image *id) +{ + INT32 i,j; + rgb_group *src,*dest; + + if (id->img) free(id->img); + *id=*is; + if (!(id->img=malloc(sizeof(rgb_group)*is->xsize*is->ysize+1))) + error("Out of memory\n"); + + id->xsize=is->ysize; + id->ysize=is->xsize; + i=is->xsize; + src=is->img+is->xsize-1; + dest=id->img; + while (i--) + { + j=is->ysize; + while (j--) *(dest++)=*(src),src+=is->xsize; + src--; + src-=is->xsize*is->ysize; + } +} + +void img_ccw(struct image *is,struct image *id) +{ + INT32 i,j; + rgb_group *src,*dest; + + if (id->img) free(id->img); + *id=*is; + if (!(id->img=malloc(sizeof(rgb_group)*is->xsize*is->ysize+1))) + error("Out of memory\n"); + + id->xsize=is->ysize; + id->ysize=is->xsize; + i=is->xsize; + src=is->img+is->xsize-1; + dest=id->img+is->xsize*is->ysize; + while (i--) + { + j=is->ysize; + while (j--) *(--dest)=*(src),src+=is->xsize; + src--; + src-=is->xsize*is->ysize; + } +} + +void image_cw(INT32 args) +{ + INT32 i,j; + rgb_group *src,*dest; + struct object *o; + struct image *img; + + pop_n_elems(args); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + img=(struct image*)o->storage; + *img=*THIS; + if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) + { + free_object(o); + error("Out of memory\n"); + } + img->xsize=THIS->ysize; + img->ysize=THIS->xsize; + i=THIS->xsize; + src=THIS->img+THIS->xsize-1; + dest=img->img+THIS->xsize*THIS->ysize; + while (i--) + { + j=THIS->ysize; + while (j--) *(--dest)=*(src),src+=THIS->xsize; + src--; + src-=THIS->xsize*THIS->ysize; + } + + push_object(o); +} + +void image_mirrorx(INT32 args) +{ + rgb_group *src,*dest; + struct object *o; + struct image *img; + INT32 i,j; + + pop_n_elems(args); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + img=(struct image*)o->storage; + *img=*THIS; + if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) + { + free_object(o); + error("Out of memory\n"); + } + + i=THIS->ysize; + src=THIS->img+THIS->xsize-1; + dest=img->img; + while (i--) + { + j=THIS->xsize; + while (j--) *(dest++)=*(src--); + src+=THIS->xsize*2; + } + + push_object(o); +} + +void image_mirrory(INT32 args) +{ + rgb_group *src,*dest; + struct object *o; + struct image *img; + INT32 i,j; + + pop_n_elems(args); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + img=(struct image*)o->storage; + *img=*THIS; + if (!(img->img=malloc(sizeof(rgb_group)*THIS->xsize*THIS->ysize+1))) + { + free_object(o); + error("Out of memory\n"); + } + + i=THIS->ysize; + src=THIS->img+THIS->xsize*(THIS->ysize-1); + dest=img->img; + while (i--) + { + j=THIS->xsize; + while (j--) *(dest++)=*(src++); + src-=THIS->xsize*2; + } + + push_object(o); + +} + + +#define ROUND(X) ((unsigned char)((X)+0.5)) + +static void img_skewx(struct image *src, + struct image *dest, + float diff, + int xpn) /* expand pixel for use with alpha instead */ +{ + double x0,xmod,xm; + INT32 y,x,len; + rgb_group *s,*d; + rgb_group rgb; + + if (dest->img) free(dest->img); + if (diff<0) + dest->xsize=ceil(-diff)+src->xsize,x0=-diff; + else + dest->xsize=ceil(diff)+src->xsize,x0=0; + dest->ysize=src->ysize; + len=src->xsize; + + d=dest->img=malloc(sizeof(rgb_group)*dest->xsize*dest->ysize); + if (!d) return; + s=src->img; + + xmod=diff/src->ysize; + rgb=dest->rgb; + + y=src->ysize; + while (y--) + { + int j; + if (xpn) rgb=*s; + for (j=x0; j--;) *(d++)=rgb; + if (!(xm=(x0-floor(x0)))) + { + for (j=len; j--;) *(d++)=*(s++); + j=dest->xsize-x0-len; + } + else + { + float xn=1-xm; + if (xpn) + *d=*s; + else + d->r=ROUND(rgb.r*xm+s->r*xn), + d->g=ROUND(rgb.g*xm+s->g*xn), + d->b=ROUND(rgb.b*xm+s->b*xn); + d++; + for (j=len-1; j--;) + { + d->r=ROUND(s->r*xm+s[1].r*xn), + d->g=ROUND(s->g*xm+s[1].g*xn), + d->b=ROUND(s->b*xm+s[1].b*xn); + d++; + s++; + } + if (xpn) + *d=*s; + else + d->r=ROUND(rgb.r*xn+s->r*xm), + d->g=ROUND(rgb.g*xn+s->g*xm), + d->b=ROUND(rgb.b*xn+s->b*xm); + d++; + s++; + j=dest->xsize-x0-len; + } + if (xpn) rgb=s[-1]; + while (j--) *(d++)=rgb; + x0+=xmod; + } +} + +static void img_skewy(struct image *src, + struct image *dest, + float diff, + int xpn) /* expand pixel for use with alpha instead */ +{ + double y0,ymod,ym; + INT32 y,x,len,xsz; + rgb_group *s,*d; + rgb_group rgb; + + if (dest->img) free(dest->img); + if (diff<0) + dest->ysize=ceil(-diff)+src->ysize,y0=-diff; + else + dest->ysize=ceil(diff)+src->ysize,y0=0; + xsz=dest->xsize=src->xsize; + len=src->ysize; + + d=dest->img=malloc(sizeof(rgb_group)*dest->ysize*dest->xsize); + if (!d) return; + s=src->img; + + ymod=diff/src->xsize; + rgb=dest->rgb; + + x=src->xsize; + while (x--) + { + int j; + if (xpn) rgb=*s; + for (j=y0; j--;) *d=rgb,d+=xsz; + if (!(ym=(y0-floor(y0)))) + { + for (j=len; j--;) *d=*s,d+=xsz,s+=xsz; + j=dest->ysize-y0-len; + } + else + { + float yn=1-ym; + if (xpn) + *d=*s; + else + d->r=ROUND(rgb.r*ym+s->r*yn), + d->g=ROUND(rgb.g*ym+s->g*yn), + d->b=ROUND(rgb.b*ym+s->b*yn); + d+=xsz; + for (j=len-1; j--;) + { + d->r=ROUND(s->r*ym+s[xsz].r*yn), + d->g=ROUND(s->g*ym+s[xsz].g*yn), + d->b=ROUND(s->b*ym+s[xsz].b*yn); + d+=xsz; + s+=xsz; + } + if (xpn) + *d=*s; + else + d->r=ROUND(rgb.r*yn+s->r*ym), + d->g=ROUND(rgb.g*yn+s->g*ym), + d->b=ROUND(rgb.b*yn+s->b*ym); + d+=xsz; + s+=xsz; + j=dest->ysize-y0-len; + } + if (xpn) rgb=s[-xsz]; + while (j--) *d=rgb,d+=xsz; + s-=len*xsz-1; + d-=dest->ysize*xsz-1; + y0+=ymod; + } +} + +void image_skewx(INT32 args) +{ + float diff; + struct object *o; + + if (args<1) + error("too few arguments to image->skewx()\n"); + else if (sp[-args].type==T_FLOAT) + diff=THIS->ysize*sp[-args].u.float_number; + else if (sp[-args].type==T_INT) + diff=sp[-args].u.integer; + else + error("illegal argument to image->skewx()\n"); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + + if (!getrgb((struct image*)(o->storage),1,args,"image->skewx()")) + ((struct image*)(o->storage))->rgb=THIS->rgb; + + img_skewx(THIS,(struct image*)(o->storage),diff,0); + + pop_n_elems(args); + push_object(o); +} + +void image_skewy(INT32 args) +{ + float diff; + struct object *o; + + if (args<1) + error("too few arguments to image->skewy()\n"); + else if (sp[-args].type==T_FLOAT) + diff=THIS->xsize*sp[-args].u.float_number; + else if (sp[-args].type==T_INT) + diff=sp[-args].u.integer; + else + error("illegal argument to image->skewx()\n"); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + + if (!getrgb((struct image*)(o->storage),1,args,"image->skewy()")) + ((struct image*)(o->storage))->rgb=THIS->rgb; + + img_skewy(THIS,(struct image*)(o->storage),diff,0); + + pop_n_elems(args); + push_object(o); +} + +void image_skewx_expand(INT32 args) +{ + float diff; + struct object *o; + + if (args<1) + error("too few arguments to image->skewx()\n"); + else if (sp[-args].type==T_FLOAT) + diff=THIS->ysize*sp[-args].u.float_number; + else if (sp[-args].type==T_INT) + diff=sp[-args].u.integer; + else + error("illegal argument to image->skewx()\n"); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + + if (!getrgb((struct image*)(o->storage),1,args,"image->skewx()")) + ((struct image*)(o->storage))->rgb=THIS->rgb; + + img_skewx(THIS,(struct image*)(o->storage),diff,1); + + pop_n_elems(args); + push_object(o); +} + +void image_skewy_expand(INT32 args) +{ + float diff; + struct object *o; + + if (args<1) + error("too few arguments to image->skewy()\n"); + else if (sp[-args].type==T_FLOAT) + diff=THIS->xsize*sp[-args].u.float_number; + else if (sp[-args].type==T_INT) + diff=sp[-args].u.integer; + else + error("illegal argument to image->skewx()\n"); + + if (!THIS->img) error("no image\n"); + + o=clone(image_program,0); + + if (!getrgb((struct image*)(o->storage),1,args,"image->skewy()")) + ((struct image*)(o->storage))->rgb=THIS->rgb; + + img_skewy(THIS,(struct image*)(o->storage),diff,1); + + pop_n_elems(args); + push_object(o); +} + + + +void img_rotate(INT32 args,int xpn) +{ + float angle; + struct object *o; + struct image *dest,d0,dest2; + + if (args<1) + error("too few arguments to image->rotate()\n"); + else if (sp[-args].type==T_FLOAT) + angle=sp[-args].u.float_number; + else if (sp[-args].type==T_INT) + angle=sp[-args].u.integer; + else + error("illegal argument to image->rotate()\n"); + + if (!THIS->img) error("no image\n"); + + dest2.img=d0.img=NULL; + + if (angle<-135) angle-=360*(int)(angle/360); + else if (angle>225) angle-=360*(int)(angle/360); + if (angle<-45) + { + img_cw(THIS,&dest2); + angle+=90; + } + else if (angle>135) + { + img_ccw(THIS,&d0); + img_ccw(&d0,&dest2); + angle-=180; + } + else if (angle>45) + { + img_ccw(THIS,&dest2); + angle-=180; + } + else dest2=*THIS; + + angle=(angle/180.0)*3.141592653589793; + + o=clone(image_program,0); + + dest=(struct image*)(o->storage); + if (!getrgb(dest,1,args,"image->rotate()")) + (dest)->rgb=THIS->rgb; + d0.rgb=dest2.rgb=dest->rgb; + + img_skewy(&dest2,dest,-tan(angle/2)*dest2.xsize,xpn); + img_skewx(dest,&d0,sin(angle)*dest->ysize,xpn); + img_skewy(&d0,dest,-tan(angle/2)*d0.xsize,xpn); + + if (dest2.img!=THIS->img) free(dest2.img); + free(d0.img); + + pop_n_elems(args); + push_object(o); +} + +void image_rotate(INT32 args) +{ + img_rotate(args,0); +} + +void image_rotate_expand(INT32 args) +{ + img_rotate(args,1); +} + diff --git a/src/modules/image/pnm.c b/src/modules/image/pnm.c new file mode 100644 index 0000000000000000000000000000000000000000..fc964dc3096824eea7aa341b799b73e5511b5ebe --- /dev/null +++ b/src/modules/image/pnm.c @@ -0,0 +1,170 @@ +#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 "image.h" + +#define THIS ((struct image *)(fp->current_storage)) +#define THISOBJ (fp->current_object) +#define pixel(_img,x,y) ((_img)->img[(x)+(y)*(_img)->xsize]) + + +static INLINE unsigned char getnext(struct pike_string *s,INT32 *pos) +{ + if (*pos>=s->len) return 0; + if (s->str[(*pos)]=='#') + for (;*pos<s->len && ISSPACE(s->str[*pos]);(*pos)++); + return s->str[(*pos)++]; +} + +static INLINE void skip_to_eol(struct pike_string *s,INT32 *pos) +{ + for (;*pos<s->len && s->str[*pos]!=10;(*pos)++); +} + +static INLINE unsigned char getnext_skip_comment(struct pike_string *s,INT32 *pos) +{ + unsigned char c; + while ((c=getnext(s,pos))=='#') + skip_to_eol(s,pos); + return c; +} + +static INLINE void skipwhite(struct pike_string *s,INT32 *pos) +{ + while (*pos<s->len && + ( ISSPACE(s->str[*pos]) || + s->str[*pos]=='#')) + getnext_skip_comment(s,pos); +} + +static INLINE INT32 getnextnum(struct pike_string *s,INT32 *pos) +{ + INT32 i; + skipwhite(s,pos); + i=0; + while (*pos<s->len && + s->str[*pos]>='0' && s->str[*pos]<='9') + { + i=(i*10)+s->str[*pos]-'0'; + getnext(s,pos); + } + return i; +} + +static char* img_frompnm(struct pike_string *s) +{ + struct image new; + INT32 type,c=0,maxval=255; + INT32 pos=0,x,y,i; + + skipwhite(s,&pos); + if (getnext(s,&pos)!='P') return "not pnm"; /* not pnm */ + type=getnext(s,&pos); + if (type<'1'||type>'6') return "unknown type"; /* unknown type */ + new.xsize=getnextnum(s,&pos); + new.ysize=getnextnum(s,&pos); + if (new.xsize<=0||new.ysize<=0) return "illegal size"; /* illegal size */ + if (type=='3'||type=='2'||type=='6'||type=='5') + maxval=getnextnum(s,&pos); + new.img=malloc(new.xsize*new.ysize*sizeof(rgb_group)+1); + if (!new.img) error("Out of memory.\n"); + + if (type=='1'||type=='2'||type=='3') + { + skipwhite(s,&pos); + } + else + { + skip_to_eol(s,&pos); + pos++; + } + for (y=0; y<new.ysize; y++) + { + for (i=0,x=0; x<new.xsize; x++) + { + switch (type) + { + case '1': + c=getnextnum(s,&pos); + pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= + (unsigned char)~(c*255); + break; + case '2': + c=getnextnum(s,&pos); + pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= + (unsigned char)((c*255L)/maxval); + break; + case '3': + pixel(&new,x,y).r=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); + pixel(&new,x,y).g=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); + pixel(&new,x,y).b=(unsigned char)((getnextnum(s,&pos)*255L)/maxval); + break; + case '4': + if (!i) c=getnext(s,&pos),i=8; + pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= + (unsigned char)~(((c>>7)&1)*255); + c<<=1; + i--; + break; + case '5': + c=getnext(s,&pos); + pixel(&new,x,y).r=pixel(&new,x,y).g=pixel(&new,x,y).b= + (unsigned char)((c*255L)/maxval); + break; + case '6': + pixel(&new,x,y).r=(unsigned char)((getnext(s,&pos)*255L)/maxval); + pixel(&new,x,y).g=(unsigned char)((getnext(s,&pos)*255L)/maxval); + pixel(&new,x,y).b=(unsigned char)((getnext(s,&pos)*255L)/maxval); + break; + } + } + } + if (THIS->img) free(THIS->img); + THIS->xsize=new.xsize; + THIS->ysize=new.ysize; + THIS->img=new.img; + return NULL; +} + +void image_toppm(INT32 args) +{ + char buf[80]; + struct pike_string *a,*b; + + pop_n_elems(args); + if (!THIS->img) { error("no image\n"); return; } + sprintf(buf,"P6\n%d %d\n255\n",THIS->xsize,THIS->ysize); + a=make_shared_string(buf); + b=make_shared_binary_string((char*)THIS->img, + THIS->xsize*THIS->ysize*3); + push_string(add_shared_strings(a,b)); + free_string(a); + free_string(b); +} + + +void image_frompnm(INT32 args) +{ + char *s; + if (args<1|| + sp[-args].type!=T_STRING) + error("Illegal argument to image->frompnm()\n"); + s=img_frompnm(sp[-args].u.string); + pop_n_elems(args); + if (!s) { push_object(THISOBJ); THISOBJ->refs++; } + else push_string(make_shared_string(s)); +} + diff --git a/src/modules/image/togif.c b/src/modules/image/togif.c index f8a15ba5980540e0e35c634cf401c3f970706251..185430022b125004fd0f2bc66d6dff767155915c 100644 --- a/src/modules/image/togif.c +++ b/src/modules/image/togif.c @@ -377,3 +377,4 @@ int image_decode_gif(struct image *dest,struct image *dest_alpha, if (arena) free(arena); return 1; /* ok */ } +