Removed a bunch of unused variables and fixed an attempt to print out a
[imager.git] / image.c
1 #include "image.h"
2 #include "io.h"
3
4 /*
5 =head1 NAME
6
7 image.c - implements most of the basic functions of Imager and much of the rest
8
9 =head1 SYNOPSIS
10
11   i_img *i;
12   i_color *c;
13   c = i_color_new(red, green, blue, alpha);
14   ICL_DESTROY(c);
15   i = i_img_new();
16   i_img_destroy(i);
17   // and much more
18
19 =head1 DESCRIPTION
20
21 image.c implements the basic functions to create and destroy image and
22 color objects for Imager.
23
24 =head1 FUNCTION REFERENCE
25
26 Some of these functions are internal.
27
28 =over 4
29
30 =cut
31 */
32
33 #define XAXIS 0
34 #define YAXIS 1
35 #define XYAXIS 2
36
37 #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i   )) )
38
39 /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
40 void fake() { ceil(1); }
41
42 /* 
43 =item ICL_new_internal(r, g, b, a)
44
45 Return a new color object with values passed to it.
46
47    r - red   component (range: 0 - 255)
48    g - green component (range: 0 - 255)
49    b - blue  component (range: 0 - 255)
50    a - alpha component (range: 0 - 255)
51
52 =cut
53 */
54
55 i_color *
56 ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
57   i_color *cl = NULL;
58
59   mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
60
61   if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
62   cl->rgba.r = r;
63   cl->rgba.g = g;
64   cl->rgba.b = b;
65   cl->rgba.a = a;
66   mm_log((1,"(%p) <- ICL_new_internal\n",cl));
67   return cl;
68 }
69
70
71 /*
72 =item ICL_set_internal(cl, r, g, b, a)
73
74  Overwrite a color with new values.
75
76    cl - pointer to color object
77    r - red   component (range: 0 - 255)
78    g - green component (range: 0 - 255)
79    b - blue  component (range: 0 - 255)
80    a - alpha component (range: 0 - 255)
81
82 =cut
83 */
84
85 i_color *
86 ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
87   mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
88   if (cl == NULL)
89     if ( (cl=mymalloc(sizeof(i_color))) == NULL)
90       m_fatal(2,"malloc() error\n");
91   cl->rgba.r=r;
92   cl->rgba.g=g;
93   cl->rgba.b=b;
94   cl->rgba.a=a;
95   mm_log((1,"(%p) <- ICL_set_internal\n",cl));
96   return cl;
97 }
98
99
100 /* 
101 =item ICL_add(dst, src, ch)
102
103 Add src to dst inplace - dst is modified.
104
105    dst - pointer to destination color object
106    src - pointer to color object that is added
107    ch - number of channels
108
109 =cut
110 */
111
112 void
113 ICL_add(i_color *dst,i_color *src,int ch) {
114   int tmp,i;
115   for(i=0;i<ch;i++) {
116     tmp=dst->channel[i]+src->channel[i];
117     dst->channel[i]= tmp>255 ? 255:tmp;
118   }
119 }
120
121 /* 
122 =item ICL_info(cl)
123
124 Dump color information to log - strictly for debugging.
125
126    cl - pointer to color object
127
128 =cut
129 */
130
131 void
132 ICL_info(i_color *cl) {
133   mm_log((1,"i_color_info(cl* %p)\n",cl));
134   mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
135 }
136
137 /* 
138 =item ICL_DESTROY
139
140 Destroy ancillary data for Color object.
141
142    cl - pointer to color object
143
144 =cut
145 */
146
147 void
148 ICL_DESTROY(i_color *cl) {
149   mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
150   myfree(cl);
151 }
152
153 /*
154 =item IIM_new(x, y, ch)
155
156 Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
157
158 =cut
159 */
160
161
162 i_img *
163 IIM_new(int x,int y,int ch) {
164   i_img *im;
165   mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
166
167   im=i_img_empty_ch(NULL,x,y,ch);
168   
169   mm_log((1,"(%p) <- IIM_new\n",im));
170   return im;
171 }
172
173
174 void
175 IIM_DESTROY(i_img *im) {
176   mm_log((1,"IIM_DESTROY(im* %p)\n",im));
177   /*   myfree(cl); */
178 }
179
180
181
182 /* 
183 =item i_img_new()
184
185 Create new image reference - notice that this isn't an object yet and
186 this should be fixed asap.
187
188 =cut
189 */
190
191
192 i_img *
193 i_img_new() {
194   i_img *im;
195   
196   mm_log((1,"i_img_struct()\n"));
197   if ( (im=mymalloc(sizeof(i_img))) == NULL)
198     m_fatal(2,"malloc() error\n");
199   
200   im->xsize=0;
201   im->ysize=0;
202   im->channels=3;
203   im->ch_mask=MAXINT;
204   im->bytes=0;
205   im->data=NULL;
206
207   im->i_f_ppix=i_ppix_d;
208   im->i_f_gpix=i_gpix_d;
209   im->i_f_plin=i_plin_d;
210   im->i_f_glin=i_glin_d;
211   im->ext_data=NULL;
212   
213   mm_log((1,"(%p) <- i_img_struct\n",im));
214   return im;
215 }
216
217 /* 
218 =item i_img_empty(im, x, y)
219
220 Re-new image reference (assumes 3 channels)
221
222    im - Image pointer
223    x - xsize of destination image
224    y - ysize of destination image
225
226 =cut
227 */
228
229 i_img *
230 i_img_empty(i_img *im,int x,int y) {
231   mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
232   if (im==NULL)
233     if ( (im=mymalloc(sizeof(i_img))) == NULL)
234       m_fatal(2,"malloc() error\n");
235   
236   im->xsize    = x;
237   im->ysize    = y;
238   im->channels = 3;
239   im->ch_mask  = MAXINT;
240   im->bytes=x*y*im->channels;
241   if ( (im->data = mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n"); 
242   memset(im->data, 0, (size_t)im->bytes);
243
244   im->i_f_ppix = i_ppix_d;
245   im->i_f_gpix = i_gpix_d;
246   im->i_f_plin = i_plin_d;
247   im->i_f_glin = i_glin_d;
248   im->ext_data = NULL;
249   
250   mm_log((1,"(%p) <- i_img_empty\n", im));
251   return im;
252 }
253
254 /* 
255 =item i_img_empty_ch(im, x, y, ch)
256
257 Re-new image reference 
258
259    im - Image pointer
260    x  - xsize of destination image
261    y  - ysize of destination image
262    ch - number of channels
263
264 =cut
265 */
266
267 i_img *
268 i_img_empty_ch(i_img *im,int x,int y,int ch) {
269   mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
270   if (im == NULL)
271     if ( (im=mymalloc(sizeof(i_img))) == NULL)
272       m_fatal(2,"malloc() error\n");
273   
274   im->xsize    = x;
275   im->ysize    = y;
276   im->channels = ch;
277   im->ch_mask  = MAXINT;
278   im->bytes=x*y*im->channels;
279   if ( (im->data=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n"); 
280   memset(im->data,0,(size_t)im->bytes);
281   
282   im->i_f_ppix = i_ppix_d;
283   im->i_f_gpix = i_gpix_d;
284   im->i_f_plin = i_plin_d;
285   im->i_f_glin = i_glin_d;
286   im->ext_data = NULL;
287   
288   mm_log((1,"(%p) <- i_img_empty_ch\n",im));
289   return im;
290 }
291
292 /* 
293 =item i_img_exorcise(im)
294
295 Free image data.
296
297    im - Image pointer
298
299 =cut
300 */
301
302 void
303 i_img_exorcise(i_img *im) {
304   mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
305   if (im->data != NULL) { myfree(im->data); }
306   im->data     = NULL;
307   im->xsize    = 0;
308   im->ysize    = 0;
309   im->channels = 0;
310
311   im->i_f_ppix=i_ppix_d;
312   im->i_f_gpix=i_gpix_d;
313   im->i_f_plin=i_plin_d;
314   im->i_f_glin=i_glin_d;
315   im->ext_data=NULL;
316 }
317
318 /* 
319 =item i_img_destroy(im)
320
321 Destroy image and free data via exorcise.
322
323    im - Image pointer
324
325 =cut
326 */
327
328 void
329 i_img_destroy(i_img *im) {
330   mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
331   i_img_exorcise(im);
332   if (im) { myfree(im); }
333 }
334
335 /* 
336 =item i_img_info(im, info)
337
338 Return image information
339
340    im - Image pointer
341    info - pointer to array to return data
342
343 info is an array of 4 integers with the following values:
344
345  info[0] - width
346  info[1] - height
347  info[2] - channels
348  info[3] - channel mask
349
350 =cut
351 */
352
353
354 void
355 i_img_info(i_img *im,int *info) {
356   mm_log((1,"i_img_info(im 0x%x)\n",im));
357   if (im != NULL) {
358     mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
359     mm_log((1,"i_img_info: data=0x%d\n",im->data));
360     info[0] = im->xsize;
361     info[1] = im->ysize;
362     info[2] = im->channels;
363     info[3] = im->ch_mask;
364   } else {
365     info[0] = 0;
366     info[1] = 0;
367     info[2] = 0;
368     info[3] = 0;
369   }
370 }
371
372 /*
373 =item i_img_setmask(im, ch_mask)
374
375 Set the image channel mask for I<im> to I<ch_mask>.
376
377 =cut
378 */
379 void
380 i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
381
382
383 /*
384 =item i_img_getmask(im)
385
386 Get the image channel mask for I<im>.
387
388 =cut
389 */
390 int
391 i_img_getmask(i_img *im) { return im->ch_mask; }
392
393 /*
394 =item i_img_getchannels(im)
395
396 Get the number of channels in I<im>.
397
398 =cut
399 */
400 int
401 i_img_getchannels(i_img *im) { return im->channels; }
402
403
404 /*
405 =item i_ppix(im, x, y, col)
406
407 Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
408
409 Returns true if the pixel could be set, false if x or y is out of
410 range.
411
412 =cut
413 */
414 int
415 i_ppix(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
416
417 /*
418 =item i_gpix(im, x, y, &col)
419
420 Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
421
422 Returns true if the pixel could be retrieved, false otherwise.
423
424 =cut
425 */
426 int
427 i_gpix(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
428
429 /*
430 =item i_ppix_d(im, x, y, col)
431
432 Internal function.
433
434 This is the function kept in the i_f_ppix member of an i_img object.
435 It does a normal store of a pixel into the image with range checking.
436
437 Returns true if the pixel could be set, false otherwise.
438
439 =cut
440 */
441 int
442 i_ppix_d(i_img *im, int x, int y, i_color *val) {
443   int ch;
444   
445   if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
446     for(ch=0;ch<im->channels;ch++)
447       if (im->ch_mask&(1<<ch)) 
448         im->data[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
449     return 0;
450   }
451   return -1; /* error was clipped */
452 }
453
454 /*
455 =item i_gpix_d(im, x, y, &col)
456
457 Internal function.
458
459 This is the function kept in the i_f_gpix member of an i_img object.
460 It does normal retrieval of a pixel from the image with range checking.
461
462 Returns true if the pixel could be set, false otherwise.
463
464 =cut
465 */
466 int 
467 i_gpix_d(i_img *im, int x, int y, i_color *val) {
468   int ch;
469   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
470     for(ch=0;ch<im->channels;ch++) 
471         val->channel[ch]=im->data[(x+y*im->xsize)*im->channels+ch];
472     return 0;
473   }
474   return -1; /* error was cliped */
475 }
476
477 /*
478 =item i_glin_d(im, l, r, y, vals)
479
480 Reads a line of data from the image, storing the pixels at vals.
481
482 The line runs from (l,y) inclusive to (r,y) non-inclusive
483
484 vals should point at space for (r-l) pixels.
485
486 l should never be less than zero (to avoid confusion about where to
487 put the pixels in vals).
488
489 Returns the number of pixels copied (eg. if r, l or y is out of range)
490
491 =cut */
492 int
493 i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
494   int ch, count, i;
495   unsigned char *data;
496   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
497     if (r > im->xsize)
498       r = im->xsize;
499     data = im->data + (l+y*im->xsize) * im->channels;
500     count = r - l;
501     for (i = 0; i < count; ++i) {
502       for (ch = 0; ch < im->channels; ++ch)
503         vals[i].channel[ch] = *data++;
504     }
505     return count;
506   }
507   else {
508     return 0;
509   }
510 }
511 /*
512 =item i_plin_d(im, l, r, y, vals)
513
514 Writes a line of data into the image, using the pixels at vals.
515
516 The line runs from (l,y) inclusive to (r,y) non-inclusive
517
518 vals should point at (r-l) pixels.
519
520 l should never be less than zero (to avoid confusion about where to
521 get the pixels in vals).
522
523 Returns the number of pixels copied (eg. if r, l or y is out of range)
524
525 =cut */
526 int
527 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
528   int ch, count, i;
529   unsigned char *data;
530   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
531     if (r > im->xsize)
532       r = im->xsize;
533     data = im->data + (l+y*im->xsize) * im->channels;
534     count = r - l;
535     for (i = 0; i < count; ++i) {
536       for (ch = 0; ch < im->channels; ++ch) {
537         if (im->ch_mask & (1 << ch)) 
538           *data = vals[i].channel[ch];
539         ++data;
540       }
541     }
542     return count;
543   }
544   else {
545     return 0;
546   }
547 }
548
549 /*
550 =item i_ppix_pch(im, x, y, ch)
551
552 Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
553 scaled to [0,1].
554
555 Returns zero if x or y is out of range.
556
557 Warning: this ignores the vptr interface for images.
558
559 =cut
560 */
561 float
562 i_gpix_pch(i_img *im,int x,int y,int ch) {
563   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
564   else return 0;
565 }
566
567
568 /*
569 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
570
571 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
572 (tx,ty) specifies the upper left corner for the target image.
573 pass NULL in trans for non transparent i_colors.
574
575 =cut
576 */
577
578 void
579 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
580   i_color pv;
581   int x,y,t,ttx,tty,tt,ch;
582
583   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",
584           im, src, x1, y1, x2, y2, tx, ty, trans));
585   
586   if (x2<x1) { t=x1; x1=x2; x2=t; }
587   if (y2<y1) { t=y1; y1=y2; y2=t; }
588
589   ttx=tx;
590   for(x=x1;x<x2;x++)
591     {
592       tty=ty;
593       for(y=y1;y<y2;y++)
594         {
595           i_gpix(src,x,y,&pv);
596           if ( trans != NULL)
597           {
598             tt=0;
599             for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
600             if (tt) i_ppix(im,ttx,tty,&pv);
601           } else i_ppix(im,ttx,tty,&pv);
602           tty++;
603         }
604       ttx++;
605     }
606 }
607
608 /*
609 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
610
611 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
612 a rectangle the same size with it's top-left corner at (tx,ty) in the
613 destination image.
614
615 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
616
617 =cut
618 */
619
620 void
621 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
622   i_color pv;
623   int x, y, t, ttx, tty;
624
625   if (x2<x1) { t=x1; x1=x2; x2=t; }
626   if (y2<y1) { t=y1; y1=y2; y2=t; }
627
628   mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
629           im, src, x1, y1, x2, y2, tx, ty));
630
631     tty = ty;
632     for(y=y1; y<y2; y++) {
633     ttx = tx;
634     for(x=x1; x<x2; x++) {
635       i_gpix(src, x,   y,   &pv);
636       i_ppix(im,  ttx, tty, &pv);
637       ttx++;
638     }
639     tty++;
640   }
641 }
642
643 /*
644 =item i_copy(im, src)
645
646 Copies the contents of the image I<src> over the image I<im>.
647
648 =cut
649 */
650
651 void
652 i_copy(i_img *im, i_img *src) {
653   i_color *pv;
654   int y, y1, x1;
655
656   mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
657
658   x1 = src->xsize;
659   y1 = src->ysize;
660   i_img_empty_ch(im, x1, y1, src->channels);
661   pv = mymalloc(sizeof(i_color) * x1);
662   
663   for (y = 0; y < y1; ++y) {
664     i_glin(src, 0, x1, y, pv);
665     i_plin(im, 0, x1, y, pv);
666   }
667   myfree(pv);
668 }
669
670
671 /*
672 =item i_rubthru(im, src, tx, ty)
673
674 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
675
676 The alpha channel of each pixel in I<src> is used to control how much
677 the existing colour in I<im> is replaced, if it is 255 then the colour
678 is completely replaced, if it is 0 then the original colour is left 
679 unmodified.
680
681 =cut
682 */
683
684 void
685 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
686   i_color pv, orig, dest;
687   int x, y, ttx, tty;
688
689   mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
690
691   if (im->channels  != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
692   if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
693
694   ttx = tx;
695   for(x=0; x<src->xsize; x++) {
696     tty=ty;
697     for(y=0;y<src->ysize;y++) {
698       /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
699       i_gpix(src, x,   y,   &pv);
700       i_gpix(im,  ttx, tty, &orig);
701       dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
702       dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
703       dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
704       i_ppix(im, ttx, tty, &dest);
705       tty++;
706     }
707     ttx++;
708   }
709 }
710
711
712 /*
713 =item i_flipxy(im, axis)
714
715 Flips the image inplace around the axis specified.
716 Returns 0 if parameters are invalid.
717
718    im   - Image pointer
719    axis - 0 = x, 1 = y, 2 = both
720
721 =cut
722 */
723
724 undef_int
725 i_flipxy(i_img *im, int direction) {
726   int x, x2, y, y2, xm, ym;
727   int xs = im->xsize;
728   int ys = im->ysize;
729   
730   mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
731
732   if (!im) return 0;
733
734   switch (direction) {
735   case XAXIS: /* Horizontal flip */
736     xm = xs/2;
737     ym = ys;
738     for(y=0; y<ym; y++) {
739       x2 = xs-1;
740       for(x=0; x<xm; x++) {
741         i_color val1, val2;
742         i_gpix(im, x,  y,  &val1);
743         i_gpix(im, x2, y,  &val2);
744         i_ppix(im, x,  y,  &val2);
745         i_ppix(im, x2, y,  &val1);
746         x2--;
747       }
748     }
749     break;
750   case YAXIS: /* Vertical flip */
751     xm = xs;
752     ym = ys/2;
753     y2 = ys-1;
754     for(y=0; y<ym; y++) {
755       for(x=0; x<xm; x++) {
756         i_color val1, val2;
757         i_gpix(im, x,  y,  &val1);
758         i_gpix(im, x,  y2, &val2);
759         i_ppix(im, x,  y,  &val2);
760         i_ppix(im, x,  y2, &val1);
761       }
762       y2--;
763     }
764     break;
765   case XYAXIS: /* Horizontal and Vertical flip */
766     xm = xs/2;
767     ym = ys/2;
768     y2 = ys-1;
769     for(y=0; y<ym; y++) {
770       x2 = xs-1;
771       for(x=0; x<xm; x++) {
772         i_color val1, val2;
773         i_gpix(im, x,  y,  &val1);
774         i_gpix(im, x2, y2, &val2);
775         i_ppix(im, x,  y,  &val2);
776         i_ppix(im, x2, y2, &val1);
777
778         i_gpix(im, x2, y,  &val1);
779         i_gpix(im, x,  y2, &val2);
780         i_ppix(im, x2, y,  &val2);
781         i_ppix(im, x,  y2, &val1);
782         x2--;
783       }
784       y2--;
785     }
786     if (xm*2 != xs) { /* odd number of column */
787       mm_log((1, "i_flipxy: odd number of columns\n"));
788       x = xm;
789       y2 = ys-1;
790       for(y=0; y<ym; y++) {
791         i_color val1, val2;
792         i_gpix(im, x,  y,  &val1);
793         i_gpix(im, x,  y2, &val2);
794         i_ppix(im, x,  y,  &val2);
795         i_ppix(im, x,  y2, &val1);
796         y2--;
797       }
798     }
799     if (ym*2 != ys) { /* odd number of rows */
800       mm_log((1, "i_flipxy: odd number of rows\n"));
801       y = ym;
802       x2 = xs-1;
803       for(x=0; x<xm; x++) {
804         i_color val1, val2;
805         i_gpix(im, x,  y,  &val1);
806         i_gpix(im, x2, y,  &val2);
807         i_ppix(im, x,  y,  &val2);
808         i_ppix(im, x2, y,  &val1);
809         x2--;
810       }
811     }
812     break;
813   default:
814     mm_log((1, "i_flipxy: direction is invalid\n" ));
815     return 0;
816   }
817   return 1;
818 }
819
820
821
822
823
824 static
825 float
826 Lanczos(float x) {
827   float PIx, PIx2;
828   
829   PIx = PI * x;
830   PIx2 = PIx / 2.0;
831   
832   if ((x >= 2.0) || (x <= -2.0)) return (0.0);
833   else if (x == 0.0) return (1.0);
834   else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
835 }
836
837 /*
838 =item i_scaleaxis(im, value, axis)
839
840 Returns a new image object which is I<im> scaled by I<value> along
841 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
842
843 =cut
844 */
845
846 i_img*
847 i_scaleaxis(i_img *im, float Value, int Axis) {
848   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
849   int LanczosWidthFactor;
850   float *l0, *l1, OldLocation;
851   int T, TempJump1, TempJump2;
852   float F, PictureValue[MAXCHANNELS];
853   short psave;
854   i_color val,val1,val2;
855   i_img *new_img;
856
857   mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
858
859   if (Axis == XAXIS) {
860     hsize = (int) ((float) im->xsize * Value);
861     vsize = im->ysize;
862     
863     jEnd = hsize;
864     iEnd = vsize;
865     
866     TempJump1 = (hsize - 1) * 3;
867     TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
868   } else {
869     hsize = im->xsize;
870     vsize = (int) ((float) im->ysize * Value);
871     
872     jEnd = vsize;
873     iEnd = hsize;
874     
875     TempJump1 = 0;
876     TempJump2 = 0;
877   }
878   
879   new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
880   
881   if (Value >=1) LanczosWidthFactor = 1;
882   else LanczosWidthFactor = (int) (1.0/Value);
883   
884   lMax = LanczosWidthFactor << 1;
885   
886   l0 = (float *) mymalloc(lMax * sizeof(float));
887   l1 = (float *) mymalloc(lMax * sizeof(float));
888   
889   for (j=0; j<jEnd; j++) {
890     OldLocation = ((float) j) / Value;
891     T = (int) (OldLocation);
892     F = OldLocation - (float) T;
893     
894     for (l = 0; l < lMax; l++) {
895       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
896       l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
897     }
898     
899     if (Axis== XAXIS) {
900       
901       for (i=0; i<iEnd; i++) {
902         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
903         for (l=0; l < lMax; l++) {
904           i_gpix(im,T+l+1, i, &val1);
905           i_gpix(im,T-lMax+l+1, i, &val2);
906           for (k=0; k<im->channels; k++) {
907             PictureValue[k] += l1[l] * val1.channel[k];
908             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
909           }
910         }
911         for(k=0;k<im->channels;k++) {
912           psave = (short)( PictureValue[k] / LanczosWidthFactor);
913           val.channel[k]=minmax(0,255,psave);
914         }
915         i_ppix(new_img,j,i,&val);
916       }
917       
918     } else {
919       
920       for (i=0; i<iEnd; i++) {
921         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
922         for (l=0; l < lMax; l++) {
923           i_gpix(im,i, T+l+1, &val1);
924           i_gpix(im,i, T-lMax+l+1, &val2);
925           for (k=0; k<im->channels; k++) {
926             PictureValue[k] += l1[l] * val1.channel[k];
927             PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
928           }
929         }
930         for (k=0; k<im->channels; k++) {
931           psave = (short)( PictureValue[k] / LanczosWidthFactor);
932           val.channel[k]=minmax(0,255,psave);
933         }
934         i_ppix(new_img,i,j,&val);
935       }
936       
937     }
938   }
939   myfree(l0);
940   myfree(l1);
941
942   mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
943
944   return new_img;
945 }
946
947
948 /* 
949 =item i_scale_nn(im, scx, scy)
950
951 Scale by using nearest neighbor 
952 Both axes scaled at the same time since 
953 nothing is gained by doing it in two steps 
954
955 =cut
956 */
957
958
959 i_img*
960 i_scale_nn(i_img *im, float scx, float scy) {
961
962   int nxsize,nysize,nx,ny;
963   i_img *new_img;
964   i_color val;
965
966   mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
967
968   nxsize = (int) ((float) im->xsize * scx);
969   nysize = (int) ((float) im->ysize * scy);
970     
971   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
972   
973   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
974     i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
975     i_ppix(new_img,nx,ny,&val);
976   }
977
978   mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
979
980   return new_img;
981 }
982
983
984 /*
985 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
986
987 Spatially transforms I<im> returning a new image.
988
989 opx for a length of opxl and opy for a length of opy are arrays of
990 operators that modify the x and y positions to retreive the pixel data from.
991
992 parm and parmlen define extra parameters that the operators may use.
993
994 Note that this function is largely superseded by the more flexible
995 L<transform.c/i_transform2>.
996
997 Returns the new image.
998
999 The operators for this function are defined in L<stackmach.c>.
1000
1001 =cut
1002 */
1003 i_img*
1004 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1005   double rx,ry;
1006   int nxsize,nysize,nx,ny;
1007   i_img *new_img;
1008   i_color val;
1009   
1010   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));
1011
1012   nxsize = im->xsize;
1013   nysize = im->ysize ;
1014   
1015   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1016   /*   fprintf(stderr,"parm[2]=%f\n",parm[2]);   */
1017   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1018     /*     parm[parmlen-2]=(double)nx;
1019            parm[parmlen-1]=(double)ny; */
1020
1021     parm[0]=(double)nx;
1022     parm[1]=(double)ny;
1023
1024     /*     fprintf(stderr,"(%d,%d) ->",nx,ny);  */
1025     rx=op_run(opx,opxl,parm,parmlen);
1026     ry=op_run(opy,opyl,parm,parmlen);
1027     /*    fprintf(stderr,"(%f,%f)\n",rx,ry); */
1028     i_gpix(im,rx,ry,&val);
1029     i_ppix(new_img,nx,ny,&val);
1030   }
1031
1032   mm_log((1,"(0x%x) <- i_transform\n",new_img));
1033   return new_img;
1034 }
1035
1036 /*
1037 =item i_img_diff(im1, im2)
1038
1039 Calculates the sum of the squares of the differences between
1040 correspoding channels in two images.
1041
1042 If the images are not the same size then only the common area is 
1043 compared, hence even if images are different sizes this function 
1044 can return zero.
1045
1046 =cut
1047 */
1048 float
1049 i_img_diff(i_img *im1,i_img *im2) {
1050   int x,y,ch,xb,yb,chb;
1051   float tdiff;
1052   i_color val1,val2;
1053
1054   mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1055
1056   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1057   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1058   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1059
1060   mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1061
1062   tdiff=0;
1063   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1064     i_gpix(im1,x,y,&val1);
1065     i_gpix(im2,x,y,&val2);
1066
1067     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1068   }
1069   mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1070   return tdiff;
1071 }
1072
1073 /* just a tiny demo of haar wavelets */
1074
1075 i_img*
1076 i_haar(i_img *im) {
1077   int mx,my;
1078   int fx,fy;
1079   int x,y;
1080   int ch,c;
1081   i_img *new_img,*new_img2;
1082   i_color val1,val2,dval1,dval2;
1083   
1084   mx=im->xsize;
1085   my=im->ysize;
1086   fx=(mx+1)/2;
1087   fy=(my+1)/2;
1088
1089
1090   /* horizontal pass */
1091   
1092   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1093   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1094
1095   c=0; 
1096   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1097     i_gpix(im,x*2,y,&val1);
1098     i_gpix(im,x*2+1,y,&val2);
1099     for(ch=0;ch<im->channels;ch++) {
1100       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1101       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1102     }
1103     i_ppix(new_img,x,y,&dval1);
1104     i_ppix(new_img,x+fx,y,&dval2);
1105   }
1106
1107   for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1108     i_gpix(new_img,x,y*2,&val1);
1109     i_gpix(new_img,x,y*2+1,&val2);
1110     for(ch=0;ch<im->channels;ch++) {
1111       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1112       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1113     }
1114     i_ppix(new_img2,x,y,&dval1);
1115     i_ppix(new_img2,x,y+fy,&dval2);
1116   }
1117
1118   i_img_destroy(new_img);
1119   return new_img2;
1120 }
1121
1122 /* 
1123 =item i_count_colors(im, maxc)
1124
1125 returns number of colors or -1 
1126 to indicate that it was more than max colors
1127
1128 =cut
1129 */
1130 int
1131 i_count_colors(i_img *im,int maxc) {
1132   struct octt *ct;
1133   int x,y;
1134   int xsize,ysize;
1135   i_color val;
1136   int colorcnt;
1137
1138   mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1139
1140   xsize=im->xsize; 
1141   ysize=im->ysize;
1142   ct=octt_new();
1143  
1144   colorcnt=0;
1145   for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1146     i_gpix(im,x,y,&val);
1147     colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1148     if (colorcnt > maxc) { octt_delete(ct); return -1; }
1149   }
1150   octt_delete(ct);
1151   return colorcnt;
1152 }
1153
1154
1155 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1156                              i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1157                              i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1158                              i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1159
1160
1161 /*
1162 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1163
1164 Performs general read buffering for file readers that permit reading
1165 to be done through a callback.
1166
1167 The final callback gets two parameters, a I<need> value, and a I<want>
1168 value, where I<need> is the amount of data that the file library needs
1169 to read, and I<want> is the amount of space available in the buffer
1170 maintained by these functions.
1171
1172 This means if you need to read from a stream that you don't know the
1173 length of, you can return I<need> bytes, taking the performance hit of
1174 possibly expensive callbacks (eg. back to perl code), or if you are
1175 reading from a stream where it doesn't matter if some data is lost, or
1176 if the total length of the stream is known, you can return I<want>
1177 bytes.
1178
1179 =cut 
1180 */
1181
1182 int
1183 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1184   int total;
1185
1186   if (length < gci->length - gci->cpos) {
1187     /* simplest case */
1188     memcpy(buf, gci->buffer+gci->cpos, length);
1189     gci->cpos += length;
1190     return length;
1191   }
1192   
1193   total = 0;
1194   memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1195   total  += gci->length - gci->cpos;
1196   length -= gci->length - gci->cpos;
1197   buf    += gci->length - gci->cpos;
1198   if (length < (int)sizeof(gci->buffer)) {
1199     int did_read;
1200     int copy_size;
1201     while (length
1202            && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
1203                                     sizeof(gci->buffer))) > 0) {
1204       gci->cpos = 0;
1205       gci->length = did_read;
1206
1207       copy_size = min(length, gci->length);
1208       memcpy(buf, gci->buffer, copy_size);
1209       gci->cpos += copy_size;
1210       buf += copy_size;
1211       total += copy_size;
1212       length -= copy_size;
1213     }
1214   }
1215   else {
1216     /* just read the rest - too big for our buffer*/
1217     int did_read;
1218     while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1219       length -= did_read;
1220       total += did_read;
1221       buf += did_read;
1222     }
1223   }
1224   return total;
1225 }
1226
1227 /*
1228 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1229
1230 For use by callback file readers to initialize the reader buffer.
1231
1232 Allocates, initializes and returns the reader buffer.
1233
1234 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1235
1236 =cut
1237 */
1238 i_gen_read_data *
1239 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1240   i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1241   self->cb = cb;
1242   self->userdata = userdata;
1243   self->length = 0;
1244   self->cpos = 0;
1245
1246   return self;
1247 }
1248
1249 /*
1250 =item free_gen_read_data(i_gen_read_data *)
1251
1252 Cleans up.
1253
1254 =cut
1255 */
1256 void free_gen_read_data(i_gen_read_data *self) {
1257   myfree(self);
1258 }
1259
1260 /*
1261 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1262
1263 Performs write buffering for a callback based file writer.
1264
1265 Failures are considered fatal, if a write fails then data will be
1266 dropped.
1267
1268 =cut
1269 */
1270 int 
1271 i_gen_writer(
1272 i_gen_write_data *self, 
1273 char const *data, 
1274 int size)
1275 {
1276   if (self->filledto && self->filledto+size > self->maxlength) {
1277     if (self->cb(self->userdata, self->buffer, self->filledto)) {
1278       self->filledto = 0;
1279     }
1280     else {
1281       self->filledto = 0;
1282       return 0;
1283     }
1284   }
1285   if (self->filledto+size <= self->maxlength) {
1286     /* just save it */
1287     memcpy(self->buffer+self->filledto, data, size);
1288     self->filledto += size;
1289     return 1;
1290   }
1291   /* doesn't fit - hand it off */
1292   return self->cb(self->userdata, data, size);
1293 }
1294
1295 /*
1296 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1297
1298 Allocates and initializes the data structure used by i_gen_writer.
1299
1300 This should be released with L<image.c/free_gen_write_data>
1301
1302 =cut
1303 */
1304 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
1305                                        char *userdata, int max_length)
1306 {
1307   i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1308   self->cb = cb;
1309   self->userdata = userdata;
1310   self->maxlength = min(max_length, sizeof(self->buffer));
1311   if (self->maxlength < 0)
1312     self->maxlength = sizeof(self->buffer);
1313   self->filledto = 0;
1314
1315   return self;
1316 }
1317
1318 /*
1319 =item free_gen_write_data(i_gen_write_data *info, int flush)
1320
1321 Cleans up the write buffer.
1322
1323 Will flush any left-over data if I<flush> is non-zero.
1324
1325 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1326
1327 Return zero only if flush is non-zero and info->cb() returns zero.
1328 ie. if it fails.
1329
1330 =cut
1331 */
1332
1333 int free_gen_write_data(i_gen_write_data *info, int flush)
1334 {
1335   int result = !flush || 
1336     info->filledto == 0 ||
1337     info->cb(info->userdata, info->buffer, info->filledto);
1338   myfree(info);
1339
1340   return result;
1341 }
1342
1343 /*
1344 =back
1345
1346 =head1 SEE ALSO
1347
1348 L<Imager>, L<gif.c>
1349
1350 =cut
1351 */