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;
211 mm_log((1,"(%p) <- i_img_struct\n",im));
216 =item i_img_empty(im, x, y)
218 Re-new image reference (assumes 3 channels)
221 x - xsize of destination image
222 y - ysize of destination image
228 i_img_empty(i_img *im,int x,int y) {
229 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
231 if ( (im=mymalloc(sizeof(i_img))) == NULL)
232 m_fatal(2,"malloc() error\n");
237 im->ch_mask = MAXINT;
238 im->bytes=x*y*im->channels;
239 if ( (im->data = mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
240 memset(im->data, 0, (size_t)im->bytes);
242 im->i_f_ppix = i_ppix_d;
243 im->i_f_gpix = i_gpix_d;
246 mm_log((1,"(%p) <- i_img_empty\n", im));
251 =item i_img_empty_ch(im, x, y, ch)
253 Re-new image reference
256 x - xsize of destination image
257 y - ysize of destination image
258 ch - number of channels
264 i_img_empty_ch(i_img *im,int x,int y,int ch) {
265 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
267 if ( (im=mymalloc(sizeof(i_img))) == NULL)
268 m_fatal(2,"malloc() error\n");
273 im->ch_mask = MAXINT;
274 im->bytes=x*y*im->channels;
275 if ( (im->data=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
276 memset(im->data,0,(size_t)im->bytes);
278 im->i_f_ppix = i_ppix_d;
279 im->i_f_gpix = i_gpix_d;
282 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
287 =item i_img_exorcise(im)
297 i_img_exorcise(i_img *im) {
298 mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
299 if (im->data != NULL) { myfree(im->data); }
305 im->i_f_ppix=i_ppix_d;
306 im->i_f_gpix=i_gpix_d;
311 =item i_img_destroy(im)
313 Destroy image and free data via exorcise.
321 i_img_destroy(i_img *im) {
322 mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
324 if (im) { myfree(im); }
328 =item i_img_info(im, info)
330 Return image information
333 info - pointer to array to return data
335 info is an array of 4 integers with the following values:
340 info[3] - channel mask
347 i_img_info(i_img *im,int *info) {
348 mm_log((1,"i_img_info(im 0x%x)\n",im));
350 mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
351 mm_log((1,"i_img_info: data=0x%d\n",im->data));
354 info[2] = im->channels;
355 info[3] = im->ch_mask;
365 =item i_img_setmask(im, ch_mask)
367 Set the image channel mask for I<im> to I<ch_mask>.
372 i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
376 =item i_img_getmask(im)
378 Get the image channel mask for I<im>.
383 i_img_getmask(i_img *im) { return im->ch_mask; }
386 =item i_img_getchannels(im)
388 Get the number of channels in I<im>.
393 i_img_getchannels(i_img *im) { return im->channels; }
397 =item i_ppix(im, x, y, col)
399 Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
401 Returns true if the pixel could be set, false if x or y is out of
407 i_ppix(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
410 =item i_gpix(im, x, y, &col)
412 Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
414 Returns true if the pixel could be retrieved, false otherwise.
419 i_gpix(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
422 =item i_ppix_d(im, x, y, col)
426 This is the function kept in the i_f_ppix member of an i_img object.
427 It does a normal store of a pixel into the image with range checking.
429 Returns true if the pixel could be set, false otherwise.
434 i_ppix_d(i_img *im, int x, int y, i_color *val) {
437 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
438 for(ch=0;ch<im->channels;ch++)
439 if (im->ch_mask&(1<<ch))
440 im->data[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
443 return -1; /* error was clipped */
447 =item i_gpix_d(im, x, y, &col)
451 This is the function kept in the i_f_gpix member of an i_img object.
452 It does normal retrieval of a pixel from the image with range checking.
454 Returns true if the pixel could be set, false otherwise.
459 i_gpix_d(i_img *im, int x, int y, i_color *val) {
461 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
462 for(ch=0;ch<im->channels;ch++)
463 val->channel[ch]=im->data[(x+y*im->xsize)*im->channels+ch];
466 return -1; /* error was cliped */
470 =item i_ppix_pch(im, x, y, ch)
472 Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
475 Returns zero if x or y is out of range.
477 Warning: this ignores the vptr interface for images.
482 i_gpix_pch(i_img *im,int x,int y,int ch) {
483 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
489 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
491 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
492 (tx,ty) specifies the upper left corner for the target image.
493 pass NULL in trans for non transparent i_colors.
499 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
501 int x,y,t,ttx,tty,tt,ch;
503 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",
504 im, src, x1, y1, x2, y2, tx, ty, trans));
506 if (x2<x1) { t=x1; x1=x2; x2=t; }
507 if (y2<y1) { t=y1; y1=y2; y2=t; }
519 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
520 if (tt) i_ppix(im,ttx,tty,&pv);
521 } else i_ppix(im,ttx,tty,&pv);
529 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
531 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
532 a rectangle the same size with it's top-left corner at (tx,ty) in the
535 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
541 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
543 int x, y, t, ttx, tty;
545 if (x2<x1) { t=x1; x1=x2; x2=t; }
546 if (y2<y1) { t=y1; y1=y2; y2=t; }
548 mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
549 im, src, x1, y1, x2, y2, tx, ty));
552 for(y=y1; y<y2; y++) {
554 for(x=x1; x<x2; x++) {
555 i_gpix(src, x, y, &pv);
556 i_ppix(im, ttx, tty, &pv);
564 =item i_copy(im, src)
566 Copies the contents of the image I<src> over the image I<im>.
572 i_copy(i_img *im, i_img *src) {
576 mm_log((1,"i_copy(im* %p,src %p)\n", im,s rc));
580 i_img_empty_ch(im, x1, y1, src->channels);
582 for(y=0; y<y1; y++) for(x=0; x<x1; x++) {
583 i_gpix(src, x, y, &pv);
584 i_ppix(im, x, y, &pv);
590 =item i_rubthru(im, src, tx, ty)
592 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
594 The alpha channel of each pixel in I<src> is used to control how much
595 the existing colour in I<im> is replaced, if it is 255 then the colour
596 is completely replaced, if it is 0 then the original colour is left
603 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
604 i_color pv, orig, dest;
607 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
609 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
610 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
613 for(x=0; x<src->xsize; x++) {
615 for(y=0;y<src->ysize;y++) {
616 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
617 i_gpix(src, x, y, &pv);
618 i_gpix(im, ttx, tty, &orig);
619 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
620 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
621 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
622 i_ppix(im, ttx, tty, &dest);
631 =item i_flipxy(im, axis)
633 Flips the image inplace around the axis specified.
634 Returns 0 if parameters are invalid.
637 axis - 0 = x, 1 = y, 2 = both
643 i_flipxy(i_img *im, int direction) {
644 int x, x2, y, y2, xm, ym;
648 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
653 case XAXIS: /* Horizontal flip */
656 for(y=0; y<ym; y++) {
658 for(x=0; x<xm; x++) {
660 i_gpix(im, x, y, &val1);
661 i_gpix(im, x2, y, &val2);
662 i_ppix(im, x, y, &val2);
663 i_ppix(im, x2, y, &val1);
668 case YAXIS: /* Vertical flip */
672 for(y=0; y<ym; y++) {
673 for(x=0; x<xm; x++) {
675 i_gpix(im, x, y, &val1);
676 i_gpix(im, x, y2, &val2);
677 i_ppix(im, x, y, &val2);
678 i_ppix(im, x, y2, &val1);
683 case XYAXIS: /* Horizontal and Vertical flip */
687 for(y=0; y<ym; y++) {
689 for(x=0; x<xm; x++) {
691 i_gpix(im, x, y, &val1);
692 i_gpix(im, x2, y2, &val2);
693 i_ppix(im, x, y, &val2);
694 i_ppix(im, x2, y2, &val1);
696 i_gpix(im, x2, y, &val1);
697 i_gpix(im, x, y2, &val2);
698 i_ppix(im, x2, y, &val2);
699 i_ppix(im, x, y2, &val1);
704 if (xm*2 != xs) { /* odd number of column */
705 mm_log((1, "i_flipxy: odd number of columns\n"));
708 for(y=0; y<ym; y++) {
710 i_gpix(im, x, y, &val1);
711 i_gpix(im, x, y2, &val2);
712 i_ppix(im, x, y, &val2);
713 i_ppix(im, x, y2, &val1);
717 if (ym*2 != ys) { /* odd number of rows */
718 mm_log((1, "i_flipxy: odd number of rows\n"));
721 for(x=0; x<xm; x++) {
723 i_gpix(im, x, y, &val1);
724 i_gpix(im, x2, y, &val2);
725 i_ppix(im, x, y, &val2);
726 i_ppix(im, x2, y, &val1);
732 mm_log((1, "i_flipxy: direction is invalid\n" ));
750 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
751 else if (x == 0.0) return (1.0);
752 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
756 =item i_scaleaxis(im, value, axis)
758 Returns a new image object which is I<im> scaled by I<value> along
759 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
765 i_scaleaxis(i_img *im, float Value, int Axis) {
766 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
767 int LanczosWidthFactor;
768 float *l0, *l1, OldLocation;
769 int T, TempJump1, TempJump2;
770 float F, PictureValue[MAXCHANNELS];
772 i_color val,val1,val2;
775 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
778 hsize = (int) ((float) im->xsize * Value);
784 TempJump1 = (hsize - 1) * 3;
785 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
788 vsize = (int) ((float) im->ysize * Value);
797 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
799 if (Value >=1) LanczosWidthFactor = 1;
800 else LanczosWidthFactor = (int) (1.0/Value);
802 lMax = LanczosWidthFactor << 1;
804 l0 = (float *) mymalloc(lMax * sizeof(float));
805 l1 = (float *) mymalloc(lMax * sizeof(float));
807 for (j=0; j<jEnd; j++) {
808 OldLocation = ((float) j) / Value;
809 T = (int) (OldLocation);
810 F = OldLocation - (float) T;
812 for (l = 0; l < lMax; l++) {
813 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
814 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
819 for (i=0; i<iEnd; i++) {
820 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
821 for (l=0; l < lMax; l++) {
822 i_gpix(im,T+l+1, i, &val1);
823 i_gpix(im,T-lMax+l+1, i, &val2);
824 for (k=0; k<im->channels; k++) {
825 PictureValue[k] += l1[l] * val1.channel[k];
826 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
829 for(k=0;k<im->channels;k++) {
830 psave = (short)( PictureValue[k] / LanczosWidthFactor);
831 val.channel[k]=minmax(0,255,psave);
833 i_ppix(new_img,j,i,&val);
838 for (i=0; i<iEnd; i++) {
839 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
840 for (l=0; l < lMax; l++) {
841 i_gpix(im,i, T+l+1, &val1);
842 i_gpix(im,i, T-lMax+l+1, &val2);
843 for (k=0; k<im->channels; k++) {
844 PictureValue[k] += l1[l] * val1.channel[k];
845 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
848 for (k=0; k<im->channels; k++) {
849 psave = (short)( PictureValue[k] / LanczosWidthFactor);
850 val.channel[k]=minmax(0,255,psave);
852 i_ppix(new_img,i,j,&val);
860 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
867 =item i_scale_nn(im, scx, scy)
869 Scale by using nearest neighbor
870 Both axes scaled at the same time since
871 nothing is gained by doing it in two steps
878 i_scale_nn(i_img *im, float scx, float scy) {
880 int nxsize,nysize,nx,ny;
884 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
886 nxsize = (int) ((float) im->xsize * scx);
887 nysize = (int) ((float) im->ysize * scy);
889 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
891 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
892 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
893 i_ppix(new_img,nx,ny,&val);
896 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
903 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
905 Spatially transforms I<im> returning a new image.
907 opx for a length of opxl and opy for a length of opy are arrays of
908 operators that modify the x and y positions to retreive the pixel data from.
910 parm and parmlen define extra parameters that the operators may use.
912 Note that this function is largely superseded by the more flexible
913 L<transform.c/i_transform2>.
915 Returns the new image.
917 The operators for this function are defined in L<stackmach.c>.
922 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
924 int nxsize,nysize,nx,ny;
928 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));
933 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
934 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
935 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
936 /* parm[parmlen-2]=(double)nx;
937 parm[parmlen-1]=(double)ny; */
942 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
943 rx=op_run(opx,opxl,parm,parmlen);
944 ry=op_run(opy,opyl,parm,parmlen);
945 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
946 i_gpix(im,rx,ry,&val);
947 i_ppix(new_img,nx,ny,&val);
950 mm_log((1,"(0x%x) <- i_transform\n",new_img));
955 =item i_img_diff(im1, im2)
957 Calculates the sum of the squares of the differences between
958 correspoding channels in two images.
960 If the images are not the same size then only the common area is
961 compared, hence even if images are different sizes this function
967 i_img_diff(i_img *im1,i_img *im2) {
968 int x,y,ch,xb,yb,chb;
972 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
974 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
975 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
976 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
978 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
981 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
982 i_gpix(im1,x,y,&val1);
983 i_gpix(im2,x,y,&val2);
985 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
987 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
991 /* just a tiny demo of haar wavelets */
999 i_img *new_img,*new_img2;
1000 i_color val1,val2,dval1,dval2;
1008 /* horizontal pass */
1010 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1011 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1014 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1015 i_gpix(im,x*2,y,&val1);
1016 i_gpix(im,x*2+1,y,&val2);
1017 for(ch=0;ch<im->channels;ch++) {
1018 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1019 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1021 i_ppix(new_img,x,y,&dval1);
1022 i_ppix(new_img,x+fx,y,&dval2);
1025 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1026 i_gpix(new_img,x,y*2,&val1);
1027 i_gpix(new_img,x,y*2+1,&val2);
1028 for(ch=0;ch<im->channels;ch++) {
1029 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1030 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1032 i_ppix(new_img2,x,y,&dval1);
1033 i_ppix(new_img2,x,y+fy,&dval2);
1036 i_img_destroy(new_img);
1041 =item i_count_colors(im, maxc)
1043 returns number of colors or -1
1044 to indicate that it was more than max colors
1049 i_count_colors(i_img *im,int maxc) {
1056 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1063 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1064 i_gpix(im,x,y,&val);
1065 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1066 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1073 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1074 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1075 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1076 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1080 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1082 Performs general read buffering for file readers that permit reading
1083 to be done through a callback.
1085 The final callback gets two parameters, a I<need> value, and a I<want>
1086 value, where I<need> is the amount of data that the file library needs
1087 to read, and I<want> is the amount of space available in the buffer
1088 maintained by these functions.
1090 This means if you need to read from a stream that you don't know the
1091 length of, you can return I<need> bytes, taking the performance hit of
1092 possibly expensive callbacks (eg. back to perl code), or if you are
1093 reading from a stream where it doesn't matter if some data is lost, or
1094 if the total length of the stream is known, you can return I<want>
1101 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1104 if (length < gci->length - gci->cpos) {
1106 memcpy(buf, gci->buffer+gci->cpos, length);
1107 gci->cpos += length;
1112 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1113 total += gci->length - gci->cpos;
1114 length -= gci->length - gci->cpos;
1115 buf += gci->length - gci->cpos;
1116 if (length < (int)sizeof(gci->buffer)) {
1120 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1121 sizeof(gci->buffer))) > 0) {
1123 gci->length = did_read;
1125 copy_size = min(length, gci->length);
1126 memcpy(buf, gci->buffer, copy_size);
1127 gci->cpos += copy_size;
1130 length -= copy_size;
1134 /* just read the rest - too big for our buffer*/
1136 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1146 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1148 For use by callback file readers to initialize the reader buffer.
1150 Allocates, initializes and returns the reader buffer.
1152 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1157 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1158 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1160 self->userdata = userdata;
1168 =item free_gen_read_data(i_gen_read_data *)
1174 void free_gen_read_data(i_gen_read_data *self) {
1179 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1181 Performs write buffering for a callback based file writer.
1183 Failures are considered fatal, if a write fails then data will be
1190 i_gen_write_data *self,
1194 if (self->filledto && self->filledto+size > self->maxlength) {
1195 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1203 if (self->filledto+size <= self->maxlength) {
1205 memcpy(self->buffer+self->filledto, data, size);
1206 self->filledto += size;
1209 /* doesn't fit - hand it off */
1210 return self->cb(self->userdata, data, size);
1214 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1216 Allocates and initializes the data structure used by i_gen_writer.
1218 This should be released with L<image.c/free_gen_write_data>
1222 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1223 char *userdata, int max_length)
1225 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1227 self->userdata = userdata;
1228 self->maxlength = min(max_length, sizeof(self->buffer));
1229 if (self->maxlength < 0)
1230 self->maxlength = sizeof(self->buffer);
1237 =item free_gen_write_data(i_gen_write_data *info, int flush)
1239 Cleans up the write buffer.
1241 Will flush any left-over data if I<flush> is non-zero.
1243 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1245 Return zero only if flush is non-zero and info->cb() returns zero.
1251 int free_gen_write_data(i_gen_write_data *info, int flush)
1253 int result = !flush ||
1254 info->filledto == 0 ||
1255 info->cb(info->userdata, info->buffer, info->filledto);