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);
676 =item i_rubthru(im, src, tx, ty)
678 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
680 The alpha channel of each pixel in I<src> is used to control how much
681 the existing colour in I<im> is replaced, if it is 255 then the colour
682 is completely replaced, if it is 0 then the original colour is left
689 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
690 i_color pv, orig, dest;
693 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
695 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
696 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
699 for(x=0; x<src->xsize; x++) {
701 for(y=0;y<src->ysize;y++) {
702 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
703 i_gpix(src, x, y, &pv);
704 i_gpix(im, ttx, tty, &orig);
705 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
706 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
707 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
708 i_ppix(im, ttx, tty, &dest);
717 =item i_flipxy(im, axis)
719 Flips the image inplace around the axis specified.
720 Returns 0 if parameters are invalid.
723 axis - 0 = x, 1 = y, 2 = both
729 i_flipxy(i_img *im, int direction) {
730 int x, x2, y, y2, xm, ym;
734 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
739 case XAXIS: /* Horizontal flip */
742 for(y=0; y<ym; y++) {
744 for(x=0; x<xm; x++) {
746 i_gpix(im, x, y, &val1);
747 i_gpix(im, x2, y, &val2);
748 i_ppix(im, x, y, &val2);
749 i_ppix(im, x2, y, &val1);
754 case YAXIS: /* Vertical flip */
758 for(y=0; y<ym; y++) {
759 for(x=0; x<xm; x++) {
761 i_gpix(im, x, y, &val1);
762 i_gpix(im, x, y2, &val2);
763 i_ppix(im, x, y, &val2);
764 i_ppix(im, x, y2, &val1);
769 case XYAXIS: /* Horizontal and Vertical flip */
773 for(y=0; y<ym; y++) {
775 for(x=0; x<xm; x++) {
777 i_gpix(im, x, y, &val1);
778 i_gpix(im, x2, y2, &val2);
779 i_ppix(im, x, y, &val2);
780 i_ppix(im, x2, y2, &val1);
782 i_gpix(im, x2, y, &val1);
783 i_gpix(im, x, y2, &val2);
784 i_ppix(im, x2, y, &val2);
785 i_ppix(im, x, y2, &val1);
790 if (xm*2 != xs) { /* odd number of column */
791 mm_log((1, "i_flipxy: odd number of columns\n"));
794 for(y=0; y<ym; y++) {
796 i_gpix(im, x, y, &val1);
797 i_gpix(im, x, y2, &val2);
798 i_ppix(im, x, y, &val2);
799 i_ppix(im, x, y2, &val1);
803 if (ym*2 != ys) { /* odd number of rows */
804 mm_log((1, "i_flipxy: odd number of rows\n"));
807 for(x=0; x<xm; x++) {
809 i_gpix(im, x, y, &val1);
810 i_gpix(im, x2, y, &val2);
811 i_ppix(im, x, y, &val2);
812 i_ppix(im, x2, y, &val1);
818 mm_log((1, "i_flipxy: direction is invalid\n" ));
836 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
837 else if (x == 0.0) return (1.0);
838 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
842 =item i_scaleaxis(im, value, axis)
844 Returns a new image object which is I<im> scaled by I<value> along
845 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
851 i_scaleaxis(i_img *im, float Value, int Axis) {
852 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
853 int LanczosWidthFactor;
854 float *l0, *l1, OldLocation;
855 int T, TempJump1, TempJump2;
856 float F, PictureValue[MAXCHANNELS];
858 i_color val,val1,val2;
861 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
864 hsize = (int) ((float) im->xsize * Value);
870 TempJump1 = (hsize - 1) * 3;
871 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
874 vsize = (int) ((float) im->ysize * Value);
883 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
885 if (Value >=1) LanczosWidthFactor = 1;
886 else LanczosWidthFactor = (int) (1.0/Value);
888 lMax = LanczosWidthFactor << 1;
890 l0 = (float *) mymalloc(lMax * sizeof(float));
891 l1 = (float *) mymalloc(lMax * sizeof(float));
893 for (j=0; j<jEnd; j++) {
894 OldLocation = ((float) j) / Value;
895 T = (int) (OldLocation);
896 F = OldLocation - (float) T;
898 for (l = 0; l < lMax; l++) {
899 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
900 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
905 for (i=0; i<iEnd; i++) {
906 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
907 for (l=0; l < lMax; l++) {
908 i_gpix(im,T+l+1, i, &val1);
909 i_gpix(im,T-lMax+l+1, i, &val2);
910 for (k=0; k<im->channels; k++) {
911 PictureValue[k] += l1[l] * val1.channel[k];
912 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
915 for(k=0;k<im->channels;k++) {
916 psave = (short)( PictureValue[k] / LanczosWidthFactor);
917 val.channel[k]=minmax(0,255,psave);
919 i_ppix(new_img,j,i,&val);
924 for (i=0; i<iEnd; i++) {
925 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
926 for (l=0; l < lMax; l++) {
927 i_gpix(im,i, T+l+1, &val1);
928 i_gpix(im,i, T-lMax+l+1, &val2);
929 for (k=0; k<im->channels; k++) {
930 PictureValue[k] += l1[l] * val1.channel[k];
931 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
934 for (k=0; k<im->channels; k++) {
935 psave = (short)( PictureValue[k] / LanczosWidthFactor);
936 val.channel[k]=minmax(0,255,psave);
938 i_ppix(new_img,i,j,&val);
946 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
953 =item i_scale_nn(im, scx, scy)
955 Scale by using nearest neighbor
956 Both axes scaled at the same time since
957 nothing is gained by doing it in two steps
964 i_scale_nn(i_img *im, float scx, float scy) {
966 int nxsize,nysize,nx,ny;
970 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
972 nxsize = (int) ((float) im->xsize * scx);
973 nysize = (int) ((float) im->ysize * scy);
975 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
977 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
978 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
979 i_ppix(new_img,nx,ny,&val);
982 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
989 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
991 Spatially transforms I<im> returning a new image.
993 opx for a length of opxl and opy for a length of opy are arrays of
994 operators that modify the x and y positions to retreive the pixel data from.
996 parm and parmlen define extra parameters that the operators may use.
998 Note that this function is largely superseded by the more flexible
999 L<transform.c/i_transform2>.
1001 Returns the new image.
1003 The operators for this function are defined in L<stackmach.c>.
1008 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1010 int nxsize,nysize,nx,ny;
1014 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));
1017 nysize = im->ysize ;
1019 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1020 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1021 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1022 /* parm[parmlen-2]=(double)nx;
1023 parm[parmlen-1]=(double)ny; */
1028 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1029 rx=op_run(opx,opxl,parm,parmlen);
1030 ry=op_run(opy,opyl,parm,parmlen);
1031 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1032 i_gpix(im,rx,ry,&val);
1033 i_ppix(new_img,nx,ny,&val);
1036 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1041 =item i_img_diff(im1, im2)
1043 Calculates the sum of the squares of the differences between
1044 correspoding channels in two images.
1046 If the images are not the same size then only the common area is
1047 compared, hence even if images are different sizes this function
1053 i_img_diff(i_img *im1,i_img *im2) {
1054 int x,y,ch,xb,yb,chb;
1058 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1060 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1061 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1062 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1064 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1067 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1068 i_gpix(im1,x,y,&val1);
1069 i_gpix(im2,x,y,&val2);
1071 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1073 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1077 /* just a tiny demo of haar wavelets */
1085 i_img *new_img,*new_img2;
1086 i_color val1,val2,dval1,dval2;
1094 /* horizontal pass */
1096 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1097 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1100 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1101 i_gpix(im,x*2,y,&val1);
1102 i_gpix(im,x*2+1,y,&val2);
1103 for(ch=0;ch<im->channels;ch++) {
1104 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1105 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1107 i_ppix(new_img,x,y,&dval1);
1108 i_ppix(new_img,x+fx,y,&dval2);
1111 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1112 i_gpix(new_img,x,y*2,&val1);
1113 i_gpix(new_img,x,y*2+1,&val2);
1114 for(ch=0;ch<im->channels;ch++) {
1115 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1116 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1118 i_ppix(new_img2,x,y,&dval1);
1119 i_ppix(new_img2,x,y+fy,&dval2);
1122 i_img_destroy(new_img);
1127 =item i_count_colors(im, maxc)
1129 returns number of colors or -1
1130 to indicate that it was more than max colors
1135 i_count_colors(i_img *im,int maxc) {
1142 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1149 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1150 i_gpix(im,x,y,&val);
1151 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1152 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1159 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1160 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1161 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1162 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1166 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1168 Performs general read buffering for file readers that permit reading
1169 to be done through a callback.
1171 The final callback gets two parameters, a I<need> value, and a I<want>
1172 value, where I<need> is the amount of data that the file library needs
1173 to read, and I<want> is the amount of space available in the buffer
1174 maintained by these functions.
1176 This means if you need to read from a stream that you don't know the
1177 length of, you can return I<need> bytes, taking the performance hit of
1178 possibly expensive callbacks (eg. back to perl code), or if you are
1179 reading from a stream where it doesn't matter if some data is lost, or
1180 if the total length of the stream is known, you can return I<want>
1187 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1190 if (length < gci->length - gci->cpos) {
1192 memcpy(buf, gci->buffer+gci->cpos, length);
1193 gci->cpos += length;
1198 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1199 total += gci->length - gci->cpos;
1200 length -= gci->length - gci->cpos;
1201 buf += gci->length - gci->cpos;
1202 if (length < (int)sizeof(gci->buffer)) {
1206 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1207 sizeof(gci->buffer))) > 0) {
1209 gci->length = did_read;
1211 copy_size = min(length, gci->length);
1212 memcpy(buf, gci->buffer, copy_size);
1213 gci->cpos += copy_size;
1216 length -= copy_size;
1220 /* just read the rest - too big for our buffer*/
1222 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1232 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1234 For use by callback file readers to initialize the reader buffer.
1236 Allocates, initializes and returns the reader buffer.
1238 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1243 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1244 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1246 self->userdata = userdata;
1254 =item free_gen_read_data(i_gen_read_data *)
1260 void free_gen_read_data(i_gen_read_data *self) {
1265 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1267 Performs write buffering for a callback based file writer.
1269 Failures are considered fatal, if a write fails then data will be
1276 i_gen_write_data *self,
1280 if (self->filledto && self->filledto+size > self->maxlength) {
1281 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1289 if (self->filledto+size <= self->maxlength) {
1291 memcpy(self->buffer+self->filledto, data, size);
1292 self->filledto += size;
1295 /* doesn't fit - hand it off */
1296 return self->cb(self->userdata, data, size);
1300 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1302 Allocates and initializes the data structure used by i_gen_writer.
1304 This should be released with L<image.c/free_gen_write_data>
1308 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1309 char *userdata, int max_length)
1311 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1313 self->userdata = userdata;
1314 self->maxlength = min(max_length, sizeof(self->buffer));
1315 if (self->maxlength < 0)
1316 self->maxlength = sizeof(self->buffer);
1323 =item free_gen_write_data(i_gen_write_data *info, int flush)
1325 Cleans up the write buffer.
1327 Will flush any left-over data if I<flush> is non-zero.
1329 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1331 Return zero only if flush is non-zero and info->cb() returns zero.
1337 int free_gen_write_data(i_gen_write_data *info, int flush)
1339 int result = !flush ||
1340 info->filledto == 0 ||
1341 info->cb(info->userdata, info->buffer, info->filledto);