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