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",cl,r,g,b,a));
61 if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
66 mm_log((1,"(0x%x) <- 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* 0x%x,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,"(0x%x) <- 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* 0x%x)\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* 0x%x)\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,"(0x%x) <- IIM_new\n",im));
175 IIM_DESTROY(i_img *im) {
176 mm_log((1,"IIM_DESTROY(im* 0x%x)\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,"(0x%x) <- 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 0x%x,x %d,y %d)\n",im,x,y));
231 if ( (im=mymalloc(sizeof(i_img))) == NULL)
232 m_fatal(2,"malloc() error\n");
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,"(0x%x) <- 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 0x%x,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");
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,"(0x%x) <- 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;
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* 0x%x,src 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,tx %d,ty %d,trans* 0x%x)\n",im,src,x1,y1,x2,y2,tx,ty,trans));
505 if (x2<x1) { t=x1; x1=x2; x2=t; }
506 if (y2<y1) { t=y1; y1=y2; y2=t; }
518 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
519 if (tt) i_ppix(im,ttx,tty,&pv);
520 } else i_ppix(im,ttx,tty,&pv);
528 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
530 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
531 a rectangle the same size with it's top-left corner at (tx,ty) in the
534 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
540 i_copyto(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty) {
544 if (x2<x1) { t=x1; x1=x2; x2=t; }
545 if (y2<y1) { t=y1; y1=y2; y2=t; }
547 mm_log((1,"i_copyto(im* 0x%x,src 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,tx %d,ty %d)\n",im,src,x1,y1,x2,y2,tx,ty));
554 i_ppix(im,ttx,tty,&pv);
562 =item i_copy(im, src)
564 Copies the contents of the image I<src> over the image I<im>.
570 i_copy(i_img *im,i_img *src) {
574 mm_log((1,"i_copy(im* 0x%x,src 0x%x)\n",im,src));
578 i_img_empty_ch(im,x1,y1,src->channels);
580 for(y=0;y<y1;y++) for(x=0;x<x1;x++) {
588 =item i_rubthru(im, src, tx, ty)
590 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
592 The alpha channel of each pixel in I<src> is used to control how much
593 the existing colour in I<im> is replaced, if it is 255 then the colour
594 is completely replaced, if it is 0 then the original colour is left
601 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
602 i_color pv,orig,dest;
605 mm_log((1,"i_rubthru(im 0x%x,src 0x%x,tx %d,ty %d)\n",im,src,tx,ty));
607 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
608 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
611 for(x=0;x<src->xsize;x++)
614 for(y=0;y<src->ysize;y++)
616 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
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);
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);
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);
706 mm_log((1, "i_flipxy: direction is invalid\n" ));
724 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
725 else if (x == 0.0) return (1.0);
726 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
730 =item i_scaleaxis(im, value, axis)
732 Returns a new image object which is I<im> scaled by I<value> along
733 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
739 i_scaleaxis(i_img *im, float Value, int Axis) {
740 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
741 int LanczosWidthFactor;
742 float *l0, *l1, OldLocation;
743 int T, TempJump1, TempJump2;
744 float F, PictureValue[MAXCHANNELS];
746 i_color val,val1,val2;
749 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
752 hsize = (int) ((float) im->xsize * Value);
758 TempJump1 = (hsize - 1) * 3;
759 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
762 vsize = (int) ((float) im->ysize * Value);
771 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
773 if (Value >=1) LanczosWidthFactor = 1;
774 else LanczosWidthFactor = (int) (1.0/Value);
776 lMax = LanczosWidthFactor << 1;
778 l0 = (float *) mymalloc(lMax * sizeof(float));
779 l1 = (float *) mymalloc(lMax * sizeof(float));
781 for (j=0; j<jEnd; j++) {
782 OldLocation = ((float) j) / Value;
783 T = (int) (OldLocation);
784 F = OldLocation - (float) T;
786 for (l = 0; l < lMax; l++) {
787 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
788 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
793 for (i=0; i<iEnd; i++) {
794 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
795 for (l=0; l < lMax; l++) {
796 i_gpix(im,T+l+1, i, &val1);
797 i_gpix(im,T-lMax+l+1, i, &val2);
798 for (k=0; k<im->channels; k++) {
799 PictureValue[k] += l1[l] * val1.channel[k];
800 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
803 for(k=0;k<im->channels;k++) {
804 psave = (short)( PictureValue[k] / LanczosWidthFactor);
805 val.channel[k]=minmax(0,255,psave);
807 i_ppix(new_img,j,i,&val);
812 for (i=0; i<iEnd; i++) {
813 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
814 for (l=0; l < lMax; l++) {
815 i_gpix(im,i, T+l+1, &val1);
816 i_gpix(im,i, T-lMax+l+1, &val2);
817 for (k=0; k<im->channels; k++) {
818 PictureValue[k] += l1[l] * val1.channel[k];
819 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
822 for (k=0; k<im->channels; k++) {
823 psave = (short)( PictureValue[k] / LanczosWidthFactor);
824 val.channel[k]=minmax(0,255,psave);
826 i_ppix(new_img,i,j,&val);
834 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
841 =item i_scale_nn(im, scx, scy)
843 Scale by using nearest neighbor
844 Both axes scaled at the same time since
845 nothing is gained by doing it in two steps
852 i_scale_nn(i_img *im, float scx, float scy) {
854 int nxsize,nysize,nx,ny;
858 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
860 nxsize = (int) ((float) im->xsize * scx);
861 nysize = (int) ((float) im->ysize * scy);
863 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
865 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
866 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
867 i_ppix(new_img,nx,ny,&val);
870 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
877 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
879 Spatially transforms I<im> returning a new image.
881 opx for a length of opxl and opy for a length of opy are arrays of
882 operators that modify the x and y positions to retreive the pixel data from.
884 parm and parmlen define extra parameters that the operators may use.
886 Note that this function is largely superseded by the more flexible
887 L<transform.c/i_transform2>.
889 Returns the new image.
891 The operators for this function are defined in L<stackmach.c>.
896 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
898 int nxsize,nysize,nx,ny;
902 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));
907 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
908 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
909 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
910 /* parm[parmlen-2]=(double)nx;
911 parm[parmlen-1]=(double)ny; */
916 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
917 rx=op_run(opx,opxl,parm,parmlen);
918 ry=op_run(opy,opyl,parm,parmlen);
919 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
920 i_gpix(im,rx,ry,&val);
921 i_ppix(new_img,nx,ny,&val);
924 mm_log((1,"(0x%x) <- i_transform\n",new_img));
929 =item i_img_diff(im1, im2)
931 Calculates the sum of the squares of the differences between
932 correspoding channels in two images.
934 If the images are not the same size then only the common area is
935 compared, hence even if images are different sizes this function
941 i_img_diff(i_img *im1,i_img *im2) {
942 int x,y,ch,xb,yb,chb;
946 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
948 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
949 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
950 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
952 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
955 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
956 i_gpix(im1,x,y,&val1);
957 i_gpix(im2,x,y,&val2);
959 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
961 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
965 /* just a tiny demo of haar wavelets */
973 i_img *new_img,*new_img2;
974 i_color val1,val2,dval1,dval2;
982 /* horizontal pass */
984 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
985 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
988 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
989 i_gpix(im,x*2,y,&val1);
990 i_gpix(im,x*2+1,y,&val2);
991 for(ch=0;ch<im->channels;ch++) {
992 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
993 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
995 i_ppix(new_img,x,y,&dval1);
996 i_ppix(new_img,x+fx,y,&dval2);
999 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1000 i_gpix(new_img,x,y*2,&val1);
1001 i_gpix(new_img,x,y*2+1,&val2);
1002 for(ch=0;ch<im->channels;ch++) {
1003 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1004 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1006 i_ppix(new_img2,x,y,&dval1);
1007 i_ppix(new_img2,x,y+fy,&dval2);
1010 i_img_destroy(new_img);
1015 =item i_count_colors(im, maxc)
1017 returns number of colors or -1
1018 to indicate that it was more than max colors
1023 i_count_colors(i_img *im,int maxc) {
1030 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1037 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1038 i_gpix(im,x,y,&val);
1039 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1040 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1047 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1048 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1049 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1050 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1054 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1056 Performs general read buffering for file readers that permit reading
1057 to be done through a callback.
1059 The final callback gets two parameters, a I<need> value, and a I<want>
1060 value, where I<need> is the amount of data that the file library needs
1061 to read, and I<want> is the amount of space available in the buffer
1062 maintained by these functions.
1064 This means if you need to read from a stream that you don't know the
1065 length of, you can return I<need> bytes, taking the performance hit of
1066 possibly expensive callbacks (eg. back to perl code), or if you are
1067 reading from a stream where it doesn't matter if some data is lost, or
1068 if the total length of the stream is known, you can return I<want>
1075 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1078 if (length < gci->length - gci->cpos) {
1080 memcpy(buf, gci->buffer+gci->cpos, length);
1081 gci->cpos += length;
1086 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1087 total += gci->length - gci->cpos;
1088 length -= gci->length - gci->cpos;
1089 buf += gci->length - gci->cpos;
1090 if (length < (int)sizeof(gci->buffer)) {
1094 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1095 sizeof(gci->buffer))) > 0) {
1097 gci->length = did_read;
1099 copy_size = min(length, gci->length);
1100 memcpy(buf, gci->buffer, copy_size);
1101 gci->cpos += copy_size;
1104 length -= copy_size;
1108 /* just read the rest - too big for our buffer*/
1110 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1120 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1122 For use by callback file readers to initialize the reader buffer.
1124 Allocates, initializes and returns the reader buffer.
1126 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1131 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1132 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1134 self->userdata = userdata;
1142 =item free_gen_read_data(i_gen_read_data *)
1148 void free_gen_read_data(i_gen_read_data *self) {
1153 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1155 Performs write buffering for a callback based file writer.
1157 Failures are considered fatal, if a write fails then data will be
1164 i_gen_write_data *self,
1168 if (self->filledto && self->filledto+size > self->maxlength) {
1169 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1177 if (self->filledto+size <= self->maxlength) {
1179 memcpy(self->buffer+self->filledto, data, size);
1180 self->filledto += size;
1183 /* doesn't fit - hand it off */
1184 return self->cb(self->userdata, data, size);
1188 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1190 Allocates and initializes the data structure used by i_gen_writer.
1192 This should be released with L<image.c/free_gen_write_data>
1196 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1197 char *userdata, int max_length)
1199 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1201 self->userdata = userdata;
1202 self->maxlength = min(max_length, sizeof(self->buffer));
1203 if (self->maxlength < 0)
1204 self->maxlength = sizeof(self->buffer);
1211 =item free_gen_write_data(i_gen_write_data *info, int flush)
1213 Cleans up the write buffer.
1215 Will flush any left-over data if I<flush> is non-zero.
1217 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1219 Return zero only if flush is non-zero and info->cb() returns zero.
1225 int free_gen_write_data(i_gen_write_data *info, int flush)
1227 int result = !flush ||
1228 info->filledto == 0 ||
1229 info->cb(info->userdata, info->buffer, info->filledto);