- check that the result of fileno($fh) is defined rather than simply
[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
97ac0a96 42static int i_ppix_d(i_img *im, int x, int y, const i_color *val);
faa9b3e7
TC
43static int i_gpix_d(i_img *im, int x, int y, i_color *val);
44static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
97ac0a96
TC
45static int i_plin_d(i_img *im, int l, int r, int y, const i_color *vals);
46static int i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val);
faa9b3e7
TC
47static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
48static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
97ac0a96 49static int i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals);
18accb2a
TC
50static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
51static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
bd8052a6
TC
52
53/*
54=item i_img_alloc()
55=category Image Implementation
56
57Allocates a new i_img structure.
58
59When implementing a new image type perform the following steps in your
60image object creation function:
61
62=over
63
64=item 1.
65
66allocate the image with i_img_alloc().
67
68=item 2.
69
70initialize any function pointers or other data as needed, you can
71overwrite the whole block if you need to.
72
73=item 3.
74
75initialize Imager's internal data by calling i_img_init() on the image
76object.
77
78=back
79
80=cut
81*/
82
83i_img *
84i_img_alloc(void) {
85 return mymalloc(sizeof(i_img));
86}
87
88/*
89=item i_img_init(img)
90=category Image Implementation
91
92Imager interal initialization of images.
93
94Currently this does very little, in the future it may be used to
95support threads, or color profiles.
96
97=cut
98*/
99
100void
101i_img_init(i_img *img) {
102 img->im_data = NULL;
103}
02d1d628
AMH
104
105/*
106=item ICL_new_internal(r, g, b, a)
107
108Return a new color object with values passed to it.
109
110 r - red component (range: 0 - 255)
111 g - green component (range: 0 - 255)
112 b - blue component (range: 0 - 255)
113 a - alpha component (range: 0 - 255)
114
115=cut
116*/
117
118i_color *
119ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
4cac9410 120 i_color *cl = NULL;
02d1d628 121
4cac9410 122 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
02d1d628 123
b1e96952 124 if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
4cac9410
AMH
125 cl->rgba.r = r;
126 cl->rgba.g = g;
127 cl->rgba.b = b;
128 cl->rgba.a = a;
129 mm_log((1,"(%p) <- ICL_new_internal\n",cl));
02d1d628
AMH
130 return cl;
131}
132
133
134/*
135=item ICL_set_internal(cl, r, g, b, a)
136
137 Overwrite a color with new values.
138
139 cl - pointer to color object
140 r - red component (range: 0 - 255)
141 g - green component (range: 0 - 255)
142 b - blue component (range: 0 - 255)
143 a - alpha component (range: 0 - 255)
144
145=cut
146*/
147
148i_color *
149ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
4cac9410 150 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
02d1d628
AMH
151 if (cl == NULL)
152 if ( (cl=mymalloc(sizeof(i_color))) == NULL)
b1e96952 153 i_fatal(2,"malloc() error\n");
02d1d628
AMH
154 cl->rgba.r=r;
155 cl->rgba.g=g;
156 cl->rgba.b=b;
157 cl->rgba.a=a;
4cac9410 158 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
02d1d628
AMH
159 return cl;
160}
161
162
163/*
164=item ICL_add(dst, src, ch)
165
166Add src to dst inplace - dst is modified.
167
168 dst - pointer to destination color object
169 src - pointer to color object that is added
170 ch - number of channels
171
172=cut
173*/
174
175void
176ICL_add(i_color *dst,i_color *src,int ch) {
177 int tmp,i;
178 for(i=0;i<ch;i++) {
179 tmp=dst->channel[i]+src->channel[i];
180 dst->channel[i]= tmp>255 ? 255:tmp;
181 }
182}
183
184/*
185=item ICL_info(cl)
186
187Dump color information to log - strictly for debugging.
188
189 cl - pointer to color object
190
191=cut
192*/
193
194void
97ac0a96 195ICL_info(i_color const *cl) {
4cac9410 196 mm_log((1,"i_color_info(cl* %p)\n",cl));
02d1d628
AMH
197 mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
198}
199
200/*
201=item ICL_DESTROY
202
203Destroy ancillary data for Color object.
204
205 cl - pointer to color object
206
207=cut
208*/
209
210void
211ICL_DESTROY(i_color *cl) {
4cac9410 212 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
02d1d628
AMH
213 myfree(cl);
214}
215
faa9b3e7
TC
216/*
217=item i_fcolor_new(double r, double g, double b, double a)
218
219=cut
220*/
221i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
222 i_fcolor *cl = NULL;
223
224 mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
225
b1e96952 226 if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
faa9b3e7
TC
227 cl->rgba.r = r;
228 cl->rgba.g = g;
229 cl->rgba.b = b;
230 cl->rgba.a = a;
231 mm_log((1,"(%p) <- i_fcolor_new\n",cl));
232
233 return cl;
234}
235
236/*
237=item i_fcolor_destroy(i_fcolor *cl)
238
239=cut
240*/
241void i_fcolor_destroy(i_fcolor *cl) {
242 myfree(cl);
243}
244
245/*
246=item IIM_base_8bit_direct (static)
247
248A static i_img object used to initialize direct 8-bit per sample images.
249
250=cut
251*/
252static i_img IIM_base_8bit_direct =
253{
254 0, /* channels set */
255 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 256 ~0U, /* ch_mask */
faa9b3e7
TC
257 i_8_bits, /* bits */
258 i_direct_type, /* type */
259 0, /* virtual */
260 NULL, /* idata */
261 { 0, 0, NULL }, /* tags */
262 NULL, /* ext_data */
263
264 i_ppix_d, /* i_f_ppix */
265 i_ppixf_d, /* i_f_ppixf */
266 i_plin_d, /* i_f_plin */
267 i_plinf_d, /* i_f_plinf */
268 i_gpix_d, /* i_f_gpix */
269 i_gpixf_d, /* i_f_gpixf */
270 i_glin_d, /* i_f_glin */
271 i_glinf_d, /* i_f_glinf */
272 i_gsamp_d, /* i_f_gsamp */
273 i_gsampf_d, /* i_f_gsampf */
274
275 NULL, /* i_f_gpal */
276 NULL, /* i_f_ppal */
277 NULL, /* i_f_addcolors */
278 NULL, /* i_f_getcolors */
279 NULL, /* i_f_colorcount */
280 NULL, /* i_f_maxcolors */
281 NULL, /* i_f_findcolor */
282 NULL, /* i_f_setcolors */
283
284 NULL, /* i_f_destroy */
bd8052a6
TC
285
286 i_gsamp_bits_fb,
287 NULL, /* i_f_psamp_bits */
faa9b3e7
TC
288};
289
290/*static void set_8bit_direct(i_img *im) {
291 im->i_f_ppix = i_ppix_d;
292 im->i_f_ppixf = i_ppixf_d;
293 im->i_f_plin = i_plin_d;
294 im->i_f_plinf = i_plinf_d;
295 im->i_f_gpix = i_gpix_d;
296 im->i_f_gpixf = i_gpixf_d;
297 im->i_f_glin = i_glin_d;
298 im->i_f_glinf = i_glinf_d;
299 im->i_f_gpal = NULL;
300 im->i_f_ppal = NULL;
301 im->i_f_addcolor = NULL;
302 im->i_f_getcolor = NULL;
303 im->i_f_colorcount = NULL;
304 im->i_f_findcolor = NULL;
305 }*/
306
02d1d628
AMH
307/*
308=item IIM_new(x, y, ch)
309
92bda632
TC
310=item i_img_8_new(x, y, ch)
311
9167a5c6
TC
312=category Image creation/destruction
313
314=synopsis i_img *img = i_img_8_new(width, height, channels);
92bda632
TC
315
316Creates a new image object I<x> pixels wide, and I<y> pixels high with
317I<ch> channels.
02d1d628
AMH
318
319=cut
320*/
321
322
323i_img *
324IIM_new(int x,int y,int ch) {
325 i_img *im;
326 mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
327
328 im=i_img_empty_ch(NULL,x,y,ch);
329
4cac9410 330 mm_log((1,"(%p) <- IIM_new\n",im));
02d1d628
AMH
331 return im;
332}
333
334
335void
336IIM_DESTROY(i_img *im) {
4cac9410 337 mm_log((1,"IIM_DESTROY(im* %p)\n",im));
faa9b3e7 338 i_img_destroy(im);
02d1d628
AMH
339 /* myfree(cl); */
340}
341
02d1d628
AMH
342/*
343=item i_img_new()
344
345Create new image reference - notice that this isn't an object yet and
346this should be fixed asap.
347
348=cut
349*/
350
351
352i_img *
353i_img_new() {
354 i_img *im;
355
356 mm_log((1,"i_img_struct()\n"));
bd8052a6
TC
357
358 im = i_img_alloc();
02d1d628 359
faa9b3e7 360 *im = IIM_base_8bit_direct;
02d1d628
AMH
361 im->xsize=0;
362 im->ysize=0;
363 im->channels=3;
364 im->ch_mask=MAXINT;
365 im->bytes=0;
faa9b3e7 366 im->idata=NULL;
bd8052a6
TC
367
368 i_img_init(im);
02d1d628 369
4cac9410 370 mm_log((1,"(%p) <- i_img_struct\n",im));
02d1d628
AMH
371 return im;
372}
373
374/*
375=item i_img_empty(im, x, y)
376
377Re-new image reference (assumes 3 channels)
378
379 im - Image pointer
380 x - xsize of destination image
381 y - ysize of destination image
382
faa9b3e7
TC
383**FIXME** what happens if a live image is passed in here?
384
385Should this just call i_img_empty_ch()?
386
02d1d628
AMH
387=cut
388*/
389
390i_img *
391i_img_empty(i_img *im,int x,int y) {
4cac9410 392 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
faa9b3e7 393 return i_img_empty_ch(im, x, y, 3);
02d1d628
AMH
394}
395
396/*
397=item i_img_empty_ch(im, x, y, ch)
398
399Re-new image reference
400
401 im - Image pointer
142c26ff
AMH
402 x - xsize of destination image
403 y - ysize of destination image
02d1d628
AMH
404 ch - number of channels
405
406=cut
407*/
408
409i_img *
410i_img_empty_ch(i_img *im,int x,int y,int ch) {
653ea321
TC
411 int bytes;
412
4cac9410 413 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
1501d9b3
TC
414
415 if (x < 1 || y < 1) {
416 i_push_error(0, "Image sizes must be positive");
417 return NULL;
418 }
419 if (ch < 1 || ch > MAXCHANNELS) {
420 i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
421 return NULL;
422 }
653ea321
TC
423 /* check this multiplication doesn't overflow */
424 bytes = x*y*ch;
425 if (bytes / y / ch != x) {
426 i_push_errorf(0, "integer overflow calculating image allocation");
427 return NULL;
428 }
1501d9b3 429
4cac9410 430 if (im == NULL)
bd8052a6 431 im = i_img_alloc();
faa9b3e7
TC
432
433 memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
434 i_tags_new(&im->tags);
4cac9410
AMH
435 im->xsize = x;
436 im->ysize = y;
437 im->channels = ch;
438 im->ch_mask = MAXINT;
653ea321
TC
439 im->bytes=bytes;
440 if ( (im->idata=mymalloc(im->bytes)) == NULL)
b1e96952 441 i_fatal(2,"malloc() error\n");
faa9b3e7 442 memset(im->idata,0,(size_t)im->bytes);
02d1d628 443
4cac9410 444 im->ext_data = NULL;
bd8052a6
TC
445
446 i_img_init(im);
02d1d628 447
4cac9410 448 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
02d1d628
AMH
449 return im;
450}
451
452/*
453=item i_img_exorcise(im)
454
455Free image data.
456
457 im - Image pointer
458
459=cut
460*/
461
462void
463i_img_exorcise(i_img *im) {
464 mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
faa9b3e7
TC
465 i_tags_destroy(&im->tags);
466 if (im->i_f_destroy)
467 (im->i_f_destroy)(im);
468 if (im->idata != NULL) { myfree(im->idata); }
469 im->idata = NULL;
4cac9410
AMH
470 im->xsize = 0;
471 im->ysize = 0;
472 im->channels = 0;
02d1d628
AMH
473
474 im->i_f_ppix=i_ppix_d;
475 im->i_f_gpix=i_gpix_d;
7a0584ef
TC
476 im->i_f_plin=i_plin_d;
477 im->i_f_glin=i_glin_d;
02d1d628
AMH
478 im->ext_data=NULL;
479}
480
481/*
9167a5c6 482=item i_img_destroy(img)
92bda632 483
9167a5c6
TC
484=category Image creation/destruction
485=synopsis i_img_destroy(img)
02d1d628 486
9167a5c6 487Destroy an image object
02d1d628
AMH
488
489=cut
490*/
491
492void
493i_img_destroy(i_img *im) {
07d70837 494 mm_log((1,"i_img_destroy(im %p)\n",im));
02d1d628
AMH
495 i_img_exorcise(im);
496 if (im) { myfree(im); }
497}
498
499/*
500=item i_img_info(im, info)
501
92bda632
TC
502=category Image
503
02d1d628
AMH
504Return image information
505
506 im - Image pointer
507 info - pointer to array to return data
508
509info is an array of 4 integers with the following values:
510
511 info[0] - width
512 info[1] - height
513 info[2] - channels
514 info[3] - channel mask
515
516=cut
517*/
518
519
520void
521i_img_info(i_img *im,int *info) {
522 mm_log((1,"i_img_info(im 0x%x)\n",im));
523 if (im != NULL) {
524 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 525 mm_log((1,"i_img_info: idata=0x%d\n",im->idata));
4cac9410
AMH
526 info[0] = im->xsize;
527 info[1] = im->ysize;
528 info[2] = im->channels;
529 info[3] = im->ch_mask;
02d1d628 530 } else {
4cac9410
AMH
531 info[0] = 0;
532 info[1] = 0;
533 info[2] = 0;
534 info[3] = 0;
02d1d628
AMH
535 }
536}
537
538/*
539=item i_img_setmask(im, ch_mask)
540
d5477d3d
TC
541=synopsis // only channel 0 writeable
542=synopsis i_img_setmask(img, 0x01);
543
02d1d628
AMH
544Set the image channel mask for I<im> to I<ch_mask>.
545
546=cut
547*/
548void
549i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
550
551
552/*
553=item i_img_getmask(im)
554
d5477d3d
TC
555=synopsis mask = i_img_getmask(img);
556
02d1d628
AMH
557Get the image channel mask for I<im>.
558
559=cut
560*/
561int
562i_img_getmask(i_img *im) { return im->ch_mask; }
563
564/*
565=item i_img_getchannels(im)
566
d5477d3d
TC
567=synopsis channels = i_img_getchannels(img);
568
02d1d628
AMH
569Get the number of channels in I<im>.
570
571=cut
572*/
573int
574i_img_getchannels(i_img *im) { return im->channels; }
575
d5477d3d
TC
576/*
577=item i_img_get_width(im)
578
579=synopsis width = i_img_get_width(im);
02d1d628 580
d5477d3d
TC
581Returns the width in pixels of the image.
582
583=cut
584*/
585i_img_dim
586i_img_get_width(i_img *im) {
587 return im->xsize;
588}
589
590/*
591=item i_img_get_height(im)
592
593=synopsis height = i_img_get_height(im);
594
595Returns the height in pixels of the image.
596
597=cut
598*/
599i_img_dim
600i_img_get_height(i_img *im) {
601 return im->ysize;
602}
02d1d628
AMH
603
604/*
605=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
606
92bda632
TC
607=category Image
608
02d1d628
AMH
609(x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
610(tx,ty) specifies the upper left corner for the target image.
611pass NULL in trans for non transparent i_colors.
612
613=cut
614*/
615
616void
97ac0a96 617i_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
618 i_color pv;
619 int x,y,t,ttx,tty,tt,ch;
620
4cac9410
AMH
621 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",
622 im, src, x1, y1, x2, y2, tx, ty, trans));
623
02d1d628
AMH
624 if (x2<x1) { t=x1; x1=x2; x2=t; }
625 if (y2<y1) { t=y1; y1=y2; y2=t; }
626
627 ttx=tx;
628 for(x=x1;x<x2;x++)
629 {
630 tty=ty;
631 for(y=y1;y<y2;y++)
632 {
633 i_gpix(src,x,y,&pv);
634 if ( trans != NULL)
635 {
636 tt=0;
637 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
638 if (tt) i_ppix(im,ttx,tty,&pv);
639 } else i_ppix(im,ttx,tty,&pv);
640 tty++;
641 }
642 ttx++;
643 }
644}
645
02d1d628 646/*
92bda632
TC
647=item i_copy(src)
648
649=category Image
650
651Creates a new image that is a copy of src.
652
653Tags are not copied, only the image data.
02d1d628 654
92bda632 655Returns: i_img *
02d1d628
AMH
656
657=cut
658*/
659
92bda632
TC
660i_img *
661i_copy(i_img *src) {
a743c0a6 662 int y, y1, x1;
92bda632
TC
663 i_img *im = i_sametype(src, src->xsize, src->ysize);
664
665 mm_log((1,"i_copy(src %p)\n", src));
02d1d628 666
92bda632
TC
667 if (!im)
668 return NULL;
02d1d628 669
4cac9410
AMH
670 x1 = src->xsize;
671 y1 = src->ysize;
faa9b3e7
TC
672 if (src->type == i_direct_type) {
673 if (src->bits == i_8_bits) {
674 i_color *pv;
faa9b3e7
TC
675 pv = mymalloc(sizeof(i_color) * x1);
676
677 for (y = 0; y < y1; ++y) {
678 i_glin(src, 0, x1, y, pv);
679 i_plin(im, 0, x1, y, pv);
680 }
681 myfree(pv);
682 }
683 else {
faa9b3e7 684 i_fcolor *pv;
af3c2450 685
faa9b3e7
TC
686 pv = mymalloc(sizeof(i_fcolor) * x1);
687 for (y = 0; y < y1; ++y) {
688 i_glinf(src, 0, x1, y, pv);
689 i_plinf(im, 0, x1, y, pv);
690 }
691 myfree(pv);
692 }
693 }
694 else {
faa9b3e7
TC
695 i_palidx *vals;
696
faa9b3e7
TC
697 vals = mymalloc(sizeof(i_palidx) * x1);
698 for (y = 0; y < y1; ++y) {
699 i_gpal(src, 0, x1, y, vals);
700 i_ppal(im, 0, x1, y, vals);
701 }
702 myfree(vals);
02d1d628 703 }
92bda632
TC
704
705 return im;
02d1d628
AMH
706}
707
708
142c26ff
AMH
709/*
710=item i_flipxy(im, axis)
711
712Flips the image inplace around the axis specified.
713Returns 0 if parameters are invalid.
714
715 im - Image pointer
716 axis - 0 = x, 1 = y, 2 = both
717
718=cut
719*/
720
721undef_int
722i_flipxy(i_img *im, int direction) {
723 int x, x2, y, y2, xm, ym;
724 int xs = im->xsize;
725 int ys = im->ysize;
726
727 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
728
729 if (!im) return 0;
730
731 switch (direction) {
732 case XAXIS: /* Horizontal flip */
733 xm = xs/2;
734 ym = ys;
735 for(y=0; y<ym; y++) {
736 x2 = xs-1;
737 for(x=0; x<xm; x++) {
738 i_color val1, val2;
739 i_gpix(im, x, y, &val1);
740 i_gpix(im, x2, y, &val2);
741 i_ppix(im, x, y, &val2);
742 i_ppix(im, x2, y, &val1);
743 x2--;
744 }
745 }
746 break;
390cd725 747 case YAXIS: /* Vertical flip */
142c26ff
AMH
748 xm = xs;
749 ym = ys/2;
750 y2 = ys-1;
751 for(y=0; y<ym; y++) {
752 for(x=0; x<xm; x++) {
753 i_color val1, val2;
754 i_gpix(im, x, y, &val1);
755 i_gpix(im, x, y2, &val2);
756 i_ppix(im, x, y, &val2);
757 i_ppix(im, x, y2, &val1);
758 }
759 y2--;
760 }
761 break;
390cd725 762 case XYAXIS: /* Horizontal and Vertical flip */
142c26ff
AMH
763 xm = xs/2;
764 ym = ys/2;
765 y2 = ys-1;
766 for(y=0; y<ym; y++) {
767 x2 = xs-1;
768 for(x=0; x<xm; x++) {
769 i_color val1, val2;
770 i_gpix(im, x, y, &val1);
771 i_gpix(im, x2, y2, &val2);
772 i_ppix(im, x, y, &val2);
773 i_ppix(im, x2, y2, &val1);
774
775 i_gpix(im, x2, y, &val1);
776 i_gpix(im, x, y2, &val2);
777 i_ppix(im, x2, y, &val2);
778 i_ppix(im, x, y2, &val1);
779 x2--;
780 }
781 y2--;
782 }
390cd725
AMH
783 if (xm*2 != xs) { /* odd number of column */
784 mm_log((1, "i_flipxy: odd number of columns\n"));
785 x = xm;
786 y2 = ys-1;
787 for(y=0; y<ym; y++) {
788 i_color val1, val2;
789 i_gpix(im, x, y, &val1);
790 i_gpix(im, x, y2, &val2);
791 i_ppix(im, x, y, &val2);
792 i_ppix(im, x, y2, &val1);
793 y2--;
794 }
795 }
796 if (ym*2 != ys) { /* odd number of rows */
797 mm_log((1, "i_flipxy: odd number of rows\n"));
798 y = ym;
799 x2 = xs-1;
800 for(x=0; x<xm; x++) {
801 i_color val1, val2;
802 i_gpix(im, x, y, &val1);
803 i_gpix(im, x2, y, &val2);
804 i_ppix(im, x, y, &val2);
805 i_ppix(im, x2, y, &val1);
806 x2--;
807 }
808 }
142c26ff
AMH
809 break;
810 default:
811 mm_log((1, "i_flipxy: direction is invalid\n" ));
812 return 0;
813 }
814 return 1;
815}
816
817
818
819
820
821static
02d1d628
AMH
822float
823Lanczos(float x) {
824 float PIx, PIx2;
825
826 PIx = PI * x;
827 PIx2 = PIx / 2.0;
828
829 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
830 else if (x == 0.0) return (1.0);
831 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
832}
833
b4e32feb 834
02d1d628
AMH
835/*
836=item i_scaleaxis(im, value, axis)
837
838Returns a new image object which is I<im> scaled by I<value> along
839wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
840
841=cut
842*/
843
844i_img*
845i_scaleaxis(i_img *im, float Value, int Axis) {
846 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
847 int LanczosWidthFactor;
848 float *l0, *l1, OldLocation;
07d70837
AMH
849 int T;
850 float t;
02d1d628
AMH
851 float F, PictureValue[MAXCHANNELS];
852 short psave;
853 i_color val,val1,val2;
854 i_img *new_img;
855
de470892 856 i_clear_error();
07d70837 857 mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
02d1d628 858
b4e32feb 859
02d1d628 860 if (Axis == XAXIS) {
07d70837 861 hsize = (int)(0.5 + im->xsize * Value);
1501d9b3
TC
862 if (hsize < 1) {
863 hsize = 1;
b0950e71 864 Value = 1.0 / im->xsize;
1501d9b3 865 }
02d1d628
AMH
866 vsize = im->ysize;
867
868 jEnd = hsize;
869 iEnd = vsize;
02d1d628
AMH
870 } else {
871 hsize = im->xsize;
07d70837
AMH
872 vsize = (int)(0.5 + im->ysize * Value);
873
1501d9b3
TC
874 if (vsize < 1) {
875 vsize = 1;
b0950e71 876 Value = 1.0 / im->ysize;
1501d9b3
TC
877 }
878
02d1d628
AMH
879 jEnd = vsize;
880 iEnd = hsize;
02d1d628
AMH
881 }
882
07d70837 883 new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
de470892
TC
884 if (!new_img) {
885 i_push_error(0, "cannot create output image");
886 return NULL;
887 }
02d1d628 888
0bcbaf60 889 /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
07d70837 890 LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value);
02d1d628
AMH
891 lMax = LanczosWidthFactor << 1;
892
07d70837
AMH
893 l0 = mymalloc(lMax * sizeof(float));
894 l1 = mymalloc(lMax * sizeof(float));
02d1d628
AMH
895
896 for (j=0; j<jEnd; j++) {
897 OldLocation = ((float) j) / Value;
898 T = (int) (OldLocation);
899 F = OldLocation - (float) T;
900
07d70837 901 for (l = 0; l<lMax; l++) {
02d1d628 902 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
07d70837
AMH
903 l1[l] = Lanczos(((float) (l+1) - F) / (float) LanczosWidthFactor);
904 }
905
906 /* Make sure filter is normalized */
907 t = 0.0;
908 for(l=0; l<lMax; l++) {
909 t+=l0[l];
910 t+=l1[l];
02d1d628 911 }
07d70837 912 t /= (float)LanczosWidthFactor;
02d1d628 913
07d70837
AMH
914 for(l=0; l<lMax; l++) {
915 l0[l] /= t;
916 l1[l] /= t;
917 }
918
919 if (Axis == XAXIS) {
02d1d628
AMH
920
921 for (i=0; i<iEnd; i++) {
922 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
0bcbaf60
AMH
923 for (l=0; l<lMax; l++) {
924 int mx = T-lMax+l+1;
925 int Mx = T+l+1;
926 mx = (mx < 0) ? 0 : mx;
927 Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
928
929 i_gpix(im, Mx, i, &val1);
930 i_gpix(im, mx, i, &val2);
931
02d1d628 932 for (k=0; k<im->channels; k++) {
07d70837 933 PictureValue[k] += l1[l] * val1.channel[k];
02d1d628
AMH
934 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
935 }
936 }
937 for(k=0;k<im->channels;k++) {
07d70837 938 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
02d1d628
AMH
939 val.channel[k]=minmax(0,255,psave);
940 }
07d70837 941 i_ppix(new_img, j, i, &val);
02d1d628
AMH
942 }
943
944 } else {
945
946 for (i=0; i<iEnd; i++) {
947 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
948 for (l=0; l < lMax; l++) {
0bcbaf60
AMH
949 int mx = T-lMax+l+1;
950 int Mx = T+l+1;
951 mx = (mx < 0) ? 0 : mx;
952 Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
953
954 i_gpix(im, i, Mx, &val1);
955 i_gpix(im, i, mx, &val2);
02d1d628 956 for (k=0; k<im->channels; k++) {
0bcbaf60 957 PictureValue[k] += l1[l] * val1.channel[k];
02d1d628
AMH
958 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
959 }
960 }
961 for (k=0; k<im->channels; k++) {
0bcbaf60 962 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
07d70837 963 val.channel[k] = minmax(0, 255, psave);
02d1d628 964 }
07d70837 965 i_ppix(new_img, i, j, &val);
02d1d628
AMH
966 }
967
968 }
969 }
970 myfree(l0);
971 myfree(l1);
972
07d70837 973 mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
02d1d628
AMH
974
975 return new_img;
976}
977
978
979/*
980=item i_scale_nn(im, scx, scy)
981
982Scale by using nearest neighbor
983Both axes scaled at the same time since
984nothing is gained by doing it in two steps
985
986=cut
987*/
988
989
990i_img*
991i_scale_nn(i_img *im, float scx, float scy) {
992
993 int nxsize,nysize,nx,ny;
994 i_img *new_img;
995 i_color val;
996
997 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
998
999 nxsize = (int) ((float) im->xsize * scx);
1501d9b3
TC
1000 if (nxsize < 1) {
1001 nxsize = 1;
1002 scx = 1 / im->xsize;
1003 }
02d1d628 1004 nysize = (int) ((float) im->ysize * scy);
1501d9b3
TC
1005 if (nysize < 1) {
1006 nysize = 1;
1007 scy = 1 / im->ysize;
1008 }
02d1d628
AMH
1009
1010 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1011
1012 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1013 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1014 i_ppix(new_img,nx,ny,&val);
1015 }
1016
1017 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1018
1019 return new_img;
1020}
1021
faa9b3e7
TC
1022/*
1023=item i_sametype(i_img *im, int xsize, int ysize)
1024
9167a5c6
TC
1025=category Image creation/destruction
1026=synopsis i_img *img = i_sametype(src, width, height);
92bda632 1027
faa9b3e7
TC
1028Returns an image of the same type (sample size, channels, paletted/direct).
1029
1030For paletted images the palette is copied from the source.
1031
1032=cut
1033*/
1034
1035i_img *i_sametype(i_img *src, int xsize, int ysize) {
1036 if (src->type == i_direct_type) {
1037 if (src->bits == 8) {
1038 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1039 }
af3c2450 1040 else if (src->bits == i_16_bits) {
faa9b3e7
TC
1041 return i_img_16_new(xsize, ysize, src->channels);
1042 }
af3c2450
TC
1043 else if (src->bits == i_double_bits) {
1044 return i_img_double_new(xsize, ysize, src->channels);
1045 }
faa9b3e7
TC
1046 else {
1047 i_push_error(0, "Unknown image bits");
1048 return NULL;
1049 }
1050 }
1051 else {
1052 i_color col;
1053 int i;
1054
1055 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1056 for (i = 0; i < i_colorcount(src); ++i) {
1057 i_getcolors(src, i, &col, 1);
1058 i_addcolors(targ, &col, 1);
1059 }
1060
1061 return targ;
1062 }
1063}
02d1d628 1064
dff75dee
TC
1065/*
1066=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1067
9167a5c6
TC
1068=category Image creation/destruction
1069=synopsis i_img *img = i_sametype_chans(src, width, height, channels);
92bda632 1070
dff75dee
TC
1071Returns an image of the same type (sample size).
1072
1073For paletted images the equivalent direct type is returned.
1074
1075=cut
1076*/
1077
1078i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1079 if (src->bits == 8) {
1080 return i_img_empty_ch(NULL, xsize, ysize, channels);
1081 }
1082 else if (src->bits == i_16_bits) {
1083 return i_img_16_new(xsize, ysize, channels);
1084 }
1085 else if (src->bits == i_double_bits) {
1086 return i_img_double_new(xsize, ysize, channels);
1087 }
1088 else {
1089 i_push_error(0, "Unknown image bits");
1090 return NULL;
1091 }
1092}
1093
02d1d628
AMH
1094/*
1095=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1096
1097Spatially transforms I<im> returning a new image.
1098
1099opx for a length of opxl and opy for a length of opy are arrays of
1100operators that modify the x and y positions to retreive the pixel data from.
1101
1102parm and parmlen define extra parameters that the operators may use.
1103
1104Note that this function is largely superseded by the more flexible
1105L<transform.c/i_transform2>.
1106
1107Returns the new image.
1108
1109The operators for this function are defined in L<stackmach.c>.
1110
1111=cut
1112*/
1113i_img*
1114i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1115 double rx,ry;
1116 int nxsize,nysize,nx,ny;
1117 i_img *new_img;
1118 i_color val;
1119
1120 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));
1121
1122 nxsize = im->xsize;
1123 nysize = im->ysize ;
1124
1125 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1126 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1127 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1128 /* parm[parmlen-2]=(double)nx;
1129 parm[parmlen-1]=(double)ny; */
1130
1131 parm[0]=(double)nx;
1132 parm[1]=(double)ny;
1133
1134 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
b33c08f8
TC
1135 rx=i_op_run(opx,opxl,parm,parmlen);
1136 ry=i_op_run(opy,opyl,parm,parmlen);
02d1d628
AMH
1137 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1138 i_gpix(im,rx,ry,&val);
1139 i_ppix(new_img,nx,ny,&val);
1140 }
1141
1142 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1143 return new_img;
1144}
1145
1146/*
1147=item i_img_diff(im1, im2)
1148
1149Calculates the sum of the squares of the differences between
1150correspoding channels in two images.
1151
1152If the images are not the same size then only the common area is
1153compared, hence even if images are different sizes this function
1154can return zero.
1155
1156=cut
1157*/
1158float
1159i_img_diff(i_img *im1,i_img *im2) {
1160 int x,y,ch,xb,yb,chb;
1161 float tdiff;
1162 i_color val1,val2;
1163
1164 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1165
1166 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1167 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1168 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1169
1170 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1171
1172 tdiff=0;
1173 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1174 i_gpix(im1,x,y,&val1);
1175 i_gpix(im2,x,y,&val2);
1176
1177 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1178 }
1179 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1180 return tdiff;
1181}
1182
1183/* just a tiny demo of haar wavelets */
1184
1185i_img*
1186i_haar(i_img *im) {
1187 int mx,my;
1188 int fx,fy;
1189 int x,y;
1190 int ch,c;
1191 i_img *new_img,*new_img2;
1192 i_color val1,val2,dval1,dval2;
1193
1194 mx=im->xsize;
1195 my=im->ysize;
1196 fx=(mx+1)/2;
1197 fy=(my+1)/2;
1198
1199
1200 /* horizontal pass */
1201
1202 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1203 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1204
1205 c=0;
1206 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1207 i_gpix(im,x*2,y,&val1);
1208 i_gpix(im,x*2+1,y,&val2);
1209 for(ch=0;ch<im->channels;ch++) {
1210 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1211 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1212 }
1213 i_ppix(new_img,x,y,&dval1);
1214 i_ppix(new_img,x+fx,y,&dval2);
1215 }
1216
1217 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1218 i_gpix(new_img,x,y*2,&val1);
1219 i_gpix(new_img,x,y*2+1,&val2);
1220 for(ch=0;ch<im->channels;ch++) {
1221 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1222 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1223 }
1224 i_ppix(new_img2,x,y,&dval1);
1225 i_ppix(new_img2,x,y+fy,&dval2);
1226 }
1227
1228 i_img_destroy(new_img);
1229 return new_img2;
1230}
1231
1232/*
1233=item i_count_colors(im, maxc)
1234
1235returns number of colors or -1
1236to indicate that it was more than max colors
1237
1238=cut
1239*/
fe622da1
TC
1240/* This function has been changed and is now faster. It's using
1241 * i_gsamp instead of i_gpix */
02d1d628
AMH
1242int
1243i_count_colors(i_img *im,int maxc) {
1244 struct octt *ct;
1245 int x,y;
02d1d628 1246 int colorcnt;
fe622da1
TC
1247 int channels[3];
1248 int *samp_chans;
1249 i_sample_t * samp;
fe622da1
TC
1250 int xsize = im->xsize;
1251 int ysize = im->ysize;
a60905e4
TC
1252 int samp_cnt = 3 * xsize;
1253
fe622da1
TC
1254 if (im->channels >= 3) {
1255 samp_chans = NULL;
1256 }
1257 else {
1258 channels[0] = channels[1] = channels[2] = 0;
1259 samp_chans = channels;
02d1d628 1260 }
a60905e4 1261
fe622da1
TC
1262 ct = octt_new();
1263
1264 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1265
1266 colorcnt = 0;
1267 for(y = 0; y < ysize; ) {
1268 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1269 for(x = 0; x < samp_cnt; ) {
1270 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1271 x += 3;
1272 if (colorcnt > maxc) {
1273 octt_delete(ct);
1274 return -1;
1275 }
1276 }
1277 }
1278 myfree(samp);
02d1d628
AMH
1279 octt_delete(ct);
1280 return colorcnt;
1281}
1282
fe622da1
TC
1283/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1284 * (adapted from the Numerical Recipes)
1285 */
1286/* Needed by get_anonymous_color_histo */
a60905e4
TC
1287static void
1288hpsort(unsigned int n, unsigned *ra) {
fe622da1
TC
1289 unsigned int i,
1290 ir,
1291 j,
1292 l,
1293 rra;
1294
1295 if (n < 2) return;
1296 l = n >> 1;
1297 ir = n - 1;
1298 for(;;) {
1299 if (l > 0) {
1300 rra = ra[--l];
1301 }
1302 else {
1303 rra = ra[ir];
1304 ra[ir] = ra[0];
1305 if (--ir == 0) {
1306 ra[0] = rra;
1307 break;
1308 }
1309 }
1310 i = l;
1311 j = 2 * l + 1;
1312 while (j <= ir) {
1313 if (j < ir && ra[j] < ra[j+1]) j++;
1314 if (rra < ra[j]) {
1315 ra[i] = ra[j];
1316 i = j;
1317 j++; j <<= 1; j--;
1318 }
1319 else break;
1320 }
1321 ra[i] = rra;
1322 }
1323}
1324
1325/* This function constructs an ordered list which represents how much the
1326 * different colors are used. So for instance (100, 100, 500) means that one
1327 * color is used for 500 pixels, another for 100 pixels and another for 100
1328 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1329 * the maxc ;-) and you might want to change the name... */
1330/* Uses octt_histo */
1331int
a60905e4
TC
1332i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1333 struct octt *ct;
1334 int x,y;
1335 int colorcnt;
1336 unsigned int *col_usage_it;
1337 i_sample_t * samp;
1338 int channels[3];
1339 int *samp_chans;
1340
1341 int xsize = im->xsize;
1342 int ysize = im->ysize;
1343 int samp_cnt = 3 * xsize;
1344 ct = octt_new();
1345
1346 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1347
1348 if (im->channels >= 3) {
1349 samp_chans = NULL;
1350 }
1351 else {
1352 channels[0] = channels[1] = channels[2] = 0;
1353 samp_chans = channels;
1354 }
1355
1356 colorcnt = 0;
1357 for(y = 0; y < ysize; ) {
1358 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1359 for(x = 0; x < samp_cnt; ) {
1360 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1361 x += 3;
1362 if (colorcnt > maxc) {
1363 octt_delete(ct);
1364 return -1;
1365 }
fe622da1 1366 }
a60905e4
TC
1367 }
1368 myfree(samp);
1369 /* Now that we know the number of colours... */
1370 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1371 octt_histo(ct, &col_usage_it);
1372 hpsort(colorcnt, *col_usage);
1373 octt_delete(ct);
1374 return colorcnt;
fe622da1
TC
1375}
1376
02d1d628 1377/*
faa9b3e7
TC
1378=back
1379
1380=head2 8-bit per sample image internal functions
1381
1382These are the functions installed in an 8-bit per sample image.
1383
1384=over
1385
1386=item i_ppix_d(im, x, y, col)
1387
1388Internal function.
1389
1390This is the function kept in the i_f_ppix member of an i_img object.
1391It does a normal store of a pixel into the image with range checking.
1392
1393Returns 0 if the pixel could be set, -1 otherwise.
1394
1395=cut
1396*/
63b018fd 1397static
faa9b3e7 1398int
97ac0a96 1399i_ppix_d(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
1400 int ch;
1401
1402 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1403 for(ch=0;ch<im->channels;ch++)
1404 if (im->ch_mask&(1<<ch))
1405 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1406 return 0;
1407 }
1408 return -1; /* error was clipped */
1409}
1410
1411/*
1412=item i_gpix_d(im, x, y, &col)
1413
1414Internal function.
1415
1416This is the function kept in the i_f_gpix member of an i_img object.
1417It does normal retrieval of a pixel from the image with range checking.
1418
1419Returns 0 if the pixel could be set, -1 otherwise.
1420
1421=cut
1422*/
63b018fd 1423static
faa9b3e7
TC
1424int
1425i_gpix_d(i_img *im, int x, int y, i_color *val) {
1426 int ch;
1427 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1428 for(ch=0;ch<im->channels;ch++)
9982a307 1429 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
faa9b3e7
TC
1430 return 0;
1431 }
0bcbaf60 1432 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
faa9b3e7
TC
1433 return -1; /* error was cliped */
1434}
1435
1436/*
1437=item i_glin_d(im, l, r, y, vals)
1438
1439Reads a line of data from the image, storing the pixels at vals.
1440
1441The line runs from (l,y) inclusive to (r,y) non-inclusive
1442
1443vals should point at space for (r-l) pixels.
1444
1445l should never be less than zero (to avoid confusion about where to
1446put the pixels in vals).
1447
1448Returns the number of pixels copied (eg. if r, l or y is out of range)
1449
1450=cut
1451*/
63b018fd 1452static
faa9b3e7
TC
1453int
1454i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1455 int ch, count, i;
1456 unsigned char *data;
1457 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1458 if (r > im->xsize)
1459 r = im->xsize;
1460 data = im->idata + (l+y*im->xsize) * im->channels;
1461 count = r - l;
1462 for (i = 0; i < count; ++i) {
1463 for (ch = 0; ch < im->channels; ++ch)
1464 vals[i].channel[ch] = *data++;
1465 }
1466 return count;
1467 }
1468 else {
1469 return 0;
1470 }
1471}
1472
1473/*
1474=item i_plin_d(im, l, r, y, vals)
1475
1476Writes a line of data into the image, using the pixels at vals.
1477
1478The line runs from (l,y) inclusive to (r,y) non-inclusive
1479
1480vals should point at (r-l) pixels.
1481
1482l should never be less than zero (to avoid confusion about where to
1483get the pixels in vals).
1484
1485Returns the number of pixels copied (eg. if r, l or y is out of range)
1486
1487=cut
1488*/
63b018fd 1489static
faa9b3e7 1490int
97ac0a96 1491i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
1492 int ch, count, i;
1493 unsigned char *data;
1494 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1495 if (r > im->xsize)
1496 r = im->xsize;
1497 data = im->idata + (l+y*im->xsize) * im->channels;
1498 count = r - l;
1499 for (i = 0; i < count; ++i) {
1500 for (ch = 0; ch < im->channels; ++ch) {
1501 if (im->ch_mask & (1 << ch))
1502 *data = vals[i].channel[ch];
1503 ++data;
1504 }
1505 }
1506 return count;
1507 }
1508 else {
1509 return 0;
1510 }
1511}
1512
1513/*
1514=item i_ppixf_d(im, x, y, val)
1515
1516=cut
1517*/
63b018fd 1518static
faa9b3e7 1519int
97ac0a96 1520i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
1521 int ch;
1522
1523 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1524 for(ch=0;ch<im->channels;ch++)
1525 if (im->ch_mask&(1<<ch)) {
1526 im->idata[(x+y*im->xsize)*im->channels+ch] =
1527 SampleFTo8(val->channel[ch]);
1528 }
1529 return 0;
1530 }
1531 return -1; /* error was clipped */
1532}
1533
1534/*
1535=item i_gpixf_d(im, x, y, val)
1536
1537=cut
1538*/
63b018fd 1539static
faa9b3e7
TC
1540int
1541i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1542 int ch;
1543 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1544 for(ch=0;ch<im->channels;ch++) {
1545 val->channel[ch] =
1546 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1547 }
1548 return 0;
1549 }
1550 return -1; /* error was cliped */
1551}
1552
1553/*
1554=item i_glinf_d(im, l, r, y, vals)
1555
1556Reads a line of data from the image, storing the pixels at vals.
1557
1558The line runs from (l,y) inclusive to (r,y) non-inclusive
1559
1560vals should point at space for (r-l) pixels.
1561
1562l should never be less than zero (to avoid confusion about where to
1563put the pixels in vals).
1564
1565Returns the number of pixels copied (eg. if r, l or y is out of range)
1566
1567=cut
1568*/
63b018fd 1569static
faa9b3e7
TC
1570int
1571i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1572 int ch, count, i;
1573 unsigned char *data;
1574 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1575 if (r > im->xsize)
1576 r = im->xsize;
1577 data = im->idata + (l+y*im->xsize) * im->channels;
1578 count = r - l;
1579 for (i = 0; i < count; ++i) {
1580 for (ch = 0; ch < im->channels; ++ch)
6607600c 1581 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1582 }
1583 return count;
1584 }
1585 else {
1586 return 0;
1587 }
1588}
1589
1590/*
1591=item i_plinf_d(im, l, r, y, vals)
1592
1593Writes a line of data into the image, using the pixels at vals.
1594
1595The line runs from (l,y) inclusive to (r,y) non-inclusive
1596
1597vals should point at (r-l) pixels.
1598
1599l should never be less than zero (to avoid confusion about where to
1600get the pixels in vals).
1601
1602Returns the number of pixels copied (eg. if r, l or y is out of range)
1603
1604=cut
1605*/
63b018fd 1606static
faa9b3e7 1607int
97ac0a96 1608i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
1609 int ch, count, i;
1610 unsigned char *data;
1611 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1612 if (r > im->xsize)
1613 r = im->xsize;
1614 data = im->idata + (l+y*im->xsize) * im->channels;
1615 count = r - l;
1616 for (i = 0; i < count; ++i) {
1617 for (ch = 0; ch < im->channels; ++ch) {
1618 if (im->ch_mask & (1 << ch))
6607600c 1619 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1620 ++data;
1621 }
1622 }
1623 return count;
1624 }
1625 else {
1626 return 0;
1627 }
1628}
1629
1630/*
1631=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1632
1633Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1634for the channels specified by chans, an array of int with chan_count
1635elements.
1636
1637Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1638
1639=cut
1640*/
63b018fd
AMH
1641static
1642int
1643i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 1644 const int *chans, int chan_count) {
faa9b3e7
TC
1645 int ch, count, i, w;
1646 unsigned char *data;
1647
1648 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1649 if (r > im->xsize)
1650 r = im->xsize;
1651 data = im->idata + (l+y*im->xsize) * im->channels;
1652 w = r - l;
1653 count = 0;
1654
1655 if (chans) {
1656 /* make sure we have good channel numbers */
1657 for (ch = 0; ch < chan_count; ++ch) {
1658 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1659 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1660 return 0;
1661 }
1662 }
1663 for (i = 0; i < w; ++i) {
1664 for (ch = 0; ch < chan_count; ++ch) {
1665 *samps++ = data[chans[ch]];
1666 ++count;
1667 }
1668 data += im->channels;
1669 }
1670 }
1671 else {
c7481ae1
TC
1672 if (chan_count <= 0 || chan_count > im->channels) {
1673 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1674 chan_count);
1675 return 0;
1676 }
faa9b3e7
TC
1677 for (i = 0; i < w; ++i) {
1678 for (ch = 0; ch < chan_count; ++ch) {
1679 *samps++ = data[ch];
1680 ++count;
1681 }
1682 data += im->channels;
1683 }
1684 }
1685
1686 return count;
1687 }
1688 else {
1689 return 0;
1690 }
1691}
1692
1693/*
1694=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1695
1696Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1697for the channels specified by chan_mask, where bit 0 is the first
1698channel.
1699
1700Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1701
1702=cut
1703*/
63b018fd
AMH
1704static
1705int
1706i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 1707 const int *chans, int chan_count) {
faa9b3e7
TC
1708 int ch, count, i, w;
1709 unsigned char *data;
1710 for (ch = 0; ch < chan_count; ++ch) {
1711 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1712 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1713 }
1714 }
1715 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1716 if (r > im->xsize)
1717 r = im->xsize;
1718 data = im->idata + (l+y*im->xsize) * im->channels;
1719 w = r - l;
1720 count = 0;
1721
1722 if (chans) {
1723 /* make sure we have good channel numbers */
1724 for (ch = 0; ch < chan_count; ++ch) {
1725 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1726 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1727 return 0;
1728 }
1729 }
1730 for (i = 0; i < w; ++i) {
1731 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1732 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1733 ++count;
1734 }
1735 data += im->channels;
1736 }
1737 }
1738 else {
c7481ae1
TC
1739 if (chan_count <= 0 || chan_count > im->channels) {
1740 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1741 chan_count);
1742 return 0;
1743 }
faa9b3e7
TC
1744 for (i = 0; i < w; ++i) {
1745 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1746 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1747 ++count;
1748 }
1749 data += im->channels;
1750 }
1751 }
1752 return count;
1753 }
1754 else {
1755 return 0;
1756 }
1757}
1758
1759/*
1760=back
1761
1762=head2 Image method wrappers
1763
1764These functions provide i_fsample_t functions in terms of their
1765i_sample_t versions.
1766
1767=over
1768
1769=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1770
1771=cut
1772*/
1773
97ac0a96 1774int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
faa9b3e7
TC
1775 i_color temp;
1776 int ch;
1777
1778 for (ch = 0; ch < im->channels; ++ch)
1779 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1780
1781 return i_ppix(im, x, y, &temp);
1782}
1783
1784/*
1785=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1786
1787=cut
1788*/
1789int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1790 i_color temp;
1791 int ch;
1792
1793 if (i_gpix(im, x, y, &temp)) {
1794 for (ch = 0; ch < im->channels; ++ch)
1795 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1796 return 0;
1797 }
1798 else
1799 return -1;
1800}
1801
1802/*
1803=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1804
1805=cut
1806*/
97ac0a96 1807int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
faa9b3e7
TC
1808 i_color *work;
1809
1810 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1811 if (r > im->xsize)
1812 r = im->xsize;
1813 if (r > l) {
1814 int ret;
1815 int i, ch;
1816 work = mymalloc(sizeof(i_color) * (r-l));
1817 for (i = 0; i < r-l; ++i) {
1818 for (ch = 0; ch < im->channels; ++ch)
1819 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1820 }
1821 ret = i_plin(im, l, r, y, work);
1822 myfree(work);
1823
1824 return ret;
1825 }
1826 else {
1827 return 0;
1828 }
1829 }
1830 else {
1831 return 0;
1832 }
1833}
1834
1835/*
1836=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1837
1838=cut
1839*/
1840int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1841 i_color *work;
1842
1843 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1844 if (r > im->xsize)
1845 r = im->xsize;
1846 if (r > l) {
1847 int ret;
1848 int i, ch;
1849 work = mymalloc(sizeof(i_color) * (r-l));
1850 ret = i_plin(im, l, r, y, work);
1851 for (i = 0; i < r-l; ++i) {
1852 for (ch = 0; ch < im->channels; ++ch)
1853 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1854 }
1855 myfree(work);
1856
1857 return ret;
1858 }
1859 else {
1860 return 0;
1861 }
1862 }
1863 else {
1864 return 0;
1865 }
1866}
1867
1868/*
1869=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1870
1871=cut
1872*/
1873int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
18accb2a 1874 int const *chans, int chan_count) {
faa9b3e7
TC
1875 i_sample_t *work;
1876
1877 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1878 if (r > im->xsize)
1879 r = im->xsize;
1880 if (r > l) {
1881 int ret;
1882 int i;
1883 work = mymalloc(sizeof(i_sample_t) * (r-l));
1884 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1885 for (i = 0; i < ret; ++i) {
1886 samp[i] = Sample8ToF(work[i]);
1887 }
1888 myfree(work);
1889
1890 return ret;
1891 }
1892 else {
1893 return 0;
1894 }
1895 }
1896 else {
1897 return 0;
1898 }
1899}
1900
1901/*
1902=back
1903
1904=head2 Palette wrapper functions
1905
1906Used for virtual images, these forward palette calls to a wrapped image,
1907assuming the wrapped image is the first pointer in the structure that
1908im->ext_data points at.
1909
1910=over
1911
97ac0a96 1912=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1913
1914=cut
1915*/
97ac0a96 1916int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1917 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1918}
1919
1920/*
1921=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1922
1923=cut
1924*/
1925int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1926 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1927}
1928
1929/*
97ac0a96 1930=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1931
1932=cut
1933*/
97ac0a96 1934int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1935 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1936}
1937
1938/*
1939=item i_colorcount_forward(i_img *im)
1940
1941=cut
1942*/
1943int i_colorcount_forward(i_img *im) {
1944 return i_colorcount(*(i_img **)im->ext_data);
1945}
1946
1947/*
1948=item i_maxcolors_forward(i_img *im)
1949
1950=cut
1951*/
1952int i_maxcolors_forward(i_img *im) {
1953 return i_maxcolors(*(i_img **)im->ext_data);
1954}
1955
1956/*
97ac0a96 1957=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1958
1959=cut
1960*/
97ac0a96 1961int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1962 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1963}
1964
1965/*
1966=back
1967
bd8052a6
TC
1968=head2 Fallback handler
1969
1970=over
1971
1972=item i_gsamp_bits_fb
1973
1974=cut
1975*/
1976
1977int
1978i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
1979 const int *chans, int chan_count, int bits) {
1980 if (bits < 1 || bits > 32) {
1981 i_push_error(0, "Invalid bits, must be 1..32");
1982 return -1;
1983 }
1984
1985 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1986 double scale;
1987 int ch, count, i, w;
1988
1989 if (bits == 32)
1990 scale = 4294967295.0;
1991 else
1992 scale = (double)(1 << bits) - 1;
1993
1994 if (r > im->xsize)
1995 r = im->xsize;
1996 w = r - l;
1997 count = 0;
1998
1999 if (chans) {
2000 /* make sure we have good channel numbers */
2001 for (ch = 0; ch < chan_count; ++ch) {
2002 if (chans[ch] < 0 || chans[ch] >= im->channels) {
2003 i_push_errorf(0, "No channel %d in this image", chans[ch]);
2004 return -1;
2005 }
2006 }
2007 for (i = 0; i < w; ++i) {
2008 i_fcolor c;
2009 i_gpixf(im, l+i, y, &c);
2010 for (ch = 0; ch < chan_count; ++ch) {
2011 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2012 ++count;
2013 }
2014 }
2015 }
2016 else {
2017 if (chan_count <= 0 || chan_count > im->channels) {
2018 i_push_error(0, "Invalid channel count");
2019 return -1;
2020 }
2021 for (i = 0; i < w; ++i) {
2022 i_fcolor c;
2023 i_gpixf(im, l+i, y, &c);
2024 for (ch = 0; ch < chan_count; ++ch) {
2025 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2026 ++count;
2027 }
2028 }
2029 }
2030
2031 return count;
2032 }
2033 else {
2034 i_push_error(0, "Image position outside of image");
2035 return -1;
2036 }
2037}
2038
2039/*
2040=back
2041
faa9b3e7
TC
2042=head2 Stream reading and writing wrapper functions
2043
2044=over
2045
02d1d628
AMH
2046=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
2047
2048Performs general read buffering for file readers that permit reading
2049to be done through a callback.
2050
2051The final callback gets two parameters, a I<need> value, and a I<want>
2052value, where I<need> is the amount of data that the file library needs
2053to read, and I<want> is the amount of space available in the buffer
2054maintained by these functions.
2055
2056This means if you need to read from a stream that you don't know the
2057length of, you can return I<need> bytes, taking the performance hit of
2058possibly expensive callbacks (eg. back to perl code), or if you are
2059reading from a stream where it doesn't matter if some data is lost, or
2060if the total length of the stream is known, you can return I<want>
2061bytes.
2062
2063=cut
2064*/
2065
2066int
2067i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
2068 int total;
2069
2070 if (length < gci->length - gci->cpos) {
2071 /* simplest case */
2072 memcpy(buf, gci->buffer+gci->cpos, length);
2073 gci->cpos += length;
2074 return length;
2075 }
2076
2077 total = 0;
2078 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
2079 total += gci->length - gci->cpos;
2080 length -= gci->length - gci->cpos;
2081 buf += gci->length - gci->cpos;
2082 if (length < (int)sizeof(gci->buffer)) {
2083 int did_read;
2084 int copy_size;
2085 while (length
2086 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
2087 sizeof(gci->buffer))) > 0) {
2088 gci->cpos = 0;
2089 gci->length = did_read;
2090
b33c08f8 2091 copy_size = i_min(length, gci->length);
02d1d628
AMH
2092 memcpy(buf, gci->buffer, copy_size);
2093 gci->cpos += copy_size;
2094 buf += copy_size;
2095 total += copy_size;
2096 length -= copy_size;
2097 }
2098 }
2099 else {
2100 /* just read the rest - too big for our buffer*/
2101 int did_read;
2102 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2103 length -= did_read;
2104 total += did_read;
2105 buf += did_read;
2106 }
2107 }
2108 return total;
2109}
2110
2111/*
2112=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2113
2114For use by callback file readers to initialize the reader buffer.
2115
2116Allocates, initializes and returns the reader buffer.
2117
2118See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2119
2120=cut
2121*/
2122i_gen_read_data *
2123i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2124 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2125 self->cb = cb;
2126 self->userdata = userdata;
2127 self->length = 0;
2128 self->cpos = 0;
2129
2130 return self;
2131}
2132
2133/*
b33c08f8 2134=item i_free_gen_read_data(i_gen_read_data *)
02d1d628
AMH
2135
2136Cleans up.
2137
2138=cut
2139*/
b33c08f8 2140void i_free_gen_read_data(i_gen_read_data *self) {
02d1d628
AMH
2141 myfree(self);
2142}
2143
2144/*
2145=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2146
2147Performs write buffering for a callback based file writer.
2148
2149Failures are considered fatal, if a write fails then data will be
2150dropped.
2151
2152=cut
2153*/
2154int
2155i_gen_writer(
2156i_gen_write_data *self,
2157char const *data,
2158int size)
2159{
2160 if (self->filledto && self->filledto+size > self->maxlength) {
2161 if (self->cb(self->userdata, self->buffer, self->filledto)) {
2162 self->filledto = 0;
2163 }
2164 else {
2165 self->filledto = 0;
2166 return 0;
2167 }
2168 }
2169 if (self->filledto+size <= self->maxlength) {
2170 /* just save it */
2171 memcpy(self->buffer+self->filledto, data, size);
2172 self->filledto += size;
2173 return 1;
2174 }
2175 /* doesn't fit - hand it off */
2176 return self->cb(self->userdata, data, size);
2177}
2178
2179/*
2180=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2181
2182Allocates and initializes the data structure used by i_gen_writer.
2183
b33c08f8 2184This should be released with L<image.c/i_free_gen_write_data>
02d1d628
AMH
2185
2186=cut
2187*/
2188i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2189 char *userdata, int max_length)
2190{
2191 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2192 self->cb = cb;
2193 self->userdata = userdata;
b33c08f8 2194 self->maxlength = i_min(max_length, sizeof(self->buffer));
02d1d628
AMH
2195 if (self->maxlength < 0)
2196 self->maxlength = sizeof(self->buffer);
2197 self->filledto = 0;
2198
2199 return self;
2200}
2201
2202/*
b33c08f8 2203=item i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2204
2205Cleans up the write buffer.
2206
2207Will flush any left-over data if I<flush> is non-zero.
2208
2209Returns non-zero if flush is zero or if info->cb() returns non-zero.
2210
2211Return zero only if flush is non-zero and info->cb() returns zero.
2212ie. if it fails.
2213
2214=cut
2215*/
2216
b33c08f8 2217int i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2218{
2219 int result = !flush ||
2220 info->filledto == 0 ||
2221 info->cb(info->userdata, info->buffer, info->filledto);
2222 myfree(info);
2223
2224 return result;
2225}
2226
8b302e44
TC
2227struct magic_entry {
2228 unsigned char *magic;
2229 size_t magic_size;
2230 char *name;
2231 unsigned char *mask;
2232};
2233
2234static int
2235test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
2236 if (length < magic->magic_size)
2237 return 0;
2238 if (magic->mask) {
2239 int i;
2240 unsigned char *bufp = buffer,
2241 *maskp = magic->mask,
2242 *magicp = magic->magic;
e10bf46e 2243
8b302e44
TC
2244 for (i = 0; i < magic->magic_size; ++i) {
2245 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
2246 ++maskp;
2247
2248 if ((*bufp++ & mask) != (*magicp++ & mask))
2249 return 0;
2250 }
2251
2252 return 1;
2253 }
2254 else {
2255 return !memcmp(magic->magic, buffer, magic->magic_size);
2256 }
2257}
e10bf46e 2258
84e51293
AMH
2259/*
2260=item i_test_format_probe(io_glue *data, int length)
2261
676d5bb5 2262Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
2263
2264=cut
2265*/
e10bf46e 2266
db7a8754
TC
2267#define FORMAT_ENTRY(magic, type) \
2268 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 2269#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 2270 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
2271
2272const char *
2273i_test_format_probe(io_glue *data, int length) {
8b302e44 2274 static const struct magic_entry formats[] = {
db7a8754
TC
2275 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
2276 FORMAT_ENTRY("GIF87a", "gif"),
2277 FORMAT_ENTRY("GIF89a", "gif"),
2278 FORMAT_ENTRY("MM\0*", "tiff"),
2279 FORMAT_ENTRY("II*\0", "tiff"),
2280 FORMAT_ENTRY("BM", "bmp"),
2281 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
2282 FORMAT_ENTRY("P1", "pnm"),
2283 FORMAT_ENTRY("P2", "pnm"),
2284 FORMAT_ENTRY("P3", "pnm"),
2285 FORMAT_ENTRY("P4", "pnm"),
2286 FORMAT_ENTRY("P5", "pnm"),
2287 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
2288 FORMAT_ENTRY("/* XPM", "xpm"),
2289 FORMAT_ENTRY("\x8aMNG", "mng"),
2290 FORMAT_ENTRY("\x8aJNG", "jng"),
2291 /* SGI RGB - with various possible parameters to avoid false positives
2292 on similar files
2293 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
2294 */
d5477d3d
TC
2295 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
2296 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
2297 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
2298 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
2299
2300 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
2301
2302 /* different versions of PCX format
2303 http://www.fileformat.info/format/pcx/
2304 */
2305 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 2306 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
2307 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
2308 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
2309 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
2310
2311 /* FITS - http://fits.gsfc.nasa.gov/ */
2312 FORMAT_ENTRY("SIMPLE =", "fits"),
2313
2314 /* PSD - Photoshop */
2315 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
2316
2317 /* EPS - Encapsulated Postscript */
2318 /* only reading 18 chars, so we don't include the F in EPSF */
2319 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
2320
2321 /* Utah RLE */
2322 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
2323
2324 /* GZIP compressed, only matching deflate for now */
2325 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
2326
2327 /* bzip2 compressed */
2328 FORMAT_ENTRY("BZh", "bzip2"),
e10bf46e 2329 };
8b302e44 2330 static const struct magic_entry more_formats[] = {
681d28fc
TC
2331 /* these were originally both listed as ico, but cur files can
2332 include hotspot information */
2333 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
2334 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
2335 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
2336 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 2337 };
db7a8754 2338
e10bf46e 2339 unsigned int i;
db7a8754 2340 unsigned char head[18];
84e51293 2341 ssize_t rc;
e10bf46e
AMH
2342
2343 io_glue_commit_types(data);
84e51293
AMH
2344 rc = data->readcb(data, head, 18);
2345 if (rc == -1) return NULL;
2346 data->seekcb(data, -rc, SEEK_CUR);
e10bf46e
AMH
2347
2348 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
2349 struct magic_entry const *entry = formats + i;
2350
2351 if (test_magic(head, rc, entry))
2352 return entry->name;
e10bf46e
AMH
2353 }
2354
ea1136fc 2355 if ((rc == 18) &&
db7a8754
TC
2356 tga_header_verify(head))
2357 return "tga";
2358
ea1136fc 2359 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
2360 struct magic_entry const *entry = more_formats + i;
2361
2362 if (test_magic(head, rc, entry))
2363 return entry->name;
ea1136fc
TC
2364 }
2365
2366 return NULL;
e10bf46e
AMH
2367}
2368
9c106321
TC
2369/*
2370=item i_img_is_monochrome(img, &zero_is_white)
2371
2372Tests an image to check it meets our monochrome tests.
2373
2374The idea is that a file writer can use this to test where it should
2375write the image in whatever bi-level format it uses, eg. pbm for pnm.
2376
2377For performance of encoders we require monochrome images:
2378
2379=over
2380
2381=item *
e10bf46e 2382
9c106321 2383be paletted
e10bf46e 2384
9c106321
TC
2385=item *
2386
2387have a palette of two colors, containing only (0,0,0) and
2388(255,255,255) in either order.
2389
2390=back
2391
2392zero_is_white is set to non-zero iff the first palette entry is white.
2393
2394=cut
2395*/
2396
2397int
2398i_img_is_monochrome(i_img *im, int *zero_is_white) {
2399 if (im->type == i_palette_type
2400 && i_colorcount(im) == 2) {
2401 i_color colors[2];
2402 i_getcolors(im, 0, colors, 2);
2403 if (im->channels == 3) {
2404 if (colors[0].rgb.r == 255 &&
2405 colors[0].rgb.g == 255 &&
2406 colors[0].rgb.b == 255 &&
2407 colors[1].rgb.r == 0 &&
2408 colors[1].rgb.g == 0 &&
2409 colors[1].rgb.b == 0) {
bd8052a6 2410 *zero_is_white = 1;
9c106321
TC
2411 return 1;
2412 }
2413 else if (colors[0].rgb.r == 0 &&
2414 colors[0].rgb.g == 0 &&
2415 colors[0].rgb.b == 0 &&
2416 colors[1].rgb.r == 255 &&
2417 colors[1].rgb.g == 255 &&
2418 colors[1].rgb.b == 255) {
bd8052a6 2419 *zero_is_white = 0;
9c106321
TC
2420 return 1;
2421 }
2422 }
2423 else if (im->channels == 1) {
2424 if (colors[0].channel[0] == 255 &&
bd8052a6
TC
2425 colors[1].channel[0] == 0) {
2426 *zero_is_white = 1;
9c106321
TC
2427 return 1;
2428 }
2429 else if (colors[0].channel[0] == 0 &&
bd8052a6
TC
2430 colors[1].channel[0] == 255) {
2431 *zero_is_white = 0;
9c106321
TC
2432 return 1;
2433 }
2434 }
2435 }
2436
2437 *zero_is_white = 0;
2438 return 0;
2439}
e10bf46e 2440
6e4af7d4
TC
2441/*
2442=item i_get_file_background(im, &bg)
2443
2444Retrieve the file write background color tag from the image.
2445
2446If not present, returns black.
2447
2448=cut
2449*/
2450
2451void
2452i_get_file_background(i_img *im, i_color *bg) {
2453 if (!i_tags_get_color(&im->tags, "i_background", 0, bg)) {
2454 /* black default */
2455 bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
2456 }
2457 /* always full alpha */
2458 bg->channel[3] = 255;
2459}
2460
fa90de94
TC
2461/*
2462=item i_get_file_backgroundf(im, &bg)
2463
2464Retrieve the file write background color tag from the image as a
2465floating point color.
2466
2467Implemented in terms of i_get_file_background().
2468
2469If not present, returns black.
2470
2471=cut
2472*/
2473
2474void
2475i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
2476 i_color bg;
2477
2478 i_get_file_background(im, &bg);
2479 fbg->rgba.r = Sample8ToF(bg.rgba.r);
2480 fbg->rgba.g = Sample8ToF(bg.rgba.g);
2481 fbg->rgba.b = Sample8ToF(bg.rgba.b);
2482 fbg->rgba.a = 1.0;
2483}
2484
02d1d628
AMH
2485/*
2486=back
2487
b8c2033e
AMH
2488=head1 AUTHOR
2489
2490Arnar M. Hrafnkelsson <addi@umich.edu>
2491
2492Tony Cook <tony@develop-help.com>
2493
02d1d628
AMH
2494=head1 SEE ALSO
2495
2496L<Imager>, L<gif.c>
2497
2498=cut
2499*/