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