simple benchmark for image copying
[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) {
4cac9410 57 i_color *cl = NULL;
02d1d628 58
4cac9410 59 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
02d1d628
AMH
60
61 if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
4cac9410
AMH
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));
02d1d628
AMH
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) {
4cac9410 87 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
02d1d628
AMH
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;
4cac9410 95 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
02d1d628
AMH
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) {
4cac9410 133 mm_log((1,"i_color_info(cl* %p)\n",cl));
02d1d628
AMH
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) {
4cac9410 149 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
02d1d628
AMH
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
4cac9410 169 mm_log((1,"(%p) <- IIM_new\n",im));
02d1d628
AMH
170 return im;
171}
172
173
174void
175IIM_DESTROY(i_img *im) {
4cac9410 176 mm_log((1,"IIM_DESTROY(im* %p)\n",im));
02d1d628
AMH
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
4cac9410 211 mm_log((1,"(%p) <- i_img_struct\n",im));
02d1d628
AMH
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) {
4cac9410 229 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
02d1d628
AMH
230 if (im==NULL)
231 if ( (im=mymalloc(sizeof(i_img))) == NULL)
232 m_fatal(2,"malloc() error\n");
233
4cac9410
AMH
234 im->xsize = x;
235 im->ysize = y;
236 im->channels = 3;
237 im->ch_mask = MAXINT;
02d1d628 238 im->bytes=x*y*im->channels;
4cac9410
AMH
239 if ( (im->data = mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
240 memset(im->data, 0, (size_t)im->bytes);
02d1d628 241
4cac9410
AMH
242 im->i_f_ppix = i_ppix_d;
243 im->i_f_gpix = i_gpix_d;
244 im->ext_data = NULL;
02d1d628 245
4cac9410 246 mm_log((1,"(%p) <- i_img_empty\n", im));
02d1d628
AMH
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) {
4cac9410
AMH
265 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
266 if (im == NULL)
02d1d628
AMH
267 if ( (im=mymalloc(sizeof(i_img))) == NULL)
268 m_fatal(2,"malloc() error\n");
269
4cac9410
AMH
270 im->xsize = x;
271 im->ysize = y;
272 im->channels = ch;
273 im->ch_mask = MAXINT;
02d1d628
AMH
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
4cac9410
AMH
278 im->i_f_ppix = i_ppix_d;
279 im->i_f_gpix = i_gpix_d;
280 im->ext_data = NULL;
02d1d628 281
4cac9410 282 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
02d1d628
AMH
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); }
4cac9410
AMH
300 im->data = NULL;
301 im->xsize = 0;
302 im->ysize = 0;
303 im->channels = 0;
02d1d628
AMH
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));
4cac9410
AMH
352 info[0] = im->xsize;
353 info[1] = im->ysize;
354 info[2] = im->channels;
355 info[3] = im->ch_mask;
02d1d628 356 } else {
4cac9410
AMH
357 info[0] = 0;
358 info[1] = 0;
359 info[2] = 0;
360 info[3] = 0;
02d1d628
AMH
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
4cac9410 407i_ppix(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
02d1d628
AMH
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
4cac9410 419i_gpix(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
02d1d628
AMH
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
4cac9410 434i_ppix_d(i_img *im, int x, int y, i_color *val) {
02d1d628
AMH
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
4cac9410 459i_gpix_d(i_img *im, int x, int y, i_color *val) {
02d1d628
AMH
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
4cac9410
AMH
503 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",
504 im, src, x1, y1, x2, y2, tx, ty, trans));
505
02d1d628
AMH
506 if (x2<x1) { t=x1; x1=x2; x2=t; }
507 if (y2<y1) { t=y1; y1=y2; y2=t; }
508
509 ttx=tx;
510 for(x=x1;x<x2;x++)
511 {
512 tty=ty;
513 for(y=y1;y<y2;y++)
514 {
515 i_gpix(src,x,y,&pv);
516 if ( trans != NULL)
517 {
518 tt=0;
519 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
520 if (tt) i_ppix(im,ttx,tty,&pv);
521 } else i_ppix(im,ttx,tty,&pv);
522 tty++;
523 }
524 ttx++;
525 }
526}
527
528/*
529=item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
530
531Copies image data from the area (x1,y1)-[x2,y2] in the source image to
532a rectangle the same size with it's top-left corner at (tx,ty) in the
533destination image.
534
535If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
536
537=cut
538*/
539
540void
4cac9410 541i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
02d1d628 542 i_color pv;
4cac9410 543 int x, y, t, ttx, tty;
02d1d628
AMH
544
545 if (x2<x1) { t=x1; x1=x2; x2=t; }
546 if (y2<y1) { t=y1; y1=y2; y2=t; }
547
4cac9410
AMH
548 mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
549 im, src, x1, y1, x2, y2, tx, ty));
02d1d628 550
4cac9410
AMH
551 tty = ty;
552 for(y=y1; y<y2; y++) {
553 ttx = tx;
554 for(x=x1; x<x2; x++) {
555 i_gpix(src, x, y, &pv);
556 i_ppix(im, ttx, tty, &pv);
557 ttx++;
02d1d628
AMH
558 }
559 tty++;
560 }
561}
562
563/*
564=item i_copy(im, src)
565
566Copies the contents of the image I<src> over the image I<im>.
567
568=cut
569*/
570
571void
4cac9410 572i_copy(i_img *im, i_img *src) {
02d1d628
AMH
573 i_color pv;
574 int x,y,y1,x1;
575
4202e066 576 mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
02d1d628 577
4cac9410
AMH
578 x1 = src->xsize;
579 y1 = src->ysize;
580 i_img_empty_ch(im, x1, y1, src->channels);
02d1d628 581
4cac9410
AMH
582 for(y=0; y<y1; y++) for(x=0; x<x1; x++) {
583 i_gpix(src, x, y, &pv);
584 i_ppix(im, x, y, &pv);
02d1d628
AMH
585 }
586}
587
588
589/*
590=item i_rubthru(im, src, tx, ty)
591
592Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
593
594The alpha channel of each pixel in I<src> is used to control how much
595the existing colour in I<im> is replaced, if it is 255 then the colour
596is completely replaced, if it is 0 then the original colour is left
597unmodified.
598
599=cut
600*/
142c26ff 601
02d1d628
AMH
602void
603i_rubthru(i_img *im,i_img *src,int tx,int ty) {
4cac9410
AMH
604 i_color pv, orig, dest;
605 int x, y, ttx, tty;
02d1d628 606
4cac9410 607 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
02d1d628 608
4cac9410 609 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
02d1d628
AMH
610 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
611
4cac9410
AMH
612 ttx = tx;
613 for(x=0; x<src->xsize; x++) {
614 tty=ty;
615 for(y=0;y<src->ysize;y++) {
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++;
02d1d628 624 }
4cac9410
AMH
625 ttx++;
626 }
02d1d628
AMH
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;
390cd725 668 case YAXIS: /* Vertical flip */
142c26ff
AMH
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;
390cd725 683 case XYAXIS: /* Horizontal and Vertical flip */
142c26ff
AMH
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 }
390cd725
AMH
704 if (xm*2 != xs) { /* odd number of column */
705 mm_log((1, "i_flipxy: odd number of columns\n"));
706 x = xm;
707 y2 = ys-1;
708 for(y=0; y<ym; y++) {
709 i_color val1, val2;
710 i_gpix(im, x, y, &val1);
711 i_gpix(im, x, y2, &val2);
712 i_ppix(im, x, y, &val2);
713 i_ppix(im, x, y2, &val1);
714 y2--;
715 }
716 }
717 if (ym*2 != ys) { /* odd number of rows */
718 mm_log((1, "i_flipxy: odd number of rows\n"));
719 y = ym;
720 x2 = xs-1;
721 for(x=0; x<xm; x++) {
722 i_color val1, val2;
723 i_gpix(im, x, y, &val1);
724 i_gpix(im, x2, y, &val2);
725 i_ppix(im, x, y, &val2);
726 i_ppix(im, x2, y, &val1);
727 x2--;
728 }
729 }
142c26ff
AMH
730 break;
731 default:
732 mm_log((1, "i_flipxy: direction is invalid\n" ));
733 return 0;
734 }
735 return 1;
736}
737
738
739
740
741
742static
02d1d628
AMH
743float
744Lanczos(float x) {
745 float PIx, PIx2;
746
747 PIx = PI * x;
748 PIx2 = PIx / 2.0;
749
750 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
751 else if (x == 0.0) return (1.0);
752 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
753}
754
755/*
756=item i_scaleaxis(im, value, axis)
757
758Returns a new image object which is I<im> scaled by I<value> along
759wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
760
761=cut
762*/
763
764i_img*
765i_scaleaxis(i_img *im, float Value, int Axis) {
766 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
767 int LanczosWidthFactor;
768 float *l0, *l1, OldLocation;
769 int T, TempJump1, TempJump2;
770 float F, PictureValue[MAXCHANNELS];
771 short psave;
772 i_color val,val1,val2;
773 i_img *new_img;
774
775 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
776
777 if (Axis == XAXIS) {
778 hsize = (int) ((float) im->xsize * Value);
779 vsize = im->ysize;
780
781 jEnd = hsize;
782 iEnd = vsize;
783
784 TempJump1 = (hsize - 1) * 3;
785 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
786 } else {
787 hsize = im->xsize;
788 vsize = (int) ((float) im->ysize * Value);
789
790 jEnd = vsize;
791 iEnd = hsize;
792
793 TempJump1 = 0;
794 TempJump2 = 0;
795 }
796
797 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
798
799 if (Value >=1) LanczosWidthFactor = 1;
800 else LanczosWidthFactor = (int) (1.0/Value);
801
802 lMax = LanczosWidthFactor << 1;
803
804 l0 = (float *) mymalloc(lMax * sizeof(float));
805 l1 = (float *) mymalloc(lMax * sizeof(float));
806
807 for (j=0; j<jEnd; j++) {
808 OldLocation = ((float) j) / Value;
809 T = (int) (OldLocation);
810 F = OldLocation - (float) T;
811
812 for (l = 0; l < lMax; l++) {
813 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
814 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
815 }
816
817 if (Axis== XAXIS) {
818
819 for (i=0; i<iEnd; i++) {
820 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
821 for (l=0; l < lMax; l++) {
822 i_gpix(im,T+l+1, i, &val1);
823 i_gpix(im,T-lMax+l+1, i, &val2);
824 for (k=0; k<im->channels; k++) {
825 PictureValue[k] += l1[l] * val1.channel[k];
826 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
827 }
828 }
829 for(k=0;k<im->channels;k++) {
830 psave = (short)( PictureValue[k] / LanczosWidthFactor);
831 val.channel[k]=minmax(0,255,psave);
832 }
833 i_ppix(new_img,j,i,&val);
834 }
835
836 } else {
837
838 for (i=0; i<iEnd; i++) {
839 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
840 for (l=0; l < lMax; l++) {
841 i_gpix(im,i, T+l+1, &val1);
842 i_gpix(im,i, T-lMax+l+1, &val2);
843 for (k=0; k<im->channels; k++) {
844 PictureValue[k] += l1[l] * val1.channel[k];
845 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
846 }
847 }
848 for (k=0; k<im->channels; k++) {
849 psave = (short)( PictureValue[k] / LanczosWidthFactor);
850 val.channel[k]=minmax(0,255,psave);
851 }
852 i_ppix(new_img,i,j,&val);
853 }
854
855 }
856 }
857 myfree(l0);
858 myfree(l1);
859
860 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
861
862 return new_img;
863}
864
865
866/*
867=item i_scale_nn(im, scx, scy)
868
869Scale by using nearest neighbor
870Both axes scaled at the same time since
871nothing is gained by doing it in two steps
872
873=cut
874*/
875
876
877i_img*
878i_scale_nn(i_img *im, float scx, float scy) {
879
880 int nxsize,nysize,nx,ny;
881 i_img *new_img;
882 i_color val;
883
884 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
885
886 nxsize = (int) ((float) im->xsize * scx);
887 nysize = (int) ((float) im->ysize * scy);
888
889 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
890
891 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
892 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
893 i_ppix(new_img,nx,ny,&val);
894 }
895
896 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
897
898 return new_img;
899}
900
901
902/*
903=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
904
905Spatially transforms I<im> returning a new image.
906
907opx for a length of opxl and opy for a length of opy are arrays of
908operators that modify the x and y positions to retreive the pixel data from.
909
910parm and parmlen define extra parameters that the operators may use.
911
912Note that this function is largely superseded by the more flexible
913L<transform.c/i_transform2>.
914
915Returns the new image.
916
917The operators for this function are defined in L<stackmach.c>.
918
919=cut
920*/
921i_img*
922i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
923 double rx,ry;
924 int nxsize,nysize,nx,ny;
925 i_img *new_img;
926 i_color val;
927
928 mm_log((1,"i_transform(im 0x%x, opx 0x%x, opxl %d, opy 0x%x, opyl %d, parm 0x%x, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
929
930 nxsize = im->xsize;
931 nysize = im->ysize ;
932
933 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
934 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
935 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
936 /* parm[parmlen-2]=(double)nx;
937 parm[parmlen-1]=(double)ny; */
938
939 parm[0]=(double)nx;
940 parm[1]=(double)ny;
941
942 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
943 rx=op_run(opx,opxl,parm,parmlen);
944 ry=op_run(opy,opyl,parm,parmlen);
945 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
946 i_gpix(im,rx,ry,&val);
947 i_ppix(new_img,nx,ny,&val);
948 }
949
950 mm_log((1,"(0x%x) <- i_transform\n",new_img));
951 return new_img;
952}
953
954/*
955=item i_img_diff(im1, im2)
956
957Calculates the sum of the squares of the differences between
958correspoding channels in two images.
959
960If the images are not the same size then only the common area is
961compared, hence even if images are different sizes this function
962can return zero.
963
964=cut
965*/
966float
967i_img_diff(i_img *im1,i_img *im2) {
968 int x,y,ch,xb,yb,chb;
969 float tdiff;
970 i_color val1,val2;
971
972 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
973
974 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
975 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
976 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
977
978 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
979
980 tdiff=0;
981 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
982 i_gpix(im1,x,y,&val1);
983 i_gpix(im2,x,y,&val2);
984
985 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
986 }
987 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
988 return tdiff;
989}
990
991/* just a tiny demo of haar wavelets */
992
993i_img*
994i_haar(i_img *im) {
995 int mx,my;
996 int fx,fy;
997 int x,y;
998 int ch,c;
999 i_img *new_img,*new_img2;
1000 i_color val1,val2,dval1,dval2;
1001
1002 mx=im->xsize;
1003 my=im->ysize;
1004 fx=(mx+1)/2;
1005 fy=(my+1)/2;
1006
1007
1008 /* horizontal pass */
1009
1010 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1011 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1012
1013 c=0;
1014 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1015 i_gpix(im,x*2,y,&val1);
1016 i_gpix(im,x*2+1,y,&val2);
1017 for(ch=0;ch<im->channels;ch++) {
1018 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1019 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1020 }
1021 i_ppix(new_img,x,y,&dval1);
1022 i_ppix(new_img,x+fx,y,&dval2);
1023 }
1024
1025 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1026 i_gpix(new_img,x,y*2,&val1);
1027 i_gpix(new_img,x,y*2+1,&val2);
1028 for(ch=0;ch<im->channels;ch++) {
1029 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1030 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1031 }
1032 i_ppix(new_img2,x,y,&dval1);
1033 i_ppix(new_img2,x,y+fy,&dval2);
1034 }
1035
1036 i_img_destroy(new_img);
1037 return new_img2;
1038}
1039
1040/*
1041=item i_count_colors(im, maxc)
1042
1043returns number of colors or -1
1044to indicate that it was more than max colors
1045
1046=cut
1047*/
1048int
1049i_count_colors(i_img *im,int maxc) {
1050 struct octt *ct;
1051 int x,y;
1052 int xsize,ysize;
1053 i_color val;
1054 int colorcnt;
1055
1056 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1057
1058 xsize=im->xsize;
1059 ysize=im->ysize;
1060 ct=octt_new();
1061
1062 colorcnt=0;
1063 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1064 i_gpix(im,x,y,&val);
1065 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1066 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1067 }
1068 octt_delete(ct);
1069 return colorcnt;
1070}
1071
1072
1073symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1074 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1075 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1076 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1077
1078
1079/*
1080=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1081
1082Performs general read buffering for file readers that permit reading
1083to be done through a callback.
1084
1085The final callback gets two parameters, a I<need> value, and a I<want>
1086value, where I<need> is the amount of data that the file library needs
1087to read, and I<want> is the amount of space available in the buffer
1088maintained by these functions.
1089
1090This means if you need to read from a stream that you don't know the
1091length of, you can return I<need> bytes, taking the performance hit of
1092possibly expensive callbacks (eg. back to perl code), or if you are
1093reading from a stream where it doesn't matter if some data is lost, or
1094if the total length of the stream is known, you can return I<want>
1095bytes.
1096
1097=cut
1098*/
1099
1100int
1101i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1102 int total;
1103
1104 if (length < gci->length - gci->cpos) {
1105 /* simplest case */
1106 memcpy(buf, gci->buffer+gci->cpos, length);
1107 gci->cpos += length;
1108 return length;
1109 }
1110
1111 total = 0;
1112 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1113 total += gci->length - gci->cpos;
1114 length -= gci->length - gci->cpos;
1115 buf += gci->length - gci->cpos;
1116 if (length < (int)sizeof(gci->buffer)) {
1117 int did_read;
1118 int copy_size;
1119 while (length
1120 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1121 sizeof(gci->buffer))) > 0) {
1122 gci->cpos = 0;
1123 gci->length = did_read;
1124
1125 copy_size = min(length, gci->length);
1126 memcpy(buf, gci->buffer, copy_size);
1127 gci->cpos += copy_size;
1128 buf += copy_size;
1129 total += copy_size;
1130 length -= copy_size;
1131 }
1132 }
1133 else {
1134 /* just read the rest - too big for our buffer*/
1135 int did_read;
1136 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1137 length -= did_read;
1138 total += did_read;
1139 buf += did_read;
1140 }
1141 }
1142 return total;
1143}
1144
1145/*
1146=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1147
1148For use by callback file readers to initialize the reader buffer.
1149
1150Allocates, initializes and returns the reader buffer.
1151
1152See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1153
1154=cut
1155*/
1156i_gen_read_data *
1157i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1158 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1159 self->cb = cb;
1160 self->userdata = userdata;
1161 self->length = 0;
1162 self->cpos = 0;
1163
1164 return self;
1165}
1166
1167/*
1168=item free_gen_read_data(i_gen_read_data *)
1169
1170Cleans up.
1171
1172=cut
1173*/
1174void free_gen_read_data(i_gen_read_data *self) {
1175 myfree(self);
1176}
1177
1178/*
1179=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1180
1181Performs write buffering for a callback based file writer.
1182
1183Failures are considered fatal, if a write fails then data will be
1184dropped.
1185
1186=cut
1187*/
1188int
1189i_gen_writer(
1190i_gen_write_data *self,
1191char const *data,
1192int size)
1193{
1194 if (self->filledto && self->filledto+size > self->maxlength) {
1195 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1196 self->filledto = 0;
1197 }
1198 else {
1199 self->filledto = 0;
1200 return 0;
1201 }
1202 }
1203 if (self->filledto+size <= self->maxlength) {
1204 /* just save it */
1205 memcpy(self->buffer+self->filledto, data, size);
1206 self->filledto += size;
1207 return 1;
1208 }
1209 /* doesn't fit - hand it off */
1210 return self->cb(self->userdata, data, size);
1211}
1212
1213/*
1214=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1215
1216Allocates and initializes the data structure used by i_gen_writer.
1217
1218This should be released with L<image.c/free_gen_write_data>
1219
1220=cut
1221*/
1222i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1223 char *userdata, int max_length)
1224{
1225 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1226 self->cb = cb;
1227 self->userdata = userdata;
1228 self->maxlength = min(max_length, sizeof(self->buffer));
1229 if (self->maxlength < 0)
1230 self->maxlength = sizeof(self->buffer);
1231 self->filledto = 0;
1232
1233 return self;
1234}
1235
1236/*
1237=item free_gen_write_data(i_gen_write_data *info, int flush)
1238
1239Cleans up the write buffer.
1240
1241Will flush any left-over data if I<flush> is non-zero.
1242
1243Returns non-zero if flush is zero or if info->cb() returns non-zero.
1244
1245Return zero only if flush is non-zero and info->cb() returns zero.
1246ie. if it fails.
1247
1248=cut
1249*/
1250
1251int free_gen_write_data(i_gen_write_data *info, int flush)
1252{
1253 int result = !flush ||
1254 info->filledto == 0 ||
1255 info->cb(info->userdata, info->buffer, info->filledto);
1256 myfree(info);
1257
1258 return result;
1259}
1260
1261/*
1262=back
1263
1264=head1 SEE ALSO
1265
1266L<Imager>, L<gif.c>
1267
1268=cut
1269*/