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