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