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