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