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