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