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