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