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