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