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