2f549866dbec67c4db5762f1b385e79c940303a0
[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 4
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 int
1314 i_ppix_d(i_img *im, int x, int y, i_color *val) {
1315   int ch;
1316   
1317   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1318     for(ch=0;ch<im->channels;ch++)
1319       if (im->ch_mask&(1<<ch)) 
1320         im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1321     return 0;
1322   }
1323   return -1; /* error was clipped */
1324 }
1325
1326 /*
1327 =item i_gpix_d(im, x, y, &col)
1328
1329 Internal function.
1330
1331 This is the function kept in the i_f_gpix member of an i_img object.
1332 It does normal retrieval of a pixel from the image with range checking.
1333
1334 Returns 0 if the pixel could be set, -1 otherwise.
1335
1336 =cut
1337 */
1338 int 
1339 i_gpix_d(i_img *im, int x, int y, i_color *val) {
1340   int ch;
1341   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1342     for(ch=0;ch<im->channels;ch++) 
1343         val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1344     return 0;
1345   }
1346   for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
1347   return -1; /* error was cliped */
1348 }
1349
1350 /*
1351 =item i_glin_d(im, l, r, y, vals)
1352
1353 Reads a line of data from the image, storing the pixels at vals.
1354
1355 The line runs from (l,y) inclusive to (r,y) non-inclusive
1356
1357 vals should point at space for (r-l) pixels.
1358
1359 l should never be less than zero (to avoid confusion about where to
1360 put the pixels in vals).
1361
1362 Returns the number of pixels copied (eg. if r, l or y is out of range)
1363
1364 =cut
1365 */
1366 int
1367 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1368   int ch, count, i;
1369   unsigned char *data;
1370   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1371     if (r > im->xsize)
1372       r = im->xsize;
1373     data = im->idata + (l+y*im->xsize) * im->channels;
1374     count = r - l;
1375     for (i = 0; i < count; ++i) {
1376       for (ch = 0; ch < im->channels; ++ch)
1377         vals[i].channel[ch] = *data++;
1378     }
1379     return count;
1380   }
1381   else {
1382     return 0;
1383   }
1384 }
1385
1386 /*
1387 =item i_plin_d(im, l, r, y, vals)
1388
1389 Writes a line of data into the image, using the pixels at vals.
1390
1391 The line runs from (l,y) inclusive to (r,y) non-inclusive
1392
1393 vals should point at (r-l) pixels.
1394
1395 l should never be less than zero (to avoid confusion about where to
1396 get the pixels in vals).
1397
1398 Returns the number of pixels copied (eg. if r, l or y is out of range)
1399
1400 =cut
1401 */
1402 int
1403 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
1404   int ch, count, i;
1405   unsigned char *data;
1406   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1407     if (r > im->xsize)
1408       r = im->xsize;
1409     data = im->idata + (l+y*im->xsize) * im->channels;
1410     count = r - l;
1411     for (i = 0; i < count; ++i) {
1412       for (ch = 0; ch < im->channels; ++ch) {
1413         if (im->ch_mask & (1 << ch)) 
1414           *data = vals[i].channel[ch];
1415         ++data;
1416       }
1417     }
1418     return count;
1419   }
1420   else {
1421     return 0;
1422   }
1423 }
1424
1425 /*
1426 =item i_ppixf_d(im, x, y, val)
1427
1428 =cut
1429 */
1430 int
1431 i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
1432   int ch;
1433   
1434   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1435     for(ch=0;ch<im->channels;ch++)
1436       if (im->ch_mask&(1<<ch)) {
1437         im->idata[(x+y*im->xsize)*im->channels+ch] = 
1438           SampleFTo8(val->channel[ch]);
1439       }
1440     return 0;
1441   }
1442   return -1; /* error was clipped */
1443 }
1444
1445 /*
1446 =item i_gpixf_d(im, x, y, val)
1447
1448 =cut
1449 */
1450 int
1451 i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1452   int ch;
1453   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1454     for(ch=0;ch<im->channels;ch++) {
1455       val->channel[ch] = 
1456         Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1457     }
1458     return 0;
1459   }
1460   return -1; /* error was cliped */
1461 }
1462
1463 /*
1464 =item i_glinf_d(im, l, r, y, vals)
1465
1466 Reads a line of data from the image, storing the pixels at vals.
1467
1468 The line runs from (l,y) inclusive to (r,y) non-inclusive
1469
1470 vals should point at space for (r-l) pixels.
1471
1472 l should never be less than zero (to avoid confusion about where to
1473 put the pixels in vals).
1474
1475 Returns the number of pixels copied (eg. if r, l or y is out of range)
1476
1477 =cut
1478 */
1479 int
1480 i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1481   int ch, count, i;
1482   unsigned char *data;
1483   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1484     if (r > im->xsize)
1485       r = im->xsize;
1486     data = im->idata + (l+y*im->xsize) * im->channels;
1487     count = r - l;
1488     for (i = 0; i < count; ++i) {
1489       for (ch = 0; ch < im->channels; ++ch)
1490         vals[i].channel[ch] = Sample8ToF(*data++);
1491     }
1492     return count;
1493   }
1494   else {
1495     return 0;
1496   }
1497 }
1498
1499 /*
1500 =item i_plinf_d(im, l, r, y, vals)
1501
1502 Writes a line of data into the image, using the pixels at vals.
1503
1504 The line runs from (l,y) inclusive to (r,y) non-inclusive
1505
1506 vals should point at (r-l) pixels.
1507
1508 l should never be less than zero (to avoid confusion about where to
1509 get the pixels in vals).
1510
1511 Returns the number of pixels copied (eg. if r, l or y is out of range)
1512
1513 =cut
1514 */
1515 int
1516 i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1517   int ch, count, i;
1518   unsigned char *data;
1519   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1520     if (r > im->xsize)
1521       r = im->xsize;
1522     data = im->idata + (l+y*im->xsize) * im->channels;
1523     count = r - l;
1524     for (i = 0; i < count; ++i) {
1525       for (ch = 0; ch < im->channels; ++ch) {
1526         if (im->ch_mask & (1 << ch)) 
1527           *data = SampleFTo8(vals[i].channel[ch]);
1528         ++data;
1529       }
1530     }
1531     return count;
1532   }
1533   else {
1534     return 0;
1535   }
1536 }
1537
1538 /*
1539 =item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1540
1541 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1542 for the channels specified by chans, an array of int with chan_count
1543 elements.
1544
1545 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1546
1547 =cut
1548 */
1549 int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
1550               int *chans, int chan_count) {
1551   int ch, count, i, w;
1552   unsigned char *data;
1553
1554   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1555     if (r > im->xsize)
1556       r = im->xsize;
1557     data = im->idata + (l+y*im->xsize) * im->channels;
1558     w = r - l;
1559     count = 0;
1560
1561     if (chans) {
1562       /* make sure we have good channel numbers */
1563       for (ch = 0; ch < chan_count; ++ch) {
1564         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1565           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1566           return 0;
1567         }
1568       }
1569       for (i = 0; i < w; ++i) {
1570         for (ch = 0; ch < chan_count; ++ch) {
1571           *samps++ = data[chans[ch]];
1572           ++count;
1573         }
1574         data += im->channels;
1575       }
1576     }
1577     else {
1578       for (i = 0; i < w; ++i) {
1579         for (ch = 0; ch < chan_count; ++ch) {
1580           *samps++ = data[ch];
1581           ++count;
1582         }
1583         data += im->channels;
1584       }
1585     }
1586
1587     return count;
1588   }
1589   else {
1590     return 0;
1591   }
1592 }
1593
1594 /*
1595 =item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1596
1597 Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1598 for the channels specified by chan_mask, where bit 0 is the first
1599 channel.
1600
1601 Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1602
1603 =cut
1604 */
1605 int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
1606                int *chans, int chan_count) {
1607   int ch, count, i, w;
1608   unsigned char *data;
1609   for (ch = 0; ch < chan_count; ++ch) {
1610     if (chans[ch] < 0 || chans[ch] >= im->channels) {
1611       i_push_errorf(0, "No channel %d in this image", chans[ch]);
1612     }
1613   }
1614   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1615     if (r > im->xsize)
1616       r = im->xsize;
1617     data = im->idata + (l+y*im->xsize) * im->channels;
1618     w = r - l;
1619     count = 0;
1620
1621     if (chans) {
1622       /* make sure we have good channel numbers */
1623       for (ch = 0; ch < chan_count; ++ch) {
1624         if (chans[ch] < 0 || chans[ch] >= im->channels) {
1625           i_push_errorf(0, "No channel %d in this image", chans[ch]);
1626           return 0;
1627         }
1628       }
1629       for (i = 0; i < w; ++i) {
1630         for (ch = 0; ch < chan_count; ++ch) {
1631           *samps++ = Sample8ToF(data[chans[ch]]);
1632           ++count;
1633         }
1634         data += im->channels;
1635       }
1636     }
1637     else {
1638       for (i = 0; i < w; ++i) {
1639         for (ch = 0; ch < chan_count; ++ch) {
1640           *samps++ = Sample8ToF(data[ch]);
1641           ++count;
1642         }
1643         data += im->channels;
1644       }
1645     }
1646     return count;
1647   }
1648   else {
1649     return 0;
1650   }
1651 }
1652
1653 /*
1654 =back
1655
1656 =head2 Image method wrappers
1657
1658 These functions provide i_fsample_t functions in terms of their
1659 i_sample_t versions.
1660
1661 =over
1662
1663 =item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1664
1665 =cut
1666 */
1667
1668 int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1669   i_color temp;
1670   int ch;
1671
1672   for (ch = 0; ch < im->channels; ++ch)
1673     temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1674   
1675   return i_ppix(im, x, y, &temp);
1676 }
1677
1678 /*
1679 =item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1680
1681 =cut
1682 */
1683 int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1684   i_color temp;
1685   int ch;
1686
1687   if (i_gpix(im, x, y, &temp)) {
1688     for (ch = 0; ch < im->channels; ++ch)
1689       pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1690     return 0;
1691   }
1692   else 
1693     return -1;
1694 }
1695
1696 /*
1697 =item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1698
1699 =cut
1700 */
1701 int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1702   i_color *work;
1703
1704   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1705     if (r > im->xsize)
1706       r = im->xsize;
1707     if (r > l) {
1708       int ret;
1709       int i, ch;
1710       work = mymalloc(sizeof(i_color) * (r-l));
1711       for (i = 0; i < r-l; ++i) {
1712         for (ch = 0; ch < im->channels; ++ch) 
1713           work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1714       }
1715       ret = i_plin(im, l, r, y, work);
1716       myfree(work);
1717
1718       return ret;
1719     }
1720     else {
1721       return 0;
1722     }
1723   }
1724   else {
1725     return 0;
1726   }
1727 }
1728
1729 /*
1730 =item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1731
1732 =cut
1733 */
1734 int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1735   i_color *work;
1736
1737   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1738     if (r > im->xsize)
1739       r = im->xsize;
1740     if (r > l) {
1741       int ret;
1742       int i, ch;
1743       work = mymalloc(sizeof(i_color) * (r-l));
1744       ret = i_plin(im, l, r, y, work);
1745       for (i = 0; i < r-l; ++i) {
1746         for (ch = 0; ch < im->channels; ++ch) 
1747           pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1748       }
1749       myfree(work);
1750
1751       return ret;
1752     }
1753     else {
1754       return 0;
1755     }
1756   }
1757   else {
1758     return 0;
1759   }
1760 }
1761
1762 /*
1763 =item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1764
1765 =cut
1766 */
1767 int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, 
1768                 int *chans, int chan_count) {
1769   i_sample_t *work;
1770
1771   if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1772     if (r > im->xsize)
1773       r = im->xsize;
1774     if (r > l) {
1775       int ret;
1776       int i;
1777       work = mymalloc(sizeof(i_sample_t) * (r-l));
1778       ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1779       for (i = 0; i < ret; ++i) {
1780           samp[i] = Sample8ToF(work[i]);
1781       }
1782       myfree(work);
1783
1784       return ret;
1785     }
1786     else {
1787       return 0;
1788     }
1789   }
1790   else {
1791     return 0;
1792   }
1793 }
1794
1795 /*
1796 =back
1797
1798 =head2 Palette wrapper functions
1799
1800 Used for virtual images, these forward palette calls to a wrapped image, 
1801 assuming the wrapped image is the first pointer in the structure that 
1802 im->ext_data points at.
1803
1804 =over
1805
1806 =item i_addcolors_forward(i_img *im, i_color *colors, int count)
1807
1808 =cut
1809 */
1810 int i_addcolors_forward(i_img *im, i_color *colors, int count) {
1811   return i_addcolors(*(i_img **)im->ext_data, colors, count);
1812 }
1813
1814 /*
1815 =item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1816
1817 =cut
1818 */
1819 int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1820   return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1821 }
1822
1823 /*
1824 =item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
1825
1826 =cut
1827 */
1828 int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
1829   return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1830 }
1831
1832 /*
1833 =item i_colorcount_forward(i_img *im)
1834
1835 =cut
1836 */
1837 int i_colorcount_forward(i_img *im) {
1838   return i_colorcount(*(i_img **)im->ext_data);
1839 }
1840
1841 /*
1842 =item i_maxcolors_forward(i_img *im)
1843
1844 =cut
1845 */
1846 int i_maxcolors_forward(i_img *im) {
1847   return i_maxcolors(*(i_img **)im->ext_data);
1848 }
1849
1850 /*
1851 =item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
1852
1853 =cut
1854 */
1855 int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
1856   return i_findcolor(*(i_img **)im->ext_data, color, entry);
1857 }
1858
1859 /*
1860 =back
1861
1862 =head2 Stream reading and writing wrapper functions
1863
1864 =over
1865
1866 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1867
1868 Performs general read buffering for file readers that permit reading
1869 to be done through a callback.
1870
1871 The final callback gets two parameters, a I<need> value, and a I<want>
1872 value, where I<need> is the amount of data that the file library needs
1873 to read, and I<want> is the amount of space available in the buffer
1874 maintained by these functions.
1875
1876 This means if you need to read from a stream that you don't know the
1877 length of, you can return I<need> bytes, taking the performance hit of
1878 possibly expensive callbacks (eg. back to perl code), or if you are
1879 reading from a stream where it doesn't matter if some data is lost, or
1880 if the total length of the stream is known, you can return I<want>
1881 bytes.
1882
1883 =cut 
1884 */
1885
1886 int
1887 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1888   int total;
1889
1890   if (length < gci->length - gci->cpos) {
1891     /* simplest case */
1892     memcpy(buf, gci->buffer+gci->cpos, length);
1893     gci->cpos += length;
1894     return length;
1895   }
1896   
1897   total = 0;
1898   memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1899   total  += gci->length - gci->cpos;
1900   length -= gci->length - gci->cpos;
1901   buf    += gci->length - gci->cpos;
1902   if (length < (int)sizeof(gci->buffer)) {
1903     int did_read;
1904     int copy_size;
1905     while (length
1906            && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
1907                                     sizeof(gci->buffer))) > 0) {
1908       gci->cpos = 0;
1909       gci->length = did_read;
1910
1911       copy_size = min(length, gci->length);
1912       memcpy(buf, gci->buffer, copy_size);
1913       gci->cpos += copy_size;
1914       buf += copy_size;
1915       total += copy_size;
1916       length -= copy_size;
1917     }
1918   }
1919   else {
1920     /* just read the rest - too big for our buffer*/
1921     int did_read;
1922     while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1923       length -= did_read;
1924       total += did_read;
1925       buf += did_read;
1926     }
1927   }
1928   return total;
1929 }
1930
1931 /*
1932 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1933
1934 For use by callback file readers to initialize the reader buffer.
1935
1936 Allocates, initializes and returns the reader buffer.
1937
1938 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1939
1940 =cut
1941 */
1942 i_gen_read_data *
1943 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1944   i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1945   self->cb = cb;
1946   self->userdata = userdata;
1947   self->length = 0;
1948   self->cpos = 0;
1949
1950   return self;
1951 }
1952
1953 /*
1954 =item free_gen_read_data(i_gen_read_data *)
1955
1956 Cleans up.
1957
1958 =cut
1959 */
1960 void free_gen_read_data(i_gen_read_data *self) {
1961   myfree(self);
1962 }
1963
1964 /*
1965 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1966
1967 Performs write buffering for a callback based file writer.
1968
1969 Failures are considered fatal, if a write fails then data will be
1970 dropped.
1971
1972 =cut
1973 */
1974 int 
1975 i_gen_writer(
1976 i_gen_write_data *self, 
1977 char const *data, 
1978 int size)
1979 {
1980   if (self->filledto && self->filledto+size > self->maxlength) {
1981     if (self->cb(self->userdata, self->buffer, self->filledto)) {
1982       self->filledto = 0;
1983     }
1984     else {
1985       self->filledto = 0;
1986       return 0;
1987     }
1988   }
1989   if (self->filledto+size <= self->maxlength) {
1990     /* just save it */
1991     memcpy(self->buffer+self->filledto, data, size);
1992     self->filledto += size;
1993     return 1;
1994   }
1995   /* doesn't fit - hand it off */
1996   return self->cb(self->userdata, data, size);
1997 }
1998
1999 /*
2000 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2001
2002 Allocates and initializes the data structure used by i_gen_writer.
2003
2004 This should be released with L<image.c/free_gen_write_data>
2005
2006 =cut
2007 */
2008 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
2009                                        char *userdata, int max_length)
2010 {
2011   i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2012   self->cb = cb;
2013   self->userdata = userdata;
2014   self->maxlength = min(max_length, sizeof(self->buffer));
2015   if (self->maxlength < 0)
2016     self->maxlength = sizeof(self->buffer);
2017   self->filledto = 0;
2018
2019   return self;
2020 }
2021
2022 /*
2023 =item free_gen_write_data(i_gen_write_data *info, int flush)
2024
2025 Cleans up the write buffer.
2026
2027 Will flush any left-over data if I<flush> is non-zero.
2028
2029 Returns non-zero if flush is zero or if info->cb() returns non-zero.
2030
2031 Return zero only if flush is non-zero and info->cb() returns zero.
2032 ie. if it fails.
2033
2034 =cut
2035 */
2036
2037 int free_gen_write_data(i_gen_write_data *info, int flush)
2038 {
2039   int result = !flush || 
2040     info->filledto == 0 ||
2041     info->cb(info->userdata, info->buffer, info->filledto);
2042   myfree(info);
2043
2044   return result;
2045 }
2046
2047 /*
2048 =back
2049
2050 =head1 SEE ALSO
2051
2052 L<Imager>, L<gif.c>
2053
2054 =cut
2055 */