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