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