diff --git a/src/modules/image/image.c b/src/modules/image/image.c index c3304167d885f52396c1c4fabf820490350a0cf3..3ead03ddf14f28549cb0a60475c62689373dae8a 100644 --- a/src/modules/image/image.c +++ b/src/modules/image/image.c @@ -1575,7 +1575,7 @@ void image_distancesq(INT32 args) { #define DISTANCE(A,B) \ (sq((long)(A).r-(B).r)+sq((long)(A).g-(B).g)+sq((long)(A).b-(B).b)) - d->r=d->g=d->b=testrange(DISTANCE(*s,rgb)/255); + d->r=d->g=d->b=testrange(DISTANCE(*s,rgb)>>8); d++; s++; } @@ -1583,6 +1583,161 @@ void image_distancesq(INT32 args) push_object(o); } +#define ISF_LEFT 4 +#define ISF_RIGHT 8 + +void isf_seek(int mode,int ydir,INT32 low_limit,INT32 x1,INT32 x2,INT32 y, + rgb_group *src,rgb_group *dest,INT32 xsize,INT32 ysize, + rgb_group rgb,int reclvl) +{ + INT32 x,xr; + INT32 j; + +#ifdef DEBUG_ISF + fprintf(stderr,"isf_seek reclvl=%d mode=%d, ydir=%d, low_limit=%d, x1=%d, x2=%d, y=%d, src=%lx, dest=%lx, xsize=%d, ysize=%d, rgb=%d,%d,%d\n",reclvl, + mode,ydir,low_limit,x1,x2,y,src,dest,xsize,ysize,rgb.r,rgb.g,rgb.b); +#endif + +#define MARK_DISTANCE(_dest,_value) ((_dest).r=(_dest).g=(_dest).b=((_value)?(_value):1)),fprintf(stderr,"%d,",_value) + if ( mode&ISF_LEFT ) /* scan left from x1 */ + { + x=x1; + while (x>0) + { + x--; +#ifdef DEBUG_ISF +fprintf(stderr,"<-- %d (",DISTANCE(rgb,src[x+y*xsize])); +fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b); +#endif + if ( (j=DISTANCE(rgb,src[x+y*xsize])) >low_limit) + { + x++; + break; + } + else + { + if (dest[x+y*xsize].r) { x++; break; } /* been there */ + MARK_DISTANCE(dest[x+y*xsize],j); + } + } + if (x1>x) + { + isf_seek(ISF_LEFT,-ydir,low_limit, + x,x1-1,y,src,dest,xsize,ysize,rgb,reclvl+1); + } + x1=x; + } + if ( mode&ISF_RIGHT ) /* scan right from x2 */ + { + x=x2; + while (x<xsize-1) + { + x++; +#ifdef DEBUG_ISF +fprintf(stderr,"--> %d (",DISTANCE(rgb,src[x+y*xsize])); +fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b); +#endif + if ( (j=DISTANCE(rgb,src[x+y*xsize])) >low_limit) + { + x--; + break; + } + else + { + if (dest[x+y*xsize].r) { x--; break; } /* done that */ + MARK_DISTANCE(dest[x+y*xsize],j); + } + } + if (x2<x) + { + isf_seek(ISF_RIGHT,-ydir,low_limit, + x2+1,x,y,src,dest,xsize,ysize,rgb,reclvl+1); + } + x2=x; + } + xr=x=x1; + y+=ydir; + if (y<0 || y>=ysize) return; + while (x<=x2) + { +#ifdef DEBUG_ISF +fprintf(stderr,"==> %d (",DISTANCE(rgb,src[x+y*xsize])); +fprintf(stderr," %d,%d,%d)\n",src[x+y*xsize].r,src[x+y*xsize].g,src[x+y*xsize].b); +#endif + if ( dest[x+y*xsize].r || + (j=DISTANCE(rgb,src[x+y*xsize])) >low_limit) /* seen that */ + { + if (xr<x) + isf_seek(ISF_LEFT*(xr==x1),ydir,low_limit, + xr,x-1,y,src,dest,xsize,ysize,rgb,reclvl+1); + while (++x<=x2) + if ( (j=DISTANCE(rgb,src[x+y*xsize])) <=low_limit) break; + xr=x; + x++; + if (x>x2) return; + continue; + } + MARK_DISTANCE(dest[x+y*xsize],j); + x++; + } + if (x>xr) + isf_seek((ISF_LEFT*(xr==x1))|ISF_RIGHT,ydir,low_limit, + xr,x-1,y,src,dest,xsize,ysize,rgb,reclvl+1); +} + +void image_select_from(INT32 args) +{ + INT32 i; + rgb_group rgb; + struct object *o; + struct image *img; + INT32 low_limit; + + if (!THIS->img) error("no image\n"); + + if (args<2 + || sp[-args].type!=T_INT + || sp[1-args].type!=T_INT) + error("Illegal argument(s) to image->select_from()\n"); + + if (args>=3) + if (sp[2-args].type!=T_INT) + error("Illegal argument 3 (edge type) to image->select_from()\n"); + else + low_limit=max(0,sp[2-args].u.integer); + else + low_limit=30; + low_limit=low_limit*low_limit; + + 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"); + } + MEMSET(img->img,sizeof(rgb_group)*img->xsize*img->ysize,0); + + if (sp[-args].u.integer>=0 && sp[-args].u.integer<img->xsize + && sp[1-args].u.integer>=0 && sp[1-args].u.integer<img->ysize) + { + isf_seek(ISF_LEFT|ISF_RIGHT,1,low_limit, + sp[-args].u.integer,sp[-args].u.integer, + sp[1-args].u.integer, + THIS->img,img->img,img->xsize,img->ysize, + pixel(THIS,sp[-args].u.integer,sp[1-args].u.integer),0); + isf_seek(ISF_LEFT|ISF_RIGHT,-1,low_limit, + sp[-args].u.integer,sp[-args].u.integer, + sp[1-args].u.integer, + THIS->img,img->img,img->xsize,img->ysize, + pixel(THIS,sp[-args].u.integer,sp[1-args].u.integer),0); + } + + pop_n_elems(args); + push_object(o); +} + void image_apply_matrix(INT32 args) { int width,height,i,j; @@ -2083,6 +2238,8 @@ void init_image_programs() "function("RGB_TYPE":object)",0); add_function("distancesq",image_distancesq, "function("RGB_TYPE":object)",0); + add_function("select_from",image_select_from, + "function(int,int:object)",0); add_function("apply_matrix",image_apply_matrix, "function(array(array(int|array(int))):object)",0);