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