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