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