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