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