]> git.imager.perl.org - imager.git/blob - image.c
fill out the large sample support docs
[imager.git] / image.c
1 #include "imager.h"
2 #include "imageri.h"
3
4 /*
5 =head1 NAME
6
7 image.c - implements most of the basic functions of Imager and much of the rest
8
9 =head1 SYNOPSIS
10
11   i_img *i;
12   i_color *c;
13   c = i_color_new(red, green, blue, alpha);
14   ICL_DESTROY(c);
15   i = i_img_new();
16   i_img_destroy(i);
17   // and much more
18
19 =head1 DESCRIPTION
20
21 image.c implements the basic functions to create and destroy image and
22 color objects for Imager.
23
24 =head1 FUNCTION REFERENCE
25
26 Some of these functions are internal.
27
28 =over
29
30 =cut
31 */
32
33 #define XAXIS 0
34 #define YAXIS 1
35 #define XYAXIS 2
36
37 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i   )) )
38
39 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
40 static void fake(void) { ceil(1); }
41
42 static int i_ppix_d(i_img *im, int x, int y, const i_color *val);
43 static int i_gpix_d(i_img *im, int x, int y, i_color *val);
44 static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
45 static int i_plin_d(i_img *im, int l, int r, int y, const i_color *vals);
46 static int i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val);
47 static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
48 static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
49 static int i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals);
50 static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
51 static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
52 /*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
53   static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/
54
55 /* 
56 =item ICL_new_internal(r, g, b, a)
57
58 Return a new color object with values passed to it.
59
60    r - red   component (range: 0 - 255)
61    g - green component (range: 0 - 255)
62    b - blue  component (range: 0 - 255)
63    a - alpha component (range: 0 - 255)
64
65 =cut
66 */
67
68 i_color *
69 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
70   i_color *cl = NULL;
71
72   mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
73
74   if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
75   cl->rgba.r = r;
76   cl->rgba.g = g;
77   cl->rgba.b = b;
78   cl->rgba.a = a;
79   mm_log((1,"(%p) <- ICL_new_internal\n",cl));
80   return cl;
81 }
82
83
84 /*
85 =item ICL_set_internal(cl, r, g, b, a)
86
87  Overwrite a color with new values.
88
89    cl - pointer to color object
90    r - red   component (range: 0 - 255)
91    g - green component (range: 0 - 255)
92    b - blue  component (range: 0 - 255)
93    a - alpha component (range: 0 - 255)
94
95 =cut
96 */
97
98 i_color *
99 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
100   mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
101   if (cl == NULL)
102     if ( (cl=mymalloc(sizeof(i_color))) == NULL)
103       i_fatal(2,"malloc() error\n");
104   cl->rgba.r=r;
105   cl->rgba.g=g;
106   cl->rgba.b=b;
107   cl->rgba.a=a;
108   mm_log((1,"(%p) <- ICL_set_internal\n",cl));
109   return cl;
110 }
111
112
113 /* 
114 =item ICL_add(dst, src, ch)
115
116 Add src to dst inplace - dst is modified.
117
118    dst - pointer to destination color object
119    src - pointer to color object that is added
120    ch - number of channels
121
122 =cut
123 */
124
125 void
126 ICL_add(i_color *dst,i_color *src,int ch) {
127   int tmp,i;
128   for(i=0;i<ch;i++) {
129     tmp=dst->channel[i]+src->channel[i];
130     dst->channel[i]= tmp>255 ? 255:tmp;
131   }
132 }
133
134 /* 
135 =item ICL_info(cl)
136
137 Dump color information to log - strictly for debugging.
138
139    cl - pointer to color object
140
141 =cut
142 */
143
144 void
145 ICL_info(i_color const *cl) {
146   mm_log((1,"i_color_info(cl* %p)\n",cl));
147   mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
148 }
149
150 /* 
151 =item ICL_DESTROY
152
153 Destroy ancillary data for Color object.
154
155    cl - pointer to color object
156
157 =cut
158 */
159
160 void
161 ICL_DESTROY(i_color *cl) {
162   mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
163   myfree(cl);
164 }
165
166 /*
167 =item i_fcolor_new(double r, double g, double b, double a)
168
169 =cut
170 */
171 i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
172   i_fcolor *cl = NULL;
173
174   mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
175
176   if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
177   cl->rgba.r = r;
178   cl->rgba.g = g;
179   cl->rgba.b = b;
180   cl->rgba.a = a;
181   mm_log((1,"(%p) <- i_fcolor_new\n",cl));
182
183   return cl;
184 }
185
186 /*
187 =item i_fcolor_destroy(i_fcolor *cl) 
188
189 =cut
190 */
191 void i_fcolor_destroy(i_fcolor *cl) {
192   myfree(cl);
193 }
194
195 /*
196 =item IIM_base_8bit_direct (static)
197
198 A static i_img object used to initialize direct 8-bit per sample images.
199
200 =cut
201 */
202 static i_img IIM_base_8bit_direct =
203 {
204   0, /* channels set */
205   0, 0, 0, /* xsize, ysize, bytes */
206   ~0U, /* ch_mask */
207   i_8_bits, /* bits */
208   i_direct_type, /* type */
209   0, /* virtual */
210   NULL, /* idata */
211   { 0, 0, NULL }, /* tags */
212   NULL, /* ext_data */
213
214   i_ppix_d, /* i_f_ppix */
215   i_ppixf_d, /* i_f_ppixf */
216   i_plin_d, /* i_f_plin */
217   i_plinf_d, /* i_f_plinf */
218   i_gpix_d, /* i_f_gpix */
219   i_gpixf_d, /* i_f_gpixf */
220   i_glin_d, /* i_f_glin */
221   i_glinf_d, /* i_f_glinf */
222   i_gsamp_d, /* i_f_gsamp */
223   i_gsampf_d, /* i_f_gsampf */
224
225   NULL, /* i_f_gpal */
226   NULL, /* i_f_ppal */
227   NULL, /* i_f_addcolors */
228   NULL, /* i_f_getcolors */
229   NULL, /* i_f_colorcount */
230   NULL, /* i_f_maxcolors */
231   NULL, /* i_f_findcolor */
232   NULL, /* i_f_setcolors */
233
234   NULL, /* i_f_destroy */
235 };
236
237 /*static void set_8bit_direct(i_img *im) {
238   im->i_f_ppix = i_ppix_d;
239   im->i_f_ppixf = i_ppixf_d;
240   im->i_f_plin = i_plin_d;
241   im->i_f_plinf = i_plinf_d;
242   im->i_f_gpix = i_gpix_d;
243   im->i_f_gpixf = i_gpixf_d;
244   im->i_f_glin = i_glin_d;
245   im->i_f_glinf = i_glinf_d;
246   im->i_f_gpal = NULL;
247   im->i_f_ppal = NULL;
248   im->i_f_addcolor = NULL;
249   im->i_f_getcolor = NULL;
250   im->i_f_colorcount = NULL;
251   im->i_f_findcolor = NULL;
252   }*/
253
254 /*
255 =item IIM_new(x, y, ch)
256
257 =item i_img_8_new(x, y, ch)
258
259 =category Image creation
260
261 Creates a new image object I<x> pixels wide, and I<y> pixels high with
262 I<ch> channels.
263
264 =cut
265 */
266
267
268 i_img *
269 IIM_new(int x,int y,int ch) {
270   i_img *im;
271   mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
272
273   im=i_img_empty_ch(NULL,x,y,ch);
274   
275   mm_log((1,"(%p) <- IIM_new\n",im));
276   return im;
277 }
278
279
280 void
281 IIM_DESTROY(i_img *im) {
282   mm_log((1,"IIM_DESTROY(im* %p)\n",im));
283   i_img_destroy(im);
284   /*   myfree(cl); */
285 }
286
287 /* 
288 =item i_img_new()
289
290 Create new image reference - notice that this isn't an object yet and
291 this should be fixed asap.
292
293 =cut
294 */
295
296
297 i_img *
298 i_img_new() {
299   i_img *im;
300   
301   mm_log((1,"i_img_struct()\n"));
302   if ( (im=mymalloc(sizeof(i_img))) == NULL)
303     i_fatal(2,"malloc() error\n");
304   
305   *im = IIM_base_8bit_direct;
306   im->xsize=0;
307   im->ysize=0;
308   im->channels=3;
309   im->ch_mask=MAXINT;
310   im->bytes=0;
311   im->idata=NULL;
312   
313   mm_log((1,"(%p) <- i_img_struct\n",im));
314   return im;
315 }
316
317 /* 
318 =item i_img_empty(im, x, y)
319
320 Re-new image reference (assumes 3 channels)
321
322    im - Image pointer
323    x - xsize of destination image
324    y - ysize of destination image
325
326 **FIXME** what happens if a live image is passed in here?
327
328 Should this just call i_img_empty_ch()?
329
330 =cut
331 */
332
333 i_img *
334 i_img_empty(i_img *im,int x,int y) {
335   mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
336   return i_img_empty_ch(im, x, y, 3);
337 }
338
339 /* 
340 =item i_img_empty_ch(im, x, y, ch)
341
342 Re-new image reference 
343
344    im - Image pointer
345    x  - xsize of destination image
346    y  - ysize of destination image
347    ch - number of channels
348
349 =cut
350 */
351
352 i_img *
353 i_img_empty_ch(i_img *im,int x,int y,int ch) {
354   int bytes;
355
356   mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
357
358   if (x < 1 || y < 1) {
359     i_push_error(0, "Image sizes must be positive");
360     return NULL;
361   }
362   if (ch < 1 || ch > MAXCHANNELS) {
363     i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
364     return NULL;
365   }
366   /* check this multiplication doesn't overflow */
367   bytes = x*y*ch;
368   if (bytes / y / ch != x) {
369     i_push_errorf(0, "integer overflow calculating image allocation");
370     return NULL;
371   }
372
373   if (im == NULL)
374     if ( (im=mymalloc(sizeof(i_img))) == NULL)
375       i_fatal(2,"malloc() error\n");
376
377   memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
378   i_tags_new(&im->tags);
379   im->xsize    = x;
380   im->ysize    = y;
381   im->channels = ch;
382   im->ch_mask  = MAXINT;
383   im->bytes=bytes;
384   if ( (im->idata=mymalloc(im->bytes)) == NULL) 
385     i_fatal(2,"malloc() error\n"); 
386   memset(im->idata,0,(size_t)im->bytes);
387   
388   im->ext_data = NULL;
389   
390   mm_log((1,"(%p) <- i_img_empty_ch\n",im));
391   return im;
392 }
393
394 /* 
395 =item i_img_exorcise(im)
396
397 Free image data.
398
399    im - Image pointer
400
401 =cut
402 */
403
404 void
405 i_img_exorcise(i_img *im) {
406   mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
407   i_tags_destroy(&im->tags);
408   if (im->i_f_destroy)
409     (im->i_f_destroy)(im);
410   if (im->idata != NULL) { myfree(im->idata); }
411   im->idata    = NULL;
412   im->xsize    = 0;
413   im->ysize    = 0;
414   im->channels = 0;
415
416   im->i_f_ppix=i_ppix_d;
417   im->i_f_gpix=i_gpix_d;
418   im->i_f_plin=i_plin_d;
419   im->i_f_glin=i_glin_d;
420   im->ext_data=NULL;
421 }
422
423 /* 
424 =item i_img_destroy(im)
425
426 =category Image
427
428 Destroy image and free data via exorcise.
429
430    im - Image pointer
431
432 =cut
433 */
434
435 void
436 i_img_destroy(i_img *im) {
437   mm_log((1,"i_img_destroy(im %p)\n",im));
438   i_img_exorcise(im);
439   if (im) { myfree(im); }
440 }
441
442 /* 
443 =item i_img_info(im, info)
444
445 =category Image
446
447 Return image information
448
449    im - Image pointer
450    info - pointer to array to return data
451
452 info is an array of 4 integers with the following values:
453
454  info[0] - width
455  info[1] - height
456  info[2] - channels
457  info[3] - channel mask
458
459 =cut
460 */
461
462
463 void
464 i_img_info(i_img *im,int *info) {
465   mm_log((1,"i_img_info(im 0x%x)\n",im));
466   if (im != NULL) {
467     mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
468     mm_log((1,"i_img_info: idata=0x%d\n",im->idata));
469     info[0] = im->xsize;
470     info[1] = im->ysize;
471     info[2] = im->channels;
472     info[3] = im->ch_mask;
473   } else {
474     info[0] = 0;
475     info[1] = 0;
476     info[2] = 0;
477     info[3] = 0;
478   }
479 }
480
481 /*
482 =item i_img_setmask(im, ch_mask)
483
484 =synopsis // only channel 0 writeable 
485 =synopsis i_img_setmask(img, 0x01);
486
487 Set the image channel mask for I<im> to I<ch_mask>.
488
489 =cut
490 */
491 void
492 i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
493
494
495 /*
496 =item i_img_getmask(im)
497
498 =synopsis mask = i_img_getmask(img);
499
500 Get the image channel mask for I<im>.
501
502 =cut
503 */
504 int
505 i_img_getmask(i_img *im) { return im->ch_mask; }
506
507 /*
508 =item i_img_getchannels(im)
509
510 =synopsis channels = i_img_getchannels(img);
511
512 Get the number of channels in I<im>.
513
514 =cut
515 */
516 int
517 i_img_getchannels(i_img *im) { return im->channels; }
518
519 /*
520 =item i_img_get_width(im)
521
522 =synopsis width = i_img_get_width(im);
523
524 Returns the width in pixels of the image.
525
526 =cut
527 */
528 i_img_dim
529 i_img_get_width(i_img *im) {
530   return im->xsize;
531 }
532
533 /*
534 =item i_img_get_height(im)
535
536 =synopsis height = i_img_get_height(im);
537
538 Returns the height in pixels of the image.
539
540 =cut
541 */
542 i_img_dim
543 i_img_get_height(i_img *im) {
544   return im->ysize;
545 }
546
547 /*
548 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
549
550 =category Image
551
552 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
553 (tx,ty) specifies the upper left corner for the target image.
554 pass NULL in trans for non transparent i_colors.
555
556 =cut
557 */
558
559 void
560 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,const i_color *trans) {
561   i_color pv;
562   int x,y,t,ttx,tty,tt,ch;
563
564   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",
565           im, src, x1, y1, x2, y2, tx, ty, trans));
566   
567   if (x2<x1) { t=x1; x1=x2; x2=t; }
568   if (y2<y1) { t=y1; y1=y2; y2=t; }
569
570   ttx=tx;
571   for(x=x1;x<x2;x++)
572     {
573       tty=ty;
574       for(y=y1;y<y2;y++)
575         {
576           i_gpix(src,x,y,&pv);
577           if ( trans != NULL)
578           {
579             tt=0;
580             for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
581             if (tt) i_ppix(im,ttx,tty,&pv);
582           } else i_ppix(im,ttx,tty,&pv);
583           tty++;
584         }
585       ttx++;
586     }
587 }
588
589 /*
590 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
591
592 =category Image
593
594 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
595 a rectangle the same size with it's top-left corner at (tx,ty) in the
596 destination image.
597
598 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
599
600 =cut
601 */
602
603 void
604 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
605   int x, y, t, ttx, tty;
606   
607   if (x2<x1) { t=x1; x1=x2; x2=t; }
608   if (y2<y1) { t=y1; y1=y2; y2=t; }
609   if (tx < 0) {
610     /* adjust everything equally */
611     x1 += -tx;
612     x2 += -tx;
613     tx = 0;
614   }
615   if (ty < 0) {
616     y1 += -ty;
617     y2 += -ty;
618     ty = 0;
619   }
620   if (x1 >= src->xsize || y1 >= src->ysize)
621     return; /* nothing to do */
622   if (x2 > src->xsize)
623     x2 = src->xsize;
624   if (y2 > src->ysize)
625     y2 = src->ysize;
626   if (x1 == x2 || y1 == y2)
627     return; /* nothing to do */
628
629   mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
630           im, src, x1, y1, x2, y2, tx, ty));
631   
632   if (im->bits == i_8_bits) {
633     i_color *row = mymalloc(sizeof(i_color) * (x2-x1));
634     tty = ty;
635     for(y=y1; y<y2; y++) {
636       ttx = tx;
637       i_glin(src, x1, x2, y, row);
638       i_plin(im, tx, tx+x2-x1, tty, row);
639       tty++;
640     }
641     myfree(row);
642   }
643   else {
644     i_fcolor pv;
645     tty = ty;
646     for(y=y1; y<y2; y++) {
647       ttx = tx;
648       for(x=x1; x<x2; x++) {
649         i_gpixf(src, x,   y,   &pv);
650         i_ppixf(im,  ttx, tty, &pv);
651         ttx++;
652       }
653       tty++;
654     }
655   }
656 }
657
658 /*
659 =item i_copy(src)
660
661 =category Image
662
663 Creates a new image that is a copy of src.
664
665 Tags are not copied, only the image data.
666
667 Returns: i_img *
668
669 =cut
670 */
671
672 i_img *
673 i_copy(i_img *src) {
674   int y, y1, x1;
675   i_img *im = i_sametype(src, src->xsize, src->ysize);
676
677   mm_log((1,"i_copy(src %p)\n", src));
678
679   if (!im)
680     return NULL;
681
682   x1 = src->xsize;
683   y1 = src->ysize;
684   if (src->type == i_direct_type) {
685     if (src->bits == i_8_bits) {
686       i_color *pv;
687       pv = mymalloc(sizeof(i_color) * x1);
688       
689       for (y = 0; y < y1; ++y) {
690         i_glin(src, 0, x1, y, pv);
691         i_plin(im, 0, x1, y, pv);
692       }
693       myfree(pv);
694     }
695     else {
696       i_fcolor *pv;
697
698       pv = mymalloc(sizeof(i_fcolor) * x1);
699       for (y = 0; y < y1; ++y) {
700         i_glinf(src, 0, x1, y, pv);
701         i_plinf(im, 0, x1, y, pv);
702       }
703       myfree(pv);
704     }
705   }
706   else {
707     i_color temp;
708     int index;
709     int count;
710     i_palidx *vals;
711
712     /* paletted image */
713     i_img_pal_new_low(im, x1, y1, src->channels, i_maxcolors(src));
714     /* copy across the palette */
715     count = i_colorcount(src);
716     for (index = 0; index < count; ++index) {
717       i_getcolors(src, index, &temp, 1);
718       i_addcolors(im, &temp, 1);
719     }
720
721     vals = mymalloc(sizeof(i_palidx) * x1);
722     for (y = 0; y < y1; ++y) {
723       i_gpal(src, 0, x1, y, vals);
724       i_ppal(im, 0, x1, y, vals);
725     }
726     myfree(vals);
727   }
728
729   return im;
730 }
731
732
733 /*
734 =item i_flipxy(im, axis)
735
736 Flips the image inplace around the axis specified.
737 Returns 0 if parameters are invalid.
738
739    im   - Image pointer
740    axis - 0 = x, 1 = y, 2 = both
741
742 =cut
743 */
744
745 undef_int
746 i_flipxy(i_img *im, int direction) {
747   int x, x2, y, y2, xm, ym;
748   int xs = im->xsize;
749   int ys = im->ysize;
750   
751   mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
752
753   if (!im) return 0;
754
755   switch (direction) {
756   case XAXIS: /* Horizontal flip */
757     xm = xs/2;
758     ym = ys;
759     for(y=0; y<ym; y++) {
760       x2 = xs-1;
761       for(x=0; x<xm; x++) {
762         i_color val1, val2;
763         i_gpix(im, x,  y,  &val1);
764         i_gpix(im, x2, y,  &val2);
765         i_ppix(im, x,  y,  &val2);
766         i_ppix(im, x2, y,  &val1);
767         x2--;
768       }
769     }
770     break;
771   case YAXIS: /* Vertical flip */
772     xm = xs;
773     ym = ys/2;
774     y2 = ys-1;
775     for(y=0; y<ym; y++) {
776       for(x=0; x<xm; x++) {
777         i_color val1, val2;
778         i_gpix(im, x,  y,  &val1);
779         i_gpix(im, x,  y2, &val2);
780         i_ppix(im, x,  y,  &val2);
781         i_ppix(im, x,  y2, &val1);
782       }
783       y2--;
784     }
785     break;
786   case XYAXIS: /* Horizontal and Vertical flip */
787     xm = xs/2;
788     ym = ys/2;
789     y2 = ys-1;
790     for(y=0; y<ym; y++) {
791       x2 = xs-1;
792       for(x=0; x<xm; x++) {
793         i_color val1, val2;
794         i_gpix(im, x,  y,  &val1);
795         i_gpix(im, x2, y2, &val2);
796         i_ppix(im, x,  y,  &val2);
797         i_ppix(im, x2, y2, &val1);
798
799         i_gpix(im, x2, y,  &val1);
800         i_gpix(im, x,  y2, &val2);
801         i_ppix(im, x2, y,  &val2);
802         i_ppix(im, x,  y2, &val1);
803         x2--;
804       }
805       y2--;
806     }
807     if (xm*2 != xs) { /* odd number of column */
808       mm_log((1, "i_flipxy: odd number of columns\n"));
809       x = xm;
810       y2 = ys-1;
811       for(y=0; y<ym; y++) {
812         i_color val1, val2;
813         i_gpix(im, x,  y,  &val1);
814         i_gpix(im, x,  y2, &val2);
815         i_ppix(im, x,  y,  &val2);
816         i_ppix(im, x,  y2, &val1);
817         y2--;
818       }
819     }
820     if (ym*2 != ys) { /* odd number of rows */
821       mm_log((1, "i_flipxy: odd number of rows\n"));
822       y = ym;
823       x2 = xs-1;
824       for(x=0; x<xm; x++) {
825         i_color val1, val2;
826         i_gpix(im, x,  y,  &val1);
827         i_gpix(im, x2, y,  &val2);
828         i_ppix(im, x,  y,  &val2);
829         i_ppix(im, x2, y,  &val1);
830         x2--;
831       }
832     }
833     break;
834   default:
835     mm_log((1, "i_flipxy: direction is invalid\n" ));
836     return 0;
837   }
838   return 1;
839 }
840
841
842
843
844
845 static
846 float
847 Lanczos(float x) {
848   float PIx, PIx2;
849   
850   PIx = PI * x;
851   PIx2 = PIx / 2.0;
852   
853   if ((x >= 2.0) || (x <= -2.0)) return (0.0);
854   else if (x == 0.0) return (1.0);
855   else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
856 }
857
858
859 /*
860 =item i_scaleaxis(im, value, axis)
861
862 Returns a new image object which is I<im> scaled by I<value> along
863 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
864
865 =cut
866 */
867
868 i_img*
869 i_scaleaxis(i_img *im, float Value, int Axis) {
870   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
871   int LanczosWidthFactor;
872   float *l0, *l1, OldLocation;
873   int T; 
874   float t;
875   float F, PictureValue[MAXCHANNELS];
876   short psave;
877   i_color val,val1,val2;
878   i_img *new_img;
879
880   mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
881
882
883   if (Axis == XAXIS) {
884     hsize = (int)(0.5 + im->xsize * Value);
885     if (hsize < 1) {
886       hsize = 1;
887       Value = 1.0 / im->xsize;
888     }
889     vsize = im->ysize;
890     
891     jEnd = hsize;
892     iEnd = vsize;
893   } else {
894     hsize = im->xsize;
895     vsize = (int)(0.5 + im->ysize * Value);
896
897     if (vsize < 1) {
898       vsize = 1;
899       Value = 1.0 / im->ysize;
900     }
901
902     jEnd = vsize;
903     iEnd = hsize;
904   }
905   
906   new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
907   
908   /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
909   LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value); 
910   lMax = LanczosWidthFactor << 1;
911   
912   l0 = mymalloc(lMax * sizeof(float));
913   l1 = mymalloc(lMax * sizeof(float));
914   
915   for (j=0; j<jEnd; j++) {
916     OldLocation = ((float) j) / Value;
917     T = (int) (OldLocation);
918     F = OldLocation - (float) T;
919     
920     for (l = 0; l<lMax; l++) {
921       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
922       l1[l]        = Lanczos(((float) (l+1)      - F) / (float) LanczosWidthFactor);
923     }
924     
925     /* Make sure filter is normalized */
926     t = 0.0;
927     for(l=0; l<lMax; l++) {
928       t+=l0[l];
929       t+=l1[l];
930     }
931     t /= (float)LanczosWidthFactor;
932     
933     for(l=0; l<lMax; l++) {
934       l0[l] /= t;
935       l1[l] /= t;
936     }
937
938     if (Axis == XAXIS) {
939       
940       for (i=0; i<iEnd; i++) {
941         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
942         for (l=0; l<lMax; l++) {
943           int mx = T-lMax+l+1;
944           int Mx = T+l+1;
945           mx = (mx < 0) ? 0 : mx;
946           Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
947           
948           i_gpix(im, Mx, i, &val1);
949           i_gpix(im, mx, i, &val2);
950           
951           for (k=0; k<im->channels; k++) {
952             PictureValue[k] += l1[l]        * val1.channel[k];
953             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
954           }
955         }
956         for(k=0;k<im->channels;k++) {
957           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
958           val.channel[k]=minmax(0,255,psave);
959         }
960         i_ppix(new_img, j, i, &val);
961       }
962       
963     } else {
964       
965       for (i=0; i<iEnd; i++) {
966         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
967         for (l=0; l < lMax; l++) {
968           int mx = T-lMax+l+1;
969           int Mx = T+l+1;
970           mx = (mx < 0) ? 0 : mx;
971           Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
972
973           i_gpix(im, i, Mx, &val1);
974           i_gpix(im, i, mx, &val2);
975           for (k=0; k<im->channels; k++) {
976             PictureValue[k] += l1[l]        * val1.channel[k];
977             PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
978           }
979         }
980         for (k=0; k<im->channels; k++) {
981           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
982           val.channel[k] = minmax(0, 255, psave);
983         }
984         i_ppix(new_img, i, j, &val);
985       }
986       
987     }
988   }
989   myfree(l0);
990   myfree(l1);
991
992   mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
993
994   return new_img;
995 }
996
997
998 /* 
999 =item i_scale_nn(im, scx, scy)
1000
1001 Scale by using nearest neighbor 
1002 Both axes scaled at the same time since 
1003 nothing is gained by doing it in two steps 
1004
1005 =cut
1006 */
1007
1008
1009 i_img*
1010 i_scale_nn(i_img *im, float scx, float scy) {
1011
1012   int nxsize,nysize,nx,ny;
1013   i_img *new_img;
1014   i_color val;
1015
1016   mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
1017
1018   nxsize = (int) ((float) im->xsize * scx);
1019   if (nxsize < 1) {
1020     nxsize = 1;
1021     scx = 1 / im->xsize;
1022   }
1023   nysize = (int) ((float) im->ysize * scy);
1024   if (nysize < 1) {
1025     nysize = 1;
1026     scy = 1 / im->ysize;
1027   }
1028     
1029   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1030   
1031   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1032     i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1033     i_ppix(new_img,nx,ny,&val);
1034   }
1035
1036   mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1037
1038   return new_img;
1039 }
1040
1041 /*
1042 =item i_sametype(i_img *im, int xsize, int ysize)
1043
1044 =category Image creation
1045
1046 Returns an image of the same type (sample size, channels, paletted/direct).
1047
1048 For paletted images the palette is copied from the source.
1049
1050 =cut
1051 */
1052
1053 i_img *i_sametype(i_img *src, int xsize, int ysize) {
1054   if (src->type == i_direct_type) {
1055     if (src->bits == 8) {
1056       return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1057     }
1058     else if (src->bits == i_16_bits) {
1059       return i_img_16_new(xsize, ysize, src->channels);
1060     }
1061     else if (src->bits == i_double_bits) {
1062       return i_img_double_new(xsize, ysize, src->channels);
1063     }
1064     else {
1065       i_push_error(0, "Unknown image bits");
1066       return NULL;
1067     }
1068   }
1069   else {
1070     i_color col;
1071     int i;
1072
1073     i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1074     for (i = 0; i < i_colorcount(src); ++i) {
1075       i_getcolors(src, i, &col, 1);
1076       i_addcolors(targ, &col, 1);
1077     }
1078
1079     return targ;
1080   }
1081 }
1082
1083 /*
1084 =item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1085
1086 =category Image creation
1087
1088 Returns an image of the same type (sample size).
1089
1090 For paletted images the equivalent direct type is returned.
1091
1092 =cut
1093 */
1094
1095 i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1096   if (src->bits == 8) {
1097     return i_img_empty_ch(NULL, xsize, ysize, channels);
1098   }
1099   else if (src->bits == i_16_bits) {
1100     return i_img_16_new(xsize, ysize, channels);
1101   }
1102   else if (src->bits == i_double_bits) {
1103     return i_img_double_new(xsize, ysize, channels);
1104   }
1105   else {
1106     i_push_error(0, "Unknown image bits");
1107     return NULL;
1108   }
1109 }
1110
1111 /*
1112 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1113
1114 Spatially transforms I<im> returning a new image.
1115
1116 opx for a length of opxl and opy for a length of opy are arrays of
1117 operators that modify the x and y positions to retreive the pixel data from.
1118
1119 parm and parmlen define extra parameters that the operators may use.
1120
1121 Note that this function is largely superseded by the more flexible
1122 L<transform.c/i_transform2>.
1123
1124 Returns the new image.
1125
1126 The operators for this function are defined in L<stackmach.c>.
1127
1128 =cut
1129 */
1130 i_img*
1131 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1132   double rx,ry;
1133   int nxsize,nysize,nx,ny;
1134   i_img *new_img;
1135   i_color val;
1136   
1137   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));
1138
1139   nxsize = im->xsize;
1140   nysize = im->ysize ;
1141   
1142   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1143   /*   fprintf(stderr,"parm[2]=%f\n",parm[2]);   */
1144   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1145     /*     parm[parmlen-2]=(double)nx;
1146            parm[parmlen-1]=(double)ny; */
1147
1148     parm[0]=(double)nx;
1149     parm[1]=(double)ny;
1150
1151     /*     fprintf(stderr,"(%d,%d) ->",nx,ny);  */
1152     rx=i_op_run(opx,opxl,parm,parmlen);
1153     ry=i_op_run(opy,opyl,parm,parmlen);
1154     /*    fprintf(stderr,"(%f,%f)\n",rx,ry); */
1155     i_gpix(im,rx,ry,&val);
1156     i_ppix(new_img,nx,ny,&val);
1157   }
1158
1159   mm_log((1,"(0x%x) <- i_transform\n",new_img));
1160   return new_img;
1161 }
1162
1163 /*
1164 =item i_img_diff(im1, im2)
1165
1166 Calculates the sum of the squares of the differences between
1167 correspoding channels in two images.
1168
1169 If the images are not the same size then only the common area is 
1170 compared, hence even if images are different sizes this function 
1171 can return zero.
1172
1173 =cut
1174 */
1175 float
1176 i_img_diff(i_img *im1,i_img *im2) {
1177   int x,y,ch,xb,yb,chb;
1178   float tdiff;
1179   i_color val1,val2;
1180
1181   mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1182
1183   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1184   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1185   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1186
1187   mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1188
1189   tdiff=0;
1190   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1191     i_gpix(im1,x,y,&val1);
1192     i_gpix(im2,x,y,&val2);
1193
1194     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1195   }
1196   mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1197   return tdiff;
1198 }
1199
1200 /* just a tiny demo of haar wavelets */
1201
1202 i_img*
1203 i_haar(i_img *im) {
1204   int mx,my;
1205   int fx,fy;
1206   int x,y;
1207   int ch,c;
1208   i_img *new_img,*new_img2;
1209   i_color val1,val2,dval1,dval2;
1210   
1211   mx=im->xsize;
1212   my=im->ysize;
1213   fx=(mx+1)/2;
1214   fy=(my+1)/2;
1215
1216
1217   /* horizontal pass */
1218   
1219   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1220   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1221
1222   c=0; 
1223   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1224     i_gpix(im,x*2,y,&val1);
1225     i_gpix(im,x*2+1,y,&val2);
1226     for(ch=0;ch<im->channels;ch++) {
1227       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1228       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1229     }
1230     i_ppix(new_img,x,y,&dval1);
1231     i_ppix(new_img,x+fx,y,&dval2);
1232   }
1233
1234   for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1235     i_gpix(new_img,x,y*2,&val1);
1236     i_gpix(new_img,x,y*2+1,&val2);
1237     for(ch=0;ch<im->channels;ch++) {
1238       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1239       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1240     }
1241     i_ppix(new_img2,x,y,&dval1);
1242     i_ppix(new_img2,x,y+fy,&dval2);
1243   }
1244
1245   i_img_destroy(new_img);
1246   return new_img2;
1247 }
1248
1249 /* 
1250 =item i_count_colors(im, maxc)
1251
1252 returns number of colors or -1 
1253 to indicate that it was more than max colors
1254
1255 =cut
1256 */
1257 /* This function has been changed and is now faster. It's using
1258  * i_gsamp instead of i_gpix */
1259 int
1260 i_count_colors(i_img *im,int maxc) {
1261   struct octt *ct;
1262   int x,y;
1263   int colorcnt;
1264   int channels[3];
1265   int *samp_chans;
1266   i_sample_t * samp;
1267   int xsize = im->xsize; 
1268   int ysize = im->ysize;
1269   int samp_cnt = 3 * xsize;
1270
1271   if (im->channels >= 3) {
1272     samp_chans = NULL;
1273   }
1274   else {
1275     channels[0] = channels[1] = channels[2] = 0;
1276     samp_chans = channels;
1277   }
1278
1279   ct = octt_new();
1280
1281   samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1282
1283   colorcnt = 0;
1284   for(y = 0; y < ysize; ) {
1285       i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1286       for(x = 0; x < samp_cnt; ) {
1287           colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1288           x += 3;
1289           if (colorcnt > maxc) { 
1290               octt_delete(ct); 
1291               return -1; 
1292           }
1293       }
1294   }
1295   myfree(samp);
1296   octt_delete(ct);
1297   return colorcnt;
1298 }
1299
1300 /* sorts the array ra[0..n-1] into increasing order using heapsort algorithm 
1301  * (adapted from the Numerical Recipes)
1302  */
1303 /* Needed by get_anonymous_color_histo */
1304 static void
1305 hpsort(unsigned int n, unsigned *ra) {
1306     unsigned int i,
1307                  ir,
1308                  j,
1309                  l, 
1310                  rra;
1311
1312     if (n < 2) return;
1313     l = n >> 1;
1314     ir = n - 1;
1315     for(;;) {
1316         if (l > 0) {
1317             rra = ra[--l];
1318         }
1319         else {
1320             rra = ra[ir];
1321             ra[ir] = ra[0];
1322             if (--ir == 0) {
1323                 ra[0] = rra;
1324                 break;
1325             }
1326         }
1327         i = l;
1328         j = 2 * l + 1;
1329         while (j <= ir) {
1330             if (j < ir && ra[j] < ra[j+1]) j++;
1331             if (rra < ra[j]) {
1332                 ra[i] = ra[j];
1333                 i = j;
1334                 j++; j <<= 1; j--;
1335             }
1336             else break;
1337         }
1338         ra[i] = rra;
1339     }
1340 }
1341
1342 /* This function constructs an ordered list which represents how much the
1343  * different colors are used. So for instance (100, 100, 500) means that one
1344  * color is used for 500 pixels, another for 100 pixels and another for 100
1345  * pixels. It's tuned for performance. You might not like the way I've hardcoded
1346  * the maxc ;-) and you might want to change the name... */
1347 /* Uses octt_histo */
1348 int
1349 i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1350   struct octt *ct;
1351   int x,y;
1352   int colorcnt;
1353   unsigned int *col_usage_it;
1354   i_sample_t * samp;
1355   int channels[3];
1356   int *samp_chans;
1357   
1358   int xsize = im->xsize; 
1359   int ysize = im->ysize;
1360   int samp_cnt = 3 * xsize;
1361   ct = octt_new();
1362   
1363   samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1364   
1365   if (im->channels >= 3) {
1366     samp_chans = NULL;
1367   }
1368   else {
1369     channels[0] = channels[1] = channels[2] = 0;
1370     samp_chans = channels;
1371   }
1372
1373   colorcnt = 0;
1374   for(y = 0; y < ysize; ) {
1375     i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1376     for(x = 0; x < samp_cnt; ) {
1377       colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1378       x += 3;
1379       if (colorcnt > maxc) { 
1380         octt_delete(ct); 
1381         return -1; 
1382       }
1383     }
1384   }
1385   myfree(samp);
1386   /* Now that we know the number of colours... */
1387   col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1388   octt_histo(ct, &col_usage_it);
1389   hpsort(colorcnt, *col_usage);
1390   octt_delete(ct);
1391   return colorcnt;
1392 }
1393
1394 /*
1395 =back
1396
1397 =head2 8-bit per sample image internal functions
1398
1399 These are the functions installed in an 8-bit per sample image.
1400
1401 =over
1402
1403 =item i_ppix_d(im, x, y, col)
1404
1405 Internal function.
1406
1407 This is the function kept in the i_f_ppix member of an i_img object.
1408 It does a normal store of a pixel into the image with range checking.
1409
1410 Returns 0 if the pixel could be set, -1 otherwise.
1411
1412 =cut
1413 */
1414 static
1415 int
1416 i_ppix_d(i_img *im, int x, int y, const i_color *val) {
1417   int ch;
1418   
1419   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1420     for(ch=0;ch<im->channels;ch++)
1421       if (im->ch_mask&(1<<ch)) 
1422         im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1423     return 0;
1424   }
1425   return -1; /* error was clipped */
1426 }
1427
1428 /*
1429 =item i_gpix_d(im, x, y, &col)
1430
1431 Internal function.
1432
1433 This is the function kept in the i_f_gpix member of an i_img object.
1434 It does normal retrieval of a pixel from the image with range checking.
1435
1436 Returns 0 if the pixel could be set, -1 otherwise.
1437
1438 =cut
1439 */
1440 static
1441 int 
1442 i_gpix_d(i_img *im, int x, int y, i_color *val) {
1443   int ch;
1444   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1445     for(ch=0;ch<im->channels;ch++) 
1446       val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1447     return 0;
1448   }
1449   for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
1450   return -1; /* error was cliped */
1451 }
1452
1453 /*
1454 =item i_glin_d(im, l, r, y, vals)
1455
1456 Reads a line of data from the image, storing the pixels at vals.
1457
1458 The line runs from (l,y) inclusive to (r,y) non-inclusive
1459
1460 vals should point at space for (r-l) pixels.
1461
1462 l should never be less than zero (to avoid confusion about where to
1463 put the pixels in vals).
1464
1465 Returns the number of pixels copied (eg. if r, l or y is out of range)
1466
1467 =cut
1468 */
1469 static
1470 int
1471 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1472   int ch, count, i;
1473   unsigned char *data;
1474   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1475     if (r > im->xsize)
1476       r = im->xsize;
1477     data = im->idata + (l+y*im->xsize) * im->channels;
1478     count = r - l;
1479     for (i = 0; i < count; ++i) {
1480       for (ch = 0; ch < im->channels; ++ch)
1481         vals[i].channel[ch] = *data++;
1482     }
1483     return count;
1484   }
1485   else {
1486     return 0;
1487   }
1488 }
1489
1490 /*
1491 =item i_plin_d(im, l, r, y, vals)
1492
1493 Writes a line of data into the image, using the pixels at vals.
1494
1495 The line runs from (l,y) inclusive to (r,y) non-inclusive
1496
1497 vals should point at (r-l) pixels.
1498
1499 l should never be less than zero (to avoid confusion about where to
1500 get the pixels in vals).
1501
1502 Returns the number of pixels copied (eg. if r, l or y is out of range)
1503
1504 =cut
1505 */
1506 static
1507 int
1508 i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
1509   int ch, count, i;
1510   unsigned char *data;
1511   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1512     if (r > im->xsize)
1513       r = im->xsize;
1514     data = im->idata + (l+y*im->xsize) * im->channels;
1515     count = r - l;
1516     for (i = 0; i < count; ++i) {
1517       for (ch = 0; ch < im->channels; ++ch) {
1518         if (im->ch_mask & (1 << ch)) 
1519           *data = vals[i].channel[ch];
1520         ++data;
1521       }
1522     }
1523     return count;
1524   }
1525   else {
1526     return 0;
1527   }
1528 }
1529
1530 /*
1531 =item i_ppixf_d(im, x, y, val)
1532
1533 =cut
1534 */
1535 static
1536 int
1537 i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
1538   int ch;
1539   
1540   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1541     for(ch=0;ch<im->channels;ch++)
1542       if (im->ch_mask&(1<<ch)) {
1543         im->idata[(x+y*im->xsize)*im->channels+ch] = 
1544           SampleFTo8(val->channel[ch]);
1545       }
1546     return 0;
1547   }
1548   return -1; /* error was clipped */
1549 }
1550
1551 /*
1552 =item i_gpixf_d(im, x, y, val)
1553
1554 =cut
1555 */
1556 static
1557 int
1558 i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1559   int ch;
1560   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1561     for(ch=0;ch<im->channels;ch++) {
1562       val->channel[ch] = 
1563         Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1564     }
1565     return 0;
1566   }
1567   return -1; /* error was cliped */
1568 }
1569
1570 /*
1571 =item i_glinf_d(im, l, r, y, vals)
1572
1573 Reads a line of data from the image, storing the pixels at vals.
1574
1575 The line runs from (l,y) inclusive to (r,y) non-inclusive
1576
1577 vals should point at space for (r-l) pixels.
1578
1579 l should never be less than zero (to avoid confusion about where to
1580 put the pixels in vals).
1581
1582 Returns the number of pixels copied (eg. if r, l or y is out of range)
1583
1584 =cut
1585 */
1586 static
1587 int
1588 i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1589   int ch, count, i;
1590   unsigned char *data;
1591   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1592     if (r > im->xsize)
1593       r = im->xsize;
1594     data = im->idata + (l+y*im->xsize) * im->channels;
1595     count = r - l;
1596     for (i = 0; i < count; ++i) {
1597       for (ch = 0; ch < im->channels; ++ch)
1598         vals[i].channel[ch] = Sample8ToF(*data++);
1599     }
1600     return count;
1601   }
1602   else {
1603     return 0;
1604   }
1605 }
1606
1607 /*
1608 =item i_plinf_d(im, l, r, y, vals)
1609
1610 Writes a line of data into the image, using the pixels at vals.
1611
1612 The line runs from (l,y) inclusive to (r,y) non-inclusive
1613
1614 vals should point at (r-l) pixels.
1615
1616 l should never be less than zero (to avoid confusion about where to
1617 get the pixels in vals).
1618
1619 Returns the number of pixels copied (eg. if r, l or y is out of range)
1620
1621 =cut
1622 */
1623 static
1624 int
1625 i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
1626   int ch, count, i;
1627   unsigned char *data;
1628   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1629     if (r > im->xsize)
1630       r = im->xsize;
1631     data = im->idata + (l+y*im->xsize) * im->channels;
1632     count = r - l;
1633     for (i = 0; i < count; ++i) {
1634       for (ch = 0; ch < im->channels; ++ch) {
1635         if (im->ch_mask & (1 << ch)) 
1636           *data = SampleFTo8(vals[i].channel[ch]);
1637         ++data;
1638       }
1639     }
1640     return count;
1641   }
1642   else {
1643     return 0;
1644   }
1645 }
1646
1647 /*
1648 =item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1649
1650 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1651 for the channels specified by chans, an array of int with chan_count
1652 elements.
1653
1654 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1655
1656 =cut
1657 */
1658 static
1659 int
1660 i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
1661               const int *chans, int chan_count) {
1662   int ch, count, i, w;
1663   unsigned char *data;
1664
1665   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1666     if (r > im->xsize)
1667       r = im->xsize;
1668     data = im->idata + (l+y*im->xsize) * im->channels;
1669     w = r - l;
1670     count = 0;
1671
1672     if (chans) {
1673       /* make sure we have good channel numbers */
1674       for (ch = 0; ch < chan_count; ++ch) {
1675         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1676           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1677           return 0;
1678         }
1679       }
1680       for (i = 0; i < w; ++i) {
1681         for (ch = 0; ch < chan_count; ++ch) {
1682           *samps++ = data[chans[ch]];
1683           ++count;
1684         }
1685         data += im->channels;
1686       }
1687     }
1688     else {
1689       for (i = 0; i < w; ++i) {
1690         for (ch = 0; ch < chan_count; ++ch) {
1691           *samps++ = data[ch];
1692           ++count;
1693         }
1694         data += im->channels;
1695       }
1696     }
1697
1698     return count;
1699   }
1700   else {
1701     return 0;
1702   }
1703 }
1704
1705 /*
1706 =item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1707
1708 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1709 for the channels specified by chan_mask, where bit 0 is the first
1710 channel.
1711
1712 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1713
1714 =cut
1715 */
1716 static
1717 int
1718 i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
1719            const int *chans, int chan_count) {
1720   int ch, count, i, w;
1721   unsigned char *data;
1722   for (ch = 0; ch < chan_count; ++ch) {
1723     if (chans[ch] < 0 || chans[ch] >= im->channels) {
1724       i_push_errorf(0, "No channel %d in this image", chans[ch]);
1725     }
1726   }
1727   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1728     if (r > im->xsize)
1729       r = im->xsize;
1730     data = im->idata + (l+y*im->xsize) * im->channels;
1731     w = r - l;
1732     count = 0;
1733
1734     if (chans) {
1735       /* make sure we have good channel numbers */
1736       for (ch = 0; ch < chan_count; ++ch) {
1737         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1738           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1739           return 0;
1740         }
1741       }
1742       for (i = 0; i < w; ++i) {
1743         for (ch = 0; ch < chan_count; ++ch) {
1744           *samps++ = Sample8ToF(data[chans[ch]]);
1745           ++count;
1746         }
1747         data += im->channels;
1748       }
1749     }
1750     else {
1751       for (i = 0; i < w; ++i) {
1752         for (ch = 0; ch < chan_count; ++ch) {
1753           *samps++ = Sample8ToF(data[ch]);
1754           ++count;
1755         }
1756         data += im->channels;
1757       }
1758     }
1759     return count;
1760   }
1761   else {
1762     return 0;
1763   }
1764 }
1765
1766 /*
1767 =back
1768
1769 =head2 Image method wrappers
1770
1771 These functions provide i_fsample_t functions in terms of their
1772 i_sample_t versions.
1773
1774 =over
1775
1776 =item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1777
1778 =cut
1779 */
1780
1781 int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
1782   i_color temp;
1783   int ch;
1784
1785   for (ch = 0; ch < im->channels; ++ch)
1786     temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1787   
1788   return i_ppix(im, x, y, &temp);
1789 }
1790
1791 /*
1792 =item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1793
1794 =cut
1795 */
1796 int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1797   i_color temp;
1798   int ch;
1799
1800   if (i_gpix(im, x, y, &temp)) {
1801     for (ch = 0; ch < im->channels; ++ch)
1802       pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1803     return 0;
1804   }
1805   else 
1806     return -1;
1807 }
1808
1809 /*
1810 =item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1811
1812 =cut
1813 */
1814 int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
1815   i_color *work;
1816
1817   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1818     if (r > im->xsize)
1819       r = im->xsize;
1820     if (r > l) {
1821       int ret;
1822       int i, ch;
1823       work = mymalloc(sizeof(i_color) * (r-l));
1824       for (i = 0; i < r-l; ++i) {
1825         for (ch = 0; ch < im->channels; ++ch) 
1826           work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1827       }
1828       ret = i_plin(im, l, r, y, work);
1829       myfree(work);
1830
1831       return ret;
1832     }
1833     else {
1834       return 0;
1835     }
1836   }
1837   else {
1838     return 0;
1839   }
1840 }
1841
1842 /*
1843 =item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1844
1845 =cut
1846 */
1847 int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1848   i_color *work;
1849
1850   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1851     if (r > im->xsize)
1852       r = im->xsize;
1853     if (r > l) {
1854       int ret;
1855       int i, ch;
1856       work = mymalloc(sizeof(i_color) * (r-l));
1857       ret = i_plin(im, l, r, y, work);
1858       for (i = 0; i < r-l; ++i) {
1859         for (ch = 0; ch < im->channels; ++ch) 
1860           pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1861       }
1862       myfree(work);
1863
1864       return ret;
1865     }
1866     else {
1867       return 0;
1868     }
1869   }
1870   else {
1871     return 0;
1872   }
1873 }
1874
1875 /*
1876 =item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1877
1878 =cut
1879 */
1880 int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, 
1881                 int const *chans, int chan_count) {
1882   i_sample_t *work;
1883
1884   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1885     if (r > im->xsize)
1886       r = im->xsize;
1887     if (r > l) {
1888       int ret;
1889       int i;
1890       work = mymalloc(sizeof(i_sample_t) * (r-l));
1891       ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1892       for (i = 0; i < ret; ++i) {
1893           samp[i] = Sample8ToF(work[i]);
1894       }
1895       myfree(work);
1896
1897       return ret;
1898     }
1899     else {
1900       return 0;
1901     }
1902   }
1903   else {
1904     return 0;
1905   }
1906 }
1907
1908 /*
1909 =back
1910
1911 =head2 Palette wrapper functions
1912
1913 Used for virtual images, these forward palette calls to a wrapped image, 
1914 assuming the wrapped image is the first pointer in the structure that 
1915 im->ext_data points at.
1916
1917 =over
1918
1919 =item i_addcolors_forward(i_img *im, const i_color *colors, int count)
1920
1921 =cut
1922 */
1923 int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
1924   return i_addcolors(*(i_img **)im->ext_data, colors, count);
1925 }
1926
1927 /*
1928 =item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1929
1930 =cut
1931 */
1932 int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1933   return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1934 }
1935
1936 /*
1937 =item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
1938
1939 =cut
1940 */
1941 int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
1942   return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1943 }
1944
1945 /*
1946 =item i_colorcount_forward(i_img *im)
1947
1948 =cut
1949 */
1950 int i_colorcount_forward(i_img *im) {
1951   return i_colorcount(*(i_img **)im->ext_data);
1952 }
1953
1954 /*
1955 =item i_maxcolors_forward(i_img *im)
1956
1957 =cut
1958 */
1959 int i_maxcolors_forward(i_img *im) {
1960   return i_maxcolors(*(i_img **)im->ext_data);
1961 }
1962
1963 /*
1964 =item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
1965
1966 =cut
1967 */
1968 int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
1969   return i_findcolor(*(i_img **)im->ext_data, color, entry);
1970 }
1971
1972 /*
1973 =back
1974
1975 =head2 Stream reading and writing wrapper functions
1976
1977 =over
1978
1979 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1980
1981 Performs general read buffering for file readers that permit reading
1982 to be done through a callback.
1983
1984 The final callback gets two parameters, a I<need> value, and a I<want>
1985 value, where I<need> is the amount of data that the file library needs
1986 to read, and I<want> is the amount of space available in the buffer
1987 maintained by these functions.
1988
1989 This means if you need to read from a stream that you don't know the
1990 length of, you can return I<need> bytes, taking the performance hit of
1991 possibly expensive callbacks (eg. back to perl code), or if you are
1992 reading from a stream where it doesn't matter if some data is lost, or
1993 if the total length of the stream is known, you can return I<want>
1994 bytes.
1995
1996 =cut 
1997 */
1998
1999 int
2000 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
2001   int total;
2002
2003   if (length < gci->length - gci->cpos) {
2004     /* simplest case */
2005     memcpy(buf, gci->buffer+gci->cpos, length);
2006     gci->cpos += length;
2007     return length;
2008   }
2009   
2010   total = 0;
2011   memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
2012   total  += gci->length - gci->cpos;
2013   length -= gci->length - gci->cpos;
2014   buf    += gci->length - gci->cpos;
2015   if (length < (int)sizeof(gci->buffer)) {
2016     int did_read;
2017     int copy_size;
2018     while (length
2019            && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
2020                                     sizeof(gci->buffer))) > 0) {
2021       gci->cpos = 0;
2022       gci->length = did_read;
2023
2024       copy_size = i_min(length, gci->length);
2025       memcpy(buf, gci->buffer, copy_size);
2026       gci->cpos += copy_size;
2027       buf += copy_size;
2028       total += copy_size;
2029       length -= copy_size;
2030     }
2031   }
2032   else {
2033     /* just read the rest - too big for our buffer*/
2034     int did_read;
2035     while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2036       length -= did_read;
2037       total += did_read;
2038       buf += did_read;
2039     }
2040   }
2041   return total;
2042 }
2043
2044 /*
2045 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2046
2047 For use by callback file readers to initialize the reader buffer.
2048
2049 Allocates, initializes and returns the reader buffer.
2050
2051 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2052
2053 =cut
2054 */
2055 i_gen_read_data *
2056 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2057   i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2058   self->cb = cb;
2059   self->userdata = userdata;
2060   self->length = 0;
2061   self->cpos = 0;
2062
2063   return self;
2064 }
2065
2066 /*
2067 =item i_free_gen_read_data(i_gen_read_data *)
2068
2069 Cleans up.
2070
2071 =cut
2072 */
2073 void i_free_gen_read_data(i_gen_read_data *self) {
2074   myfree(self);
2075 }
2076
2077 /*
2078 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2079
2080 Performs write buffering for a callback based file writer.
2081
2082 Failures are considered fatal, if a write fails then data will be
2083 dropped.
2084
2085 =cut
2086 */
2087 int 
2088 i_gen_writer(
2089 i_gen_write_data *self, 
2090 char const *data, 
2091 int size)
2092 {
2093   if (self->filledto && self->filledto+size > self->maxlength) {
2094     if (self->cb(self->userdata, self->buffer, self->filledto)) {
2095       self->filledto = 0;
2096     }
2097     else {
2098       self->filledto = 0;
2099       return 0;
2100     }
2101   }
2102   if (self->filledto+size <= self->maxlength) {
2103     /* just save it */
2104     memcpy(self->buffer+self->filledto, data, size);
2105     self->filledto += size;
2106     return 1;
2107   }
2108   /* doesn't fit - hand it off */
2109   return self->cb(self->userdata, data, size);
2110 }
2111
2112 /*
2113 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2114
2115 Allocates and initializes the data structure used by i_gen_writer.
2116
2117 This should be released with L<image.c/i_free_gen_write_data>
2118
2119 =cut
2120 */
2121 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
2122                                        char *userdata, int max_length)
2123 {
2124   i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2125   self->cb = cb;
2126   self->userdata = userdata;
2127   self->maxlength = i_min(max_length, sizeof(self->buffer));
2128   if (self->maxlength < 0)
2129     self->maxlength = sizeof(self->buffer);
2130   self->filledto = 0;
2131
2132   return self;
2133 }
2134
2135 /*
2136 =item i_free_gen_write_data(i_gen_write_data *info, int flush)
2137
2138 Cleans up the write buffer.
2139
2140 Will flush any left-over data if I<flush> is non-zero.
2141
2142 Returns non-zero if flush is zero or if info->cb() returns non-zero.
2143
2144 Return zero only if flush is non-zero and info->cb() returns zero.
2145 ie. if it fails.
2146
2147 =cut
2148 */
2149
2150 int i_free_gen_write_data(i_gen_write_data *info, int flush)
2151 {
2152   int result = !flush || 
2153     info->filledto == 0 ||
2154     info->cb(info->userdata, info->buffer, info->filledto);
2155   myfree(info);
2156
2157   return result;
2158 }
2159
2160 struct magic_entry {
2161   unsigned char *magic;
2162   size_t magic_size;
2163   char *name;
2164   unsigned char *mask;  
2165 };
2166
2167 static int
2168 test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
2169   if (length < magic->magic_size)
2170     return 0;
2171   if (magic->mask) {
2172     int i;
2173     unsigned char *bufp = buffer, 
2174       *maskp = magic->mask, 
2175       *magicp = magic->magic;
2176
2177     for (i = 0; i < magic->magic_size; ++i) {
2178       int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
2179       ++maskp;
2180
2181       if ((*bufp++ & mask) != (*magicp++ & mask)) 
2182         return 0;
2183     }
2184
2185     return 1;
2186   }
2187   else {
2188     return !memcmp(magic->magic, buffer, magic->magic_size);
2189   }
2190 }
2191
2192 /*
2193 =item i_test_format_probe(io_glue *data, int length)
2194
2195 Check the beginning of the supplied file for a 'magic number'
2196
2197 =cut
2198 */
2199
2200 #define FORMAT_ENTRY(magic, type) \
2201   { (unsigned char *)(magic ""), sizeof(magic)-1, type }
2202 #define FORMAT_ENTRY2(magic, type, mask) \
2203   { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
2204
2205 const char *
2206 i_test_format_probe(io_glue *data, int length) {
2207   static const struct magic_entry formats[] = {
2208     FORMAT_ENTRY("\xFF\xD8", "jpeg"),
2209     FORMAT_ENTRY("GIF87a", "gif"),
2210     FORMAT_ENTRY("GIF89a", "gif"),
2211     FORMAT_ENTRY("MM\0*", "tiff"),
2212     FORMAT_ENTRY("II*\0", "tiff"),
2213     FORMAT_ENTRY("BM", "bmp"),
2214     FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
2215     FORMAT_ENTRY("P1", "pnm"),
2216     FORMAT_ENTRY("P2", "pnm"),
2217     FORMAT_ENTRY("P3", "pnm"),
2218     FORMAT_ENTRY("P4", "pnm"),
2219     FORMAT_ENTRY("P5", "pnm"),
2220     FORMAT_ENTRY("P6", "pnm"),
2221     FORMAT_ENTRY("/* XPM", "xpm"),
2222     FORMAT_ENTRY("\x8aMNG", "mng"),
2223     FORMAT_ENTRY("\x8aJNG", "jng"),
2224     /* SGI RGB - with various possible parameters to avoid false positives
2225        on similar files 
2226        values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
2227     */
2228     FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
2229     FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
2230     FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
2231     FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
2232     
2233     FORMAT_ENTRY2("FORM    ILBM", "ilbm", "xxxx    xxxx"),
2234
2235     /* different versions of PCX format 
2236        http://www.fileformat.info/format/pcx/
2237     */
2238     FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
2239     FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
2240     FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
2241     FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
2242     FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
2243
2244     /* FITS - http://fits.gsfc.nasa.gov/ */
2245     FORMAT_ENTRY("SIMPLE  =", "fits"),
2246
2247     /* PSD - Photoshop */
2248     FORMAT_ENTRY("8BPS\x00\x01", "psd"),
2249     
2250     /* EPS - Encapsulated Postscript */
2251     /* only reading 18 chars, so we don't include the F in EPSF */
2252     FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
2253
2254     /* Utah RLE */
2255     FORMAT_ENTRY("\x52\xCC", "utah"),
2256
2257     /* GZIP compressed, only matching deflate for now */
2258     FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
2259
2260     /* bzip2 compressed */
2261     FORMAT_ENTRY("BZh", "bzip2"),
2262   };
2263   static const struct magic_entry more_formats[] = {
2264     /* these were originally both listed as ico, but cur files can
2265        include hotspot information */
2266     FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
2267     FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
2268     FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07", 
2269                   "xwd", "    xxxx"), /* X Windows Dump */
2270   };
2271
2272   unsigned int i;
2273   unsigned char head[18];
2274   ssize_t rc;
2275
2276   io_glue_commit_types(data);
2277   rc = data->readcb(data, head, 18);
2278   if (rc == -1) return NULL;
2279   data->seekcb(data, -rc, SEEK_CUR);
2280
2281   for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) { 
2282     struct magic_entry const *entry = formats + i;
2283
2284     if (test_magic(head, rc, entry)) 
2285       return entry->name;
2286   }
2287
2288   if ((rc == 18) &&
2289       tga_header_verify(head))
2290     return "tga";
2291
2292   for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) { 
2293     struct magic_entry const *entry = more_formats + i;
2294
2295     if (test_magic(head, rc, entry)) 
2296       return entry->name;
2297   }
2298
2299   return NULL;
2300 }
2301
2302 /*
2303 =item i_img_is_monochrome(img, &zero_is_white)
2304
2305 Tests an image to check it meets our monochrome tests.
2306
2307 The idea is that a file writer can use this to test where it should
2308 write the image in whatever bi-level format it uses, eg. pbm for pnm.
2309
2310 For performance of encoders we require monochrome images:
2311
2312 =over
2313
2314 =item *
2315
2316 be paletted
2317
2318 =item *
2319
2320 have a palette of two colors, containing only (0,0,0) and
2321 (255,255,255) in either order.
2322
2323 =back
2324
2325 zero_is_white is set to non-zero iff the first palette entry is white.
2326
2327 =cut
2328 */
2329
2330 int
2331 i_img_is_monochrome(i_img *im, int *zero_is_white) {
2332   if (im->type == i_palette_type
2333       && i_colorcount(im) == 2) {
2334     i_color colors[2];
2335     i_getcolors(im, 0, colors, 2);
2336     if (im->channels == 3) {
2337       if (colors[0].rgb.r == 255 && 
2338           colors[0].rgb.g == 255 &&
2339           colors[0].rgb.b == 255 &&
2340           colors[1].rgb.r == 0 &&
2341           colors[1].rgb.g == 0 &&
2342           colors[1].rgb.b == 0) {
2343         *zero_is_white = 0;
2344         return 1;
2345       }
2346       else if (colors[0].rgb.r == 0 && 
2347                colors[0].rgb.g == 0 &&
2348                colors[0].rgb.b == 0 &&
2349                colors[1].rgb.r == 255 &&
2350                colors[1].rgb.g == 255 &&
2351                colors[1].rgb.b == 255) {
2352         *zero_is_white = 1;
2353         return 1;
2354       }
2355     }
2356     else if (im->channels == 1) {
2357       if (colors[0].channel[0] == 255 &&
2358           colors[1].channel[1] == 0) {
2359         *zero_is_white = 0;
2360         return 1;
2361       }
2362       else if (colors[0].channel[0] == 0 &&
2363                colors[0].channel[0] == 255) {
2364         *zero_is_white = 1;
2365         return 1;         
2366       }
2367     }
2368   }
2369
2370   *zero_is_white = 0;
2371   return 0;
2372 }
2373
2374 /*
2375 =back
2376
2377 =head1 AUTHOR
2378
2379 Arnar M. Hrafnkelsson <addi@umich.edu>
2380
2381 Tony Cook <tony@develop-help.com>
2382
2383 =head1 SEE ALSO
2384
2385 L<Imager>, L<gif.c>
2386
2387 =cut
2388 */