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