WIP, it compiles
[imager.git] / image.c
CommitLineData
696cb85d
TC
1#define IMAGER_NO_CONTEXT
2
92bda632
TC
3#include "imager.h"
4#include "imageri.h"
02d1d628
AMH
5
6/*
7=head1 NAME
8
9image.c - implements most of the basic functions of Imager and much of the rest
10
11=head1 SYNOPSIS
12
13 i_img *i;
14 i_color *c;
15 c = i_color_new(red, green, blue, alpha);
16 ICL_DESTROY(c);
d03fd5a4 17 i = i_img_new();
02d1d628
AMH
18 i_img_destroy(i);
19 // and much more
20
21=head1 DESCRIPTION
22
23image.c implements the basic functions to create and destroy image and
24color objects for Imager.
25
26=head1 FUNCTION REFERENCE
27
28Some of these functions are internal.
29
b8c2033e 30=over
02d1d628
AMH
31
32=cut
33*/
34
44d86483
TC
35im_context_t (*im_get_context)(void) = NULL;
36
02d1d628
AMH
37#define XAXIS 0
38#define YAXIS 1
142c26ff 39#define XYAXIS 2
02d1d628
AMH
40
41#define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i )) )
42
43/* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
8d14daab 44void i_linker_bug_fake(void) { ceil(1); }
faa9b3e7 45
bd8052a6 46/*
d03fd5a4 47=item i_img_alloc()
bd8052a6
TC
48=category Image Implementation
49
50Allocates a new i_img structure.
51
52When implementing a new image type perform the following steps in your
53image object creation function:
54
55=over
56
57=item 1.
58
59allocate the image with i_img_alloc().
60
61=item 2.
62
63initialize any function pointers or other data as needed, you can
64overwrite the whole block if you need to.
65
66=item 3.
67
68initialize Imager's internal data by calling i_img_init() on the image
69object.
70
71=back
72
73=cut
74*/
75
76i_img *
696cb85d 77im_img_alloc(pIMCTX) {
bd8052a6
TC
78 return mymalloc(sizeof(i_img));
79}
80
81/*
d03fd5a4 82=item i_img_init(C<img>)
bd8052a6
TC
83=category Image Implementation
84
5715f7c3 85Imager internal initialization of images.
bd8052a6 86
d03fd5a4
TC
87Currently this does very little, in the future it may be used to
88support threads, or color profiles.
bd8052a6
TC
89
90=cut
91*/
92
93void
696cb85d 94im_img_init(pIMCTX, i_img *img) {
bd8052a6 95 img->im_data = NULL;
696cb85d 96 img->context = aIMCTX;
bd8052a6 97}
02d1d628
AMH
98
99/*
100=item ICL_new_internal(r, g, b, a)
101
102Return a new color object with values passed to it.
103
104 r - red component (range: 0 - 255)
105 g - green component (range: 0 - 255)
106 b - blue component (range: 0 - 255)
107 a - alpha component (range: 0 - 255)
108
109=cut
110*/
111
112i_color *
113ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
4cac9410 114 i_color *cl = NULL;
02d1d628 115
d03fd5a4 116 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
02d1d628 117
d03fd5a4 118 if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
4cac9410
AMH
119 cl->rgba.r = r;
120 cl->rgba.g = g;
121 cl->rgba.b = b;
122 cl->rgba.a = a;
d03fd5a4 123 mm_log((1,"(%p) <- ICL_new_internal\n",cl));
02d1d628
AMH
124 return cl;
125}
126
127
128/*
129=item ICL_set_internal(cl, r, g, b, a)
130
131 Overwrite a color with new values.
132
133 cl - pointer to color object
134 r - red component (range: 0 - 255)
135 g - green component (range: 0 - 255)
136 b - blue component (range: 0 - 255)
137 a - alpha component (range: 0 - 255)
138
139=cut
140*/
141
142i_color *
143ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
d03fd5a4 144 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
02d1d628
AMH
145 if (cl == NULL)
146 if ( (cl=mymalloc(sizeof(i_color))) == NULL)
d03fd5a4 147 i_fatal(2,"malloc() error\n");
02d1d628
AMH
148 cl->rgba.r=r;
149 cl->rgba.g=g;
150 cl->rgba.b=b;
151 cl->rgba.a=a;
d03fd5a4 152 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
02d1d628
AMH
153 return cl;
154}
155
156
157/*
158=item ICL_add(dst, src, ch)
159
160Add src to dst inplace - dst is modified.
161
162 dst - pointer to destination color object
163 src - pointer to color object that is added
164 ch - number of channels
165
166=cut
167*/
168
169void
170ICL_add(i_color *dst,i_color *src,int ch) {
171 int tmp,i;
172 for(i=0;i<ch;i++) {
173 tmp=dst->channel[i]+src->channel[i];
174 dst->channel[i]= tmp>255 ? 255:tmp;
175 }
176}
177
178/*
179=item ICL_info(cl)
180
181Dump color information to log - strictly for debugging.
182
183 cl - pointer to color object
184
185=cut
186*/
187
188void
97ac0a96 189ICL_info(i_color const *cl) {
d03fd5a4
TC
190 mm_log((1,"i_color_info(cl* %p)\n",cl));
191 mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
02d1d628
AMH
192}
193
194/*
195=item ICL_DESTROY
196
197Destroy ancillary data for Color object.
198
199 cl - pointer to color object
200
201=cut
202*/
203
204void
205ICL_DESTROY(i_color *cl) {
d03fd5a4 206 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
02d1d628
AMH
207 myfree(cl);
208}
209
faa9b3e7
TC
210/*
211=item i_fcolor_new(double r, double g, double b, double a)
212
213=cut
214*/
215i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
216 i_fcolor *cl = NULL;
217
d03fd5a4 218 mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
faa9b3e7 219
d03fd5a4 220 if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
faa9b3e7
TC
221 cl->rgba.r = r;
222 cl->rgba.g = g;
223 cl->rgba.b = b;
224 cl->rgba.a = a;
d03fd5a4 225 mm_log((1,"(%p) <- i_fcolor_new\n",cl));
faa9b3e7
TC
226
227 return cl;
228}
229
230/*
231=item i_fcolor_destroy(i_fcolor *cl)
232
233=cut
234*/
235void i_fcolor_destroy(i_fcolor *cl) {
236 myfree(cl);
237}
238
02d1d628
AMH
239/*
240=item i_img_exorcise(im)
241
242Free image data.
243
244 im - Image pointer
245
246=cut
247*/
248
249void
250i_img_exorcise(i_img *im) {
d03fd5a4 251 mm_log((1,"i_img_exorcise(im* %p)\n",im));
faa9b3e7
TC
252 i_tags_destroy(&im->tags);
253 if (im->i_f_destroy)
254 (im->i_f_destroy)(im);
255 if (im->idata != NULL) { myfree(im->idata); }
256 im->idata = NULL;
4cac9410
AMH
257 im->xsize = 0;
258 im->ysize = 0;
259 im->channels = 0;
02d1d628 260
02d1d628
AMH
261 im->ext_data=NULL;
262}
263
264/*
5715f7c3 265=item i_img_destroy(C<img>)
6cfee9d1 266=order 90
9167a5c6
TC
267=category Image creation/destruction
268=synopsis i_img_destroy(img)
02d1d628 269
9167a5c6 270Destroy an image object
02d1d628
AMH
271
272=cut
273*/
274
275void
276i_img_destroy(i_img *im) {
d03fd5a4 277 mm_log((1,"i_img_destroy(im %p)\n",im));
02d1d628
AMH
278 i_img_exorcise(im);
279 if (im) { myfree(im); }
280}
281
282/*
283=item i_img_info(im, info)
284
92bda632
TC
285=category Image
286
02d1d628
AMH
287Return image information
288
289 im - Image pointer
290 info - pointer to array to return data
291
292info is an array of 4 integers with the following values:
293
294 info[0] - width
295 info[1] - height
296 info[2] - channels
297 info[3] - channel mask
298
299=cut
300*/
301
302
303void
8d14daab 304i_img_info(i_img *im, i_img_dim *info) {
d03fd5a4 305 mm_log((1,"i_img_info(im %p)\n",im));
02d1d628 306 if (im != NULL) {
d03fd5a4 307 mm_log((1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
8d14daab
TC
308 "mask=%ud\n",
309 i_DFc(im->xsize), i_DFc(im->ysize), im->channels,im->ch_mask));
d03fd5a4 310 mm_log((1,"i_img_info: idata=%p\n",im->idata));
4cac9410
AMH
311 info[0] = im->xsize;
312 info[1] = im->ysize;
313 info[2] = im->channels;
314 info[3] = im->ch_mask;
02d1d628 315 } else {
4cac9410
AMH
316 info[0] = 0;
317 info[1] = 0;
318 info[2] = 0;
319 info[3] = 0;
02d1d628
AMH
320 }
321}
322
323/*
5715f7c3 324=item i_img_setmask(C<im>, C<ch_mask>)
6cfee9d1 325=category Image Information
372ba12c 326=synopsis // only channel 0 writable
d5477d3d
TC
327=synopsis i_img_setmask(img, 0x01);
328
5715f7c3 329Set the image channel mask for C<im> to C<ch_mask>.
02d1d628 330
6cfee9d1
TC
331The image channel mask gives some control over which channels can be
332written to in the image.
333
02d1d628
AMH
334=cut
335*/
336void
337i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
338
339
340/*
5715f7c3 341=item i_img_getmask(C<im>)
6cfee9d1
TC
342=category Image Information
343=synopsis int mask = i_img_getmask(img);
d5477d3d 344
5715f7c3 345Get the image channel mask for C<im>.
02d1d628
AMH
346
347=cut
348*/
349int
350i_img_getmask(i_img *im) { return im->ch_mask; }
351
352/*
5715f7c3 353=item i_img_getchannels(C<im>)
6cfee9d1
TC
354=category Image Information
355=synopsis int channels = i_img_getchannels(img);
d5477d3d 356
5715f7c3 357Get the number of channels in C<im>.
02d1d628
AMH
358
359=cut
360*/
361int
362i_img_getchannels(i_img *im) { return im->channels; }
363
d5477d3d 364/*
5715f7c3 365=item i_img_get_width(C<im>)
6cfee9d1
TC
366=category Image Information
367=synopsis i_img_dim width = i_img_get_width(im);
02d1d628 368
d5477d3d
TC
369Returns the width in pixels of the image.
370
371=cut
372*/
373i_img_dim
374i_img_get_width(i_img *im) {
375 return im->xsize;
376}
377
378/*
5715f7c3 379=item i_img_get_height(C<im>)
6cfee9d1
TC
380=category Image Information
381=synopsis i_img_dim height = i_img_get_height(im);
d5477d3d
TC
382
383Returns the height in pixels of the image.
384
385=cut
386*/
387i_img_dim
388i_img_get_height(i_img *im) {
389 return im->ysize;
390}
02d1d628
AMH
391
392/*
5715f7c3 393=item i_copyto_trans(C<im>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>, C<trans>)
02d1d628 394
92bda632
TC
395=category Image
396
5715f7c3
TC
397(C<x1>,C<y1>) (C<x2>,C<y2>) specifies the region to copy (in the
398source coordinates) (C<tx>,C<ty>) specifies the upper left corner for
399the target image. pass NULL in C<trans> for non transparent i_colors.
02d1d628
AMH
400
401=cut
402*/
403
404void
8d14daab 405i_copyto_trans(i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty,const i_color *trans) {
02d1d628 406 i_color pv;
8d14daab
TC
407 i_img_dim x,y,t,ttx,tty,tt;
408 int ch;
02d1d628 409
d03fd5a4 410 mm_log((1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
8d14daab
TC
411 "to(" i_DFp "), trans* %p)\n",
412 im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty), trans));
4cac9410 413
02d1d628
AMH
414 if (x2<x1) { t=x1; x1=x2; x2=t; }
415 if (y2<y1) { t=y1; y1=y2; y2=t; }
416
417 ttx=tx;
418 for(x=x1;x<x2;x++)
419 {
420 tty=ty;
421 for(y=y1;y<y2;y++)
422 {
423 i_gpix(src,x,y,&pv);
424 if ( trans != NULL)
425 {
426 tt=0;
427 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
428 if (tt) i_ppix(im,ttx,tty,&pv);
429 } else i_ppix(im,ttx,tty,&pv);
430 tty++;
431 }
432 ttx++;
433 }
434}
435
02d1d628 436/*
5715f7c3 437=item i_copy(source)
92bda632
TC
438
439=category Image
440
5715f7c3 441Creates a new image that is a copy of the image C<source>.
92bda632
TC
442
443Tags are not copied, only the image data.
02d1d628 444
92bda632 445Returns: i_img *
02d1d628
AMH
446
447=cut
448*/
449
92bda632
TC
450i_img *
451i_copy(i_img *src) {
8d14daab 452 i_img_dim y, y1, x1;
92bda632
TC
453 i_img *im = i_sametype(src, src->xsize, src->ysize);
454
d03fd5a4 455 mm_log((1,"i_copy(src %p)\n", src));
02d1d628 456
92bda632
TC
457 if (!im)
458 return NULL;
02d1d628 459
4cac9410
AMH
460 x1 = src->xsize;
461 y1 = src->ysize;
faa9b3e7
TC
462 if (src->type == i_direct_type) {
463 if (src->bits == i_8_bits) {
464 i_color *pv;
faa9b3e7
TC
465 pv = mymalloc(sizeof(i_color) * x1);
466
467 for (y = 0; y < y1; ++y) {
468 i_glin(src, 0, x1, y, pv);
469 i_plin(im, 0, x1, y, pv);
470 }
471 myfree(pv);
472 }
473 else {
faa9b3e7 474 i_fcolor *pv;
af3c2450 475
faa9b3e7
TC
476 pv = mymalloc(sizeof(i_fcolor) * x1);
477 for (y = 0; y < y1; ++y) {
478 i_glinf(src, 0, x1, y, pv);
479 i_plinf(im, 0, x1, y, pv);
480 }
481 myfree(pv);
482 }
483 }
484 else {
faa9b3e7
TC
485 i_palidx *vals;
486
faa9b3e7
TC
487 vals = mymalloc(sizeof(i_palidx) * x1);
488 for (y = 0; y < y1; ++y) {
489 i_gpal(src, 0, x1, y, vals);
490 i_ppal(im, 0, x1, y, vals);
491 }
492 myfree(vals);
02d1d628 493 }
92bda632
TC
494
495 return im;
02d1d628
AMH
496}
497
8d14daab 498/*
02d1d628 499
8d14daab 500http://en.wikipedia.org/wiki/Lanczos_resampling
142c26ff 501
8d14daab 502*/
142c26ff
AMH
503
504static
02d1d628
AMH
505float
506Lanczos(float x) {
507 float PIx, PIx2;
508
509 PIx = PI * x;
510 PIx2 = PIx / 2.0;
511
512 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
513 else if (x == 0.0) return (1.0);
514 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
515}
516
b4e32feb 517
02d1d628
AMH
518/*
519=item i_scaleaxis(im, value, axis)
520
521Returns a new image object which is I<im> scaled by I<value> along
522wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
523
524=cut
525*/
526
527i_img*
8d14daab
TC
528i_scaleaxis(i_img *im, double Value, int Axis) {
529 i_img_dim hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
530 i_img_dim LanczosWidthFactor;
531 float *l0, *l1;
532 double OldLocation;
533 i_img_dim T;
534 double t;
02d1d628
AMH
535 float F, PictureValue[MAXCHANNELS];
536 short psave;
537 i_color val,val1,val2;
538 i_img *new_img;
95c08d71
TC
539 int has_alpha = i_img_has_alpha(im);
540 int color_chans = i_img_color_channels(im);
696cb85d 541 dIMCTXim(im);
02d1d628 542
de470892 543 i_clear_error();
d03fd5a4 544 mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
02d1d628
AMH
545
546 if (Axis == XAXIS) {
8d14daab 547 hsize = (i_img_dim)(0.5 + im->xsize * Value);
1501d9b3
TC
548 if (hsize < 1) {
549 hsize = 1;
b0950e71 550 Value = 1.0 / im->xsize;
1501d9b3 551 }
02d1d628
AMH
552 vsize = im->ysize;
553
554 jEnd = hsize;
555 iEnd = vsize;
02d1d628
AMH
556 } else {
557 hsize = im->xsize;
8d14daab 558 vsize = (i_img_dim)(0.5 + im->ysize * Value);
07d70837 559
1501d9b3
TC
560 if (vsize < 1) {
561 vsize = 1;
b0950e71 562 Value = 1.0 / im->ysize;
1501d9b3
TC
563 }
564
02d1d628
AMH
565 jEnd = vsize;
566 iEnd = hsize;
02d1d628
AMH
567 }
568
d03fd5a4 569 new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
de470892
TC
570 if (!new_img) {
571 i_push_error(0, "cannot create output image");
572 return NULL;
573 }
02d1d628 574
0bcbaf60 575 /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
8d14daab 576 LanczosWidthFactor = (Value >= 1) ? 1 : (i_img_dim) (1.4/Value);
02d1d628
AMH
577 lMax = LanczosWidthFactor << 1;
578
07d70837
AMH
579 l0 = mymalloc(lMax * sizeof(float));
580 l1 = mymalloc(lMax * sizeof(float));
02d1d628
AMH
581
582 for (j=0; j<jEnd; j++) {
8d14daab
TC
583 OldLocation = ((double) j) / Value;
584 T = (i_img_dim) (OldLocation);
585 F = OldLocation - T;
02d1d628 586
07d70837 587 for (l = 0; l<lMax; l++) {
02d1d628 588 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
07d70837
AMH
589 l1[l] = Lanczos(((float) (l+1) - F) / (float) LanczosWidthFactor);
590 }
591
592 /* Make sure filter is normalized */
593 t = 0.0;
594 for(l=0; l<lMax; l++) {
595 t+=l0[l];
596 t+=l1[l];
02d1d628 597 }
8d14daab 598 t /= (double)LanczosWidthFactor;
02d1d628 599
07d70837
AMH
600 for(l=0; l<lMax; l++) {
601 l0[l] /= t;
602 l1[l] /= t;
603 }
604
605 if (Axis == XAXIS) {
02d1d628
AMH
606
607 for (i=0; i<iEnd; i++) {
608 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
0bcbaf60 609 for (l=0; l<lMax; l++) {
8d14daab
TC
610 i_img_dim mx = T-lMax+l+1;
611 i_img_dim Mx = T+l+1;
0bcbaf60
AMH
612 mx = (mx < 0) ? 0 : mx;
613 Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
614
615 i_gpix(im, Mx, i, &val1);
616 i_gpix(im, mx, i, &val2);
95c08d71
TC
617
618 if (has_alpha) {
619 i_sample_t alpha1 = val1.channel[color_chans];
620 i_sample_t alpha2 = val2.channel[color_chans];
621 for (k=0; k < color_chans; k++) {
622 PictureValue[k] += l1[l] * val1.channel[k] * alpha1 / 255;
623 PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
624 }
625 PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
626 PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
627 }
628 else {
629 for (k=0; k<im->channels; k++) {
630 PictureValue[k] += l1[l] * val1.channel[k];
631 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
632 }
633 }
634 }
635
636 if (has_alpha) {
637 float fa = PictureValue[color_chans] / LanczosWidthFactor;
638 int alpha = minmax(0, 255, fa+0.5);
639 if (alpha) {
640 for (k = 0; k < color_chans; ++k) {
641 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
642 val.channel[k]=minmax(0,255,psave);
643 }
644 val.channel[color_chans] = alpha;
645 }
646 else {
647 /* zero alpha, so the pixel has no color */
648 for (k = 0; k < im->channels; ++k)
649 val.channel[k] = 0;
02d1d628
AMH
650 }
651 }
95c08d71
TC
652 else {
653 for(k=0;k<im->channels;k++) {
654 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
655 val.channel[k]=minmax(0,255,psave);
656 }
02d1d628 657 }
07d70837 658 i_ppix(new_img, j, i, &val);
02d1d628
AMH
659 }
660
661 } else {
662
663 for (i=0; i<iEnd; i++) {
664 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
665 for (l=0; l < lMax; l++) {
8d14daab
TC
666 i_img_dim mx = T-lMax+l+1;
667 i_img_dim Mx = T+l+1;
0bcbaf60
AMH
668 mx = (mx < 0) ? 0 : mx;
669 Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
670
671 i_gpix(im, i, Mx, &val1);
672 i_gpix(im, i, mx, &val2);
95c08d71
TC
673 if (has_alpha) {
674 i_sample_t alpha1 = val1.channel[color_chans];
675 i_sample_t alpha2 = val2.channel[color_chans];
676 for (k=0; k < color_chans; k++) {
677 PictureValue[k] += l1[l] * val1.channel[k] * alpha1 / 255;
678 PictureValue[k] += l0[lMax-l-1] * val2.channel[k] * alpha2 / 255;
679 }
680 PictureValue[color_chans] += l1[l] * val1.channel[color_chans];
681 PictureValue[color_chans] += l0[lMax-l-1] * val2.channel[color_chans];
682 }
683 else {
684 for (k=0; k<im->channels; k++) {
685 PictureValue[k] += l1[l] * val1.channel[k];
686 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
687 }
02d1d628
AMH
688 }
689 }
95c08d71
TC
690 if (has_alpha) {
691 float fa = PictureValue[color_chans] / LanczosWidthFactor;
692 int alpha = minmax(0, 255, fa+0.5);
693 if (alpha) {
694 for (k = 0; k < color_chans; ++k) {
695 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor * 255 / fa));
696 val.channel[k]=minmax(0,255,psave);
697 }
698 val.channel[color_chans] = alpha;
699 }
700 else {
701 for (k = 0; k < im->channels; ++k)
702 val.channel[k] = 0;
703 }
704 }
705 else {
706 for(k=0;k<im->channels;k++) {
707 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
708 val.channel[k]=minmax(0,255,psave);
709 }
02d1d628 710 }
07d70837 711 i_ppix(new_img, i, j, &val);
02d1d628
AMH
712 }
713
714 }
715 }
716 myfree(l0);
717 myfree(l1);
718
d03fd5a4 719 mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
02d1d628
AMH
720
721 return new_img;
722}
723
724
725/*
726=item i_scale_nn(im, scx, scy)
727
728Scale by using nearest neighbor
729Both axes scaled at the same time since
730nothing is gained by doing it in two steps
731
732=cut
733*/
734
735
736i_img*
8d14daab 737i_scale_nn(i_img *im, double scx, double scy) {
02d1d628 738
8d14daab 739 i_img_dim nxsize,nysize,nx,ny;
02d1d628
AMH
740 i_img *new_img;
741 i_color val;
696cb85d 742 dIMCTXim(im);
02d1d628 743
d03fd5a4 744 mm_log((1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
02d1d628 745
8d14daab 746 nxsize = (i_img_dim) ((double) im->xsize * scx);
1501d9b3
TC
747 if (nxsize < 1) {
748 nxsize = 1;
b3afeed5 749 scx = 1.0 / im->xsize;
1501d9b3 750 }
8d14daab 751 nysize = (i_img_dim) ((double) im->ysize * scy);
1501d9b3
TC
752 if (nysize < 1) {
753 nysize = 1;
b3afeed5 754 scy = 1.0 / im->ysize;
1501d9b3 755 }
b3afeed5 756 im_assert(scx != 0 && scy != 0);
02d1d628
AMH
757
758 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
759
760 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
8d14daab 761 i_gpix(im,((double)nx)/scx,((double)ny)/scy,&val);
02d1d628
AMH
762 i_ppix(new_img,nx,ny,&val);
763 }
764
d03fd5a4 765 mm_log((1,"(%p) <- i_scale_nn\n",new_img));
02d1d628
AMH
766
767 return new_img;
768}
769
faa9b3e7 770/*
5715f7c3 771=item i_sametype(C<im>, C<xsize>, C<ysize>)
faa9b3e7 772
9167a5c6
TC
773=category Image creation/destruction
774=synopsis i_img *img = i_sametype(src, width, height);
92bda632 775
faa9b3e7
TC
776Returns an image of the same type (sample size, channels, paletted/direct).
777
778For paletted images the palette is copied from the source.
779
780=cut
781*/
782
696cb85d
TC
783i_img *
784i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
785 dIMCTXim(src);
786
faa9b3e7
TC
787 if (src->type == i_direct_type) {
788 if (src->bits == 8) {
789 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
790 }
af3c2450 791 else if (src->bits == i_16_bits) {
faa9b3e7
TC
792 return i_img_16_new(xsize, ysize, src->channels);
793 }
af3c2450
TC
794 else if (src->bits == i_double_bits) {
795 return i_img_double_new(xsize, ysize, src->channels);
796 }
faa9b3e7
TC
797 else {
798 i_push_error(0, "Unknown image bits");
799 return NULL;
800 }
801 }
802 else {
803 i_color col;
804 int i;
805
806 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
807 for (i = 0; i < i_colorcount(src); ++i) {
808 i_getcolors(src, i, &col, 1);
809 i_addcolors(targ, &col, 1);
810 }
811
812 return targ;
813 }
814}
02d1d628 815
dff75dee 816/*
5715f7c3 817=item i_sametype_chans(C<im>, C<xsize>, C<ysize>, C<channels>)
dff75dee 818
9167a5c6
TC
819=category Image creation/destruction
820=synopsis i_img *img = i_sametype_chans(src, width, height, channels);
92bda632 821
dff75dee
TC
822Returns an image of the same type (sample size).
823
824For paletted images the equivalent direct type is returned.
825
826=cut
827*/
828
696cb85d
TC
829i_img *
830i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
831 dIMCTXim(src);
832
dff75dee
TC
833 if (src->bits == 8) {
834 return i_img_empty_ch(NULL, xsize, ysize, channels);
835 }
836 else if (src->bits == i_16_bits) {
837 return i_img_16_new(xsize, ysize, channels);
838 }
839 else if (src->bits == i_double_bits) {
840 return i_img_double_new(xsize, ysize, channels);
841 }
842 else {
843 i_push_error(0, "Unknown image bits");
844 return NULL;
845 }
846}
847
02d1d628
AMH
848/*
849=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
850
851Spatially transforms I<im> returning a new image.
852
853opx for a length of opxl and opy for a length of opy are arrays of
854operators that modify the x and y positions to retreive the pixel data from.
855
856parm and parmlen define extra parameters that the operators may use.
857
858Note that this function is largely superseded by the more flexible
859L<transform.c/i_transform2>.
860
861Returns the new image.
862
863The operators for this function are defined in L<stackmach.c>.
864
865=cut
866*/
867i_img*
868i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
869 double rx,ry;
8d14daab 870 i_img_dim nxsize,nysize,nx,ny;
02d1d628
AMH
871 i_img *new_img;
872 i_color val;
696cb85d 873 dIMCTXim(im);
02d1d628 874
d03fd5a4 875 mm_log((1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
02d1d628
AMH
876
877 nxsize = im->xsize;
878 nysize = im->ysize ;
879
880 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
881 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
882 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
883 /* parm[parmlen-2]=(double)nx;
884 parm[parmlen-1]=(double)ny; */
885
886 parm[0]=(double)nx;
887 parm[1]=(double)ny;
888
889 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
b33c08f8
TC
890 rx=i_op_run(opx,opxl,parm,parmlen);
891 ry=i_op_run(opy,opyl,parm,parmlen);
02d1d628
AMH
892 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
893 i_gpix(im,rx,ry,&val);
894 i_ppix(new_img,nx,ny,&val);
895 }
896
d03fd5a4 897 mm_log((1,"(%p) <- i_transform\n",new_img));
02d1d628
AMH
898 return new_img;
899}
900
901/*
902=item i_img_diff(im1, im2)
903
904Calculates the sum of the squares of the differences between
905correspoding channels in two images.
906
907If the images are not the same size then only the common area is
908compared, hence even if images are different sizes this function
909can return zero.
910
911=cut
912*/
e41cfe8f 913
02d1d628
AMH
914float
915i_img_diff(i_img *im1,i_img *im2) {
8d14daab
TC
916 i_img_dim x, y, xb, yb;
917 int ch, chb;
02d1d628
AMH
918 float tdiff;
919 i_color val1,val2;
696cb85d 920 dIMCTXim(im1);
02d1d628 921
d03fd5a4 922 mm_log((1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
02d1d628
AMH
923
924 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
925 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
926 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
927
d03fd5a4 928 mm_log((1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
8d14daab 929 i_DFcp(xb,yb), chb));
02d1d628
AMH
930
931 tdiff=0;
932 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
933 i_gpix(im1,x,y,&val1);
934 i_gpix(im2,x,y,&val2);
935
936 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
937 }
d03fd5a4 938 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
02d1d628
AMH
939 return tdiff;
940}
941
e41cfe8f
TC
942/*
943=item i_img_diffd(im1, im2)
944
945Calculates the sum of the squares of the differences between
946correspoding channels in two images.
947
948If the images are not the same size then only the common area is
949compared, hence even if images are different sizes this function
950can return zero.
951
952This is like i_img_diff() but looks at floating point samples instead.
953
954=cut
955*/
956
957double
958i_img_diffd(i_img *im1,i_img *im2) {
8d14daab
TC
959 i_img_dim x, y, xb, yb;
960 int ch, chb;
e41cfe8f
TC
961 double tdiff;
962 i_fcolor val1,val2;
963
d03fd5a4 964 mm_log((1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
e41cfe8f
TC
965
966 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
967 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
968 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
969
d03fd5a4 970 mm_log((1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
8d14daab 971 i_DFcp(xb, yb), chb));
e41cfe8f
TC
972
973 tdiff=0;
974 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
975 i_gpixf(im1,x,y,&val1);
976 i_gpixf(im2,x,y,&val2);
977
978 for(ch=0;ch<chb;ch++) {
979 double sdiff = val1.channel[ch]-val2.channel[ch];
980 tdiff += sdiff * sdiff;
981 }
982 }
d03fd5a4 983 mm_log((1,"i_img_diffd <- (%.2f)\n",tdiff));
e41cfe8f
TC
984
985 return tdiff;
986}
987
4498c8bd
TC
988int
989i_img_samef(i_img *im1,i_img *im2, double epsilon, char const *what) {
8d14daab
TC
990 i_img_dim x,y,xb,yb;
991 int ch, chb;
4498c8bd
TC
992 i_fcolor val1,val2;
993
994 if (what == NULL)
995 what = "(null)";
996
d03fd5a4 997 mm_log((1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
4498c8bd
TC
998
999 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1000 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1001 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1002
d03fd5a4 1003 mm_log((1,"i_img_samef: b(" i_DFp ") chb=%d\n",
8d14daab 1004 i_DFcp(xb, yb), chb));
4498c8bd
TC
1005
1006 for(y = 0; y < yb; y++) {
1007 for(x = 0; x < xb; x++) {
1008 i_gpixf(im1, x, y, &val1);
1009 i_gpixf(im2, x, y, &val2);
1010
1011 for(ch = 0; ch < chb; ch++) {
1012 double sdiff = val1.channel[ch] - val2.channel[ch];
1013 if (fabs(sdiff) > epsilon) {
d03fd5a4 1014 mm_log((1,"i_img_samef <- different %g @(" i_DFp ")\n",
8d14daab 1015 sdiff, i_DFcp(x, y)));
4498c8bd
TC
1016 return 0;
1017 }
1018 }
1019 }
1020 }
d03fd5a4 1021 mm_log((1,"i_img_samef <- same\n"));
4498c8bd
TC
1022
1023 return 1;
1024}
1025
02d1d628
AMH
1026/* just a tiny demo of haar wavelets */
1027
1028i_img*
1029i_haar(i_img *im) {
8d14daab
TC
1030 i_img_dim mx,my;
1031 i_img_dim fx,fy;
1032 i_img_dim x,y;
02d1d628
AMH
1033 int ch,c;
1034 i_img *new_img,*new_img2;
1035 i_color val1,val2,dval1,dval2;
696cb85d 1036 dIMCTXim(im);
02d1d628
AMH
1037
1038 mx=im->xsize;
1039 my=im->ysize;
1040 fx=(mx+1)/2;
1041 fy=(my+1)/2;
1042
1043
1044 /* horizontal pass */
1045
1046 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1047 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1048
1049 c=0;
1050 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1051 i_gpix(im,x*2,y,&val1);
1052 i_gpix(im,x*2+1,y,&val2);
1053 for(ch=0;ch<im->channels;ch++) {
1054 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1055 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1056 }
1057 i_ppix(new_img,x,y,&dval1);
1058 i_ppix(new_img,x+fx,y,&dval2);
1059 }
1060
1061 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1062 i_gpix(new_img,x,y*2,&val1);
1063 i_gpix(new_img,x,y*2+1,&val2);
1064 for(ch=0;ch<im->channels;ch++) {
1065 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1066 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1067 }
1068 i_ppix(new_img2,x,y,&dval1);
1069 i_ppix(new_img2,x,y+fy,&dval2);
1070 }
1071
1072 i_img_destroy(new_img);
1073 return new_img2;
1074}
1075
1076/*
1077=item i_count_colors(im, maxc)
1078
1079returns number of colors or -1
1080to indicate that it was more than max colors
1081
1082=cut
1083*/
fe622da1
TC
1084/* This function has been changed and is now faster. It's using
1085 * i_gsamp instead of i_gpix */
02d1d628
AMH
1086int
1087i_count_colors(i_img *im,int maxc) {
1088 struct octt *ct;
8d14daab 1089 i_img_dim x,y;
02d1d628 1090 int colorcnt;
fe622da1
TC
1091 int channels[3];
1092 int *samp_chans;
1093 i_sample_t * samp;
8d14daab
TC
1094 i_img_dim xsize = im->xsize;
1095 i_img_dim ysize = im->ysize;
a60905e4
TC
1096 int samp_cnt = 3 * xsize;
1097
fe622da1
TC
1098 if (im->channels >= 3) {
1099 samp_chans = NULL;
1100 }
1101 else {
1102 channels[0] = channels[1] = channels[2] = 0;
1103 samp_chans = channels;
02d1d628 1104 }
a60905e4 1105
fe622da1
TC
1106 ct = octt_new();
1107
1108 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1109
1110 colorcnt = 0;
1111 for(y = 0; y < ysize; ) {
1112 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1113 for(x = 0; x < samp_cnt; ) {
1114 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1115 x += 3;
1116 if (colorcnt > maxc) {
1117 octt_delete(ct);
1118 return -1;
1119 }
1120 }
1121 }
1122 myfree(samp);
02d1d628
AMH
1123 octt_delete(ct);
1124 return colorcnt;
1125}
1126
fe622da1
TC
1127/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1128 * (adapted from the Numerical Recipes)
1129 */
1130/* Needed by get_anonymous_color_histo */
a60905e4
TC
1131static void
1132hpsort(unsigned int n, unsigned *ra) {
fe622da1
TC
1133 unsigned int i,
1134 ir,
1135 j,
1136 l,
1137 rra;
1138
1139 if (n < 2) return;
1140 l = n >> 1;
1141 ir = n - 1;
1142 for(;;) {
1143 if (l > 0) {
1144 rra = ra[--l];
1145 }
1146 else {
1147 rra = ra[ir];
1148 ra[ir] = ra[0];
1149 if (--ir == 0) {
1150 ra[0] = rra;
1151 break;
1152 }
1153 }
1154 i = l;
1155 j = 2 * l + 1;
1156 while (j <= ir) {
1157 if (j < ir && ra[j] < ra[j+1]) j++;
1158 if (rra < ra[j]) {
1159 ra[i] = ra[j];
1160 i = j;
1161 j++; j <<= 1; j--;
1162 }
1163 else break;
1164 }
1165 ra[i] = rra;
1166 }
1167}
1168
1169/* This function constructs an ordered list which represents how much the
1170 * different colors are used. So for instance (100, 100, 500) means that one
1171 * color is used for 500 pixels, another for 100 pixels and another for 100
1172 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1173 * the maxc ;-) and you might want to change the name... */
1174/* Uses octt_histo */
1175int
a60905e4
TC
1176i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1177 struct octt *ct;
8d14daab 1178 i_img_dim x,y;
a60905e4
TC
1179 int colorcnt;
1180 unsigned int *col_usage_it;
1181 i_sample_t * samp;
1182 int channels[3];
1183 int *samp_chans;
1184
8d14daab
TC
1185 i_img_dim xsize = im->xsize;
1186 i_img_dim ysize = im->ysize;
a60905e4
TC
1187 int samp_cnt = 3 * xsize;
1188 ct = octt_new();
1189
1190 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1191
1192 if (im->channels >= 3) {
1193 samp_chans = NULL;
1194 }
1195 else {
1196 channels[0] = channels[1] = channels[2] = 0;
1197 samp_chans = channels;
1198 }
1199
1200 colorcnt = 0;
1201 for(y = 0; y < ysize; ) {
1202 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1203 for(x = 0; x < samp_cnt; ) {
1204 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1205 x += 3;
1206 if (colorcnt > maxc) {
1207 octt_delete(ct);
1208 return -1;
1209 }
fe622da1 1210 }
a60905e4
TC
1211 }
1212 myfree(samp);
1213 /* Now that we know the number of colours... */
1214 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1215 octt_histo(ct, &col_usage_it);
1216 hpsort(colorcnt, *col_usage);
1217 octt_delete(ct);
1218 return colorcnt;
fe622da1
TC
1219}
1220
02d1d628 1221/*
faa9b3e7
TC
1222=back
1223
faa9b3e7
TC
1224=head2 Image method wrappers
1225
1226These functions provide i_fsample_t functions in terms of their
1227i_sample_t versions.
1228
1229=over
1230
8d14daab 1231=item i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1232
1233=cut
1234*/
1235
8d14daab 1236int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) {
faa9b3e7
TC
1237 i_color temp;
1238 int ch;
1239
1240 for (ch = 0; ch < im->channels; ++ch)
1241 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1242
1243 return i_ppix(im, x, y, &temp);
1244}
1245
1246/*
8d14daab 1247=item i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1248
1249=cut
1250*/
8d14daab 1251int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
faa9b3e7
TC
1252 i_color temp;
1253 int ch;
1254
93eab01e 1255 if (i_gpix(im, x, y, &temp) == 0) {
faa9b3e7
TC
1256 for (ch = 0; ch < im->channels; ++ch)
1257 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1258 return 0;
1259 }
1260 else
1261 return -1;
1262}
1263
1264/*
8d14daab 1265=item i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1266
1267=cut
1268*/
8d14daab
TC
1269i_img_dim
1270i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix) {
faa9b3e7
TC
1271 i_color *work;
1272
1273 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1274 if (r > im->xsize)
1275 r = im->xsize;
1276 if (r > l) {
8d14daab
TC
1277 i_img_dim ret;
1278 i_img_dim i;
1279 int ch;
faa9b3e7
TC
1280 work = mymalloc(sizeof(i_color) * (r-l));
1281 for (i = 0; i < r-l; ++i) {
1282 for (ch = 0; ch < im->channels; ++ch)
1283 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1284 }
1285 ret = i_plin(im, l, r, y, work);
1286 myfree(work);
1287
1288 return ret;
1289 }
1290 else {
1291 return 0;
1292 }
1293 }
1294 else {
1295 return 0;
1296 }
1297}
1298
1299/*
8d14daab 1300=item i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1301
1302=cut
1303*/
8d14daab
TC
1304i_img_dim
1305i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) {
faa9b3e7
TC
1306 i_color *work;
1307
1308 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1309 if (r > im->xsize)
1310 r = im->xsize;
1311 if (r > l) {
8d14daab
TC
1312 i_img_dim ret;
1313 i_img_dim i;
1314 int ch;
faa9b3e7
TC
1315 work = mymalloc(sizeof(i_color) * (r-l));
1316 ret = i_plin(im, l, r, y, work);
1317 for (i = 0; i < r-l; ++i) {
1318 for (ch = 0; ch < im->channels; ++ch)
1319 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1320 }
1321 myfree(work);
1322
1323 return ret;
1324 }
1325 else {
1326 return 0;
1327 }
1328 }
1329 else {
1330 return 0;
1331 }
1332}
1333
1334/*
8d14daab 1335=item i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp, int *chans, int chan_count)
faa9b3e7
TC
1336
1337=cut
1338*/
8d14daab
TC
1339
1340i_img_dim
1341i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
18accb2a 1342 int const *chans, int chan_count) {
faa9b3e7
TC
1343 i_sample_t *work;
1344
1345 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1346 if (r > im->xsize)
1347 r = im->xsize;
1348 if (r > l) {
8d14daab
TC
1349 i_img_dim ret;
1350 i_img_dim i;
faa9b3e7
TC
1351 work = mymalloc(sizeof(i_sample_t) * (r-l));
1352 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1353 for (i = 0; i < ret; ++i) {
1354 samp[i] = Sample8ToF(work[i]);
1355 }
1356 myfree(work);
1357
1358 return ret;
1359 }
1360 else {
1361 return 0;
1362 }
1363 }
1364 else {
1365 return 0;
1366 }
1367}
1368
1369/*
1370=back
1371
1372=head2 Palette wrapper functions
1373
1374Used for virtual images, these forward palette calls to a wrapped image,
1375assuming the wrapped image is the first pointer in the structure that
1376im->ext_data points at.
1377
1378=over
1379
97ac0a96 1380=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1381
1382=cut
1383*/
97ac0a96 1384int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1385 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1386}
1387
1388/*
1389=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1390
1391=cut
1392*/
1393int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1394 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1395}
1396
1397/*
97ac0a96 1398=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1399
1400=cut
1401*/
97ac0a96 1402int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1403 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1404}
1405
1406/*
1407=item i_colorcount_forward(i_img *im)
1408
1409=cut
1410*/
1411int i_colorcount_forward(i_img *im) {
1412 return i_colorcount(*(i_img **)im->ext_data);
1413}
1414
1415/*
1416=item i_maxcolors_forward(i_img *im)
1417
1418=cut
1419*/
1420int i_maxcolors_forward(i_img *im) {
1421 return i_maxcolors(*(i_img **)im->ext_data);
1422}
1423
1424/*
97ac0a96 1425=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1426
1427=cut
1428*/
97ac0a96 1429int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1430 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1431}
1432
1433/*
1434=back
1435
bd8052a6
TC
1436=head2 Fallback handler
1437
1438=over
1439
1440=item i_gsamp_bits_fb
1441
1442=cut
1443*/
1444
8d14daab
TC
1445i_img_dim
1446i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
bd8052a6 1447 const int *chans, int chan_count, int bits) {
696cb85d
TC
1448 dIMCTXim(im);
1449
bd8052a6
TC
1450 if (bits < 1 || bits > 32) {
1451 i_push_error(0, "Invalid bits, must be 1..32");
1452 return -1;
1453 }
1454
1455 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1456 double scale;
8d14daab
TC
1457 int ch;
1458 i_img_dim count, i, w;
bd8052a6
TC
1459
1460 if (bits == 32)
1461 scale = 4294967295.0;
1462 else
1463 scale = (double)(1 << bits) - 1;
1464
1465 if (r > im->xsize)
1466 r = im->xsize;
1467 w = r - l;
1468 count = 0;
1469
1470 if (chans) {
1471 /* make sure we have good channel numbers */
1472 for (ch = 0; ch < chan_count; ++ch) {
1473 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d03fd5a4 1474 i_push_errorf(0, "No channel %d in this image", chans[ch]);
bd8052a6
TC
1475 return -1;
1476 }
1477 }
1478 for (i = 0; i < w; ++i) {
1479 i_fcolor c;
1480 i_gpixf(im, l+i, y, &c);
1481 for (ch = 0; ch < chan_count; ++ch) {
1482 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
1483 ++count;
1484 }
1485 }
1486 }
1487 else {
1488 if (chan_count <= 0 || chan_count > im->channels) {
1489 i_push_error(0, "Invalid channel count");
1490 return -1;
1491 }
1492 for (i = 0; i < w; ++i) {
1493 i_fcolor c;
1494 i_gpixf(im, l+i, y, &c);
1495 for (ch = 0; ch < chan_count; ++ch) {
1496 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
1497 ++count;
1498 }
1499 }
1500 }
1501
1502 return count;
1503 }
1504 else {
1505 i_push_error(0, "Image position outside of image");
1506 return -1;
1507 }
1508}
1509
8b302e44
TC
1510struct magic_entry {
1511 unsigned char *magic;
1512 size_t magic_size;
1513 char *name;
1514 unsigned char *mask;
1515};
1516
1517static int
1518test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
1519 if (length < magic->magic_size)
1520 return 0;
1521 if (magic->mask) {
1522 int i;
1523 unsigned char *bufp = buffer,
1524 *maskp = magic->mask,
1525 *magicp = magic->magic;
e10bf46e 1526
8b302e44
TC
1527 for (i = 0; i < magic->magic_size; ++i) {
1528 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
1529 ++maskp;
1530
1531 if ((*bufp++ & mask) != (*magicp++ & mask))
1532 return 0;
1533 }
1534
1535 return 1;
1536 }
1537 else {
1538 return !memcmp(magic->magic, buffer, magic->magic_size);
1539 }
1540}
e10bf46e 1541
84e51293
AMH
1542/*
1543=item i_test_format_probe(io_glue *data, int length)
1544
676d5bb5 1545Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
1546
1547=cut
1548*/
e10bf46e 1549
db7a8754
TC
1550#define FORMAT_ENTRY(magic, type) \
1551 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 1552#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 1553 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
1554
1555const char *
1556i_test_format_probe(io_glue *data, int length) {
8b302e44 1557 static const struct magic_entry formats[] = {
db7a8754
TC
1558 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
1559 FORMAT_ENTRY("GIF87a", "gif"),
1560 FORMAT_ENTRY("GIF89a", "gif"),
1561 FORMAT_ENTRY("MM\0*", "tiff"),
1562 FORMAT_ENTRY("II*\0", "tiff"),
1563 FORMAT_ENTRY("BM", "bmp"),
1564 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
1565 FORMAT_ENTRY("P1", "pnm"),
1566 FORMAT_ENTRY("P2", "pnm"),
1567 FORMAT_ENTRY("P3", "pnm"),
1568 FORMAT_ENTRY("P4", "pnm"),
1569 FORMAT_ENTRY("P5", "pnm"),
1570 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
1571 FORMAT_ENTRY("/* XPM", "xpm"),
1572 FORMAT_ENTRY("\x8aMNG", "mng"),
1573 FORMAT_ENTRY("\x8aJNG", "jng"),
1574 /* SGI RGB - with various possible parameters to avoid false positives
1575 on similar files
1576 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
1577 */
d5477d3d
TC
1578 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
1579 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
1580 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
1581 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
1582
1583 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
1584
1585 /* different versions of PCX format
1586 http://www.fileformat.info/format/pcx/
1587 */
1588 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 1589 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
1590 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
1591 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
1592 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
1593
1594 /* FITS - http://fits.gsfc.nasa.gov/ */
1595 FORMAT_ENTRY("SIMPLE =", "fits"),
1596
1597 /* PSD - Photoshop */
1598 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
1599
1600 /* EPS - Encapsulated Postscript */
1601 /* only reading 18 chars, so we don't include the F in EPSF */
1602 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
1603
1604 /* Utah RLE */
1605 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
1606
1607 /* GZIP compressed, only matching deflate for now */
1608 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
1609
1610 /* bzip2 compressed */
1611 FORMAT_ENTRY("BZh", "bzip2"),
bca6a3d5
TC
1612
1613 /* WEBP
1614 http://code.google.com/speed/webp/docs/riff_container.html */
1615 FORMAT_ENTRY2("RIFF WEBP", "webp", "xxxx xxxx"),
1616
1617 /* JPEG 2000
1618 This might match a little loosely */
1619 FORMAT_ENTRY("\x00\x00\x00\x0CjP \x0D\x0A\x87\x0A", "jp2"),
e10bf46e 1620 };
8b302e44 1621 static const struct magic_entry more_formats[] = {
681d28fc
TC
1622 /* these were originally both listed as ico, but cur files can
1623 include hotspot information */
1624 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
1625 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
1626 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
1627 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 1628 };
db7a8754 1629
e10bf46e 1630 unsigned int i;
db7a8754 1631 unsigned char head[18];
84e51293 1632 ssize_t rc;
e10bf46e 1633
6d5c85a2 1634 rc = i_io_peekn(data, head, 18);
84e51293 1635 if (rc == -1) return NULL;
6d5c85a2
TC
1636#if 0
1637 {
1638 int i;
1639 fprintf(stderr, "%d bytes -", (int)rc);
1640 for (i = 0; i < rc; ++i)
1641 fprintf(stderr, " %02x", head[i]);
1642 fprintf(stderr, "\n");
1643 }
1644#endif
e10bf46e
AMH
1645
1646 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
1647 struct magic_entry const *entry = formats + i;
1648
1649 if (test_magic(head, rc, entry))
1650 return entry->name;
e10bf46e
AMH
1651 }
1652
ea1136fc 1653 if ((rc == 18) &&
db7a8754
TC
1654 tga_header_verify(head))
1655 return "tga";
1656
ea1136fc 1657 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
1658 struct magic_entry const *entry = more_formats + i;
1659
1660 if (test_magic(head, rc, entry))
1661 return entry->name;
ea1136fc
TC
1662 }
1663
1664 return NULL;
e10bf46e
AMH
1665}
1666
9c106321
TC
1667/*
1668=item i_img_is_monochrome(img, &zero_is_white)
1669
e5ee047b
TC
1670=category Image Information
1671
9c106321
TC
1672Tests an image to check it meets our monochrome tests.
1673
1674The idea is that a file writer can use this to test where it should
e5ee047b
TC
1675write the image in whatever bi-level format it uses, eg. C<pbm> for
1676C<pnm>.
9c106321
TC
1677
1678For performance of encoders we require monochrome images:
1679
1680=over
1681
1682=item *
e10bf46e 1683
9c106321 1684be paletted
e10bf46e 1685
9c106321
TC
1686=item *
1687
e5ee047b
TC
1688have a palette of two colors, containing only C<(0,0,0)> and
1689C<(255,255,255)> in either order.
9c106321
TC
1690
1691=back
1692
e5ee047b 1693C<zero_is_white> is set to non-zero if the first palette entry is white.
9c106321
TC
1694
1695=cut
1696*/
1697
1698int
1699i_img_is_monochrome(i_img *im, int *zero_is_white) {
1700 if (im->type == i_palette_type
1701 && i_colorcount(im) == 2) {
1702 i_color colors[2];
1703 i_getcolors(im, 0, colors, 2);
1704 if (im->channels == 3) {
1705 if (colors[0].rgb.r == 255 &&
1706 colors[0].rgb.g == 255 &&
1707 colors[0].rgb.b == 255 &&
1708 colors[1].rgb.r == 0 &&
1709 colors[1].rgb.g == 0 &&
1710 colors[1].rgb.b == 0) {
bd8052a6 1711 *zero_is_white = 1;
9c106321
TC
1712 return 1;
1713 }
1714 else if (colors[0].rgb.r == 0 &&
1715 colors[0].rgb.g == 0 &&
1716 colors[0].rgb.b == 0 &&
1717 colors[1].rgb.r == 255 &&
1718 colors[1].rgb.g == 255 &&
1719 colors[1].rgb.b == 255) {
bd8052a6 1720 *zero_is_white = 0;
9c106321
TC
1721 return 1;
1722 }
1723 }
1724 else if (im->channels == 1) {
1725 if (colors[0].channel[0] == 255 &&
bd8052a6
TC
1726 colors[1].channel[0] == 0) {
1727 *zero_is_white = 1;
9c106321
TC
1728 return 1;
1729 }
1730 else if (colors[0].channel[0] == 0 &&
bd8052a6
TC
1731 colors[1].channel[0] == 255) {
1732 *zero_is_white = 0;
9c106321
TC
1733 return 1;
1734 }
1735 }
1736 }
1737
1738 *zero_is_white = 0;
1739 return 0;
1740}
e10bf46e 1741
6e4af7d4
TC
1742/*
1743=item i_get_file_background(im, &bg)
1744
797a9f9c
TC
1745=category Files
1746
6e4af7d4
TC
1747Retrieve the file write background color tag from the image.
1748
594f5933
TC
1749If not present, C<bg> is set to black.
1750
1751Returns 1 if the C<i_background> tag was found and valid.
6e4af7d4
TC
1752
1753=cut
1754*/
1755
594f5933 1756int
6e4af7d4 1757i_get_file_background(i_img *im, i_color *bg) {
594f5933
TC
1758 int result = i_tags_get_color(&im->tags, "i_background", 0, bg);
1759 if (!result) {
6e4af7d4
TC
1760 /* black default */
1761 bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
1762 }
1763 /* always full alpha */
1764 bg->channel[3] = 255;
594f5933
TC
1765
1766 return result;
6e4af7d4
TC
1767}
1768
fa90de94
TC
1769/*
1770=item i_get_file_backgroundf(im, &bg)
1771
797a9f9c
TC
1772=category Files
1773
fa90de94
TC
1774Retrieve the file write background color tag from the image as a
1775floating point color.
1776
1777Implemented in terms of i_get_file_background().
1778
594f5933
TC
1779If not present, C<bg> is set to black.
1780
1781Returns 1 if the C<i_background> tag was found and valid.
fa90de94
TC
1782
1783=cut
1784*/
1785
594f5933 1786int
fa90de94
TC
1787i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
1788 i_color bg;
594f5933 1789 int result = i_get_file_background(im, &bg);
fa90de94
TC
1790 fbg->rgba.r = Sample8ToF(bg.rgba.r);
1791 fbg->rgba.g = Sample8ToF(bg.rgba.g);
1792 fbg->rgba.b = Sample8ToF(bg.rgba.b);
1793 fbg->rgba.a = 1.0;
594f5933
TC
1794
1795 return result;
fa90de94
TC
1796}
1797
02d1d628
AMH
1798/*
1799=back
1800
b8c2033e
AMH
1801=head1 AUTHOR
1802
1803Arnar M. Hrafnkelsson <addi@umich.edu>
1804
8d14daab 1805Tony Cook <tonyc@cpan.org>
b8c2033e 1806
02d1d628
AMH
1807=head1 SEE ALSO
1808
1809L<Imager>, L<gif.c>
1810
1811=cut
1812*/