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