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