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