return a value from test_mutex()
[imager.git] / image.c
CommitLineData
156699af
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);
a0349ca2 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
a482206e
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/*
934c0e37
TC
47=item im_img_alloc(aIMCTX)
48X<im_img_alloc API>X<i_img_alloc API>
bd8052a6 49=category Image Implementation
934c0e37
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 *
156699af 80im_img_alloc(pIMCTX) {
bd8052a6
TC
81 return mymalloc(sizeof(i_img));
82}
83
84/*
934c0e37
TC
85=item im_img_init(aIMCTX, image)
86X<im_img_init API>X<i_img_init API>
bd8052a6 87=category Image Implementation
934c0e37
TC
88=synopsis im_img_init(aIMCTX, im);
89=synopsis i_img_init(im);
bd8052a6 90
5715f7c3 91Imager internal initialization of images.
bd8052a6 92
934c0e37 93See L</im_img_alloc(aIMCTX)> for more information.
bd8052a6
TC
94
95=cut
96*/
97
98void
156699af 99im_img_init(pIMCTX, i_img *img) {
bd8052a6 100 img->im_data = NULL;
156699af 101 img->context = aIMCTX;
28da39ee 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;
d2a045fa 121 dIMCTX;
02d1d628 122
d2a045fa 123 im_log((aIMCTX,1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
02d1d628 124
d8ea80b1 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;
d2a045fa 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) {
d2a045fa
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)
d8ea80b1 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;
d2a045fa 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) {
d2a045fa
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) {
d2a045fa
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;
d2a045fa 227 dIMCTX;
faa9b3e7 228
d2a045fa 229 im_log((aIMCTX, 1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
faa9b3e7 230
d8ea80b1 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;
d2a045fa 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) {
d2a045fa
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) {
28da39ee 289 dIMCTXim(im);
d2a045fa 290 im_log((aIMCTX, 1,"i_img_destroy(im %p)\n",im));
02d1d628
AMH
291 i_img_exorcise(im);
292 if (im) { myfree(im); }
28da39ee 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) {
d2a045fa
TC
319 dIMCTXim(im);
320 im_log((aIMCTX,1,"i_img_info(im %p)\n",im));
02d1d628 321 if (im != NULL) {
d2a045fa 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));
d2a045fa 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;
d2a045fa 424 dIMCTXim(im);
02d1d628 425
d2a045fa 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;
d2a045fa 469 dIMCTXim(src);
92bda632
TC
470 i_img *im = i_sametype(src, src->xsize, src->ysize);
471
d2a045fa 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);
156699af 558 dIMCTXim(im);
02d1d628 559
de470892 560 i_clear_error();
d2a045fa 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
d2a045fa 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
d2a045fa 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;
156699af 759 dIMCTXim(im);
02d1d628 760
d2a045fa 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
d2a045fa 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
156699af
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
156699af
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;
156699af 890 dIMCTXim(im);
02d1d628 891
d2a045fa 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
d2a045fa 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;
156699af 937 dIMCTXim(im1);
02d1d628 938
d2a045fa 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
d2a045fa 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 }
d2a045fa 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;
d2a045fa 980 dIMCTXim(im1);
e41cfe8f 981
d2a045fa 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
d2a045fa 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 }
d2a045fa 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;
d2a045fa 1011 dIMCTXim(im1);
4498c8bd
TC
1012
1013 if (what == NULL)
1014 what = "(null)";
1015
d2a045fa 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
d2a045fa 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) {
d2a045fa 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 }
d2a045fa 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;
02d1d628
AMH
1052 int ch,c;
1053 i_img *new_img,*new_img2;
1054 i_color val1,val2,dval1,dval2;
156699af 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
1068 c=0;
1069 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1070 i_gpix(im,x*2,y,&val1);
1071 i_gpix(im,x*2+1,y,&val2);
1072 for(ch=0;ch<im->channels;ch++) {
1073 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1074 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1075 }
1076 i_ppix(new_img,x,y,&dval1);
1077 i_ppix(new_img,x+fx,y,&dval2);
1078 }
1079
1080 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1081 i_gpix(new_img,x,y*2,&val1);
1082 i_gpix(new_img,x,y*2+1,&val2);
1083 for(ch=0;ch<im->channels;ch++) {
1084 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1085 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1086 }
1087 i_ppix(new_img2,x,y,&dval1);
1088 i_ppix(new_img2,x,y+fy,&dval2);
1089 }
1090
1091 i_img_destroy(new_img);
1092 return new_img2;
1093}
1094
1095/*
1096=item i_count_colors(im, maxc)
1097
1098returns number of colors or -1
1099to indicate that it was more than max colors
1100
1101=cut
1102*/
fe622da1
TC
1103/* This function has been changed and is now faster. It's using
1104 * i_gsamp instead of i_gpix */
02d1d628
AMH
1105int
1106i_count_colors(i_img *im,int maxc) {
1107 struct octt *ct;
8d14daab 1108 i_img_dim x,y;
02d1d628 1109 int colorcnt;
fe622da1
TC
1110 int channels[3];
1111 int *samp_chans;
1112 i_sample_t * samp;
8d14daab
TC
1113 i_img_dim xsize = im->xsize;
1114 i_img_dim ysize = im->ysize;
a60905e4
TC
1115 int samp_cnt = 3 * xsize;
1116
fe622da1
TC
1117 if (im->channels >= 3) {
1118 samp_chans = NULL;
1119 }
1120 else {
1121 channels[0] = channels[1] = channels[2] = 0;
1122 samp_chans = channels;
02d1d628 1123 }
a60905e4 1124
fe622da1
TC
1125 ct = octt_new();
1126
1127 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1128
1129 colorcnt = 0;
1130 for(y = 0; y < ysize; ) {
1131 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1132 for(x = 0; x < samp_cnt; ) {
1133 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1134 x += 3;
1135 if (colorcnt > maxc) {
1136 octt_delete(ct);
1137 return -1;
1138 }
1139 }
1140 }
1141 myfree(samp);
02d1d628
AMH
1142 octt_delete(ct);
1143 return colorcnt;
1144}
1145
fe622da1
TC
1146/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1147 * (adapted from the Numerical Recipes)
1148 */
1149/* Needed by get_anonymous_color_histo */
a60905e4
TC
1150static void
1151hpsort(unsigned int n, unsigned *ra) {
fe622da1
TC
1152 unsigned int i,
1153 ir,
1154 j,
1155 l,
1156 rra;
1157
1158 if (n < 2) return;
1159 l = n >> 1;
1160 ir = n - 1;
1161 for(;;) {
1162 if (l > 0) {
1163 rra = ra[--l];
1164 }
1165 else {
1166 rra = ra[ir];
1167 ra[ir] = ra[0];
1168 if (--ir == 0) {
1169 ra[0] = rra;
1170 break;
1171 }
1172 }
1173 i = l;
1174 j = 2 * l + 1;
1175 while (j <= ir) {
1176 if (j < ir && ra[j] < ra[j+1]) j++;
1177 if (rra < ra[j]) {
1178 ra[i] = ra[j];
1179 i = j;
1180 j++; j <<= 1; j--;
1181 }
1182 else break;
1183 }
1184 ra[i] = rra;
1185 }
1186}
1187
1188/* This function constructs an ordered list which represents how much the
1189 * different colors are used. So for instance (100, 100, 500) means that one
1190 * color is used for 500 pixels, another for 100 pixels and another for 100
1191 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1192 * the maxc ;-) and you might want to change the name... */
1193/* Uses octt_histo */
1194int
a60905e4
TC
1195i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1196 struct octt *ct;
8d14daab 1197 i_img_dim x,y;
a60905e4
TC
1198 int colorcnt;
1199 unsigned int *col_usage_it;
1200 i_sample_t * samp;
1201 int channels[3];
1202 int *samp_chans;
1203
8d14daab
TC
1204 i_img_dim xsize = im->xsize;
1205 i_img_dim ysize = im->ysize;
a60905e4
TC
1206 int samp_cnt = 3 * xsize;
1207 ct = octt_new();
1208
1209 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1210
1211 if (im->channels >= 3) {
1212 samp_chans = NULL;
1213 }
1214 else {
1215 channels[0] = channels[1] = channels[2] = 0;
1216 samp_chans = channels;
1217 }
1218
1219 colorcnt = 0;
1220 for(y = 0; y < ysize; ) {
1221 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1222 for(x = 0; x < samp_cnt; ) {
1223 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1224 x += 3;
1225 if (colorcnt > maxc) {
1226 octt_delete(ct);
1227 return -1;
1228 }
fe622da1 1229 }
a60905e4
TC
1230 }
1231 myfree(samp);
1232 /* Now that we know the number of colours... */
1233 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1234 octt_histo(ct, &col_usage_it);
1235 hpsort(colorcnt, *col_usage);
1236 octt_delete(ct);
1237 return colorcnt;
fe622da1
TC
1238}
1239
02d1d628 1240/*
faa9b3e7
TC
1241=back
1242
faa9b3e7
TC
1243=head2 Image method wrappers
1244
1245These functions provide i_fsample_t functions in terms of their
1246i_sample_t versions.
1247
1248=over
1249
8d14daab 1250=item i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1251
1252=cut
1253*/
1254
8d14daab 1255int i_ppixf_fp(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *pix) {
faa9b3e7
TC
1256 i_color temp;
1257 int ch;
1258
1259 for (ch = 0; ch < im->channels; ++ch)
1260 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1261
1262 return i_ppix(im, x, y, &temp);
1263}
1264
1265/*
8d14daab 1266=item i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1267
1268=cut
1269*/
8d14daab 1270int i_gpixf_fp(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *pix) {
faa9b3e7
TC
1271 i_color temp;
1272 int ch;
1273
93eab01e 1274 if (i_gpix(im, x, y, &temp) == 0) {
faa9b3e7
TC
1275 for (ch = 0; ch < im->channels; ++ch)
1276 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1277 return 0;
1278 }
1279 else
1280 return -1;
1281}
1282
1283/*
8d14daab 1284=item i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1285
1286=cut
1287*/
8d14daab
TC
1288i_img_dim
1289i_plinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *pix) {
faa9b3e7
TC
1290 i_color *work;
1291
1292 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1293 if (r > im->xsize)
1294 r = im->xsize;
1295 if (r > l) {
8d14daab
TC
1296 i_img_dim ret;
1297 i_img_dim i;
1298 int ch;
faa9b3e7
TC
1299 work = mymalloc(sizeof(i_color) * (r-l));
1300 for (i = 0; i < r-l; ++i) {
1301 for (ch = 0; ch < im->channels; ++ch)
1302 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1303 }
1304 ret = i_plin(im, l, r, y, work);
1305 myfree(work);
1306
1307 return ret;
1308 }
1309 else {
1310 return 0;
1311 }
1312 }
1313 else {
1314 return 0;
1315 }
1316}
1317
1318/*
8d14daab 1319=item i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix)
faa9b3e7
TC
1320
1321=cut
1322*/
8d14daab
TC
1323i_img_dim
1324i_glinf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *pix) {
faa9b3e7
TC
1325 i_color *work;
1326
1327 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1328 if (r > im->xsize)
1329 r = im->xsize;
1330 if (r > l) {
8d14daab
TC
1331 i_img_dim ret;
1332 i_img_dim i;
1333 int ch;
faa9b3e7
TC
1334 work = mymalloc(sizeof(i_color) * (r-l));
1335 ret = i_plin(im, l, r, y, work);
1336 for (i = 0; i < r-l; ++i) {
1337 for (ch = 0; ch < im->channels; ++ch)
1338 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1339 }
1340 myfree(work);
1341
1342 return ret;
1343 }
1344 else {
1345 return 0;
1346 }
1347 }
1348 else {
1349 return 0;
1350 }
1351}
1352
1353/*
8d14daab 1354=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
1355
1356=cut
1357*/
8d14daab
TC
1358
1359i_img_dim
1360i_gsampf_fp(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samp,
18accb2a 1361 int const *chans, int chan_count) {
faa9b3e7
TC
1362 i_sample_t *work;
1363
1364 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1365 if (r > im->xsize)
1366 r = im->xsize;
1367 if (r > l) {
8d14daab
TC
1368 i_img_dim ret;
1369 i_img_dim i;
faa9b3e7
TC
1370 work = mymalloc(sizeof(i_sample_t) * (r-l));
1371 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1372 for (i = 0; i < ret; ++i) {
1373 samp[i] = Sample8ToF(work[i]);
1374 }
1375 myfree(work);
1376
1377 return ret;
1378 }
1379 else {
1380 return 0;
1381 }
1382 }
1383 else {
1384 return 0;
1385 }
1386}
1387
1388/*
1389=back
1390
1391=head2 Palette wrapper functions
1392
1393Used for virtual images, these forward palette calls to a wrapped image,
1394assuming the wrapped image is the first pointer in the structure that
1395im->ext_data points at.
1396
1397=over
1398
97ac0a96 1399=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1400
1401=cut
1402*/
97ac0a96 1403int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1404 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1405}
1406
1407/*
1408=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1409
1410=cut
1411*/
1412int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1413 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1414}
1415
1416/*
97ac0a96 1417=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1418
1419=cut
1420*/
97ac0a96 1421int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1422 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1423}
1424
1425/*
1426=item i_colorcount_forward(i_img *im)
1427
1428=cut
1429*/
1430int i_colorcount_forward(i_img *im) {
1431 return i_colorcount(*(i_img **)im->ext_data);
1432}
1433
1434/*
1435=item i_maxcolors_forward(i_img *im)
1436
1437=cut
1438*/
1439int i_maxcolors_forward(i_img *im) {
1440 return i_maxcolors(*(i_img **)im->ext_data);
1441}
1442
1443/*
97ac0a96 1444=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1445
1446=cut
1447*/
97ac0a96 1448int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1449 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1450}
1451
1452/*
1453=back
1454
bd8052a6
TC
1455=head2 Fallback handler
1456
1457=over
1458
1459=item i_gsamp_bits_fb
1460
1461=cut
1462*/
1463
8d14daab
TC
1464i_img_dim
1465i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
bd8052a6 1466 const int *chans, int chan_count, int bits) {
156699af
TC
1467 dIMCTXim(im);
1468
bd8052a6
TC
1469 if (bits < 1 || bits > 32) {
1470 i_push_error(0, "Invalid bits, must be 1..32");
1471 return -1;
1472 }
1473
1474 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1475 double scale;
8d14daab
TC
1476 int ch;
1477 i_img_dim count, i, w;
bd8052a6
TC
1478
1479 if (bits == 32)
1480 scale = 4294967295.0;
1481 else
1482 scale = (double)(1 << bits) - 1;
1483
1484 if (r > im->xsize)
1485 r = im->xsize;
1486 w = r - l;
1487 count = 0;
1488
1489 if (chans) {
1490 /* make sure we have good channel numbers */
1491 for (ch = 0; ch < chan_count; ++ch) {
1492 if (chans[ch] < 0 || chans[ch] >= im->channels) {
d2a045fa 1493 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
bd8052a6
TC
1494 return -1;
1495 }
1496 }
1497 for (i = 0; i < w; ++i) {
1498 i_fcolor c;
1499 i_gpixf(im, l+i, y, &c);
1500 for (ch = 0; ch < chan_count; ++ch) {
1501 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
1502 ++count;
1503 }
1504 }
1505 }
1506 else {
1507 if (chan_count <= 0 || chan_count > im->channels) {
1508 i_push_error(0, "Invalid channel count");
1509 return -1;
1510 }
1511 for (i = 0; i < w; ++i) {
1512 i_fcolor c;
1513 i_gpixf(im, l+i, y, &c);
1514 for (ch = 0; ch < chan_count; ++ch) {
1515 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
1516 ++count;
1517 }
1518 }
1519 }
1520
1521 return count;
1522 }
1523 else {
1524 i_push_error(0, "Image position outside of image");
1525 return -1;
1526 }
1527}
1528
8b302e44
TC
1529struct magic_entry {
1530 unsigned char *magic;
1531 size_t magic_size;
1532 char *name;
1533 unsigned char *mask;
1534};
1535
1536static int
1537test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
1538 if (length < magic->magic_size)
1539 return 0;
1540 if (magic->mask) {
1541 int i;
1542 unsigned char *bufp = buffer,
1543 *maskp = magic->mask,
1544 *magicp = magic->magic;
e10bf46e 1545
8b302e44
TC
1546 for (i = 0; i < magic->magic_size; ++i) {
1547 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
1548 ++maskp;
1549
1550 if ((*bufp++ & mask) != (*magicp++ & mask))
1551 return 0;
1552 }
1553
1554 return 1;
1555 }
1556 else {
1557 return !memcmp(magic->magic, buffer, magic->magic_size);
1558 }
1559}
e10bf46e 1560
84e51293
AMH
1561/*
1562=item i_test_format_probe(io_glue *data, int length)
1563
676d5bb5 1564Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
1565
1566=cut
1567*/
e10bf46e 1568
db7a8754
TC
1569#define FORMAT_ENTRY(magic, type) \
1570 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 1571#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 1572 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
1573
1574const char *
1575i_test_format_probe(io_glue *data, int length) {
8b302e44 1576 static const struct magic_entry formats[] = {
db7a8754
TC
1577 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
1578 FORMAT_ENTRY("GIF87a", "gif"),
1579 FORMAT_ENTRY("GIF89a", "gif"),
1580 FORMAT_ENTRY("MM\0*", "tiff"),
1581 FORMAT_ENTRY("II*\0", "tiff"),
1582 FORMAT_ENTRY("BM", "bmp"),
1583 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
1584 FORMAT_ENTRY("P1", "pnm"),
1585 FORMAT_ENTRY("P2", "pnm"),
1586 FORMAT_ENTRY("P3", "pnm"),
1587 FORMAT_ENTRY("P4", "pnm"),
1588 FORMAT_ENTRY("P5", "pnm"),
1589 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
1590 FORMAT_ENTRY("/* XPM", "xpm"),
1591 FORMAT_ENTRY("\x8aMNG", "mng"),
1592 FORMAT_ENTRY("\x8aJNG", "jng"),
1593 /* SGI RGB - with various possible parameters to avoid false positives
1594 on similar files
1595 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
1596 */
d5477d3d
TC
1597 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
1598 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
1599 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
1600 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
1601
1602 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
1603
1604 /* different versions of PCX format
1605 http://www.fileformat.info/format/pcx/
1606 */
1607 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 1608 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
1609 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
1610 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
1611 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
1612
1613 /* FITS - http://fits.gsfc.nasa.gov/ */
1614 FORMAT_ENTRY("SIMPLE =", "fits"),
1615
1616 /* PSD - Photoshop */
1617 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
1618
1619 /* EPS - Encapsulated Postscript */
1620 /* only reading 18 chars, so we don't include the F in EPSF */
1621 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
1622
1623 /* Utah RLE */
1624 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
1625
1626 /* GZIP compressed, only matching deflate for now */
1627 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
1628
1629 /* bzip2 compressed */
1630 FORMAT_ENTRY("BZh", "bzip2"),
bca6a3d5
TC
1631
1632 /* WEBP
1633 http://code.google.com/speed/webp/docs/riff_container.html */
1634 FORMAT_ENTRY2("RIFF WEBP", "webp", "xxxx xxxx"),
1635
1636 /* JPEG 2000
1637 This might match a little loosely */
1638 FORMAT_ENTRY("\x00\x00\x00\x0CjP \x0D\x0A\x87\x0A", "jp2"),
e10bf46e 1639 };
8b302e44 1640 static const struct magic_entry more_formats[] = {
681d28fc
TC
1641 /* these were originally both listed as ico, but cur files can
1642 include hotspot information */
1643 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
1644 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
1645 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
1646 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 1647 };
db7a8754 1648
e10bf46e 1649 unsigned int i;
db7a8754 1650 unsigned char head[18];
84e51293 1651 ssize_t rc;
e10bf46e 1652
6d5c85a2 1653 rc = i_io_peekn(data, head, 18);
84e51293 1654 if (rc == -1) return NULL;
6d5c85a2
TC
1655#if 0
1656 {
1657 int i;
1658 fprintf(stderr, "%d bytes -", (int)rc);
1659 for (i = 0; i < rc; ++i)
1660 fprintf(stderr, " %02x", head[i]);
1661 fprintf(stderr, "\n");
1662 }
1663#endif
e10bf46e
AMH
1664
1665 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
1666 struct magic_entry const *entry = formats + i;
1667
1668 if (test_magic(head, rc, entry))
1669 return entry->name;
e10bf46e
AMH
1670 }
1671
ea1136fc 1672 if ((rc == 18) &&
db7a8754
TC
1673 tga_header_verify(head))
1674 return "tga";
1675
ea1136fc 1676 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
1677 struct magic_entry const *entry = more_formats + i;
1678
1679 if (test_magic(head, rc, entry))
1680 return entry->name;
ea1136fc
TC
1681 }
1682
1683 return NULL;
e10bf46e
AMH
1684}
1685
9c106321
TC
1686/*
1687=item i_img_is_monochrome(img, &zero_is_white)
1688
e5ee047b
TC
1689=category Image Information
1690
9c106321
TC
1691Tests an image to check it meets our monochrome tests.
1692
1693The idea is that a file writer can use this to test where it should
e5ee047b
TC
1694write the image in whatever bi-level format it uses, eg. C<pbm> for
1695C<pnm>.
9c106321
TC
1696
1697For performance of encoders we require monochrome images:
1698
1699=over
1700
1701=item *
e10bf46e 1702
9c106321 1703be paletted
e10bf46e 1704
9c106321
TC
1705=item *
1706
e5ee047b
TC
1707have a palette of two colors, containing only C<(0,0,0)> and
1708C<(255,255,255)> in either order.
9c106321
TC
1709
1710=back
1711
e5ee047b 1712C<zero_is_white> is set to non-zero if the first palette entry is white.
9c106321
TC
1713
1714=cut
1715*/
1716
1717int
1718i_img_is_monochrome(i_img *im, int *zero_is_white) {
1719 if (im->type == i_palette_type
1720 && i_colorcount(im) == 2) {
1721 i_color colors[2];
1722 i_getcolors(im, 0, colors, 2);
1723 if (im->channels == 3) {
1724 if (colors[0].rgb.r == 255 &&
1725 colors[0].rgb.g == 255 &&
1726 colors[0].rgb.b == 255 &&
1727 colors[1].rgb.r == 0 &&
1728 colors[1].rgb.g == 0 &&
1729 colors[1].rgb.b == 0) {
bd8052a6 1730 *zero_is_white = 1;
9c106321
TC
1731 return 1;
1732 }
1733 else if (colors[0].rgb.r == 0 &&
1734 colors[0].rgb.g == 0 &&
1735 colors[0].rgb.b == 0 &&
1736 colors[1].rgb.r == 255 &&
1737 colors[1].rgb.g == 255 &&
1738 colors[1].rgb.b == 255) {
bd8052a6 1739 *zero_is_white = 0;
9c106321
TC
1740 return 1;
1741 }
1742 }
1743 else if (im->channels == 1) {
1744 if (colors[0].channel[0] == 255 &&
bd8052a6
TC
1745 colors[1].channel[0] == 0) {
1746 *zero_is_white = 1;
9c106321
TC
1747 return 1;
1748 }
1749 else if (colors[0].channel[0] == 0 &&
bd8052a6
TC
1750 colors[1].channel[0] == 255) {
1751 *zero_is_white = 0;
9c106321
TC
1752 return 1;
1753 }
1754 }
1755 }
1756
1757 *zero_is_white = 0;
1758 return 0;
1759}
e10bf46e 1760
6e4af7d4
TC
1761/*
1762=item i_get_file_background(im, &bg)
1763
797a9f9c
TC
1764=category Files
1765
6e4af7d4
TC
1766Retrieve the file write background color tag from the image.
1767
594f5933
TC
1768If not present, C<bg> is set to black.
1769
1770Returns 1 if the C<i_background> tag was found and valid.
6e4af7d4
TC
1771
1772=cut
1773*/
1774
594f5933 1775int
6e4af7d4 1776i_get_file_background(i_img *im, i_color *bg) {
594f5933
TC
1777 int result = i_tags_get_color(&im->tags, "i_background", 0, bg);
1778 if (!result) {
6e4af7d4
TC
1779 /* black default */
1780 bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
1781 }
1782 /* always full alpha */
1783 bg->channel[3] = 255;
594f5933
TC
1784
1785 return result;
6e4af7d4
TC
1786}
1787
fa90de94
TC
1788/*
1789=item i_get_file_backgroundf(im, &bg)
1790
797a9f9c
TC
1791=category Files
1792
fa90de94
TC
1793Retrieve the file write background color tag from the image as a
1794floating point color.
1795
1796Implemented in terms of i_get_file_background().
1797
594f5933
TC
1798If not present, C<bg> is set to black.
1799
1800Returns 1 if the C<i_background> tag was found and valid.
fa90de94
TC
1801
1802=cut
1803*/
1804
594f5933 1805int
fa90de94
TC
1806i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
1807 i_color bg;
594f5933 1808 int result = i_get_file_background(im, &bg);
fa90de94
TC
1809 fbg->rgba.r = Sample8ToF(bg.rgba.r);
1810 fbg->rgba.g = Sample8ToF(bg.rgba.g);
1811 fbg->rgba.b = Sample8ToF(bg.rgba.b);
1812 fbg->rgba.a = 1.0;
594f5933
TC
1813
1814 return result;
fa90de94
TC
1815}
1816
02d1d628
AMH
1817/*
1818=back
1819
b8c2033e
AMH
1820=head1 AUTHOR
1821
1822Arnar M. Hrafnkelsson <addi@umich.edu>
1823
8d14daab 1824Tony Cook <tonyc@cpan.org>
b8c2033e 1825
02d1d628
AMH
1826=head1 SEE ALSO
1827
1828L<Imager>, L<gif.c>
1829
1830=cut
1831*/