Initial revision
[imager.git] / image.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2#include "io.h"
3
4/*
5=head1 NAME
6
7image.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
21image.c implements the basic functions to create and destroy image and
22color objects for Imager.
23
24=head1 FUNCTION REFERENCE
25
26Some 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 */
39void fake() { ceil(1); }
40
41/*
42=item ICL_new_internal(r, g, b, a)
43
44Return 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
54i_color *
55ICL_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
84i_color *
85ICL_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
102Add 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
111void
112ICL_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
123Dump color information to log - strictly for debugging.
124
125 cl - pointer to color object
126
127=cut
128*/
129
130void
131ICL_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
139Destroy ancillary data for Color object.
140
141 cl - pointer to color object
142
143=cut
144*/
145
146void
147ICL_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
155Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
156
157=cut
158*/
159
160
161i_img *
162IIM_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
173void
174IIM_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
184Create new image reference - notice that this isn't an object yet and
185this should be fixed asap.
186
187=cut
188*/
189
190
191i_img *
192i_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
217Re-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
226i_img *
227i_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
252Re-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
262i_img *
263i_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
288Free image data.
289
290 im - Image pointer
291
292=cut
293*/
294
295void
296i_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
312Destroy image and free data via exorcise.
313
314 im - Image pointer
315
316=cut
317*/
318
319void
320i_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
329Return image information
330
331 im - Image pointer
332 info - pointer to array to return data
333
334info 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
345void
346i_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
366Set the image channel mask for I<im> to I<ch_mask>.
367
368=cut
369*/
370void
371i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
372
373
374/*
375=item i_img_getmask(im)
376
377Get the image channel mask for I<im>.
378
379=cut
380*/
381int
382i_img_getmask(i_img *im) { return im->ch_mask; }
383
384/*
385=item i_img_getchannels(im)
386
387Get the number of channels in I<im>.
388
389=cut
390*/
391int
392i_img_getchannels(i_img *im) { return im->channels; }
393
394
395/*
396=item i_ppix(im, x, y, col)
397
398Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
399
400Returns true if the pixel could be set, false if x or y is out of
401range.
402
403=cut
404*/
405int
406i_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
411Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
412
413Returns true if the pixel could be retrieved, false otherwise.
414
415=cut
416*/
417int
418i_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
423Internal function.
424
425This is the function kept in the i_f_ppix member of an i_img object.
426It does a normal store of a pixel into the image with range checking.
427
428Returns true if the pixel could be set, false otherwise.
429
430=cut
431*/
432int
433i_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
448Internal function.
449
450This is the function kept in the i_f_gpix member of an i_img object.
451It does normal retrieval of a pixel from the image with range checking.
452
453Returns true if the pixel could be set, false otherwise.
454
455=cut
456*/
457int
458i_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
471Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
472scaled to [0,1].
473
474Returns zero if x or y is out of range.
475
476Warning: this ignores the vptr interface for images.
477
478=cut
479*/
480float
481i_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.
492pass NULL in trans for non transparent i_colors.
493
494=cut
495*/
496
497void
498i_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
529Copies image data from the area (x1,y1)-[x2,y2] in the source image to
530a rectangle the same size with it's top-left corner at (tx,ty) in the
531destination image.
532
533If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
534
535=cut
536*/
537
538void
539i_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
563Copies the contents of the image I<src> over the image I<im>.
564
565=cut
566*/
567
568void
569i_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
589Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
590
591The alpha channel of each pixel in I<src> is used to control how much
592the existing colour in I<im> is replaced, if it is 255 then the colour
593is completely replaced, if it is 0 then the original colour is left
594unmodified.
595
596=cut
597*/
598void
599i_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
627float
628Lanczos(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
642Returns a new image object which is I<im> scaled by I<value> along
643wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
644
645=cut
646*/
647
648i_img*
649i_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
753Scale by using nearest neighbor
754Both axes scaled at the same time since
755nothing is gained by doing it in two steps
756
757=cut
758*/
759
760
761i_img*
762i_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
789Spatially transforms I<im> returning a new image.
790
791opx for a length of opxl and opy for a length of opy are arrays of
792operators that modify the x and y positions to retreive the pixel data from.
793
794parm and parmlen define extra parameters that the operators may use.
795
796Note that this function is largely superseded by the more flexible
797L<transform.c/i_transform2>.
798
799Returns the new image.
800
801The operators for this function are defined in L<stackmach.c>.
802
803=cut
804*/
805i_img*
806i_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
841Calculates the sum of the squares of the differences between
842correspoding channels in two images.
843
844If the images are not the same size then only the common area is
845compared, hence even if images are different sizes this function
846can return zero.
847
848=cut
849*/
850float
851i_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
877i_img*
878i_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
927returns number of colors or -1
928to indicate that it was more than max colors
929
930=cut
931*/
932int
933i_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
957symbol_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
966Performs general read buffering for file readers that permit reading
967to be done through a callback.
968
969The final callback gets two parameters, a I<need> value, and a I<want>
970value, where I<need> is the amount of data that the file library needs
971to read, and I<want> is the amount of space available in the buffer
972maintained by these functions.
973
974This means if you need to read from a stream that you don't know the
975length of, you can return I<need> bytes, taking the performance hit of
976possibly expensive callbacks (eg. back to perl code), or if you are
977reading from a stream where it doesn't matter if some data is lost, or
978if the total length of the stream is known, you can return I<want>
979bytes.
980
981=cut
982*/
983
984int
985i_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
1032For use by callback file readers to initialize the reader buffer.
1033
1034Allocates, initializes and returns the reader buffer.
1035
1036See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1037
1038=cut
1039*/
1040i_gen_read_data *
1041i_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
1054Cleans up.
1055
1056=cut
1057*/
1058void 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
1065Performs write buffering for a callback based file writer.
1066
1067Failures are considered fatal, if a write fails then data will be
1068dropped.
1069
1070=cut
1071*/
1072int
1073i_gen_writer(
1074i_gen_write_data *self,
1075char const *data,
1076int 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
1100Allocates and initializes the data structure used by i_gen_writer.
1101
1102This should be released with L<image.c/free_gen_write_data>
1103
1104=cut
1105*/
1106i_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
1123Cleans up the write buffer.
1124
1125Will flush any left-over data if I<flush> is non-zero.
1126
1127Returns non-zero if flush is zero or if info->cb() returns non-zero.
1128
1129Return zero only if flush is non-zero and info->cb() returns zero.
1130ie. if it fails.
1131
1132=cut
1133*/
1134
1135int 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
1150L<Imager>, L<gif.c>
1151
1152=cut
1153*/