]> git.imager.perl.org - imager.git/blob - image.c
flood fill fix added to changelog.
[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 =item i_scaleaxis(im, value, axis)
872
873 Returns a new image object which is I<im> scaled by I<value> along
874 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
875
876 =cut
877 */
878
879 i_img*
880 i_scaleaxis(i_img *im, float Value, int Axis) {
881   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
882   int LanczosWidthFactor;
883   float *l0, *l1, OldLocation;
884   int T; 
885   float t;
886   float F, PictureValue[MAXCHANNELS];
887   short psave;
888   i_color val,val1,val2;
889   i_img *new_img;
890
891   mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
892
893   if (Axis == XAXIS) {
894     hsize = (int)(0.5 + im->xsize * Value);
895     vsize = im->ysize;
896     
897     jEnd = hsize;
898     iEnd = vsize;
899   } else {
900     hsize = im->xsize;
901     vsize = (int)(0.5 + im->ysize * Value);
902
903     jEnd = vsize;
904     iEnd = hsize;
905   }
906   
907   new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
908   
909   /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
910   LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value); 
911   lMax = LanczosWidthFactor << 1;
912   
913   l0 = mymalloc(lMax * sizeof(float));
914   l1 = mymalloc(lMax * sizeof(float));
915   
916   for (j=0; j<jEnd; j++) {
917     OldLocation = ((float) j) / Value;
918     T = (int) (OldLocation);
919     F = OldLocation - (float) T;
920     
921     for (l = 0; l<lMax; l++) {
922       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
923       l1[l]        = Lanczos(((float) (l+1)      - F) / (float) LanczosWidthFactor);
924     }
925     
926     /* Make sure filter is normalized */
927     t = 0.0;
928     for(l=0; l<lMax; l++) {
929       t+=l0[l];
930       t+=l1[l];
931     }
932     t /= (float)LanczosWidthFactor;
933     
934     for(l=0; l<lMax; l++) {
935       l0[l] /= t;
936       l1[l] /= t;
937     }
938
939     if (Axis == XAXIS) {
940       
941       for (i=0; i<iEnd; i++) {
942         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
943         for (l=0; l<lMax; l++) {
944           int mx = T-lMax+l+1;
945           int Mx = T+l+1;
946           mx = (mx < 0) ? 0 : mx;
947           Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
948           
949           i_gpix(im, Mx, i, &val1);
950           i_gpix(im, mx, i, &val2);
951           
952           for (k=0; k<im->channels; k++) {
953             PictureValue[k] += l1[l]        * val1.channel[k];
954             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
955           }
956         }
957         for(k=0;k<im->channels;k++) {
958           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
959           val.channel[k]=minmax(0,255,psave);
960         }
961         i_ppix(new_img, j, i, &val);
962       }
963       
964     } else {
965       
966       for (i=0; i<iEnd; i++) {
967         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
968         for (l=0; l < lMax; l++) {
969           int mx = T-lMax+l+1;
970           int Mx = T+l+1;
971           mx = (mx < 0) ? 0 : mx;
972           Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
973
974           i_gpix(im, i, Mx, &val1);
975           i_gpix(im, i, mx, &val2);
976           for (k=0; k<im->channels; k++) {
977             PictureValue[k] += l1[l]        * val1.channel[k];
978             PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
979           }
980         }
981         for (k=0; k<im->channels; k++) {
982           psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
983           val.channel[k] = minmax(0, 255, psave);
984         }
985         i_ppix(new_img, i, j, &val);
986       }
987       
988     }
989   }
990   myfree(l0);
991   myfree(l1);
992
993   mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
994
995   return new_img;
996 }
997
998
999 /* 
1000 =item i_scale_nn(im, scx, scy)
1001
1002 Scale by using nearest neighbor 
1003 Both axes scaled at the same time since 
1004 nothing is gained by doing it in two steps 
1005
1006 =cut
1007 */
1008
1009
1010 i_img*
1011 i_scale_nn(i_img *im, float scx, float scy) {
1012
1013   int nxsize,nysize,nx,ny;
1014   i_img *new_img;
1015   i_color val;
1016
1017   mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
1018
1019   nxsize = (int) ((float) im->xsize * scx);
1020   nysize = (int) ((float) im->ysize * scy);
1021     
1022   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1023   
1024   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1025     i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1026     i_ppix(new_img,nx,ny,&val);
1027   }
1028
1029   mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1030
1031   return new_img;
1032 }
1033
1034 /*
1035 =item i_sametype(i_img *im, int xsize, int ysize)
1036
1037 Returns an image of the same type (sample size, channels, paletted/direct).
1038
1039 For paletted images the palette is copied from the source.
1040
1041 =cut
1042 */
1043
1044 i_img *i_sametype(i_img *src, int xsize, int ysize) {
1045   if (src->type == i_direct_type) {
1046     if (src->bits == 8) {
1047       return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1048     }
1049     else if (src->bits == i_16_bits) {
1050       return i_img_16_new(xsize, ysize, src->channels);
1051     }
1052     else if (src->bits == i_double_bits) {
1053       return i_img_double_new(xsize, ysize, src->channels);
1054     }
1055     else {
1056       i_push_error(0, "Unknown image bits");
1057       return NULL;
1058     }
1059   }
1060   else {
1061     i_color col;
1062     int i;
1063
1064     i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1065     for (i = 0; i < i_colorcount(src); ++i) {
1066       i_getcolors(src, i, &col, 1);
1067       i_addcolors(targ, &col, 1);
1068     }
1069
1070     return targ;
1071   }
1072 }
1073
1074 /*
1075 =item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1076
1077 Returns an image of the same type (sample size).
1078
1079 For paletted images the equivalent direct type is returned.
1080
1081 =cut
1082 */
1083
1084 i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1085   if (src->bits == 8) {
1086     return i_img_empty_ch(NULL, xsize, ysize, channels);
1087   }
1088   else if (src->bits == i_16_bits) {
1089     return i_img_16_new(xsize, ysize, channels);
1090   }
1091   else if (src->bits == i_double_bits) {
1092     return i_img_double_new(xsize, ysize, channels);
1093   }
1094   else {
1095     i_push_error(0, "Unknown image bits");
1096     return NULL;
1097   }
1098 }
1099
1100 /*
1101 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1102
1103 Spatially transforms I<im> returning a new image.
1104
1105 opx for a length of opxl and opy for a length of opy are arrays of
1106 operators that modify the x and y positions to retreive the pixel data from.
1107
1108 parm and parmlen define extra parameters that the operators may use.
1109
1110 Note that this function is largely superseded by the more flexible
1111 L<transform.c/i_transform2>.
1112
1113 Returns the new image.
1114
1115 The operators for this function are defined in L<stackmach.c>.
1116
1117 =cut
1118 */
1119 i_img*
1120 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1121   double rx,ry;
1122   int nxsize,nysize,nx,ny;
1123   i_img *new_img;
1124   i_color val;
1125   
1126   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));
1127
1128   nxsize = im->xsize;
1129   nysize = im->ysize ;
1130   
1131   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1132   /*   fprintf(stderr,"parm[2]=%f\n",parm[2]);   */
1133   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1134     /*     parm[parmlen-2]=(double)nx;
1135            parm[parmlen-1]=(double)ny; */
1136
1137     parm[0]=(double)nx;
1138     parm[1]=(double)ny;
1139
1140     /*     fprintf(stderr,"(%d,%d) ->",nx,ny);  */
1141     rx=i_op_run(opx,opxl,parm,parmlen);
1142     ry=i_op_run(opy,opyl,parm,parmlen);
1143     /*    fprintf(stderr,"(%f,%f)\n",rx,ry); */
1144     i_gpix(im,rx,ry,&val);
1145     i_ppix(new_img,nx,ny,&val);
1146   }
1147
1148   mm_log((1,"(0x%x) <- i_transform\n",new_img));
1149   return new_img;
1150 }
1151
1152 /*
1153 =item i_img_diff(im1, im2)
1154
1155 Calculates the sum of the squares of the differences between
1156 correspoding channels in two images.
1157
1158 If the images are not the same size then only the common area is 
1159 compared, hence even if images are different sizes this function 
1160 can return zero.
1161
1162 =cut
1163 */
1164 float
1165 i_img_diff(i_img *im1,i_img *im2) {
1166   int x,y,ch,xb,yb,chb;
1167   float tdiff;
1168   i_color val1,val2;
1169
1170   mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1171
1172   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1173   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1174   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1175
1176   mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1177
1178   tdiff=0;
1179   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1180     i_gpix(im1,x,y,&val1);
1181     i_gpix(im2,x,y,&val2);
1182
1183     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1184   }
1185   mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1186   return tdiff;
1187 }
1188
1189 /* just a tiny demo of haar wavelets */
1190
1191 i_img*
1192 i_haar(i_img *im) {
1193   int mx,my;
1194   int fx,fy;
1195   int x,y;
1196   int ch,c;
1197   i_img *new_img,*new_img2;
1198   i_color val1,val2,dval1,dval2;
1199   
1200   mx=im->xsize;
1201   my=im->ysize;
1202   fx=(mx+1)/2;
1203   fy=(my+1)/2;
1204
1205
1206   /* horizontal pass */
1207   
1208   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1209   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1210
1211   c=0; 
1212   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1213     i_gpix(im,x*2,y,&val1);
1214     i_gpix(im,x*2+1,y,&val2);
1215     for(ch=0;ch<im->channels;ch++) {
1216       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1217       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1218     }
1219     i_ppix(new_img,x,y,&dval1);
1220     i_ppix(new_img,x+fx,y,&dval2);
1221   }
1222
1223   for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1224     i_gpix(new_img,x,y*2,&val1);
1225     i_gpix(new_img,x,y*2+1,&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_img2,x,y,&dval1);
1231     i_ppix(new_img2,x,y+fy,&dval2);
1232   }
1233
1234   i_img_destroy(new_img);
1235   return new_img2;
1236 }
1237
1238 /* 
1239 =item i_count_colors(im, maxc)
1240
1241 returns number of colors or -1 
1242 to indicate that it was more than max colors
1243
1244 =cut
1245 */
1246 int
1247 i_count_colors(i_img *im,int maxc) {
1248   struct octt *ct;
1249   int x,y;
1250   int xsize,ysize;
1251   i_color val;
1252   int colorcnt;
1253
1254   mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1255
1256   xsize=im->xsize; 
1257   ysize=im->ysize;
1258   ct=octt_new();
1259  
1260   colorcnt=0;
1261   for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1262     i_gpix(im,x,y,&val);
1263     colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1264     if (colorcnt > maxc) { octt_delete(ct); return -1; }
1265   }
1266   octt_delete(ct);
1267   return colorcnt;
1268 }
1269
1270 /*
1271 =back
1272
1273 =head2 8-bit per sample image internal functions
1274
1275 These are the functions installed in an 8-bit per sample image.
1276
1277 =over
1278
1279 =item i_ppix_d(im, x, y, col)
1280
1281 Internal function.
1282
1283 This is the function kept in the i_f_ppix member of an i_img object.
1284 It does a normal store of a pixel into the image with range checking.
1285
1286 Returns 0 if the pixel could be set, -1 otherwise.
1287
1288 =cut
1289 */
1290 static
1291 int
1292 i_ppix_d(i_img *im, int x, int y, i_color *val) {
1293   int ch;
1294   
1295   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1296     for(ch=0;ch<im->channels;ch++)
1297       if (im->ch_mask&(1<<ch)) 
1298         im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1299     return 0;
1300   }
1301   return -1; /* error was clipped */
1302 }
1303
1304 /*
1305 =item i_gpix_d(im, x, y, &col)
1306
1307 Internal function.
1308
1309 This is the function kept in the i_f_gpix member of an i_img object.
1310 It does normal retrieval of a pixel from the image with range checking.
1311
1312 Returns 0 if the pixel could be set, -1 otherwise.
1313
1314 =cut
1315 */
1316 static
1317 int 
1318 i_gpix_d(i_img *im, int x, int y, i_color *val) {
1319   int ch;
1320   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1321     for(ch=0;ch<im->channels;ch++) 
1322       val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1323     return 0;
1324   }
1325   for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
1326   return -1; /* error was cliped */
1327 }
1328
1329 /*
1330 =item i_glin_d(im, l, r, y, vals)
1331
1332 Reads a line of data from the image, storing the pixels at vals.
1333
1334 The line runs from (l,y) inclusive to (r,y) non-inclusive
1335
1336 vals should point at space for (r-l) pixels.
1337
1338 l should never be less than zero (to avoid confusion about where to
1339 put the pixels in vals).
1340
1341 Returns the number of pixels copied (eg. if r, l or y is out of range)
1342
1343 =cut
1344 */
1345 static
1346 int
1347 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1348   int ch, count, i;
1349   unsigned char *data;
1350   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1351     if (r > im->xsize)
1352       r = im->xsize;
1353     data = im->idata + (l+y*im->xsize) * im->channels;
1354     count = r - l;
1355     for (i = 0; i < count; ++i) {
1356       for (ch = 0; ch < im->channels; ++ch)
1357         vals[i].channel[ch] = *data++;
1358     }
1359     return count;
1360   }
1361   else {
1362     return 0;
1363   }
1364 }
1365
1366 /*
1367 =item i_plin_d(im, l, r, y, vals)
1368
1369 Writes a line of data into the image, using the pixels at vals.
1370
1371 The line runs from (l,y) inclusive to (r,y) non-inclusive
1372
1373 vals should point at (r-l) pixels.
1374
1375 l should never be less than zero (to avoid confusion about where to
1376 get the pixels in vals).
1377
1378 Returns the number of pixels copied (eg. if r, l or y is out of range)
1379
1380 =cut
1381 */
1382 static
1383 int
1384 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
1385   int ch, count, i;
1386   unsigned char *data;
1387   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1388     if (r > im->xsize)
1389       r = im->xsize;
1390     data = im->idata + (l+y*im->xsize) * im->channels;
1391     count = r - l;
1392     for (i = 0; i < count; ++i) {
1393       for (ch = 0; ch < im->channels; ++ch) {
1394         if (im->ch_mask & (1 << ch)) 
1395           *data = vals[i].channel[ch];
1396         ++data;
1397       }
1398     }
1399     return count;
1400   }
1401   else {
1402     return 0;
1403   }
1404 }
1405
1406 /*
1407 =item i_ppixf_d(im, x, y, val)
1408
1409 =cut
1410 */
1411 static
1412 int
1413 i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
1414   int ch;
1415   
1416   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1417     for(ch=0;ch<im->channels;ch++)
1418       if (im->ch_mask&(1<<ch)) {
1419         im->idata[(x+y*im->xsize)*im->channels+ch] = 
1420           SampleFTo8(val->channel[ch]);
1421       }
1422     return 0;
1423   }
1424   return -1; /* error was clipped */
1425 }
1426
1427 /*
1428 =item i_gpixf_d(im, x, y, val)
1429
1430 =cut
1431 */
1432 static
1433 int
1434 i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1435   int ch;
1436   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1437     for(ch=0;ch<im->channels;ch++) {
1438       val->channel[ch] = 
1439         Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1440     }
1441     return 0;
1442   }
1443   return -1; /* error was cliped */
1444 }
1445
1446 /*
1447 =item i_glinf_d(im, l, r, y, vals)
1448
1449 Reads a line of data from the image, storing the pixels at vals.
1450
1451 The line runs from (l,y) inclusive to (r,y) non-inclusive
1452
1453 vals should point at space for (r-l) pixels.
1454
1455 l should never be less than zero (to avoid confusion about where to
1456 put the pixels in vals).
1457
1458 Returns the number of pixels copied (eg. if r, l or y is out of range)
1459
1460 =cut
1461 */
1462 static
1463 int
1464 i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1465   int ch, count, i;
1466   unsigned char *data;
1467   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1468     if (r > im->xsize)
1469       r = im->xsize;
1470     data = im->idata + (l+y*im->xsize) * im->channels;
1471     count = r - l;
1472     for (i = 0; i < count; ++i) {
1473       for (ch = 0; ch < im->channels; ++ch)
1474         vals[i].channel[ch] = Sample8ToF(*data++);
1475     }
1476     return count;
1477   }
1478   else {
1479     return 0;
1480   }
1481 }
1482
1483 /*
1484 =item i_plinf_d(im, l, r, y, vals)
1485
1486 Writes a line of data into the image, using the pixels at vals.
1487
1488 The line runs from (l,y) inclusive to (r,y) non-inclusive
1489
1490 vals should point at (r-l) pixels.
1491
1492 l should never be less than zero (to avoid confusion about where to
1493 get the pixels in vals).
1494
1495 Returns the number of pixels copied (eg. if r, l or y is out of range)
1496
1497 =cut
1498 */
1499 static
1500 int
1501 i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1502   int ch, count, i;
1503   unsigned char *data;
1504   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1505     if (r > im->xsize)
1506       r = im->xsize;
1507     data = im->idata + (l+y*im->xsize) * im->channels;
1508     count = r - l;
1509     for (i = 0; i < count; ++i) {
1510       for (ch = 0; ch < im->channels; ++ch) {
1511         if (im->ch_mask & (1 << ch)) 
1512           *data = SampleFTo8(vals[i].channel[ch]);
1513         ++data;
1514       }
1515     }
1516     return count;
1517   }
1518   else {
1519     return 0;
1520   }
1521 }
1522
1523 /*
1524 =item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1525
1526 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1527 for the channels specified by chans, an array of int with chan_count
1528 elements.
1529
1530 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1531
1532 =cut
1533 */
1534 static
1535 int
1536 i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
1537               const int *chans, int chan_count) {
1538   int ch, count, i, w;
1539   unsigned char *data;
1540
1541   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1542     if (r > im->xsize)
1543       r = im->xsize;
1544     data = im->idata + (l+y*im->xsize) * im->channels;
1545     w = r - l;
1546     count = 0;
1547
1548     if (chans) {
1549       /* make sure we have good channel numbers */
1550       for (ch = 0; ch < chan_count; ++ch) {
1551         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1552           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1553           return 0;
1554         }
1555       }
1556       for (i = 0; i < w; ++i) {
1557         for (ch = 0; ch < chan_count; ++ch) {
1558           *samps++ = data[chans[ch]];
1559           ++count;
1560         }
1561         data += im->channels;
1562       }
1563     }
1564     else {
1565       for (i = 0; i < w; ++i) {
1566         for (ch = 0; ch < chan_count; ++ch) {
1567           *samps++ = data[ch];
1568           ++count;
1569         }
1570         data += im->channels;
1571       }
1572     }
1573
1574     return count;
1575   }
1576   else {
1577     return 0;
1578   }
1579 }
1580
1581 /*
1582 =item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1583
1584 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1585 for the channels specified by chan_mask, where bit 0 is the first
1586 channel.
1587
1588 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1589
1590 =cut
1591 */
1592 static
1593 int
1594 i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
1595            const int *chans, int chan_count) {
1596   int ch, count, i, w;
1597   unsigned char *data;
1598   for (ch = 0; ch < chan_count; ++ch) {
1599     if (chans[ch] < 0 || chans[ch] >= im->channels) {
1600       i_push_errorf(0, "No channel %d in this image", chans[ch]);
1601     }
1602   }
1603   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1604     if (r > im->xsize)
1605       r = im->xsize;
1606     data = im->idata + (l+y*im->xsize) * im->channels;
1607     w = r - l;
1608     count = 0;
1609
1610     if (chans) {
1611       /* make sure we have good channel numbers */
1612       for (ch = 0; ch < chan_count; ++ch) {
1613         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1614           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1615           return 0;
1616         }
1617       }
1618       for (i = 0; i < w; ++i) {
1619         for (ch = 0; ch < chan_count; ++ch) {
1620           *samps++ = Sample8ToF(data[chans[ch]]);
1621           ++count;
1622         }
1623         data += im->channels;
1624       }
1625     }
1626     else {
1627       for (i = 0; i < w; ++i) {
1628         for (ch = 0; ch < chan_count; ++ch) {
1629           *samps++ = Sample8ToF(data[ch]);
1630           ++count;
1631         }
1632         data += im->channels;
1633       }
1634     }
1635     return count;
1636   }
1637   else {
1638     return 0;
1639   }
1640 }
1641
1642 /*
1643 =back
1644
1645 =head2 Image method wrappers
1646
1647 These functions provide i_fsample_t functions in terms of their
1648 i_sample_t versions.
1649
1650 =over
1651
1652 =item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1653
1654 =cut
1655 */
1656
1657 int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1658   i_color temp;
1659   int ch;
1660
1661   for (ch = 0; ch < im->channels; ++ch)
1662     temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1663   
1664   return i_ppix(im, x, y, &temp);
1665 }
1666
1667 /*
1668 =item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1669
1670 =cut
1671 */
1672 int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1673   i_color temp;
1674   int ch;
1675
1676   if (i_gpix(im, x, y, &temp)) {
1677     for (ch = 0; ch < im->channels; ++ch)
1678       pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1679     return 0;
1680   }
1681   else 
1682     return -1;
1683 }
1684
1685 /*
1686 =item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1687
1688 =cut
1689 */
1690 int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1691   i_color *work;
1692
1693   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1694     if (r > im->xsize)
1695       r = im->xsize;
1696     if (r > l) {
1697       int ret;
1698       int i, ch;
1699       work = mymalloc(sizeof(i_color) * (r-l));
1700       for (i = 0; i < r-l; ++i) {
1701         for (ch = 0; ch < im->channels; ++ch) 
1702           work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1703       }
1704       ret = i_plin(im, l, r, y, work);
1705       myfree(work);
1706
1707       return ret;
1708     }
1709     else {
1710       return 0;
1711     }
1712   }
1713   else {
1714     return 0;
1715   }
1716 }
1717
1718 /*
1719 =item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1720
1721 =cut
1722 */
1723 int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1724   i_color *work;
1725
1726   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1727     if (r > im->xsize)
1728       r = im->xsize;
1729     if (r > l) {
1730       int ret;
1731       int i, ch;
1732       work = mymalloc(sizeof(i_color) * (r-l));
1733       ret = i_plin(im, l, r, y, work);
1734       for (i = 0; i < r-l; ++i) {
1735         for (ch = 0; ch < im->channels; ++ch) 
1736           pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1737       }
1738       myfree(work);
1739
1740       return ret;
1741     }
1742     else {
1743       return 0;
1744     }
1745   }
1746   else {
1747     return 0;
1748   }
1749 }
1750
1751 /*
1752 =item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1753
1754 =cut
1755 */
1756 int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, 
1757                 int const *chans, int chan_count) {
1758   i_sample_t *work;
1759
1760   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1761     if (r > im->xsize)
1762       r = im->xsize;
1763     if (r > l) {
1764       int ret;
1765       int i;
1766       work = mymalloc(sizeof(i_sample_t) * (r-l));
1767       ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1768       for (i = 0; i < ret; ++i) {
1769           samp[i] = Sample8ToF(work[i]);
1770       }
1771       myfree(work);
1772
1773       return ret;
1774     }
1775     else {
1776       return 0;
1777     }
1778   }
1779   else {
1780     return 0;
1781   }
1782 }
1783
1784 /*
1785 =back
1786
1787 =head2 Palette wrapper functions
1788
1789 Used for virtual images, these forward palette calls to a wrapped image, 
1790 assuming the wrapped image is the first pointer in the structure that 
1791 im->ext_data points at.
1792
1793 =over
1794
1795 =item i_addcolors_forward(i_img *im, i_color *colors, int count)
1796
1797 =cut
1798 */
1799 int i_addcolors_forward(i_img *im, i_color *colors, int count) {
1800   return i_addcolors(*(i_img **)im->ext_data, colors, count);
1801 }
1802
1803 /*
1804 =item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1805
1806 =cut
1807 */
1808 int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1809   return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1810 }
1811
1812 /*
1813 =item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
1814
1815 =cut
1816 */
1817 int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
1818   return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1819 }
1820
1821 /*
1822 =item i_colorcount_forward(i_img *im)
1823
1824 =cut
1825 */
1826 int i_colorcount_forward(i_img *im) {
1827   return i_colorcount(*(i_img **)im->ext_data);
1828 }
1829
1830 /*
1831 =item i_maxcolors_forward(i_img *im)
1832
1833 =cut
1834 */
1835 int i_maxcolors_forward(i_img *im) {
1836   return i_maxcolors(*(i_img **)im->ext_data);
1837 }
1838
1839 /*
1840 =item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
1841
1842 =cut
1843 */
1844 int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
1845   return i_findcolor(*(i_img **)im->ext_data, color, entry);
1846 }
1847
1848 /*
1849 =back
1850
1851 =head2 Stream reading and writing wrapper functions
1852
1853 =over
1854
1855 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1856
1857 Performs general read buffering for file readers that permit reading
1858 to be done through a callback.
1859
1860 The final callback gets two parameters, a I<need> value, and a I<want>
1861 value, where I<need> is the amount of data that the file library needs
1862 to read, and I<want> is the amount of space available in the buffer
1863 maintained by these functions.
1864
1865 This means if you need to read from a stream that you don't know the
1866 length of, you can return I<need> bytes, taking the performance hit of
1867 possibly expensive callbacks (eg. back to perl code), or if you are
1868 reading from a stream where it doesn't matter if some data is lost, or
1869 if the total length of the stream is known, you can return I<want>
1870 bytes.
1871
1872 =cut 
1873 */
1874
1875 int
1876 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1877   int total;
1878
1879   if (length < gci->length - gci->cpos) {
1880     /* simplest case */
1881     memcpy(buf, gci->buffer+gci->cpos, length);
1882     gci->cpos += length;
1883     return length;
1884   }
1885   
1886   total = 0;
1887   memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1888   total  += gci->length - gci->cpos;
1889   length -= gci->length - gci->cpos;
1890   buf    += gci->length - gci->cpos;
1891   if (length < (int)sizeof(gci->buffer)) {
1892     int did_read;
1893     int copy_size;
1894     while (length
1895            && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
1896                                     sizeof(gci->buffer))) > 0) {
1897       gci->cpos = 0;
1898       gci->length = did_read;
1899
1900       copy_size = i_min(length, gci->length);
1901       memcpy(buf, gci->buffer, copy_size);
1902       gci->cpos += copy_size;
1903       buf += copy_size;
1904       total += copy_size;
1905       length -= copy_size;
1906     }
1907   }
1908   else {
1909     /* just read the rest - too big for our buffer*/
1910     int did_read;
1911     while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1912       length -= did_read;
1913       total += did_read;
1914       buf += did_read;
1915     }
1916   }
1917   return total;
1918 }
1919
1920 /*
1921 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1922
1923 For use by callback file readers to initialize the reader buffer.
1924
1925 Allocates, initializes and returns the reader buffer.
1926
1927 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1928
1929 =cut
1930 */
1931 i_gen_read_data *
1932 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1933   i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1934   self->cb = cb;
1935   self->userdata = userdata;
1936   self->length = 0;
1937   self->cpos = 0;
1938
1939   return self;
1940 }
1941
1942 /*
1943 =item i_free_gen_read_data(i_gen_read_data *)
1944
1945 Cleans up.
1946
1947 =cut
1948 */
1949 void i_free_gen_read_data(i_gen_read_data *self) {
1950   myfree(self);
1951 }
1952
1953 /*
1954 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1955
1956 Performs write buffering for a callback based file writer.
1957
1958 Failures are considered fatal, if a write fails then data will be
1959 dropped.
1960
1961 =cut
1962 */
1963 int 
1964 i_gen_writer(
1965 i_gen_write_data *self, 
1966 char const *data, 
1967 int size)
1968 {
1969   if (self->filledto && self->filledto+size > self->maxlength) {
1970     if (self->cb(self->userdata, self->buffer, self->filledto)) {
1971       self->filledto = 0;
1972     }
1973     else {
1974       self->filledto = 0;
1975       return 0;
1976     }
1977   }
1978   if (self->filledto+size <= self->maxlength) {
1979     /* just save it */
1980     memcpy(self->buffer+self->filledto, data, size);
1981     self->filledto += size;
1982     return 1;
1983   }
1984   /* doesn't fit - hand it off */
1985   return self->cb(self->userdata, data, size);
1986 }
1987
1988 /*
1989 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1990
1991 Allocates and initializes the data structure used by i_gen_writer.
1992
1993 This should be released with L<image.c/i_free_gen_write_data>
1994
1995 =cut
1996 */
1997 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
1998                                        char *userdata, int max_length)
1999 {
2000   i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2001   self->cb = cb;
2002   self->userdata = userdata;
2003   self->maxlength = i_min(max_length, sizeof(self->buffer));
2004   if (self->maxlength < 0)
2005     self->maxlength = sizeof(self->buffer);
2006   self->filledto = 0;
2007
2008   return self;
2009 }
2010
2011 /*
2012 =item i_free_gen_write_data(i_gen_write_data *info, int flush)
2013
2014 Cleans up the write buffer.
2015
2016 Will flush any left-over data if I<flush> is non-zero.
2017
2018 Returns non-zero if flush is zero or if info->cb() returns non-zero.
2019
2020 Return zero only if flush is non-zero and info->cb() returns zero.
2021 ie. if it fails.
2022
2023 =cut
2024 */
2025
2026 int i_free_gen_write_data(i_gen_write_data *info, int flush)
2027 {
2028   int result = !flush || 
2029     info->filledto == 0 ||
2030     info->cb(info->userdata, info->buffer, info->filledto);
2031   myfree(info);
2032
2033   return result;
2034 }
2035
2036 /*
2037 =back
2038
2039 =head1 AUTHOR
2040
2041 Arnar M. Hrafnkelsson <addi@umich.edu>
2042
2043 Tony Cook <tony@develop-help.com>
2044
2045 =head1 SEE ALSO
2046
2047 L<Imager>, L<gif.c>
2048
2049 =cut
2050 */