8 image.c - implements most of the basic functions of Imager and much of the rest
14 c = i_color_new(red, green, blue, alpha);
22 image.c implements the basic functions to create and destroy image and
23 color objects for Imager.
25 =head1 FUNCTION REFERENCE
27 Some of these functions are internal.
38 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i )) )
40 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
41 static void fake(void) { ceil(1); }
43 static int i_ppix_d(i_img *im, int x, int y, i_color *val);
44 static int i_gpix_d(i_img *im, int x, int y, i_color *val);
45 static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
46 static int i_plin_d(i_img *im, int l, int r, int y, i_color *vals);
47 static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val);
48 static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
49 static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
50 static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
51 static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
52 static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
53 /*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
54 static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/
57 =item ICL_new_internal(r, g, b, a)
59 Return a new color object with values passed to it.
61 r - red component (range: 0 - 255)
62 g - green component (range: 0 - 255)
63 b - blue component (range: 0 - 255)
64 a - alpha component (range: 0 - 255)
70 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
73 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
75 if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
80 mm_log((1,"(%p) <- ICL_new_internal\n",cl));
86 =item ICL_set_internal(cl, r, g, b, a)
88 Overwrite a color with new values.
90 cl - pointer to color object
91 r - red component (range: 0 - 255)
92 g - green component (range: 0 - 255)
93 b - blue component (range: 0 - 255)
94 a - alpha component (range: 0 - 255)
100 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
101 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
103 if ( (cl=mymalloc(sizeof(i_color))) == NULL)
104 m_fatal(2,"malloc() error\n");
109 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
115 =item ICL_add(dst, src, ch)
117 Add src to dst inplace - dst is modified.
119 dst - pointer to destination color object
120 src - pointer to color object that is added
121 ch - number of channels
127 ICL_add(i_color *dst,i_color *src,int ch) {
130 tmp=dst->channel[i]+src->channel[i];
131 dst->channel[i]= tmp>255 ? 255:tmp;
138 Dump color information to log - strictly for debugging.
140 cl - pointer to color object
146 ICL_info(i_color *cl) {
147 mm_log((1,"i_color_info(cl* %p)\n",cl));
148 mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
154 Destroy ancillary data for Color object.
156 cl - pointer to color object
162 ICL_DESTROY(i_color *cl) {
163 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
168 =item i_fcolor_new(double r, double g, double b, double a)
172 i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
175 mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
177 if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) m_fatal(2,"malloc() error\n");
182 mm_log((1,"(%p) <- i_fcolor_new\n",cl));
188 =item i_fcolor_destroy(i_fcolor *cl)
192 void i_fcolor_destroy(i_fcolor *cl) {
197 =item IIM_base_8bit_direct (static)
199 A static i_img object used to initialize direct 8-bit per sample images.
203 static i_img IIM_base_8bit_direct =
205 0, /* channels set */
206 0, 0, 0, /* xsize, ysize, bytes */
209 i_direct_type, /* type */
212 { 0, 0, NULL }, /* tags */
215 i_ppix_d, /* i_f_ppix */
216 i_ppixf_d, /* i_f_ppixf */
217 i_plin_d, /* i_f_plin */
218 i_plinf_d, /* i_f_plinf */
219 i_gpix_d, /* i_f_gpix */
220 i_gpixf_d, /* i_f_gpixf */
221 i_glin_d, /* i_f_glin */
222 i_glinf_d, /* i_f_glinf */
223 i_gsamp_d, /* i_f_gsamp */
224 i_gsampf_d, /* i_f_gsampf */
228 NULL, /* i_f_addcolors */
229 NULL, /* i_f_getcolors */
230 NULL, /* i_f_colorcount */
231 NULL, /* i_f_maxcolors */
232 NULL, /* i_f_findcolor */
233 NULL, /* i_f_setcolors */
235 NULL, /* i_f_destroy */
238 /*static void set_8bit_direct(i_img *im) {
239 im->i_f_ppix = i_ppix_d;
240 im->i_f_ppixf = i_ppixf_d;
241 im->i_f_plin = i_plin_d;
242 im->i_f_plinf = i_plinf_d;
243 im->i_f_gpix = i_gpix_d;
244 im->i_f_gpixf = i_gpixf_d;
245 im->i_f_glin = i_glin_d;
246 im->i_f_glinf = i_glinf_d;
249 im->i_f_addcolor = NULL;
250 im->i_f_getcolor = NULL;
251 im->i_f_colorcount = NULL;
252 im->i_f_findcolor = NULL;
256 =item IIM_new(x, y, ch)
258 Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
265 IIM_new(int x,int y,int ch) {
267 mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
269 im=i_img_empty_ch(NULL,x,y,ch);
271 mm_log((1,"(%p) <- IIM_new\n",im));
277 IIM_DESTROY(i_img *im) {
278 mm_log((1,"IIM_DESTROY(im* %p)\n",im));
288 Create new image reference - notice that this isn't an object yet and
289 this should be fixed asap.
299 mm_log((1,"i_img_struct()\n"));
300 if ( (im=mymalloc(sizeof(i_img))) == NULL)
301 m_fatal(2,"malloc() error\n");
303 *im = IIM_base_8bit_direct;
311 mm_log((1,"(%p) <- i_img_struct\n",im));
316 =item i_img_empty(im, x, y)
318 Re-new image reference (assumes 3 channels)
321 x - xsize of destination image
322 y - ysize of destination image
324 **FIXME** what happens if a live image is passed in here?
326 Should this just call i_img_empty_ch()?
332 i_img_empty(i_img *im,int x,int y) {
333 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
334 return i_img_empty_ch(im, x, y, 3);
338 =item i_img_empty_ch(im, x, y, ch)
340 Re-new image reference
343 x - xsize of destination image
344 y - ysize of destination image
345 ch - number of channels
351 i_img_empty_ch(i_img *im,int x,int y,int ch) {
352 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
354 if ( (im=mymalloc(sizeof(i_img))) == NULL)
355 m_fatal(2,"malloc() error\n");
357 memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
358 i_tags_new(&im->tags);
362 im->ch_mask = MAXINT;
363 im->bytes=x*y*im->channels;
364 if ( (im->idata=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
365 memset(im->idata,0,(size_t)im->bytes);
369 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
374 =item i_img_exorcise(im)
384 i_img_exorcise(i_img *im) {
385 mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
386 i_tags_destroy(&im->tags);
388 (im->i_f_destroy)(im);
389 if (im->idata != NULL) { myfree(im->idata); }
395 im->i_f_ppix=i_ppix_d;
396 im->i_f_gpix=i_gpix_d;
397 im->i_f_plin=i_plin_d;
398 im->i_f_glin=i_glin_d;
403 =item i_img_destroy(im)
405 Destroy image and free data via exorcise.
413 i_img_destroy(i_img *im) {
414 mm_log((1,"i_img_destroy(im %p)\n",im));
416 if (im) { myfree(im); }
420 =item i_img_info(im, info)
422 Return image information
425 info - pointer to array to return data
427 info is an array of 4 integers with the following values:
432 info[3] - channel mask
439 i_img_info(i_img *im,int *info) {
440 mm_log((1,"i_img_info(im 0x%x)\n",im));
442 mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
443 mm_log((1,"i_img_info: idata=0x%d\n",im->idata));
446 info[2] = im->channels;
447 info[3] = im->ch_mask;
457 =item i_img_setmask(im, ch_mask)
459 Set the image channel mask for I<im> to I<ch_mask>.
464 i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
468 =item i_img_getmask(im)
470 Get the image channel mask for I<im>.
475 i_img_getmask(i_img *im) { return im->ch_mask; }
478 =item i_img_getchannels(im)
480 Get the number of channels in I<im>.
485 i_img_getchannels(i_img *im) { return im->channels; }
490 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
492 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
493 (tx,ty) specifies the upper left corner for the target image.
494 pass NULL in trans for non transparent i_colors.
500 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
502 int x,y,t,ttx,tty,tt,ch;
504 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",
505 im, src, x1, y1, x2, y2, tx, ty, trans));
507 if (x2<x1) { t=x1; x1=x2; x2=t; }
508 if (y2<y1) { t=y1; y1=y2; y2=t; }
520 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
521 if (tt) i_ppix(im,ttx,tty,&pv);
522 } else i_ppix(im,ttx,tty,&pv);
530 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
532 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
533 a rectangle the same size with it's top-left corner at (tx,ty) in the
536 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
542 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));
551 if (im->bits == i_8_bits) {
554 for(y=y1; y<y2; y++) {
556 for(x=x1; x<x2; x++) {
557 i_gpix(src, x, y, &pv);
558 i_ppix(im, ttx, tty, &pv);
567 for(y=y1; y<y2; y++) {
569 for(x=x1; x<x2; x++) {
570 i_gpixf(src, x, y, &pv);
571 i_ppixf(im, ttx, tty, &pv);
580 =item i_copy(im, src)
582 Copies the contents of the image I<src> over the image I<im>.
588 i_copy(i_img *im, i_img *src) {
591 mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
595 if (src->type == i_direct_type) {
596 if (src->bits == i_8_bits) {
598 i_img_empty_ch(im, x1, y1, src->channels);
599 pv = mymalloc(sizeof(i_color) * x1);
601 for (y = 0; y < y1; ++y) {
602 i_glin(src, 0, x1, y, pv);
603 i_plin(im, 0, x1, y, pv);
609 if (src->bits == i_16_bits)
610 i_img_16_new_low(im, x1, y1, src->channels);
611 else if (src->bits == i_double_bits)
612 i_img_double_new_low(im, x1, y1, src->channels);
614 fprintf(stderr, "i_copy(): Unknown image bit size %d\n", src->bits);
615 return; /* I dunno */
618 pv = mymalloc(sizeof(i_fcolor) * x1);
619 for (y = 0; y < y1; ++y) {
620 i_glinf(src, 0, x1, y, pv);
621 i_plinf(im, 0, x1, y, pv);
633 i_img_pal_new_low(im, x1, y1, src->channels, i_maxcolors(src));
634 /* copy across the palette */
635 count = i_colorcount(src);
636 for (index = 0; index < count; ++index) {
637 i_getcolors(src, index, &temp, 1);
638 i_addcolors(im, &temp, 1);
641 vals = mymalloc(sizeof(i_palidx) * x1);
642 for (y = 0; y < y1; ++y) {
643 i_gpal(src, 0, x1, y, vals);
644 i_ppal(im, 0, x1, y, vals);
652 =item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy )
654 Takes the sub image I<src[src_minx, src_maxx)[src_miny, src_maxy)> and
655 overlays it at (I<tx>,I<ty>) on the image object.
657 The alpha channel of each pixel in I<src> is used to control how much
658 the existing colour in I<im> is replaced, if it is 255 then the colour
659 is completely replaced, if it is 0 then the original colour is left
666 i_rubthru(i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny,
667 int src_maxx, int src_maxy) {
674 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d, src_minx %d, "
675 "src_miny %d, src_maxx %d, src_maxy %d)\n",
676 im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy));
679 if (im->channels == 3 && src->channels == 4) {
681 chans[0] = 0; chans[1] = 1; chans[2] = 2;
684 else if (im->channels == 3 && src->channels == 2) {
686 chans[0] = chans[1] = chans[2] = 0;
689 else if (im->channels == 1 && src->channels == 2) {
695 i_push_error(0, "rubthru can only work where (dest, src) channels are (3,4), (3,2) or (1,2)");
700 /* if you change this code, please make sure the else branch is
701 changed in a similar fashion - TC */
703 i_color pv, orig, dest;
705 for(y = src_miny; y < src_maxy; y++) {
707 for(x = src_minx; x < src_maxx; x++) {
708 i_gpix(src, x, y, &pv);
709 i_gpix(im, ttx, tty, &orig);
710 alpha = pv.channel[alphachan];
711 for (ch = 0; ch < chancount; ++ch) {
712 dest.channel[ch] = (alpha * pv.channel[chans[ch]]
713 + (255 - alpha) * orig.channel[ch])/255;
715 i_ppix(im, ttx, tty, &dest);
723 i_fcolor pv, orig, dest;
726 for(y = src_miny; y < src_maxy; y++) {
728 for(x = src_minx; x < src_maxx; x++) {
729 i_gpixf(src, x, y, &pv);
730 i_gpixf(im, ttx, tty, &orig);
731 alpha = pv.channel[alphachan];
732 for (ch = 0; ch < chancount; ++ch) {
733 dest.channel[ch] = alpha * pv.channel[chans[ch]]
734 + (1 - alpha) * orig.channel[ch];
736 i_ppixf(im, ttx, tty, &dest);
748 =item i_flipxy(im, axis)
750 Flips the image inplace around the axis specified.
751 Returns 0 if parameters are invalid.
754 axis - 0 = x, 1 = y, 2 = both
760 i_flipxy(i_img *im, int direction) {
761 int x, x2, y, y2, xm, ym;
765 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
770 case XAXIS: /* Horizontal 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, y, &val2);
779 i_ppix(im, x, y, &val2);
780 i_ppix(im, x2, y, &val1);
785 case YAXIS: /* Vertical flip */
789 for(y=0; y<ym; y++) {
790 for(x=0; x<xm; x++) {
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);
800 case XYAXIS: /* Horizontal and Vertical flip */
804 for(y=0; y<ym; y++) {
806 for(x=0; x<xm; x++) {
808 i_gpix(im, x, y, &val1);
809 i_gpix(im, x2, y2, &val2);
810 i_ppix(im, x, y, &val2);
811 i_ppix(im, x2, y2, &val1);
813 i_gpix(im, x2, y, &val1);
814 i_gpix(im, x, y2, &val2);
815 i_ppix(im, x2, y, &val2);
816 i_ppix(im, x, y2, &val1);
821 if (xm*2 != xs) { /* odd number of column */
822 mm_log((1, "i_flipxy: odd number of columns\n"));
825 for(y=0; y<ym; y++) {
827 i_gpix(im, x, y, &val1);
828 i_gpix(im, x, y2, &val2);
829 i_ppix(im, x, y, &val2);
830 i_ppix(im, x, y2, &val1);
834 if (ym*2 != ys) { /* odd number of rows */
835 mm_log((1, "i_flipxy: odd number of rows\n"));
838 for(x=0; x<xm; x++) {
840 i_gpix(im, x, y, &val1);
841 i_gpix(im, x2, y, &val2);
842 i_ppix(im, x, y, &val2);
843 i_ppix(im, x2, y, &val1);
849 mm_log((1, "i_flipxy: direction is invalid\n" ));
867 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
868 else if (x == 0.0) return (1.0);
869 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
881 i_scaleaxis_3ch_8bit(i_img *im, int size, int Axis) {
889 unsigned long *pixels;
893 mm_log((1,"i_scaleaxis_3ch_8bit(im %p, size %d,Axis %d)\n",im, size, Axis));
901 pixels = mymalloc(sizeof(*pixels) * im->xsize);
908 pixels = mymalloc(sizeof(*pixels) * im->ysize);
911 new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
916 for (i=0; i<iEnd; i++) {
919 for(j=0; j<im->xsize; j++) {
920 i_gpix(im, j, i, &val);
921 pixels[j] = (val.rgba.r<<24) | (val.rgba.g<<16) | (val.rgba.b<<8) | (val.rgba.a<<0);
924 /* printf("jEnd = %d, end = %d\n", jEnd, end); */
925 while ((end+1)/2>=size) {
929 for(j=0; j<lend; j++) {
930 unsigned long a = pixels[2*j];
931 unsigned long b = pixels[2*j+1];
932 pixels[j] = (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
935 pixels[j] = pixels[2*j];
940 printf("end = %d size = %d\n", end, size);
942 /* Replace this with Bresenham later */
943 for(j=0; j<size; j++) {
945 /* if ((i*size)/end <) */
946 unsigned long t = pixels[j];
947 val.rgba.r = (t >> 24) & 0xff;
948 val.rgba.g = (t >> 16) & 0xff;
949 val.rgba.b = (t >> 8) & 0xff;
950 val.rgba.a = t & 0xff;
951 i_ppix(new_img, j, i, &val);
966 =item i_scaleaxis(im, value, axis)
968 Returns a new image object which is I<im> scaled by I<value> along
969 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
975 i_scaleaxis(i_img *im, float Value, int Axis) {
976 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
977 int LanczosWidthFactor;
978 float *l0, *l1, OldLocation;
981 float F, PictureValue[MAXCHANNELS];
983 i_color val,val1,val2;
986 mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
990 return i_scaleaxis_3ch_8bit(im, (int)(0.5+im->xsize*Value), Axis);
992 hsize = (int)(0.5 + im->xsize * Value);
999 vsize = (int)(0.5 + im->ysize * Value);
1005 new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
1007 /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
1008 LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value);
1009 lMax = LanczosWidthFactor << 1;
1011 l0 = mymalloc(lMax * sizeof(float));
1012 l1 = mymalloc(lMax * sizeof(float));
1014 for (j=0; j<jEnd; j++) {
1015 OldLocation = ((float) j) / Value;
1016 T = (int) (OldLocation);
1017 F = OldLocation - (float) T;
1019 for (l = 0; l<lMax; l++) {
1020 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
1021 l1[l] = Lanczos(((float) (l+1) - F) / (float) LanczosWidthFactor);
1024 /* Make sure filter is normalized */
1026 for(l=0; l<lMax; l++) {
1030 t /= (float)LanczosWidthFactor;
1032 for(l=0; l<lMax; l++) {
1037 if (Axis == XAXIS) {
1039 for (i=0; i<iEnd; i++) {
1040 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
1041 for (l=0; l<lMax; l++) {
1042 int mx = T-lMax+l+1;
1044 mx = (mx < 0) ? 0 : mx;
1045 Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
1047 i_gpix(im, Mx, i, &val1);
1048 i_gpix(im, mx, i, &val2);
1050 for (k=0; k<im->channels; k++) {
1051 PictureValue[k] += l1[l] * val1.channel[k];
1052 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
1055 for(k=0;k<im->channels;k++) {
1056 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
1057 val.channel[k]=minmax(0,255,psave);
1059 i_ppix(new_img, j, i, &val);
1064 for (i=0; i<iEnd; i++) {
1065 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
1066 for (l=0; l < lMax; l++) {
1067 int mx = T-lMax+l+1;
1069 mx = (mx < 0) ? 0 : mx;
1070 Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
1072 i_gpix(im, i, Mx, &val1);
1073 i_gpix(im, i, mx, &val2);
1074 for (k=0; k<im->channels; k++) {
1075 PictureValue[k] += l1[l] * val1.channel[k];
1076 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
1079 for (k=0; k<im->channels; k++) {
1080 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
1081 val.channel[k] = minmax(0, 255, psave);
1083 i_ppix(new_img, i, j, &val);
1091 mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
1098 =item i_scale_nn(im, scx, scy)
1100 Scale by using nearest neighbor
1101 Both axes scaled at the same time since
1102 nothing is gained by doing it in two steps
1109 i_scale_nn(i_img *im, float scx, float scy) {
1111 int nxsize,nysize,nx,ny;
1115 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
1117 nxsize = (int) ((float) im->xsize * scx);
1118 nysize = (int) ((float) im->ysize * scy);
1120 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1122 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1123 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1124 i_ppix(new_img,nx,ny,&val);
1127 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1133 =item i_sametype(i_img *im, int xsize, int ysize)
1135 Returns an image of the same type (sample size, channels, paletted/direct).
1137 For paletted images the palette is copied from the source.
1142 i_img *i_sametype(i_img *src, int xsize, int ysize) {
1143 if (src->type == i_direct_type) {
1144 if (src->bits == 8) {
1145 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1147 else if (src->bits == i_16_bits) {
1148 return i_img_16_new(xsize, ysize, src->channels);
1150 else if (src->bits == i_double_bits) {
1151 return i_img_double_new(xsize, ysize, src->channels);
1154 i_push_error(0, "Unknown image bits");
1162 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1163 for (i = 0; i < i_colorcount(src); ++i) {
1164 i_getcolors(src, i, &col, 1);
1165 i_addcolors(targ, &col, 1);
1173 =item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1175 Returns an image of the same type (sample size).
1177 For paletted images the equivalent direct type is returned.
1182 i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1183 if (src->bits == 8) {
1184 return i_img_empty_ch(NULL, xsize, ysize, channels);
1186 else if (src->bits == i_16_bits) {
1187 return i_img_16_new(xsize, ysize, channels);
1189 else if (src->bits == i_double_bits) {
1190 return i_img_double_new(xsize, ysize, channels);
1193 i_push_error(0, "Unknown image bits");
1199 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1201 Spatially transforms I<im> returning a new image.
1203 opx for a length of opxl and opy for a length of opy are arrays of
1204 operators that modify the x and y positions to retreive the pixel data from.
1206 parm and parmlen define extra parameters that the operators may use.
1208 Note that this function is largely superseded by the more flexible
1209 L<transform.c/i_transform2>.
1211 Returns the new image.
1213 The operators for this function are defined in L<stackmach.c>.
1218 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1220 int nxsize,nysize,nx,ny;
1224 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));
1227 nysize = im->ysize ;
1229 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1230 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1231 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1232 /* parm[parmlen-2]=(double)nx;
1233 parm[parmlen-1]=(double)ny; */
1238 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1239 rx=i_op_run(opx,opxl,parm,parmlen);
1240 ry=i_op_run(opy,opyl,parm,parmlen);
1241 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1242 i_gpix(im,rx,ry,&val);
1243 i_ppix(new_img,nx,ny,&val);
1246 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1251 =item i_img_diff(im1, im2)
1253 Calculates the sum of the squares of the differences between
1254 correspoding channels in two images.
1256 If the images are not the same size then only the common area is
1257 compared, hence even if images are different sizes this function
1263 i_img_diff(i_img *im1,i_img *im2) {
1264 int x,y,ch,xb,yb,chb;
1268 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1270 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1271 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1272 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1274 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1277 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1278 i_gpix(im1,x,y,&val1);
1279 i_gpix(im2,x,y,&val2);
1281 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1283 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1287 /* just a tiny demo of haar wavelets */
1295 i_img *new_img,*new_img2;
1296 i_color val1,val2,dval1,dval2;
1304 /* horizontal pass */
1306 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1307 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1310 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1311 i_gpix(im,x*2,y,&val1);
1312 i_gpix(im,x*2+1,y,&val2);
1313 for(ch=0;ch<im->channels;ch++) {
1314 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1315 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1317 i_ppix(new_img,x,y,&dval1);
1318 i_ppix(new_img,x+fx,y,&dval2);
1321 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1322 i_gpix(new_img,x,y*2,&val1);
1323 i_gpix(new_img,x,y*2+1,&val2);
1324 for(ch=0;ch<im->channels;ch++) {
1325 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1326 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1328 i_ppix(new_img2,x,y,&dval1);
1329 i_ppix(new_img2,x,y+fy,&dval2);
1332 i_img_destroy(new_img);
1337 =item i_count_colors(im, maxc)
1339 returns number of colors or -1
1340 to indicate that it was more than max colors
1345 i_count_colors(i_img *im,int maxc) {
1352 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1359 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1360 i_gpix(im,x,y,&val);
1361 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1362 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1371 =head2 8-bit per sample image internal functions
1373 These are the functions installed in an 8-bit per sample image.
1377 =item i_ppix_d(im, x, y, col)
1381 This is the function kept in the i_f_ppix member of an i_img object.
1382 It does a normal store of a pixel into the image with range checking.
1384 Returns 0 if the pixel could be set, -1 otherwise.
1390 i_ppix_d(i_img *im, int x, int y, i_color *val) {
1393 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1394 for(ch=0;ch<im->channels;ch++)
1395 if (im->ch_mask&(1<<ch))
1396 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1399 return -1; /* error was clipped */
1403 =item i_gpix_d(im, x, y, &col)
1407 This is the function kept in the i_f_gpix member of an i_img object.
1408 It does normal retrieval of a pixel from the image with range checking.
1410 Returns 0 if the pixel could be set, -1 otherwise.
1416 i_gpix_d(i_img *im, int x, int y, i_color *val) {
1418 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1419 for(ch=0;ch<im->channels;ch++)
1420 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1423 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
1424 return -1; /* error was cliped */
1428 =item i_glin_d(im, l, r, y, vals)
1430 Reads a line of data from the image, storing the pixels at vals.
1432 The line runs from (l,y) inclusive to (r,y) non-inclusive
1434 vals should point at space for (r-l) pixels.
1436 l should never be less than zero (to avoid confusion about where to
1437 put the pixels in vals).
1439 Returns the number of pixels copied (eg. if r, l or y is out of range)
1445 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1447 unsigned char *data;
1448 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1451 data = im->idata + (l+y*im->xsize) * im->channels;
1453 for (i = 0; i < count; ++i) {
1454 for (ch = 0; ch < im->channels; ++ch)
1455 vals[i].channel[ch] = *data++;
1465 =item i_plin_d(im, l, r, y, vals)
1467 Writes a line of data into the image, using the pixels at vals.
1469 The line runs from (l,y) inclusive to (r,y) non-inclusive
1471 vals should point at (r-l) pixels.
1473 l should never be less than zero (to avoid confusion about where to
1474 get the pixels in vals).
1476 Returns the number of pixels copied (eg. if r, l or y is out of range)
1482 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
1484 unsigned char *data;
1485 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1488 data = im->idata + (l+y*im->xsize) * im->channels;
1490 for (i = 0; i < count; ++i) {
1491 for (ch = 0; ch < im->channels; ++ch) {
1492 if (im->ch_mask & (1 << ch))
1493 *data = vals[i].channel[ch];
1505 =item i_ppixf_d(im, x, y, val)
1511 i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
1514 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1515 for(ch=0;ch<im->channels;ch++)
1516 if (im->ch_mask&(1<<ch)) {
1517 im->idata[(x+y*im->xsize)*im->channels+ch] =
1518 SampleFTo8(val->channel[ch]);
1522 return -1; /* error was clipped */
1526 =item i_gpixf_d(im, x, y, val)
1532 i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1534 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1535 for(ch=0;ch<im->channels;ch++) {
1537 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1541 return -1; /* error was cliped */
1545 =item i_glinf_d(im, l, r, y, vals)
1547 Reads a line of data from the image, storing the pixels at vals.
1549 The line runs from (l,y) inclusive to (r,y) non-inclusive
1551 vals should point at space for (r-l) pixels.
1553 l should never be less than zero (to avoid confusion about where to
1554 put the pixels in vals).
1556 Returns the number of pixels copied (eg. if r, l or y is out of range)
1562 i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1564 unsigned char *data;
1565 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1568 data = im->idata + (l+y*im->xsize) * im->channels;
1570 for (i = 0; i < count; ++i) {
1571 for (ch = 0; ch < im->channels; ++ch)
1572 vals[i].channel[ch] = Sample8ToF(*data++);
1582 =item i_plinf_d(im, l, r, y, vals)
1584 Writes a line of data into the image, using the pixels at vals.
1586 The line runs from (l,y) inclusive to (r,y) non-inclusive
1588 vals should point at (r-l) pixels.
1590 l should never be less than zero (to avoid confusion about where to
1591 get the pixels in vals).
1593 Returns the number of pixels copied (eg. if r, l or y is out of range)
1599 i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1601 unsigned char *data;
1602 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1605 data = im->idata + (l+y*im->xsize) * im->channels;
1607 for (i = 0; i < count; ++i) {
1608 for (ch = 0; ch < im->channels; ++ch) {
1609 if (im->ch_mask & (1 << ch))
1610 *data = SampleFTo8(vals[i].channel[ch]);
1622 =item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1624 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1625 for the channels specified by chans, an array of int with chan_count
1628 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1634 i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
1635 const int *chans, int chan_count) {
1636 int ch, count, i, w;
1637 unsigned char *data;
1639 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1642 data = im->idata + (l+y*im->xsize) * im->channels;
1647 /* make sure we have good channel numbers */
1648 for (ch = 0; ch < chan_count; ++ch) {
1649 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1650 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1654 for (i = 0; i < w; ++i) {
1655 for (ch = 0; ch < chan_count; ++ch) {
1656 *samps++ = data[chans[ch]];
1659 data += im->channels;
1663 for (i = 0; i < w; ++i) {
1664 for (ch = 0; ch < chan_count; ++ch) {
1665 *samps++ = data[ch];
1668 data += im->channels;
1680 =item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1682 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1683 for the channels specified by chan_mask, where bit 0 is the first
1686 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1692 i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
1693 const int *chans, int chan_count) {
1694 int ch, count, i, w;
1695 unsigned char *data;
1696 for (ch = 0; ch < chan_count; ++ch) {
1697 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1698 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1701 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1704 data = im->idata + (l+y*im->xsize) * im->channels;
1709 /* make sure we have good channel numbers */
1710 for (ch = 0; ch < chan_count; ++ch) {
1711 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1712 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1716 for (i = 0; i < w; ++i) {
1717 for (ch = 0; ch < chan_count; ++ch) {
1718 *samps++ = Sample8ToF(data[chans[ch]]);
1721 data += im->channels;
1725 for (i = 0; i < w; ++i) {
1726 for (ch = 0; ch < chan_count; ++ch) {
1727 *samps++ = Sample8ToF(data[ch]);
1730 data += im->channels;
1743 =head2 Image method wrappers
1745 These functions provide i_fsample_t functions in terms of their
1746 i_sample_t versions.
1750 =item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1755 int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1759 for (ch = 0; ch < im->channels; ++ch)
1760 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1762 return i_ppix(im, x, y, &temp);
1766 =item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1770 int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1774 if (i_gpix(im, x, y, &temp)) {
1775 for (ch = 0; ch < im->channels; ++ch)
1776 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1784 =item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1788 int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1791 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1797 work = mymalloc(sizeof(i_color) * (r-l));
1798 for (i = 0; i < r-l; ++i) {
1799 for (ch = 0; ch < im->channels; ++ch)
1800 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1802 ret = i_plin(im, l, r, y, work);
1817 =item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1821 int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1824 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1830 work = mymalloc(sizeof(i_color) * (r-l));
1831 ret = i_plin(im, l, r, y, work);
1832 for (i = 0; i < r-l; ++i) {
1833 for (ch = 0; ch < im->channels; ++ch)
1834 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1850 =item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1854 int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
1855 int const *chans, int chan_count) {
1858 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1864 work = mymalloc(sizeof(i_sample_t) * (r-l));
1865 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1866 for (i = 0; i < ret; ++i) {
1867 samp[i] = Sample8ToF(work[i]);
1885 =head2 Palette wrapper functions
1887 Used for virtual images, these forward palette calls to a wrapped image,
1888 assuming the wrapped image is the first pointer in the structure that
1889 im->ext_data points at.
1893 =item i_addcolors_forward(i_img *im, i_color *colors, int count)
1897 int i_addcolors_forward(i_img *im, i_color *colors, int count) {
1898 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1902 =item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1906 int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1907 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1911 =item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
1915 int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
1916 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1920 =item i_colorcount_forward(i_img *im)
1924 int i_colorcount_forward(i_img *im) {
1925 return i_colorcount(*(i_img **)im->ext_data);
1929 =item i_maxcolors_forward(i_img *im)
1933 int i_maxcolors_forward(i_img *im) {
1934 return i_maxcolors(*(i_img **)im->ext_data);
1938 =item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
1942 int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
1943 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1949 =head2 Stream reading and writing wrapper functions
1953 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1955 Performs general read buffering for file readers that permit reading
1956 to be done through a callback.
1958 The final callback gets two parameters, a I<need> value, and a I<want>
1959 value, where I<need> is the amount of data that the file library needs
1960 to read, and I<want> is the amount of space available in the buffer
1961 maintained by these functions.
1963 This means if you need to read from a stream that you don't know the
1964 length of, you can return I<need> bytes, taking the performance hit of
1965 possibly expensive callbacks (eg. back to perl code), or if you are
1966 reading from a stream where it doesn't matter if some data is lost, or
1967 if the total length of the stream is known, you can return I<want>
1974 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1977 if (length < gci->length - gci->cpos) {
1979 memcpy(buf, gci->buffer+gci->cpos, length);
1980 gci->cpos += length;
1985 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1986 total += gci->length - gci->cpos;
1987 length -= gci->length - gci->cpos;
1988 buf += gci->length - gci->cpos;
1989 if (length < (int)sizeof(gci->buffer)) {
1993 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1994 sizeof(gci->buffer))) > 0) {
1996 gci->length = did_read;
1998 copy_size = i_min(length, gci->length);
1999 memcpy(buf, gci->buffer, copy_size);
2000 gci->cpos += copy_size;
2003 length -= copy_size;
2007 /* just read the rest - too big for our buffer*/
2009 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2019 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2021 For use by callback file readers to initialize the reader buffer.
2023 Allocates, initializes and returns the reader buffer.
2025 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2030 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2031 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2033 self->userdata = userdata;
2041 =item i_free_gen_read_data(i_gen_read_data *)
2047 void i_free_gen_read_data(i_gen_read_data *self) {
2052 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2054 Performs write buffering for a callback based file writer.
2056 Failures are considered fatal, if a write fails then data will be
2063 i_gen_write_data *self,
2067 if (self->filledto && self->filledto+size > self->maxlength) {
2068 if (self->cb(self->userdata, self->buffer, self->filledto)) {
2076 if (self->filledto+size <= self->maxlength) {
2078 memcpy(self->buffer+self->filledto, data, size);
2079 self->filledto += size;
2082 /* doesn't fit - hand it off */
2083 return self->cb(self->userdata, data, size);
2087 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2089 Allocates and initializes the data structure used by i_gen_writer.
2091 This should be released with L<image.c/i_free_gen_write_data>
2095 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2096 char *userdata, int max_length)
2098 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2100 self->userdata = userdata;
2101 self->maxlength = i_min(max_length, sizeof(self->buffer));
2102 if (self->maxlength < 0)
2103 self->maxlength = sizeof(self->buffer);
2110 =item i_free_gen_write_data(i_gen_write_data *info, int flush)
2112 Cleans up the write buffer.
2114 Will flush any left-over data if I<flush> is non-zero.
2116 Returns non-zero if flush is zero or if info->cb() returns non-zero.
2118 Return zero only if flush is non-zero and info->cb() returns zero.
2124 int i_free_gen_write_data(i_gen_write_data *info, int flush)
2126 int result = !flush ||
2127 info->filledto == 0 ||
2128 info->cb(info->userdata, info->buffer, info->filledto);
2137 =item i_test_format_probe(io_glue *data, int length)
2139 Cleans up the write buffer.
2141 Will flush any left-over data if I<flush> is non-zero.
2143 Returns non-zero if flush is zero or if info->cb() returns non-zero.
2145 Return zero only if flush is non-zero and info->cb() returns zero.
2153 i_test_format_probe(io_glue *data, int length) {
2159 {"\xFF\xD8", "jpeg"},
2165 {"\x89PNG\x0d\x0a\x1a\x0a", "png"},
2178 io_glue_commit_types(data);
2179 rc = data->readcb(data, head, 18);
2180 if (rc == -1) return NULL;
2181 data->seekcb(data, -rc, SEEK_CUR);
2183 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
2185 ssize_t len = strlen(formats[i].magic);
2186 if (rc<len) continue;
2187 c = !strncmp(formats[i].magic, head, len);
2189 match = formats[i].name;
2195 if (match && !strcmp(match, "jpeg")) {
2196 unsigned int x0, x1;
2197 rc = data->readcb(data, head, 18);
2198 if (rc == -1) return NULL;
2199 x0 = (unsigned char)head[0];
2200 x1 = (unsigned char)head[1];
2201 data->seekcb(data, -rc, SEEK_CUR);
2202 printf("Jpeg reread: %x %x\n", x0, x1);
2208 tga_header_verify(head)) return "tga";
2220 Arnar M. Hrafnkelsson <addi@umich.edu>
2222 Tony Cook <tony@develop-help.com>