7 image.c - implements most of the basic functions of Imager and much of the rest
13 c = i_color_new(red, green, blue, alpha);
21 image.c implements the basic functions to create and destroy image and
22 color objects for Imager.
24 =head1 FUNCTION REFERENCE
26 Some of these functions are internal.
37 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i )) )
39 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
40 void fake() { ceil(1); }
43 =item ICL_new_internal(r, g, b, a)
45 Return a new color object with values passed to it.
47 r - red component (range: 0 - 255)
48 g - green component (range: 0 - 255)
49 b - blue component (range: 0 - 255)
50 a - alpha component (range: 0 - 255)
56 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
59 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
61 if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
66 mm_log((1,"(%p) <- ICL_new_internal\n",cl));
72 =item ICL_set_internal(cl, r, g, b, a)
74 Overwrite a color with new values.
76 cl - pointer to color object
77 r - red component (range: 0 - 255)
78 g - green component (range: 0 - 255)
79 b - blue component (range: 0 - 255)
80 a - alpha component (range: 0 - 255)
86 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
87 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
89 if ( (cl=mymalloc(sizeof(i_color))) == NULL)
90 m_fatal(2,"malloc() error\n");
95 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
101 =item ICL_add(dst, src, ch)
103 Add src to dst inplace - dst is modified.
105 dst - pointer to destination color object
106 src - pointer to color object that is added
107 ch - number of channels
113 ICL_add(i_color *dst,i_color *src,int ch) {
116 tmp=dst->channel[i]+src->channel[i];
117 dst->channel[i]= tmp>255 ? 255:tmp;
124 Dump color information to log - strictly for debugging.
126 cl - pointer to color object
132 ICL_info(i_color *cl) {
133 mm_log((1,"i_color_info(cl* %p)\n",cl));
134 mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
140 Destroy ancillary data for Color object.
142 cl - pointer to color object
148 ICL_DESTROY(i_color *cl) {
149 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
154 =item IIM_new(x, y, ch)
156 Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
163 IIM_new(int x,int y,int ch) {
165 mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
167 im=i_img_empty_ch(NULL,x,y,ch);
169 mm_log((1,"(%p) <- IIM_new\n",im));
175 IIM_DESTROY(i_img *im) {
176 mm_log((1,"IIM_DESTROY(im* %p)\n",im));
185 Create new image reference - notice that this isn't an object yet and
186 this should be fixed asap.
196 mm_log((1,"i_img_struct()\n"));
197 if ( (im=mymalloc(sizeof(i_img))) == NULL)
198 m_fatal(2,"malloc() error\n");
207 im->i_f_ppix=i_ppix_d;
208 im->i_f_gpix=i_gpix_d;
209 im->i_f_plin=i_plin_d;
210 im->i_f_glin=i_glin_d;
213 mm_log((1,"(%p) <- i_img_struct\n",im));
218 =item i_img_empty(im, x, y)
220 Re-new image reference (assumes 3 channels)
223 x - xsize of destination image
224 y - ysize of destination image
230 i_img_empty(i_img *im,int x,int y) {
231 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
233 if ( (im=mymalloc(sizeof(i_img))) == NULL)
234 m_fatal(2,"malloc() error\n");
239 im->ch_mask = MAXINT;
240 im->bytes=x*y*im->channels;
241 if ( (im->data = mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
242 memset(im->data, 0, (size_t)im->bytes);
244 im->i_f_ppix = i_ppix_d;
245 im->i_f_gpix = i_gpix_d;
246 im->i_f_plin = i_plin_d;
247 im->i_f_glin = i_glin_d;
250 mm_log((1,"(%p) <- i_img_empty\n", im));
255 =item i_img_empty_ch(im, x, y, ch)
257 Re-new image reference
260 x - xsize of destination image
261 y - ysize of destination image
262 ch - number of channels
268 i_img_empty_ch(i_img *im,int x,int y,int ch) {
269 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
271 if ( (im=mymalloc(sizeof(i_img))) == NULL)
272 m_fatal(2,"malloc() error\n");
277 im->ch_mask = MAXINT;
278 im->bytes=x*y*im->channels;
279 if ( (im->data=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
280 memset(im->data,0,(size_t)im->bytes);
282 im->i_f_ppix = i_ppix_d;
283 im->i_f_gpix = i_gpix_d;
284 im->i_f_plin = i_plin_d;
285 im->i_f_glin = i_glin_d;
288 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
293 =item i_img_exorcise(im)
303 i_img_exorcise(i_img *im) {
304 mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
305 if (im->data != NULL) { myfree(im->data); }
311 im->i_f_ppix=i_ppix_d;
312 im->i_f_gpix=i_gpix_d;
313 im->i_f_plin=i_plin_d;
314 im->i_f_glin=i_glin_d;
319 =item i_img_destroy(im)
321 Destroy image and free data via exorcise.
329 i_img_destroy(i_img *im) {
330 mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
332 if (im) { myfree(im); }
336 =item i_img_info(im, info)
338 Return image information
341 info - pointer to array to return data
343 info is an array of 4 integers with the following values:
348 info[3] - channel mask
355 i_img_info(i_img *im,int *info) {
356 mm_log((1,"i_img_info(im 0x%x)\n",im));
358 mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
359 mm_log((1,"i_img_info: data=0x%d\n",im->data));
362 info[2] = im->channels;
363 info[3] = im->ch_mask;
373 =item i_img_setmask(im, ch_mask)
375 Set the image channel mask for I<im> to I<ch_mask>.
380 i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
384 =item i_img_getmask(im)
386 Get the image channel mask for I<im>.
391 i_img_getmask(i_img *im) { return im->ch_mask; }
394 =item i_img_getchannels(im)
396 Get the number of channels in I<im>.
401 i_img_getchannels(i_img *im) { return im->channels; }
405 =item i_ppix(im, x, y, col)
407 Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
409 Returns true if the pixel could be set, false if x or y is out of
415 i_ppix(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
418 =item i_gpix(im, x, y, &col)
420 Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
422 Returns true if the pixel could be retrieved, false otherwise.
427 i_gpix(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
430 =item i_ppix_d(im, x, y, col)
434 This is the function kept in the i_f_ppix member of an i_img object.
435 It does a normal store of a pixel into the image with range checking.
437 Returns true if the pixel could be set, false otherwise.
442 i_ppix_d(i_img *im, int x, int y, i_color *val) {
445 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
446 for(ch=0;ch<im->channels;ch++)
447 if (im->ch_mask&(1<<ch))
448 im->data[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
451 return -1; /* error was clipped */
455 =item i_gpix_d(im, x, y, &col)
459 This is the function kept in the i_f_gpix member of an i_img object.
460 It does normal retrieval of a pixel from the image with range checking.
462 Returns true if the pixel could be set, false otherwise.
467 i_gpix_d(i_img *im, int x, int y, i_color *val) {
469 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
470 for(ch=0;ch<im->channels;ch++)
471 val->channel[ch]=im->data[(x+y*im->xsize)*im->channels+ch];
474 return -1; /* error was cliped */
478 =item i_glin_d(im, l, r, y, vals)
480 Reads a line of data from the image, storing the pixels at vals.
482 The line runs from (l,y) inclusive to (r,y) non-inclusive
484 vals should point at space for (r-l) pixels.
486 l should never be less than zero (to avoid confusion about where to
487 put the pixels in vals).
489 Returns the number of pixels copied (eg. if r, l or y is out of range)
493 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
498 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
501 data = im->data + (l+y*im->xsize) * im->channels;
503 for (i = 0; i < count; ++i) {
504 for (ch = 0; ch < im->channels; ++ch)
505 vals[i].channel[ch] = *data++;
514 =item i_plin_d(im, l, r, y, vals)
516 Writes a line of data into the image, using the pixels at vals.
518 The line runs from (l,y) inclusive to (r,y) non-inclusive
520 vals should point at (r-l) pixels.
522 l should never be less than zero (to avoid confusion about where to
523 get the pixels in vals).
525 Returns the number of pixels copied (eg. if r, l or y is out of range)
529 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
534 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
537 data = im->data + (l+y*im->xsize) * im->channels;
539 for (i = 0; i < count; ++i) {
540 for (ch = 0; ch < im->channels; ++ch) {
541 if (im->ch_mask & (1 << ch))
542 *data = vals[i].channel[ch];
554 =item i_ppix_pch(im, x, y, ch)
556 Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
559 Returns zero if x or y is out of range.
561 Warning: this ignores the vptr interface for images.
566 i_gpix_pch(i_img *im,int x,int y,int ch) {
567 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
573 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
575 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
576 (tx,ty) specifies the upper left corner for the target image.
577 pass NULL in trans for non transparent i_colors.
583 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
585 int x,y,t,ttx,tty,tt,ch;
587 mm_log((1,"i_copyto_trans(im* %p,src 0x%x, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d, trans* 0x%x)\n",
588 im, src, x1, y1, x2, y2, tx, ty, trans));
590 if (x2<x1) { t=x1; x1=x2; x2=t; }
591 if (y2<y1) { t=y1; y1=y2; y2=t; }
603 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
604 if (tt) i_ppix(im,ttx,tty,&pv);
605 } else i_ppix(im,ttx,tty,&pv);
613 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
615 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
616 a rectangle the same size with it's top-left corner at (tx,ty) in the
619 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
625 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
627 int x, y, t, ttx, tty;
629 if (x2<x1) { t=x1; x1=x2; x2=t; }
630 if (y2<y1) { t=y1; y1=y2; y2=t; }
632 mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
633 im, src, x1, y1, x2, y2, tx, ty));
636 for(y=y1; y<y2; y++) {
638 for(x=x1; x<x2; x++) {
639 i_gpix(src, x, y, &pv);
640 i_ppix(im, ttx, tty, &pv);
648 =item i_copy(im, src)
650 Copies the contents of the image I<src> over the image I<im>.
656 i_copy(i_img *im, i_img *src) {
660 mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
664 i_img_empty_ch(im, x1, y1, src->channels);
665 pv = mymalloc(sizeof(i_color) * x1);
667 for (y = 0; y < y1; ++y) {
668 i_glin(src, 0, x1, y, pv);
669 i_plin(im, 0, x1, y, pv);
675 =item i_rubthru(im, src, tx, ty)
677 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
679 The alpha channel of each pixel in I<src> is used to control how much
680 the existing colour in I<im> is replaced, if it is 255 then the colour
681 is completely replaced, if it is 0 then the original colour is left
688 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
689 i_color pv, orig, dest;
692 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
694 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
695 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
698 for(x=0; x<src->xsize; x++) {
700 for(y=0;y<src->ysize;y++) {
701 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
702 i_gpix(src, x, y, &pv);
703 i_gpix(im, ttx, tty, &orig);
704 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
705 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
706 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
707 i_ppix(im, ttx, tty, &dest);
716 =item i_flipxy(im, axis)
718 Flips the image inplace around the axis specified.
719 Returns 0 if parameters are invalid.
722 axis - 0 = x, 1 = y, 2 = both
728 i_flipxy(i_img *im, int direction) {
729 int x, x2, y, y2, xm, ym;
733 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
738 case XAXIS: /* Horizontal flip */
741 for(y=0; y<ym; y++) {
743 for(x=0; x<xm; x++) {
745 i_gpix(im, x, y, &val1);
746 i_gpix(im, x2, y, &val2);
747 i_ppix(im, x, y, &val2);
748 i_ppix(im, x2, y, &val1);
753 case YAXIS: /* Vertical flip */
757 for(y=0; y<ym; y++) {
758 for(x=0; x<xm; x++) {
760 i_gpix(im, x, y, &val1);
761 i_gpix(im, x, y2, &val2);
762 i_ppix(im, x, y, &val2);
763 i_ppix(im, x, y2, &val1);
768 case XYAXIS: /* Horizontal and Vertical flip */
772 for(y=0; y<ym; y++) {
774 for(x=0; x<xm; x++) {
776 i_gpix(im, x, y, &val1);
777 i_gpix(im, x2, y2, &val2);
778 i_ppix(im, x, y, &val2);
779 i_ppix(im, x2, y2, &val1);
781 i_gpix(im, x2, y, &val1);
782 i_gpix(im, x, y2, &val2);
783 i_ppix(im, x2, y, &val2);
784 i_ppix(im, x, y2, &val1);
789 if (xm*2 != xs) { /* odd number of column */
790 mm_log((1, "i_flipxy: odd number of columns\n"));
793 for(y=0; y<ym; y++) {
795 i_gpix(im, x, y, &val1);
796 i_gpix(im, x, y2, &val2);
797 i_ppix(im, x, y, &val2);
798 i_ppix(im, x, y2, &val1);
802 if (ym*2 != ys) { /* odd number of rows */
803 mm_log((1, "i_flipxy: odd number of rows\n"));
806 for(x=0; x<xm; x++) {
808 i_gpix(im, x, y, &val1);
809 i_gpix(im, x2, y, &val2);
810 i_ppix(im, x, y, &val2);
811 i_ppix(im, x2, y, &val1);
817 mm_log((1, "i_flipxy: direction is invalid\n" ));
835 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
836 else if (x == 0.0) return (1.0);
837 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
841 =item i_scaleaxis(im, value, axis)
843 Returns a new image object which is I<im> scaled by I<value> along
844 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
850 i_scaleaxis(i_img *im, float Value, int Axis) {
851 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
852 int LanczosWidthFactor;
853 float *l0, *l1, OldLocation;
854 int T, TempJump1, TempJump2;
855 float F, PictureValue[MAXCHANNELS];
857 i_color val,val1,val2;
860 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
863 hsize = (int) ((float) im->xsize * Value);
869 TempJump1 = (hsize - 1) * 3;
870 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
873 vsize = (int) ((float) im->ysize * Value);
882 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
884 if (Value >=1) LanczosWidthFactor = 1;
885 else LanczosWidthFactor = (int) (1.0/Value);
887 lMax = LanczosWidthFactor << 1;
889 l0 = (float *) mymalloc(lMax * sizeof(float));
890 l1 = (float *) mymalloc(lMax * sizeof(float));
892 for (j=0; j<jEnd; j++) {
893 OldLocation = ((float) j) / Value;
894 T = (int) (OldLocation);
895 F = OldLocation - (float) T;
897 for (l = 0; l < lMax; l++) {
898 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
899 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
904 for (i=0; i<iEnd; i++) {
905 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
906 for (l=0; l < lMax; l++) {
907 i_gpix(im,T+l+1, i, &val1);
908 i_gpix(im,T-lMax+l+1, i, &val2);
909 for (k=0; k<im->channels; k++) {
910 PictureValue[k] += l1[l] * val1.channel[k];
911 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
914 for(k=0;k<im->channels;k++) {
915 psave = (short)( PictureValue[k] / LanczosWidthFactor);
916 val.channel[k]=minmax(0,255,psave);
918 i_ppix(new_img,j,i,&val);
923 for (i=0; i<iEnd; i++) {
924 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
925 for (l=0; l < lMax; l++) {
926 i_gpix(im,i, T+l+1, &val1);
927 i_gpix(im,i, T-lMax+l+1, &val2);
928 for (k=0; k<im->channels; k++) {
929 PictureValue[k] += l1[l] * val1.channel[k];
930 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
933 for (k=0; k<im->channels; k++) {
934 psave = (short)( PictureValue[k] / LanczosWidthFactor);
935 val.channel[k]=minmax(0,255,psave);
937 i_ppix(new_img,i,j,&val);
945 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
952 =item i_scale_nn(im, scx, scy)
954 Scale by using nearest neighbor
955 Both axes scaled at the same time since
956 nothing is gained by doing it in two steps
963 i_scale_nn(i_img *im, float scx, float scy) {
965 int nxsize,nysize,nx,ny;
969 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
971 nxsize = (int) ((float) im->xsize * scx);
972 nysize = (int) ((float) im->ysize * scy);
974 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
976 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
977 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
978 i_ppix(new_img,nx,ny,&val);
981 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
988 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
990 Spatially transforms I<im> returning a new image.
992 opx for a length of opxl and opy for a length of opy are arrays of
993 operators that modify the x and y positions to retreive the pixel data from.
995 parm and parmlen define extra parameters that the operators may use.
997 Note that this function is largely superseded by the more flexible
998 L<transform.c/i_transform2>.
1000 Returns the new image.
1002 The operators for this function are defined in L<stackmach.c>.
1007 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1009 int nxsize,nysize,nx,ny;
1013 mm_log((1,"i_transform(im 0x%x, opx 0x%x, opxl %d, opy 0x%x, opyl %d, parm 0x%x, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
1016 nysize = im->ysize ;
1018 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1019 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1020 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1021 /* parm[parmlen-2]=(double)nx;
1022 parm[parmlen-1]=(double)ny; */
1027 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1028 rx=op_run(opx,opxl,parm,parmlen);
1029 ry=op_run(opy,opyl,parm,parmlen);
1030 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1031 i_gpix(im,rx,ry,&val);
1032 i_ppix(new_img,nx,ny,&val);
1035 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1040 =item i_img_diff(im1, im2)
1042 Calculates the sum of the squares of the differences between
1043 correspoding channels in two images.
1045 If the images are not the same size then only the common area is
1046 compared, hence even if images are different sizes this function
1052 i_img_diff(i_img *im1,i_img *im2) {
1053 int x,y,ch,xb,yb,chb;
1057 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1059 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1060 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1061 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1063 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1066 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1067 i_gpix(im1,x,y,&val1);
1068 i_gpix(im2,x,y,&val2);
1070 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1072 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1076 /* just a tiny demo of haar wavelets */
1084 i_img *new_img,*new_img2;
1085 i_color val1,val2,dval1,dval2;
1093 /* horizontal pass */
1095 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1096 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1099 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1100 i_gpix(im,x*2,y,&val1);
1101 i_gpix(im,x*2+1,y,&val2);
1102 for(ch=0;ch<im->channels;ch++) {
1103 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1104 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1106 i_ppix(new_img,x,y,&dval1);
1107 i_ppix(new_img,x+fx,y,&dval2);
1110 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1111 i_gpix(new_img,x,y*2,&val1);
1112 i_gpix(new_img,x,y*2+1,&val2);
1113 for(ch=0;ch<im->channels;ch++) {
1114 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1115 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1117 i_ppix(new_img2,x,y,&dval1);
1118 i_ppix(new_img2,x,y+fy,&dval2);
1121 i_img_destroy(new_img);
1126 =item i_count_colors(im, maxc)
1128 returns number of colors or -1
1129 to indicate that it was more than max colors
1134 i_count_colors(i_img *im,int maxc) {
1141 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1148 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1149 i_gpix(im,x,y,&val);
1150 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1151 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1158 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1159 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1160 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1161 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1165 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1167 Performs general read buffering for file readers that permit reading
1168 to be done through a callback.
1170 The final callback gets two parameters, a I<need> value, and a I<want>
1171 value, where I<need> is the amount of data that the file library needs
1172 to read, and I<want> is the amount of space available in the buffer
1173 maintained by these functions.
1175 This means if you need to read from a stream that you don't know the
1176 length of, you can return I<need> bytes, taking the performance hit of
1177 possibly expensive callbacks (eg. back to perl code), or if you are
1178 reading from a stream where it doesn't matter if some data is lost, or
1179 if the total length of the stream is known, you can return I<want>
1186 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1189 if (length < gci->length - gci->cpos) {
1191 memcpy(buf, gci->buffer+gci->cpos, length);
1192 gci->cpos += length;
1197 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1198 total += gci->length - gci->cpos;
1199 length -= gci->length - gci->cpos;
1200 buf += gci->length - gci->cpos;
1201 if (length < (int)sizeof(gci->buffer)) {
1205 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1206 sizeof(gci->buffer))) > 0) {
1208 gci->length = did_read;
1210 copy_size = min(length, gci->length);
1211 memcpy(buf, gci->buffer, copy_size);
1212 gci->cpos += copy_size;
1215 length -= copy_size;
1219 /* just read the rest - too big for our buffer*/
1221 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1231 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1233 For use by callback file readers to initialize the reader buffer.
1235 Allocates, initializes and returns the reader buffer.
1237 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1242 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1243 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1245 self->userdata = userdata;
1253 =item free_gen_read_data(i_gen_read_data *)
1259 void free_gen_read_data(i_gen_read_data *self) {
1264 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1266 Performs write buffering for a callback based file writer.
1268 Failures are considered fatal, if a write fails then data will be
1275 i_gen_write_data *self,
1279 if (self->filledto && self->filledto+size > self->maxlength) {
1280 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1288 if (self->filledto+size <= self->maxlength) {
1290 memcpy(self->buffer+self->filledto, data, size);
1291 self->filledto += size;
1294 /* doesn't fit - hand it off */
1295 return self->cb(self->userdata, data, size);
1299 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1301 Allocates and initializes the data structure used by i_gen_writer.
1303 This should be released with L<image.c/free_gen_write_data>
1307 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1308 char *userdata, int max_length)
1310 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1312 self->userdata = userdata;
1313 self->maxlength = min(max_length, sizeof(self->buffer));
1314 if (self->maxlength < 0)
1315 self->maxlength = sizeof(self->buffer);
1322 =item free_gen_write_data(i_gen_write_data *info, int flush)
1324 Cleans up the write buffer.
1326 Will flush any left-over data if I<flush> is non-zero.
1328 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1330 Return zero only if flush is non-zero and info->cb() returns zero.
1336 int free_gen_write_data(i_gen_write_data *info, int flush)
1338 int result = !flush ||
1339 info->filledto == 0 ||
1340 info->cb(info->userdata, info->buffer, info->filledto);