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) {
496 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
499 data = im->data + (l+y*im->xsize) * im->channels;
501 for (i = 0; i < count; ++i) {
502 for (ch = 0; ch < im->channels; ++ch)
503 vals[i].channel[ch] = *data++;
512 =item i_plin_d(im, l, r, y, vals)
514 Writes a line of data into the image, using the pixels at vals.
516 The line runs from (l,y) inclusive to (r,y) non-inclusive
518 vals should point at (r-l) pixels.
520 l should never be less than zero (to avoid confusion about where to
521 get the pixels in vals).
523 Returns the number of pixels copied (eg. if r, l or y is out of range)
527 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
530 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
533 data = im->data + (l+y*im->xsize) * im->channels;
535 for (i = 0; i < count; ++i) {
536 for (ch = 0; ch < im->channels; ++ch) {
537 if (im->ch_mask & (1 << ch))
538 *data = vals[i].channel[ch];
550 =item i_ppix_pch(im, x, y, ch)
552 Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
555 Returns zero if x or y is out of range.
557 Warning: this ignores the vptr interface for images.
562 i_gpix_pch(i_img *im,int x,int y,int ch) {
563 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
569 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
571 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
572 (tx,ty) specifies the upper left corner for the target image.
573 pass NULL in trans for non transparent i_colors.
579 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
581 int x,y,t,ttx,tty,tt,ch;
583 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",
584 im, src, x1, y1, x2, y2, tx, ty, trans));
586 if (x2<x1) { t=x1; x1=x2; x2=t; }
587 if (y2<y1) { t=y1; y1=y2; y2=t; }
599 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
600 if (tt) i_ppix(im,ttx,tty,&pv);
601 } else i_ppix(im,ttx,tty,&pv);
609 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
611 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
612 a rectangle the same size with it's top-left corner at (tx,ty) in the
615 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
621 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
623 int x, y, t, ttx, tty;
625 if (x2<x1) { t=x1; x1=x2; x2=t; }
626 if (y2<y1) { t=y1; y1=y2; y2=t; }
628 mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
629 im, src, x1, y1, x2, y2, tx, ty));
632 for(y=y1; y<y2; y++) {
634 for(x=x1; x<x2; x++) {
635 i_gpix(src, x, y, &pv);
636 i_ppix(im, ttx, tty, &pv);
644 =item i_copy(im, src)
646 Copies the contents of the image I<src> over the image I<im>.
652 i_copy(i_img *im, i_img *src) {
656 mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
660 i_img_empty_ch(im, x1, y1, src->channels);
661 pv = mymalloc(sizeof(i_color) * x1);
663 for (y = 0; y < y1; ++y) {
664 i_glin(src, 0, x1, y, pv);
665 i_plin(im, 0, x1, y, pv);
672 =item i_rubthru(im, src, tx, ty)
674 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
676 The alpha channel of each pixel in I<src> is used to control how much
677 the existing colour in I<im> is replaced, if it is 255 then the colour
678 is completely replaced, if it is 0 then the original colour is left
685 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
686 i_color pv, orig, dest;
689 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
691 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
692 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
695 for(x=0; x<src->xsize; x++) {
697 for(y=0;y<src->ysize;y++) {
698 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
699 i_gpix(src, x, y, &pv);
700 i_gpix(im, ttx, tty, &orig);
701 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
702 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
703 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
704 i_ppix(im, ttx, tty, &dest);
713 =item i_flipxy(im, axis)
715 Flips the image inplace around the axis specified.
716 Returns 0 if parameters are invalid.
719 axis - 0 = x, 1 = y, 2 = both
725 i_flipxy(i_img *im, int direction) {
726 int x, x2, y, y2, xm, ym;
730 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
735 case XAXIS: /* Horizontal flip */
738 for(y=0; y<ym; y++) {
740 for(x=0; x<xm; x++) {
742 i_gpix(im, x, y, &val1);
743 i_gpix(im, x2, y, &val2);
744 i_ppix(im, x, y, &val2);
745 i_ppix(im, x2, y, &val1);
750 case YAXIS: /* Vertical flip */
754 for(y=0; y<ym; y++) {
755 for(x=0; x<xm; x++) {
757 i_gpix(im, x, y, &val1);
758 i_gpix(im, x, y2, &val2);
759 i_ppix(im, x, y, &val2);
760 i_ppix(im, x, y2, &val1);
765 case XYAXIS: /* Horizontal and Vertical flip */
769 for(y=0; y<ym; y++) {
771 for(x=0; x<xm; x++) {
773 i_gpix(im, x, y, &val1);
774 i_gpix(im, x2, y2, &val2);
775 i_ppix(im, x, y, &val2);
776 i_ppix(im, x2, y2, &val1);
778 i_gpix(im, x2, y, &val1);
779 i_gpix(im, x, y2, &val2);
780 i_ppix(im, x2, y, &val2);
781 i_ppix(im, x, y2, &val1);
786 if (xm*2 != xs) { /* odd number of column */
787 mm_log((1, "i_flipxy: odd number of columns\n"));
790 for(y=0; y<ym; y++) {
792 i_gpix(im, x, y, &val1);
793 i_gpix(im, x, y2, &val2);
794 i_ppix(im, x, y, &val2);
795 i_ppix(im, x, y2, &val1);
799 if (ym*2 != ys) { /* odd number of rows */
800 mm_log((1, "i_flipxy: odd number of rows\n"));
803 for(x=0; x<xm; x++) {
805 i_gpix(im, x, y, &val1);
806 i_gpix(im, x2, y, &val2);
807 i_ppix(im, x, y, &val2);
808 i_ppix(im, x2, y, &val1);
814 mm_log((1, "i_flipxy: direction is invalid\n" ));
832 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
833 else if (x == 0.0) return (1.0);
834 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
838 =item i_scaleaxis(im, value, axis)
840 Returns a new image object which is I<im> scaled by I<value> along
841 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
847 i_scaleaxis(i_img *im, float Value, int Axis) {
848 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
849 int LanczosWidthFactor;
850 float *l0, *l1, OldLocation;
851 int T, TempJump1, TempJump2;
852 float F, PictureValue[MAXCHANNELS];
854 i_color val,val1,val2;
857 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
860 hsize = (int) ((float) im->xsize * Value);
866 TempJump1 = (hsize - 1) * 3;
867 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
870 vsize = (int) ((float) im->ysize * Value);
879 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
881 if (Value >=1) LanczosWidthFactor = 1;
882 else LanczosWidthFactor = (int) (1.0/Value);
884 lMax = LanczosWidthFactor << 1;
886 l0 = (float *) mymalloc(lMax * sizeof(float));
887 l1 = (float *) mymalloc(lMax * sizeof(float));
889 for (j=0; j<jEnd; j++) {
890 OldLocation = ((float) j) / Value;
891 T = (int) (OldLocation);
892 F = OldLocation - (float) T;
894 for (l = 0; l < lMax; l++) {
895 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
896 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
901 for (i=0; i<iEnd; i++) {
902 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
903 for (l=0; l < lMax; l++) {
904 i_gpix(im,T+l+1, i, &val1);
905 i_gpix(im,T-lMax+l+1, i, &val2);
906 for (k=0; k<im->channels; k++) {
907 PictureValue[k] += l1[l] * val1.channel[k];
908 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
911 for(k=0;k<im->channels;k++) {
912 psave = (short)( PictureValue[k] / LanczosWidthFactor);
913 val.channel[k]=minmax(0,255,psave);
915 i_ppix(new_img,j,i,&val);
920 for (i=0; i<iEnd; i++) {
921 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
922 for (l=0; l < lMax; l++) {
923 i_gpix(im,i, T+l+1, &val1);
924 i_gpix(im,i, T-lMax+l+1, &val2);
925 for (k=0; k<im->channels; k++) {
926 PictureValue[k] += l1[l] * val1.channel[k];
927 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
930 for (k=0; k<im->channels; k++) {
931 psave = (short)( PictureValue[k] / LanczosWidthFactor);
932 val.channel[k]=minmax(0,255,psave);
934 i_ppix(new_img,i,j,&val);
942 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
949 =item i_scale_nn(im, scx, scy)
951 Scale by using nearest neighbor
952 Both axes scaled at the same time since
953 nothing is gained by doing it in two steps
960 i_scale_nn(i_img *im, float scx, float scy) {
962 int nxsize,nysize,nx,ny;
966 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
968 nxsize = (int) ((float) im->xsize * scx);
969 nysize = (int) ((float) im->ysize * scy);
971 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
973 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
974 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
975 i_ppix(new_img,nx,ny,&val);
978 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
985 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
987 Spatially transforms I<im> returning a new image.
989 opx for a length of opxl and opy for a length of opy are arrays of
990 operators that modify the x and y positions to retreive the pixel data from.
992 parm and parmlen define extra parameters that the operators may use.
994 Note that this function is largely superseded by the more flexible
995 L<transform.c/i_transform2>.
997 Returns the new image.
999 The operators for this function are defined in L<stackmach.c>.
1004 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1006 int nxsize,nysize,nx,ny;
1010 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));
1013 nysize = im->ysize ;
1015 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1016 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1017 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1018 /* parm[parmlen-2]=(double)nx;
1019 parm[parmlen-1]=(double)ny; */
1024 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1025 rx=op_run(opx,opxl,parm,parmlen);
1026 ry=op_run(opy,opyl,parm,parmlen);
1027 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1028 i_gpix(im,rx,ry,&val);
1029 i_ppix(new_img,nx,ny,&val);
1032 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1037 =item i_img_diff(im1, im2)
1039 Calculates the sum of the squares of the differences between
1040 correspoding channels in two images.
1042 If the images are not the same size then only the common area is
1043 compared, hence even if images are different sizes this function
1049 i_img_diff(i_img *im1,i_img *im2) {
1050 int x,y,ch,xb,yb,chb;
1054 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1056 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1057 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1058 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1060 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1063 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1064 i_gpix(im1,x,y,&val1);
1065 i_gpix(im2,x,y,&val2);
1067 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1069 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1073 /* just a tiny demo of haar wavelets */
1081 i_img *new_img,*new_img2;
1082 i_color val1,val2,dval1,dval2;
1090 /* horizontal pass */
1092 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1093 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1096 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1097 i_gpix(im,x*2,y,&val1);
1098 i_gpix(im,x*2+1,y,&val2);
1099 for(ch=0;ch<im->channels;ch++) {
1100 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1101 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1103 i_ppix(new_img,x,y,&dval1);
1104 i_ppix(new_img,x+fx,y,&dval2);
1107 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1108 i_gpix(new_img,x,y*2,&val1);
1109 i_gpix(new_img,x,y*2+1,&val2);
1110 for(ch=0;ch<im->channels;ch++) {
1111 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1112 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1114 i_ppix(new_img2,x,y,&dval1);
1115 i_ppix(new_img2,x,y+fy,&dval2);
1118 i_img_destroy(new_img);
1123 =item i_count_colors(im, maxc)
1125 returns number of colors or -1
1126 to indicate that it was more than max colors
1131 i_count_colors(i_img *im,int maxc) {
1138 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1145 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1146 i_gpix(im,x,y,&val);
1147 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1148 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1155 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1156 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1157 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1158 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1162 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1164 Performs general read buffering for file readers that permit reading
1165 to be done through a callback.
1167 The final callback gets two parameters, a I<need> value, and a I<want>
1168 value, where I<need> is the amount of data that the file library needs
1169 to read, and I<want> is the amount of space available in the buffer
1170 maintained by these functions.
1172 This means if you need to read from a stream that you don't know the
1173 length of, you can return I<need> bytes, taking the performance hit of
1174 possibly expensive callbacks (eg. back to perl code), or if you are
1175 reading from a stream where it doesn't matter if some data is lost, or
1176 if the total length of the stream is known, you can return I<want>
1183 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1186 if (length < gci->length - gci->cpos) {
1188 memcpy(buf, gci->buffer+gci->cpos, length);
1189 gci->cpos += length;
1194 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1195 total += gci->length - gci->cpos;
1196 length -= gci->length - gci->cpos;
1197 buf += gci->length - gci->cpos;
1198 if (length < (int)sizeof(gci->buffer)) {
1202 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1203 sizeof(gci->buffer))) > 0) {
1205 gci->length = did_read;
1207 copy_size = min(length, gci->length);
1208 memcpy(buf, gci->buffer, copy_size);
1209 gci->cpos += copy_size;
1212 length -= copy_size;
1216 /* just read the rest - too big for our buffer*/
1218 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1228 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1230 For use by callback file readers to initialize the reader buffer.
1232 Allocates, initializes and returns the reader buffer.
1234 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1239 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1240 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1242 self->userdata = userdata;
1250 =item free_gen_read_data(i_gen_read_data *)
1256 void free_gen_read_data(i_gen_read_data *self) {
1261 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1263 Performs write buffering for a callback based file writer.
1265 Failures are considered fatal, if a write fails then data will be
1272 i_gen_write_data *self,
1276 if (self->filledto && self->filledto+size > self->maxlength) {
1277 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1285 if (self->filledto+size <= self->maxlength) {
1287 memcpy(self->buffer+self->filledto, data, size);
1288 self->filledto += size;
1291 /* doesn't fit - hand it off */
1292 return self->cb(self->userdata, data, size);
1296 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1298 Allocates and initializes the data structure used by i_gen_writer.
1300 This should be released with L<image.c/free_gen_write_data>
1304 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1305 char *userdata, int max_length)
1307 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1309 self->userdata = userdata;
1310 self->maxlength = min(max_length, sizeof(self->buffer));
1311 if (self->maxlength < 0)
1312 self->maxlength = sizeof(self->buffer);
1319 =item free_gen_write_data(i_gen_write_data *info, int flush)
1321 Cleans up the write buffer.
1323 Will flush any left-over data if I<flush> is non-zero.
1325 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1327 Return zero only if flush is non-zero and info->cb() returns zero.
1333 int free_gen_write_data(i_gen_write_data *info, int flush)
1335 int result = !flush ||
1336 info->filledto == 0 ||
1337 info->cb(info->userdata, info->buffer, info->filledto);