oops, forgot to free the memory I allocated
[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 x, ch;
495   int count;
496   int i;
497   unsigned char *data;
498   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
499     if (r > im->xsize)
500       r = im->xsize;
501     data = im->data + (l+y*im->xsize) * im->channels;
502     count = r - l;
503     for (i = 0; i < count; ++i) {
504       for (ch = 0; ch < im->channels; ++ch)
505         vals[i].channel[ch] = *data++;
506     }
507     return count;
508   }
509   else {
510     return 0;
511   }
512 }
513 /*
514 =item i_plin_d(im, l, r, y, vals)
515
516 Writes a line of data into the image, using the pixels at vals.
517
518 The line runs from (l,y) inclusive to (r,y) non-inclusive
519
520 vals should point at (r-l) pixels.
521
522 l should never be less than zero (to avoid confusion about where to
523 get the pixels in vals).
524
525 Returns the number of pixels copied (eg. if r, l or y is out of range)
526
527 =cut */
528 int
529 i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
530   int x, ch;
531   int count;
532   int i;
533   unsigned char *data;
534   if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
535     if (r > im->xsize)
536       r = im->xsize;
537     data = im->data + (l+y*im->xsize) * im->channels;
538     count = r - l;
539     for (i = 0; i < count; ++i) {
540       for (ch = 0; ch < im->channels; ++ch) {
541         if (im->ch_mask & (1 << ch)) 
542           *data = vals[i].channel[ch];
543         ++data;
544       }
545     }
546     return count;
547   }
548   else {
549     return 0;
550   }
551 }
552
553 /*
554 =item i_ppix_pch(im, x, y, ch)
555
556 Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
557 scaled to [0,1].
558
559 Returns zero if x or y is out of range.
560
561 Warning: this ignores the vptr interface for images.
562
563 =cut
564 */
565 float
566 i_gpix_pch(i_img *im,int x,int y,int ch) {
567   if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
568   else return 0;
569 }
570
571
572 /*
573 =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
574
575 (x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
576 (tx,ty) specifies the upper left corner for the target image.
577 pass NULL in trans for non transparent i_colors.
578
579 =cut
580 */
581
582 void
583 i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
584   i_color pv;
585   int x,y,t,ttx,tty,tt,ch;
586
587   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",
588           im, src, x1, y1, x2, y2, tx, ty, trans));
589   
590   if (x2<x1) { t=x1; x1=x2; x2=t; }
591   if (y2<y1) { t=y1; y1=y2; y2=t; }
592
593   ttx=tx;
594   for(x=x1;x<x2;x++)
595     {
596       tty=ty;
597       for(y=y1;y<y2;y++)
598         {
599           i_gpix(src,x,y,&pv);
600           if ( trans != NULL)
601           {
602             tt=0;
603             for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
604             if (tt) i_ppix(im,ttx,tty,&pv);
605           } else i_ppix(im,ttx,tty,&pv);
606           tty++;
607         }
608       ttx++;
609     }
610 }
611
612 /*
613 =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
614
615 Copies image data from the area (x1,y1)-[x2,y2] in the source image to
616 a rectangle the same size with it's top-left corner at (tx,ty) in the
617 destination image.
618
619 If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
620
621 =cut
622 */
623
624 void
625 i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
626   i_color pv;
627   int x, y, t, ttx, tty;
628
629   if (x2<x1) { t=x1; x1=x2; x2=t; }
630   if (y2<y1) { t=y1; y1=y2; y2=t; }
631
632   mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
633           im, src, x1, y1, x2, y2, tx, ty));
634
635     tty = ty;
636     for(y=y1; y<y2; y++) {
637     ttx = tx;
638     for(x=x1; x<x2; x++) {
639       i_gpix(src, x,   y,   &pv);
640       i_ppix(im,  ttx, tty, &pv);
641       ttx++;
642     }
643     tty++;
644   }
645 }
646
647 /*
648 =item i_copy(im, src)
649
650 Copies the contents of the image I<src> over the image I<im>.
651
652 =cut
653 */
654
655 void
656 i_copy(i_img *im, i_img *src) {
657   i_color *pv;
658   int x,y,y1,x1;
659
660   mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
661
662   x1 = src->xsize;
663   y1 = src->ysize;
664   i_img_empty_ch(im, x1, y1, src->channels);
665   pv = mymalloc(sizeof(i_color) * x1);
666   
667   for (y = 0; y < y1; ++y) {
668     i_glin(src, 0, x1, y, pv);
669     i_plin(im, 0, x1, y, pv);
670   }
671   myfree(pv);
672 }
673
674
675 /*
676 =item i_rubthru(im, src, tx, ty)
677
678 Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
679
680 The alpha channel of each pixel in I<src> is used to control how much
681 the existing colour in I<im> is replaced, if it is 255 then the colour
682 is completely replaced, if it is 0 then the original colour is left 
683 unmodified.
684
685 =cut
686 */
687
688 void
689 i_rubthru(i_img *im,i_img *src,int tx,int ty) {
690   i_color pv, orig, dest;
691   int x, y, ttx, tty;
692
693   mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
694
695   if (im->channels  != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
696   if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
697
698   ttx = tx;
699   for(x=0; x<src->xsize; x++) {
700     tty=ty;
701     for(y=0;y<src->ysize;y++) {
702       /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
703       i_gpix(src, x,   y,   &pv);
704       i_gpix(im,  ttx, tty, &orig);
705       dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
706       dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
707       dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
708       i_ppix(im, ttx, tty, &dest);
709       tty++;
710     }
711     ttx++;
712   }
713 }
714
715
716 /*
717 =item i_flipxy(im, axis)
718
719 Flips the image inplace around the axis specified.
720 Returns 0 if parameters are invalid.
721
722    im   - Image pointer
723    axis - 0 = x, 1 = y, 2 = both
724
725 =cut
726 */
727
728 undef_int
729 i_flipxy(i_img *im, int direction) {
730   int x, x2, y, y2, xm, ym;
731   int xs = im->xsize;
732   int ys = im->ysize;
733   
734   mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
735
736   if (!im) return 0;
737
738   switch (direction) {
739   case XAXIS: /* Horizontal flip */
740     xm = xs/2;
741     ym = ys;
742     for(y=0; y<ym; y++) {
743       x2 = xs-1;
744       for(x=0; x<xm; x++) {
745         i_color val1, val2;
746         i_gpix(im, x,  y,  &val1);
747         i_gpix(im, x2, y,  &val2);
748         i_ppix(im, x,  y,  &val2);
749         i_ppix(im, x2, y,  &val1);
750         x2--;
751       }
752     }
753     break;
754   case YAXIS: /* Vertical flip */
755     xm = xs;
756     ym = ys/2;
757     y2 = ys-1;
758     for(y=0; y<ym; y++) {
759       for(x=0; x<xm; x++) {
760         i_color val1, val2;
761         i_gpix(im, x,  y,  &val1);
762         i_gpix(im, x,  y2, &val2);
763         i_ppix(im, x,  y,  &val2);
764         i_ppix(im, x,  y2, &val1);
765       }
766       y2--;
767     }
768     break;
769   case XYAXIS: /* Horizontal and Vertical flip */
770     xm = xs/2;
771     ym = ys/2;
772     y2 = ys-1;
773     for(y=0; y<ym; y++) {
774       x2 = xs-1;
775       for(x=0; x<xm; x++) {
776         i_color val1, val2;
777         i_gpix(im, x,  y,  &val1);
778         i_gpix(im, x2, y2, &val2);
779         i_ppix(im, x,  y,  &val2);
780         i_ppix(im, x2, y2, &val1);
781
782         i_gpix(im, x2, y,  &val1);
783         i_gpix(im, x,  y2, &val2);
784         i_ppix(im, x2, y,  &val2);
785         i_ppix(im, x,  y2, &val1);
786         x2--;
787       }
788       y2--;
789     }
790     if (xm*2 != xs) { /* odd number of column */
791       mm_log((1, "i_flipxy: odd number of columns\n"));
792       x = xm;
793       y2 = ys-1;
794       for(y=0; y<ym; y++) {
795         i_color val1, val2;
796         i_gpix(im, x,  y,  &val1);
797         i_gpix(im, x,  y2, &val2);
798         i_ppix(im, x,  y,  &val2);
799         i_ppix(im, x,  y2, &val1);
800         y2--;
801       }
802     }
803     if (ym*2 != ys) { /* odd number of rows */
804       mm_log((1, "i_flipxy: odd number of rows\n"));
805       y = ym;
806       x2 = xs-1;
807       for(x=0; x<xm; x++) {
808         i_color val1, val2;
809         i_gpix(im, x,  y,  &val1);
810         i_gpix(im, x2, y,  &val2);
811         i_ppix(im, x,  y,  &val2);
812         i_ppix(im, x2, y,  &val1);
813         x2--;
814       }
815     }
816     break;
817   default:
818     mm_log((1, "i_flipxy: direction is invalid\n" ));
819     return 0;
820   }
821   return 1;
822 }
823
824
825
826
827
828 static
829 float
830 Lanczos(float x) {
831   float PIx, PIx2;
832   
833   PIx = PI * x;
834   PIx2 = PIx / 2.0;
835   
836   if ((x >= 2.0) || (x <= -2.0)) return (0.0);
837   else if (x == 0.0) return (1.0);
838   else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
839 }
840
841 /*
842 =item i_scaleaxis(im, value, axis)
843
844 Returns a new image object which is I<im> scaled by I<value> along
845 wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
846
847 =cut
848 */
849
850 i_img*
851 i_scaleaxis(i_img *im, float Value, int Axis) {
852   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
853   int LanczosWidthFactor;
854   float *l0, *l1, OldLocation;
855   int T, TempJump1, TempJump2;
856   float F, PictureValue[MAXCHANNELS];
857   short psave;
858   i_color val,val1,val2;
859   i_img *new_img;
860
861   mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
862
863   if (Axis == XAXIS) {
864     hsize = (int) ((float) im->xsize * Value);
865     vsize = im->ysize;
866     
867     jEnd = hsize;
868     iEnd = vsize;
869     
870     TempJump1 = (hsize - 1) * 3;
871     TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
872   } else {
873     hsize = im->xsize;
874     vsize = (int) ((float) im->ysize * Value);
875     
876     jEnd = vsize;
877     iEnd = hsize;
878     
879     TempJump1 = 0;
880     TempJump2 = 0;
881   }
882   
883   new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
884   
885   if (Value >=1) LanczosWidthFactor = 1;
886   else LanczosWidthFactor = (int) (1.0/Value);
887   
888   lMax = LanczosWidthFactor << 1;
889   
890   l0 = (float *) mymalloc(lMax * sizeof(float));
891   l1 = (float *) mymalloc(lMax * sizeof(float));
892   
893   for (j=0; j<jEnd; j++) {
894     OldLocation = ((float) j) / Value;
895     T = (int) (OldLocation);
896     F = OldLocation - (float) T;
897     
898     for (l = 0; l < lMax; l++) {
899       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
900       l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
901     }
902     
903     if (Axis== XAXIS) {
904       
905       for (i=0; i<iEnd; i++) {
906         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
907         for (l=0; l < lMax; l++) {
908           i_gpix(im,T+l+1, i, &val1);
909           i_gpix(im,T-lMax+l+1, i, &val2);
910           for (k=0; k<im->channels; k++) {
911             PictureValue[k] += l1[l] * val1.channel[k];
912             PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
913           }
914         }
915         for(k=0;k<im->channels;k++) {
916           psave = (short)( PictureValue[k] / LanczosWidthFactor);
917           val.channel[k]=minmax(0,255,psave);
918         }
919         i_ppix(new_img,j,i,&val);
920       }
921       
922     } else {
923       
924       for (i=0; i<iEnd; i++) {
925         for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
926         for (l=0; l < lMax; l++) {
927           i_gpix(im,i, T+l+1, &val1);
928           i_gpix(im,i, T-lMax+l+1, &val2);
929           for (k=0; k<im->channels; k++) {
930             PictureValue[k] += l1[l] * val1.channel[k];
931             PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
932           }
933         }
934         for (k=0; k<im->channels; k++) {
935           psave = (short)( PictureValue[k] / LanczosWidthFactor);
936           val.channel[k]=minmax(0,255,psave);
937         }
938         i_ppix(new_img,i,j,&val);
939       }
940       
941     }
942   }
943   myfree(l0);
944   myfree(l1);
945
946   mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
947
948   return new_img;
949 }
950
951
952 /* 
953 =item i_scale_nn(im, scx, scy)
954
955 Scale by using nearest neighbor 
956 Both axes scaled at the same time since 
957 nothing is gained by doing it in two steps 
958
959 =cut
960 */
961
962
963 i_img*
964 i_scale_nn(i_img *im, float scx, float scy) {
965
966   int nxsize,nysize,nx,ny;
967   i_img *new_img;
968   i_color val;
969
970   mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
971
972   nxsize = (int) ((float) im->xsize * scx);
973   nysize = (int) ((float) im->ysize * scy);
974     
975   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
976   
977   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
978     i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
979     i_ppix(new_img,nx,ny,&val);
980   }
981
982   mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
983
984   return new_img;
985 }
986
987
988 /*
989 =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
990
991 Spatially transforms I<im> returning a new image.
992
993 opx for a length of opxl and opy for a length of opy are arrays of
994 operators that modify the x and y positions to retreive the pixel data from.
995
996 parm and parmlen define extra parameters that the operators may use.
997
998 Note that this function is largely superseded by the more flexible
999 L<transform.c/i_transform2>.
1000
1001 Returns the new image.
1002
1003 The operators for this function are defined in L<stackmach.c>.
1004
1005 =cut
1006 */
1007 i_img*
1008 i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1009   double rx,ry;
1010   int nxsize,nysize,nx,ny;
1011   i_img *new_img;
1012   i_color val;
1013   
1014   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));
1015
1016   nxsize = im->xsize;
1017   nysize = im->ysize ;
1018   
1019   new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1020   /*   fprintf(stderr,"parm[2]=%f\n",parm[2]);   */
1021   for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1022     /*     parm[parmlen-2]=(double)nx;
1023            parm[parmlen-1]=(double)ny; */
1024
1025     parm[0]=(double)nx;
1026     parm[1]=(double)ny;
1027
1028     /*     fprintf(stderr,"(%d,%d) ->",nx,ny);  */
1029     rx=op_run(opx,opxl,parm,parmlen);
1030     ry=op_run(opy,opyl,parm,parmlen);
1031     /*    fprintf(stderr,"(%f,%f)\n",rx,ry); */
1032     i_gpix(im,rx,ry,&val);
1033     i_ppix(new_img,nx,ny,&val);
1034   }
1035
1036   mm_log((1,"(0x%x) <- i_transform\n",new_img));
1037   return new_img;
1038 }
1039
1040 /*
1041 =item i_img_diff(im1, im2)
1042
1043 Calculates the sum of the squares of the differences between
1044 correspoding channels in two images.
1045
1046 If the images are not the same size then only the common area is 
1047 compared, hence even if images are different sizes this function 
1048 can return zero.
1049
1050 =cut
1051 */
1052 float
1053 i_img_diff(i_img *im1,i_img *im2) {
1054   int x,y,ch,xb,yb,chb;
1055   float tdiff;
1056   i_color val1,val2;
1057
1058   mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1059
1060   xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1061   yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1062   chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1063
1064   mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1065
1066   tdiff=0;
1067   for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1068     i_gpix(im1,x,y,&val1);
1069     i_gpix(im2,x,y,&val2);
1070
1071     for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1072   }
1073   mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1074   return tdiff;
1075 }
1076
1077 /* just a tiny demo of haar wavelets */
1078
1079 i_img*
1080 i_haar(i_img *im) {
1081   int mx,my;
1082   int fx,fy;
1083   int x,y;
1084   int ch,c;
1085   i_img *new_img,*new_img2;
1086   i_color val1,val2,dval1,dval2;
1087   
1088   mx=im->xsize;
1089   my=im->ysize;
1090   fx=(mx+1)/2;
1091   fy=(my+1)/2;
1092
1093
1094   /* horizontal pass */
1095   
1096   new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1097   new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1098
1099   c=0; 
1100   for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1101     i_gpix(im,x*2,y,&val1);
1102     i_gpix(im,x*2+1,y,&val2);
1103     for(ch=0;ch<im->channels;ch++) {
1104       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1105       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1106     }
1107     i_ppix(new_img,x,y,&dval1);
1108     i_ppix(new_img,x+fx,y,&dval2);
1109   }
1110
1111   for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1112     i_gpix(new_img,x,y*2,&val1);
1113     i_gpix(new_img,x,y*2+1,&val2);
1114     for(ch=0;ch<im->channels;ch++) {
1115       dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1116       dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1117     }
1118     i_ppix(new_img2,x,y,&dval1);
1119     i_ppix(new_img2,x,y+fy,&dval2);
1120   }
1121
1122   i_img_destroy(new_img);
1123   return new_img2;
1124 }
1125
1126 /* 
1127 =item i_count_colors(im, maxc)
1128
1129 returns number of colors or -1 
1130 to indicate that it was more than max colors
1131
1132 =cut
1133 */
1134 int
1135 i_count_colors(i_img *im,int maxc) {
1136   struct octt *ct;
1137   int x,y;
1138   int xsize,ysize;
1139   i_color val;
1140   int colorcnt;
1141
1142   mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1143
1144   xsize=im->xsize; 
1145   ysize=im->ysize;
1146   ct=octt_new();
1147  
1148   colorcnt=0;
1149   for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1150     i_gpix(im,x,y,&val);
1151     colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1152     if (colorcnt > maxc) { octt_delete(ct); return -1; }
1153   }
1154   octt_delete(ct);
1155   return colorcnt;
1156 }
1157
1158
1159 symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1160                              i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1161                              i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1162                              i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1163
1164
1165 /*
1166 =item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1167
1168 Performs general read buffering for file readers that permit reading
1169 to be done through a callback.
1170
1171 The final callback gets two parameters, a I<need> value, and a I<want>
1172 value, where I<need> is the amount of data that the file library needs
1173 to read, and I<want> is the amount of space available in the buffer
1174 maintained by these functions.
1175
1176 This means if you need to read from a stream that you don't know the
1177 length of, you can return I<need> bytes, taking the performance hit of
1178 possibly expensive callbacks (eg. back to perl code), or if you are
1179 reading from a stream where it doesn't matter if some data is lost, or
1180 if the total length of the stream is known, you can return I<want>
1181 bytes.
1182
1183 =cut 
1184 */
1185
1186 int
1187 i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1188   int total;
1189
1190   if (length < gci->length - gci->cpos) {
1191     /* simplest case */
1192     memcpy(buf, gci->buffer+gci->cpos, length);
1193     gci->cpos += length;
1194     return length;
1195   }
1196   
1197   total = 0;
1198   memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1199   total  += gci->length - gci->cpos;
1200   length -= gci->length - gci->cpos;
1201   buf    += gci->length - gci->cpos;
1202   if (length < (int)sizeof(gci->buffer)) {
1203     int did_read;
1204     int copy_size;
1205     while (length
1206            && (did_read = (gci->cb)(gci->userdata, gci->buffer, length, 
1207                                     sizeof(gci->buffer))) > 0) {
1208       gci->cpos = 0;
1209       gci->length = did_read;
1210
1211       copy_size = min(length, gci->length);
1212       memcpy(buf, gci->buffer, copy_size);
1213       gci->cpos += copy_size;
1214       buf += copy_size;
1215       total += copy_size;
1216       length -= copy_size;
1217     }
1218   }
1219   else {
1220     /* just read the rest - too big for our buffer*/
1221     int did_read;
1222     while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1223       length -= did_read;
1224       total += did_read;
1225       buf += did_read;
1226     }
1227   }
1228   return total;
1229 }
1230
1231 /*
1232 =item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1233
1234 For use by callback file readers to initialize the reader buffer.
1235
1236 Allocates, initializes and returns the reader buffer.
1237
1238 See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1239
1240 =cut
1241 */
1242 i_gen_read_data *
1243 i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1244   i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1245   self->cb = cb;
1246   self->userdata = userdata;
1247   self->length = 0;
1248   self->cpos = 0;
1249
1250   return self;
1251 }
1252
1253 /*
1254 =item free_gen_read_data(i_gen_read_data *)
1255
1256 Cleans up.
1257
1258 =cut
1259 */
1260 void free_gen_read_data(i_gen_read_data *self) {
1261   myfree(self);
1262 }
1263
1264 /*
1265 =item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1266
1267 Performs write buffering for a callback based file writer.
1268
1269 Failures are considered fatal, if a write fails then data will be
1270 dropped.
1271
1272 =cut
1273 */
1274 int 
1275 i_gen_writer(
1276 i_gen_write_data *self, 
1277 char const *data, 
1278 int size)
1279 {
1280   if (self->filledto && self->filledto+size > self->maxlength) {
1281     if (self->cb(self->userdata, self->buffer, self->filledto)) {
1282       self->filledto = 0;
1283     }
1284     else {
1285       self->filledto = 0;
1286       return 0;
1287     }
1288   }
1289   if (self->filledto+size <= self->maxlength) {
1290     /* just save it */
1291     memcpy(self->buffer+self->filledto, data, size);
1292     self->filledto += size;
1293     return 1;
1294   }
1295   /* doesn't fit - hand it off */
1296   return self->cb(self->userdata, data, size);
1297 }
1298
1299 /*
1300 =item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1301
1302 Allocates and initializes the data structure used by i_gen_writer.
1303
1304 This should be released with L<image.c/free_gen_write_data>
1305
1306 =cut
1307 */
1308 i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, 
1309                                        char *userdata, int max_length)
1310 {
1311   i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1312   self->cb = cb;
1313   self->userdata = userdata;
1314   self->maxlength = min(max_length, sizeof(self->buffer));
1315   if (self->maxlength < 0)
1316     self->maxlength = sizeof(self->buffer);
1317   self->filledto = 0;
1318
1319   return self;
1320 }
1321
1322 /*
1323 =item free_gen_write_data(i_gen_write_data *info, int flush)
1324
1325 Cleans up the write buffer.
1326
1327 Will flush any left-over data if I<flush> is non-zero.
1328
1329 Returns non-zero if flush is zero or if info->cb() returns non-zero.
1330
1331 Return zero only if flush is non-zero and info->cb() returns zero.
1332 ie. if it fails.
1333
1334 =cut
1335 */
1336
1337 int free_gen_write_data(i_gen_write_data *info, int flush)
1338 {
1339   int result = !flush || 
1340     info->filledto == 0 ||
1341     info->cb(info->userdata, info->buffer, info->filledto);
1342   myfree(info);
1343
1344   return result;
1345 }
1346
1347 /*
1348 =back
1349
1350 =head1 SEE ALSO
1351
1352 L<Imager>, L<gif.c>
1353
1354 =cut
1355 */