- writing a 2 or 4 channel image to a JPEG will now write that image as
[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
07d70837 856 mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
02d1d628 857
b4e32feb 858
02d1d628 859 if (Axis == XAXIS) {
07d70837 860 hsize = (int)(0.5 + im->xsize * Value);
1501d9b3
TC
861 if (hsize < 1) {
862 hsize = 1;
b0950e71 863 Value = 1.0 / im->xsize;
1501d9b3 864 }
02d1d628
AMH
865 vsize = im->ysize;
866
867 jEnd = hsize;
868 iEnd = vsize;
02d1d628
AMH
869 } else {
870 hsize = im->xsize;
07d70837
AMH
871 vsize = (int)(0.5 + im->ysize * Value);
872
1501d9b3
TC
873 if (vsize < 1) {
874 vsize = 1;
b0950e71 875 Value = 1.0 / im->ysize;
1501d9b3
TC
876 }
877
02d1d628
AMH
878 jEnd = vsize;
879 iEnd = hsize;
02d1d628
AMH
880 }
881
07d70837 882 new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
02d1d628 883
0bcbaf60 884 /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
07d70837 885 LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value);
02d1d628
AMH
886 lMax = LanczosWidthFactor << 1;
887
07d70837
AMH
888 l0 = mymalloc(lMax * sizeof(float));
889 l1 = mymalloc(lMax * sizeof(float));
02d1d628
AMH
890
891 for (j=0; j<jEnd; j++) {
892 OldLocation = ((float) j) / Value;
893 T = (int) (OldLocation);
894 F = OldLocation - (float) T;
895
07d70837 896 for (l = 0; l<lMax; l++) {
02d1d628 897 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
07d70837
AMH
898 l1[l] = Lanczos(((float) (l+1) - F) / (float) LanczosWidthFactor);
899 }
900
901 /* Make sure filter is normalized */
902 t = 0.0;
903 for(l=0; l<lMax; l++) {
904 t+=l0[l];
905 t+=l1[l];
02d1d628 906 }
07d70837 907 t /= (float)LanczosWidthFactor;
02d1d628 908
07d70837
AMH
909 for(l=0; l<lMax; l++) {
910 l0[l] /= t;
911 l1[l] /= t;
912 }
913
914 if (Axis == XAXIS) {
02d1d628
AMH
915
916 for (i=0; i<iEnd; i++) {
917 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
0bcbaf60
AMH
918 for (l=0; l<lMax; l++) {
919 int mx = T-lMax+l+1;
920 int Mx = T+l+1;
921 mx = (mx < 0) ? 0 : mx;
922 Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
923
924 i_gpix(im, Mx, i, &val1);
925 i_gpix(im, mx, i, &val2);
926
02d1d628 927 for (k=0; k<im->channels; k++) {
07d70837 928 PictureValue[k] += l1[l] * val1.channel[k];
02d1d628
AMH
929 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
930 }
931 }
932 for(k=0;k<im->channels;k++) {
07d70837 933 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
02d1d628
AMH
934 val.channel[k]=minmax(0,255,psave);
935 }
07d70837 936 i_ppix(new_img, j, i, &val);
02d1d628
AMH
937 }
938
939 } else {
940
941 for (i=0; i<iEnd; i++) {
942 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
943 for (l=0; l < lMax; l++) {
0bcbaf60
AMH
944 int mx = T-lMax+l+1;
945 int Mx = T+l+1;
946 mx = (mx < 0) ? 0 : mx;
947 Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
948
949 i_gpix(im, i, Mx, &val1);
950 i_gpix(im, i, mx, &val2);
02d1d628 951 for (k=0; k<im->channels; k++) {
0bcbaf60 952 PictureValue[k] += l1[l] * val1.channel[k];
02d1d628
AMH
953 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
954 }
955 }
956 for (k=0; k<im->channels; k++) {
0bcbaf60 957 psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
07d70837 958 val.channel[k] = minmax(0, 255, psave);
02d1d628 959 }
07d70837 960 i_ppix(new_img, i, j, &val);
02d1d628
AMH
961 }
962
963 }
964 }
965 myfree(l0);
966 myfree(l1);
967
07d70837 968 mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
02d1d628
AMH
969
970 return new_img;
971}
972
973
974/*
975=item i_scale_nn(im, scx, scy)
976
977Scale by using nearest neighbor
978Both axes scaled at the same time since
979nothing is gained by doing it in two steps
980
981=cut
982*/
983
984
985i_img*
986i_scale_nn(i_img *im, float scx, float scy) {
987
988 int nxsize,nysize,nx,ny;
989 i_img *new_img;
990 i_color val;
991
992 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
993
994 nxsize = (int) ((float) im->xsize * scx);
1501d9b3
TC
995 if (nxsize < 1) {
996 nxsize = 1;
997 scx = 1 / im->xsize;
998 }
02d1d628 999 nysize = (int) ((float) im->ysize * scy);
1501d9b3
TC
1000 if (nysize < 1) {
1001 nysize = 1;
1002 scy = 1 / im->ysize;
1003 }
02d1d628
AMH
1004
1005 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1006
1007 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1008 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1009 i_ppix(new_img,nx,ny,&val);
1010 }
1011
1012 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1013
1014 return new_img;
1015}
1016
faa9b3e7
TC
1017/*
1018=item i_sametype(i_img *im, int xsize, int ysize)
1019
9167a5c6
TC
1020=category Image creation/destruction
1021=synopsis i_img *img = i_sametype(src, width, height);
92bda632 1022
faa9b3e7
TC
1023Returns an image of the same type (sample size, channels, paletted/direct).
1024
1025For paletted images the palette is copied from the source.
1026
1027=cut
1028*/
1029
1030i_img *i_sametype(i_img *src, int xsize, int ysize) {
1031 if (src->type == i_direct_type) {
1032 if (src->bits == 8) {
1033 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1034 }
af3c2450 1035 else if (src->bits == i_16_bits) {
faa9b3e7
TC
1036 return i_img_16_new(xsize, ysize, src->channels);
1037 }
af3c2450
TC
1038 else if (src->bits == i_double_bits) {
1039 return i_img_double_new(xsize, ysize, src->channels);
1040 }
faa9b3e7
TC
1041 else {
1042 i_push_error(0, "Unknown image bits");
1043 return NULL;
1044 }
1045 }
1046 else {
1047 i_color col;
1048 int i;
1049
1050 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1051 for (i = 0; i < i_colorcount(src); ++i) {
1052 i_getcolors(src, i, &col, 1);
1053 i_addcolors(targ, &col, 1);
1054 }
1055
1056 return targ;
1057 }
1058}
02d1d628 1059
dff75dee
TC
1060/*
1061=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1062
9167a5c6
TC
1063=category Image creation/destruction
1064=synopsis i_img *img = i_sametype_chans(src, width, height, channels);
92bda632 1065
dff75dee
TC
1066Returns an image of the same type (sample size).
1067
1068For paletted images the equivalent direct type is returned.
1069
1070=cut
1071*/
1072
1073i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1074 if (src->bits == 8) {
1075 return i_img_empty_ch(NULL, xsize, ysize, channels);
1076 }
1077 else if (src->bits == i_16_bits) {
1078 return i_img_16_new(xsize, ysize, channels);
1079 }
1080 else if (src->bits == i_double_bits) {
1081 return i_img_double_new(xsize, ysize, channels);
1082 }
1083 else {
1084 i_push_error(0, "Unknown image bits");
1085 return NULL;
1086 }
1087}
1088
02d1d628
AMH
1089/*
1090=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1091
1092Spatially transforms I<im> returning a new image.
1093
1094opx for a length of opxl and opy for a length of opy are arrays of
1095operators that modify the x and y positions to retreive the pixel data from.
1096
1097parm and parmlen define extra parameters that the operators may use.
1098
1099Note that this function is largely superseded by the more flexible
1100L<transform.c/i_transform2>.
1101
1102Returns the new image.
1103
1104The operators for this function are defined in L<stackmach.c>.
1105
1106=cut
1107*/
1108i_img*
1109i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1110 double rx,ry;
1111 int nxsize,nysize,nx,ny;
1112 i_img *new_img;
1113 i_color val;
1114
1115 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));
1116
1117 nxsize = im->xsize;
1118 nysize = im->ysize ;
1119
1120 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1121 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1122 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1123 /* parm[parmlen-2]=(double)nx;
1124 parm[parmlen-1]=(double)ny; */
1125
1126 parm[0]=(double)nx;
1127 parm[1]=(double)ny;
1128
1129 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
b33c08f8
TC
1130 rx=i_op_run(opx,opxl,parm,parmlen);
1131 ry=i_op_run(opy,opyl,parm,parmlen);
02d1d628
AMH
1132 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1133 i_gpix(im,rx,ry,&val);
1134 i_ppix(new_img,nx,ny,&val);
1135 }
1136
1137 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1138 return new_img;
1139}
1140
1141/*
1142=item i_img_diff(im1, im2)
1143
1144Calculates the sum of the squares of the differences between
1145correspoding channels in two images.
1146
1147If the images are not the same size then only the common area is
1148compared, hence even if images are different sizes this function
1149can return zero.
1150
1151=cut
1152*/
1153float
1154i_img_diff(i_img *im1,i_img *im2) {
1155 int x,y,ch,xb,yb,chb;
1156 float tdiff;
1157 i_color val1,val2;
1158
1159 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1160
1161 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1162 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1163 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1164
1165 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1166
1167 tdiff=0;
1168 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1169 i_gpix(im1,x,y,&val1);
1170 i_gpix(im2,x,y,&val2);
1171
1172 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1173 }
1174 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1175 return tdiff;
1176}
1177
1178/* just a tiny demo of haar wavelets */
1179
1180i_img*
1181i_haar(i_img *im) {
1182 int mx,my;
1183 int fx,fy;
1184 int x,y;
1185 int ch,c;
1186 i_img *new_img,*new_img2;
1187 i_color val1,val2,dval1,dval2;
1188
1189 mx=im->xsize;
1190 my=im->ysize;
1191 fx=(mx+1)/2;
1192 fy=(my+1)/2;
1193
1194
1195 /* horizontal pass */
1196
1197 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1198 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1199
1200 c=0;
1201 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1202 i_gpix(im,x*2,y,&val1);
1203 i_gpix(im,x*2+1,y,&val2);
1204 for(ch=0;ch<im->channels;ch++) {
1205 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1206 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1207 }
1208 i_ppix(new_img,x,y,&dval1);
1209 i_ppix(new_img,x+fx,y,&dval2);
1210 }
1211
1212 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1213 i_gpix(new_img,x,y*2,&val1);
1214 i_gpix(new_img,x,y*2+1,&val2);
1215 for(ch=0;ch<im->channels;ch++) {
1216 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1217 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1218 }
1219 i_ppix(new_img2,x,y,&dval1);
1220 i_ppix(new_img2,x,y+fy,&dval2);
1221 }
1222
1223 i_img_destroy(new_img);
1224 return new_img2;
1225}
1226
1227/*
1228=item i_count_colors(im, maxc)
1229
1230returns number of colors or -1
1231to indicate that it was more than max colors
1232
1233=cut
1234*/
fe622da1
TC
1235/* This function has been changed and is now faster. It's using
1236 * i_gsamp instead of i_gpix */
02d1d628
AMH
1237int
1238i_count_colors(i_img *im,int maxc) {
1239 struct octt *ct;
1240 int x,y;
02d1d628 1241 int colorcnt;
fe622da1
TC
1242 int channels[3];
1243 int *samp_chans;
1244 i_sample_t * samp;
fe622da1
TC
1245 int xsize = im->xsize;
1246 int ysize = im->ysize;
a60905e4
TC
1247 int samp_cnt = 3 * xsize;
1248
fe622da1
TC
1249 if (im->channels >= 3) {
1250 samp_chans = NULL;
1251 }
1252 else {
1253 channels[0] = channels[1] = channels[2] = 0;
1254 samp_chans = channels;
02d1d628 1255 }
a60905e4 1256
fe622da1
TC
1257 ct = octt_new();
1258
1259 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1260
1261 colorcnt = 0;
1262 for(y = 0; y < ysize; ) {
1263 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1264 for(x = 0; x < samp_cnt; ) {
1265 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1266 x += 3;
1267 if (colorcnt > maxc) {
1268 octt_delete(ct);
1269 return -1;
1270 }
1271 }
1272 }
1273 myfree(samp);
02d1d628
AMH
1274 octt_delete(ct);
1275 return colorcnt;
1276}
1277
fe622da1
TC
1278/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1279 * (adapted from the Numerical Recipes)
1280 */
1281/* Needed by get_anonymous_color_histo */
a60905e4
TC
1282static void
1283hpsort(unsigned int n, unsigned *ra) {
fe622da1
TC
1284 unsigned int i,
1285 ir,
1286 j,
1287 l,
1288 rra;
1289
1290 if (n < 2) return;
1291 l = n >> 1;
1292 ir = n - 1;
1293 for(;;) {
1294 if (l > 0) {
1295 rra = ra[--l];
1296 }
1297 else {
1298 rra = ra[ir];
1299 ra[ir] = ra[0];
1300 if (--ir == 0) {
1301 ra[0] = rra;
1302 break;
1303 }
1304 }
1305 i = l;
1306 j = 2 * l + 1;
1307 while (j <= ir) {
1308 if (j < ir && ra[j] < ra[j+1]) j++;
1309 if (rra < ra[j]) {
1310 ra[i] = ra[j];
1311 i = j;
1312 j++; j <<= 1; j--;
1313 }
1314 else break;
1315 }
1316 ra[i] = rra;
1317 }
1318}
1319
1320/* This function constructs an ordered list which represents how much the
1321 * different colors are used. So for instance (100, 100, 500) means that one
1322 * color is used for 500 pixels, another for 100 pixels and another for 100
1323 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1324 * the maxc ;-) and you might want to change the name... */
1325/* Uses octt_histo */
1326int
a60905e4
TC
1327i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1328 struct octt *ct;
1329 int x,y;
1330 int colorcnt;
1331 unsigned int *col_usage_it;
1332 i_sample_t * samp;
1333 int channels[3];
1334 int *samp_chans;
1335
1336 int xsize = im->xsize;
1337 int ysize = im->ysize;
1338 int samp_cnt = 3 * xsize;
1339 ct = octt_new();
1340
1341 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1342
1343 if (im->channels >= 3) {
1344 samp_chans = NULL;
1345 }
1346 else {
1347 channels[0] = channels[1] = channels[2] = 0;
1348 samp_chans = channels;
1349 }
1350
1351 colorcnt = 0;
1352 for(y = 0; y < ysize; ) {
1353 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1354 for(x = 0; x < samp_cnt; ) {
1355 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1356 x += 3;
1357 if (colorcnt > maxc) {
1358 octt_delete(ct);
1359 return -1;
1360 }
fe622da1 1361 }
a60905e4
TC
1362 }
1363 myfree(samp);
1364 /* Now that we know the number of colours... */
1365 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1366 octt_histo(ct, &col_usage_it);
1367 hpsort(colorcnt, *col_usage);
1368 octt_delete(ct);
1369 return colorcnt;
fe622da1
TC
1370}
1371
02d1d628 1372/*
faa9b3e7
TC
1373=back
1374
1375=head2 8-bit per sample image internal functions
1376
1377These are the functions installed in an 8-bit per sample image.
1378
1379=over
1380
1381=item i_ppix_d(im, x, y, col)
1382
1383Internal function.
1384
1385This is the function kept in the i_f_ppix member of an i_img object.
1386It does a normal store of a pixel into the image with range checking.
1387
1388Returns 0 if the pixel could be set, -1 otherwise.
1389
1390=cut
1391*/
63b018fd 1392static
faa9b3e7 1393int
97ac0a96 1394i_ppix_d(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
1395 int ch;
1396
1397 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1398 for(ch=0;ch<im->channels;ch++)
1399 if (im->ch_mask&(1<<ch))
1400 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1401 return 0;
1402 }
1403 return -1; /* error was clipped */
1404}
1405
1406/*
1407=item i_gpix_d(im, x, y, &col)
1408
1409Internal function.
1410
1411This is the function kept in the i_f_gpix member of an i_img object.
1412It does normal retrieval of a pixel from the image with range checking.
1413
1414Returns 0 if the pixel could be set, -1 otherwise.
1415
1416=cut
1417*/
63b018fd 1418static
faa9b3e7
TC
1419int
1420i_gpix_d(i_img *im, int x, int y, i_color *val) {
1421 int ch;
1422 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1423 for(ch=0;ch<im->channels;ch++)
9982a307 1424 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
faa9b3e7
TC
1425 return 0;
1426 }
0bcbaf60 1427 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
faa9b3e7
TC
1428 return -1; /* error was cliped */
1429}
1430
1431/*
1432=item i_glin_d(im, l, r, y, vals)
1433
1434Reads a line of data from the image, storing the pixels at vals.
1435
1436The line runs from (l,y) inclusive to (r,y) non-inclusive
1437
1438vals should point at space for (r-l) pixels.
1439
1440l should never be less than zero (to avoid confusion about where to
1441put the pixels in vals).
1442
1443Returns the number of pixels copied (eg. if r, l or y is out of range)
1444
1445=cut
1446*/
63b018fd 1447static
faa9b3e7
TC
1448int
1449i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1450 int ch, count, i;
1451 unsigned char *data;
1452 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1453 if (r > im->xsize)
1454 r = im->xsize;
1455 data = im->idata + (l+y*im->xsize) * im->channels;
1456 count = r - l;
1457 for (i = 0; i < count; ++i) {
1458 for (ch = 0; ch < im->channels; ++ch)
1459 vals[i].channel[ch] = *data++;
1460 }
1461 return count;
1462 }
1463 else {
1464 return 0;
1465 }
1466}
1467
1468/*
1469=item i_plin_d(im, l, r, y, vals)
1470
1471Writes a line of data into the image, using the pixels at vals.
1472
1473The line runs from (l,y) inclusive to (r,y) non-inclusive
1474
1475vals should point at (r-l) pixels.
1476
1477l should never be less than zero (to avoid confusion about where to
1478get the pixels in vals).
1479
1480Returns the number of pixels copied (eg. if r, l or y is out of range)
1481
1482=cut
1483*/
63b018fd 1484static
faa9b3e7 1485int
97ac0a96 1486i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
1487 int ch, count, i;
1488 unsigned char *data;
1489 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1490 if (r > im->xsize)
1491 r = im->xsize;
1492 data = im->idata + (l+y*im->xsize) * im->channels;
1493 count = r - l;
1494 for (i = 0; i < count; ++i) {
1495 for (ch = 0; ch < im->channels; ++ch) {
1496 if (im->ch_mask & (1 << ch))
1497 *data = vals[i].channel[ch];
1498 ++data;
1499 }
1500 }
1501 return count;
1502 }
1503 else {
1504 return 0;
1505 }
1506}
1507
1508/*
1509=item i_ppixf_d(im, x, y, val)
1510
1511=cut
1512*/
63b018fd 1513static
faa9b3e7 1514int
97ac0a96 1515i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
1516 int ch;
1517
1518 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1519 for(ch=0;ch<im->channels;ch++)
1520 if (im->ch_mask&(1<<ch)) {
1521 im->idata[(x+y*im->xsize)*im->channels+ch] =
1522 SampleFTo8(val->channel[ch]);
1523 }
1524 return 0;
1525 }
1526 return -1; /* error was clipped */
1527}
1528
1529/*
1530=item i_gpixf_d(im, x, y, val)
1531
1532=cut
1533*/
63b018fd 1534static
faa9b3e7
TC
1535int
1536i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1537 int ch;
1538 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1539 for(ch=0;ch<im->channels;ch++) {
1540 val->channel[ch] =
1541 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1542 }
1543 return 0;
1544 }
1545 return -1; /* error was cliped */
1546}
1547
1548/*
1549=item i_glinf_d(im, l, r, y, vals)
1550
1551Reads a line of data from the image, storing the pixels at vals.
1552
1553The line runs from (l,y) inclusive to (r,y) non-inclusive
1554
1555vals should point at space for (r-l) pixels.
1556
1557l should never be less than zero (to avoid confusion about where to
1558put the pixels in vals).
1559
1560Returns the number of pixels copied (eg. if r, l or y is out of range)
1561
1562=cut
1563*/
63b018fd 1564static
faa9b3e7
TC
1565int
1566i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1567 int ch, count, i;
1568 unsigned char *data;
1569 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1570 if (r > im->xsize)
1571 r = im->xsize;
1572 data = im->idata + (l+y*im->xsize) * im->channels;
1573 count = r - l;
1574 for (i = 0; i < count; ++i) {
1575 for (ch = 0; ch < im->channels; ++ch)
6607600c 1576 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1577 }
1578 return count;
1579 }
1580 else {
1581 return 0;
1582 }
1583}
1584
1585/*
1586=item i_plinf_d(im, l, r, y, vals)
1587
1588Writes a line of data into the image, using the pixels at vals.
1589
1590The line runs from (l,y) inclusive to (r,y) non-inclusive
1591
1592vals should point at (r-l) pixels.
1593
1594l should never be less than zero (to avoid confusion about where to
1595get the pixels in vals).
1596
1597Returns the number of pixels copied (eg. if r, l or y is out of range)
1598
1599=cut
1600*/
63b018fd 1601static
faa9b3e7 1602int
97ac0a96 1603i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
1604 int ch, count, i;
1605 unsigned char *data;
1606 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1607 if (r > im->xsize)
1608 r = im->xsize;
1609 data = im->idata + (l+y*im->xsize) * im->channels;
1610 count = r - l;
1611 for (i = 0; i < count; ++i) {
1612 for (ch = 0; ch < im->channels; ++ch) {
1613 if (im->ch_mask & (1 << ch))
6607600c 1614 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1615 ++data;
1616 }
1617 }
1618 return count;
1619 }
1620 else {
1621 return 0;
1622 }
1623}
1624
1625/*
1626=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1627
1628Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1629for the channels specified by chans, an array of int with chan_count
1630elements.
1631
1632Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1633
1634=cut
1635*/
63b018fd
AMH
1636static
1637int
1638i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 1639 const int *chans, int chan_count) {
faa9b3e7
TC
1640 int ch, count, i, w;
1641 unsigned char *data;
1642
1643 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1644 if (r > im->xsize)
1645 r = im->xsize;
1646 data = im->idata + (l+y*im->xsize) * im->channels;
1647 w = r - l;
1648 count = 0;
1649
1650 if (chans) {
1651 /* make sure we have good channel numbers */
1652 for (ch = 0; ch < chan_count; ++ch) {
1653 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1654 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1655 return 0;
1656 }
1657 }
1658 for (i = 0; i < w; ++i) {
1659 for (ch = 0; ch < chan_count; ++ch) {
1660 *samps++ = data[chans[ch]];
1661 ++count;
1662 }
1663 data += im->channels;
1664 }
1665 }
1666 else {
c7481ae1
TC
1667 if (chan_count <= 0 || chan_count > im->channels) {
1668 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1669 chan_count);
1670 return 0;
1671 }
faa9b3e7
TC
1672 for (i = 0; i < w; ++i) {
1673 for (ch = 0; ch < chan_count; ++ch) {
1674 *samps++ = data[ch];
1675 ++count;
1676 }
1677 data += im->channels;
1678 }
1679 }
1680
1681 return count;
1682 }
1683 else {
1684 return 0;
1685 }
1686}
1687
1688/*
1689=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1690
1691Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1692for the channels specified by chan_mask, where bit 0 is the first
1693channel.
1694
1695Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1696
1697=cut
1698*/
63b018fd
AMH
1699static
1700int
1701i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 1702 const int *chans, int chan_count) {
faa9b3e7
TC
1703 int ch, count, i, w;
1704 unsigned char *data;
1705 for (ch = 0; ch < chan_count; ++ch) {
1706 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1707 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1708 }
1709 }
1710 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1711 if (r > im->xsize)
1712 r = im->xsize;
1713 data = im->idata + (l+y*im->xsize) * im->channels;
1714 w = r - l;
1715 count = 0;
1716
1717 if (chans) {
1718 /* make sure we have good channel numbers */
1719 for (ch = 0; ch < chan_count; ++ch) {
1720 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1721 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1722 return 0;
1723 }
1724 }
1725 for (i = 0; i < w; ++i) {
1726 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1727 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1728 ++count;
1729 }
1730 data += im->channels;
1731 }
1732 }
1733 else {
c7481ae1
TC
1734 if (chan_count <= 0 || chan_count > im->channels) {
1735 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1736 chan_count);
1737 return 0;
1738 }
faa9b3e7
TC
1739 for (i = 0; i < w; ++i) {
1740 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1741 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1742 ++count;
1743 }
1744 data += im->channels;
1745 }
1746 }
1747 return count;
1748 }
1749 else {
1750 return 0;
1751 }
1752}
1753
1754/*
1755=back
1756
1757=head2 Image method wrappers
1758
1759These functions provide i_fsample_t functions in terms of their
1760i_sample_t versions.
1761
1762=over
1763
1764=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1765
1766=cut
1767*/
1768
97ac0a96 1769int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
faa9b3e7
TC
1770 i_color temp;
1771 int ch;
1772
1773 for (ch = 0; ch < im->channels; ++ch)
1774 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1775
1776 return i_ppix(im, x, y, &temp);
1777}
1778
1779/*
1780=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1781
1782=cut
1783*/
1784int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1785 i_color temp;
1786 int ch;
1787
1788 if (i_gpix(im, x, y, &temp)) {
1789 for (ch = 0; ch < im->channels; ++ch)
1790 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1791 return 0;
1792 }
1793 else
1794 return -1;
1795}
1796
1797/*
1798=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1799
1800=cut
1801*/
97ac0a96 1802int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
faa9b3e7
TC
1803 i_color *work;
1804
1805 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1806 if (r > im->xsize)
1807 r = im->xsize;
1808 if (r > l) {
1809 int ret;
1810 int i, ch;
1811 work = mymalloc(sizeof(i_color) * (r-l));
1812 for (i = 0; i < r-l; ++i) {
1813 for (ch = 0; ch < im->channels; ++ch)
1814 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1815 }
1816 ret = i_plin(im, l, r, y, work);
1817 myfree(work);
1818
1819 return ret;
1820 }
1821 else {
1822 return 0;
1823 }
1824 }
1825 else {
1826 return 0;
1827 }
1828}
1829
1830/*
1831=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1832
1833=cut
1834*/
1835int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1836 i_color *work;
1837
1838 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1839 if (r > im->xsize)
1840 r = im->xsize;
1841 if (r > l) {
1842 int ret;
1843 int i, ch;
1844 work = mymalloc(sizeof(i_color) * (r-l));
1845 ret = i_plin(im, l, r, y, work);
1846 for (i = 0; i < r-l; ++i) {
1847 for (ch = 0; ch < im->channels; ++ch)
1848 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1849 }
1850 myfree(work);
1851
1852 return ret;
1853 }
1854 else {
1855 return 0;
1856 }
1857 }
1858 else {
1859 return 0;
1860 }
1861}
1862
1863/*
1864=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1865
1866=cut
1867*/
1868int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
18accb2a 1869 int const *chans, int chan_count) {
faa9b3e7
TC
1870 i_sample_t *work;
1871
1872 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1873 if (r > im->xsize)
1874 r = im->xsize;
1875 if (r > l) {
1876 int ret;
1877 int i;
1878 work = mymalloc(sizeof(i_sample_t) * (r-l));
1879 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1880 for (i = 0; i < ret; ++i) {
1881 samp[i] = Sample8ToF(work[i]);
1882 }
1883 myfree(work);
1884
1885 return ret;
1886 }
1887 else {
1888 return 0;
1889 }
1890 }
1891 else {
1892 return 0;
1893 }
1894}
1895
1896/*
1897=back
1898
1899=head2 Palette wrapper functions
1900
1901Used for virtual images, these forward palette calls to a wrapped image,
1902assuming the wrapped image is the first pointer in the structure that
1903im->ext_data points at.
1904
1905=over
1906
97ac0a96 1907=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1908
1909=cut
1910*/
97ac0a96 1911int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1912 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1913}
1914
1915/*
1916=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1917
1918=cut
1919*/
1920int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1921 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1922}
1923
1924/*
97ac0a96 1925=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1926
1927=cut
1928*/
97ac0a96 1929int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1930 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1931}
1932
1933/*
1934=item i_colorcount_forward(i_img *im)
1935
1936=cut
1937*/
1938int i_colorcount_forward(i_img *im) {
1939 return i_colorcount(*(i_img **)im->ext_data);
1940}
1941
1942/*
1943=item i_maxcolors_forward(i_img *im)
1944
1945=cut
1946*/
1947int i_maxcolors_forward(i_img *im) {
1948 return i_maxcolors(*(i_img **)im->ext_data);
1949}
1950
1951/*
97ac0a96 1952=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1953
1954=cut
1955*/
97ac0a96 1956int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1957 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1958}
1959
1960/*
1961=back
1962
bd8052a6
TC
1963=head2 Fallback handler
1964
1965=over
1966
1967=item i_gsamp_bits_fb
1968
1969=cut
1970*/
1971
1972int
1973i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
1974 const int *chans, int chan_count, int bits) {
1975 if (bits < 1 || bits > 32) {
1976 i_push_error(0, "Invalid bits, must be 1..32");
1977 return -1;
1978 }
1979
1980 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1981 double scale;
1982 int ch, count, i, w;
1983
1984 if (bits == 32)
1985 scale = 4294967295.0;
1986 else
1987 scale = (double)(1 << bits) - 1;
1988
1989 if (r > im->xsize)
1990 r = im->xsize;
1991 w = r - l;
1992 count = 0;
1993
1994 if (chans) {
1995 /* make sure we have good channel numbers */
1996 for (ch = 0; ch < chan_count; ++ch) {
1997 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1998 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1999 return -1;
2000 }
2001 }
2002 for (i = 0; i < w; ++i) {
2003 i_fcolor c;
2004 i_gpixf(im, l+i, y, &c);
2005 for (ch = 0; ch < chan_count; ++ch) {
2006 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2007 ++count;
2008 }
2009 }
2010 }
2011 else {
2012 if (chan_count <= 0 || chan_count > im->channels) {
2013 i_push_error(0, "Invalid channel count");
2014 return -1;
2015 }
2016 for (i = 0; i < w; ++i) {
2017 i_fcolor c;
2018 i_gpixf(im, l+i, y, &c);
2019 for (ch = 0; ch < chan_count; ++ch) {
2020 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2021 ++count;
2022 }
2023 }
2024 }
2025
2026 return count;
2027 }
2028 else {
2029 i_push_error(0, "Image position outside of image");
2030 return -1;
2031 }
2032}
2033
2034/*
2035=back
2036
faa9b3e7
TC
2037=head2 Stream reading and writing wrapper functions
2038
2039=over
2040
02d1d628
AMH
2041=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
2042
2043Performs general read buffering for file readers that permit reading
2044to be done through a callback.
2045
2046The final callback gets two parameters, a I<need> value, and a I<want>
2047value, where I<need> is the amount of data that the file library needs
2048to read, and I<want> is the amount of space available in the buffer
2049maintained by these functions.
2050
2051This means if you need to read from a stream that you don't know the
2052length of, you can return I<need> bytes, taking the performance hit of
2053possibly expensive callbacks (eg. back to perl code), or if you are
2054reading from a stream where it doesn't matter if some data is lost, or
2055if the total length of the stream is known, you can return I<want>
2056bytes.
2057
2058=cut
2059*/
2060
2061int
2062i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
2063 int total;
2064
2065 if (length < gci->length - gci->cpos) {
2066 /* simplest case */
2067 memcpy(buf, gci->buffer+gci->cpos, length);
2068 gci->cpos += length;
2069 return length;
2070 }
2071
2072 total = 0;
2073 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
2074 total += gci->length - gci->cpos;
2075 length -= gci->length - gci->cpos;
2076 buf += gci->length - gci->cpos;
2077 if (length < (int)sizeof(gci->buffer)) {
2078 int did_read;
2079 int copy_size;
2080 while (length
2081 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
2082 sizeof(gci->buffer))) > 0) {
2083 gci->cpos = 0;
2084 gci->length = did_read;
2085
b33c08f8 2086 copy_size = i_min(length, gci->length);
02d1d628
AMH
2087 memcpy(buf, gci->buffer, copy_size);
2088 gci->cpos += copy_size;
2089 buf += copy_size;
2090 total += copy_size;
2091 length -= copy_size;
2092 }
2093 }
2094 else {
2095 /* just read the rest - too big for our buffer*/
2096 int did_read;
2097 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2098 length -= did_read;
2099 total += did_read;
2100 buf += did_read;
2101 }
2102 }
2103 return total;
2104}
2105
2106/*
2107=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2108
2109For use by callback file readers to initialize the reader buffer.
2110
2111Allocates, initializes and returns the reader buffer.
2112
2113See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2114
2115=cut
2116*/
2117i_gen_read_data *
2118i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2119 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2120 self->cb = cb;
2121 self->userdata = userdata;
2122 self->length = 0;
2123 self->cpos = 0;
2124
2125 return self;
2126}
2127
2128/*
b33c08f8 2129=item i_free_gen_read_data(i_gen_read_data *)
02d1d628
AMH
2130
2131Cleans up.
2132
2133=cut
2134*/
b33c08f8 2135void i_free_gen_read_data(i_gen_read_data *self) {
02d1d628
AMH
2136 myfree(self);
2137}
2138
2139/*
2140=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2141
2142Performs write buffering for a callback based file writer.
2143
2144Failures are considered fatal, if a write fails then data will be
2145dropped.
2146
2147=cut
2148*/
2149int
2150i_gen_writer(
2151i_gen_write_data *self,
2152char const *data,
2153int size)
2154{
2155 if (self->filledto && self->filledto+size > self->maxlength) {
2156 if (self->cb(self->userdata, self->buffer, self->filledto)) {
2157 self->filledto = 0;
2158 }
2159 else {
2160 self->filledto = 0;
2161 return 0;
2162 }
2163 }
2164 if (self->filledto+size <= self->maxlength) {
2165 /* just save it */
2166 memcpy(self->buffer+self->filledto, data, size);
2167 self->filledto += size;
2168 return 1;
2169 }
2170 /* doesn't fit - hand it off */
2171 return self->cb(self->userdata, data, size);
2172}
2173
2174/*
2175=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2176
2177Allocates and initializes the data structure used by i_gen_writer.
2178
b33c08f8 2179This should be released with L<image.c/i_free_gen_write_data>
02d1d628
AMH
2180
2181=cut
2182*/
2183i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2184 char *userdata, int max_length)
2185{
2186 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2187 self->cb = cb;
2188 self->userdata = userdata;
b33c08f8 2189 self->maxlength = i_min(max_length, sizeof(self->buffer));
02d1d628
AMH
2190 if (self->maxlength < 0)
2191 self->maxlength = sizeof(self->buffer);
2192 self->filledto = 0;
2193
2194 return self;
2195}
2196
2197/*
b33c08f8 2198=item i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2199
2200Cleans up the write buffer.
2201
2202Will flush any left-over data if I<flush> is non-zero.
2203
2204Returns non-zero if flush is zero or if info->cb() returns non-zero.
2205
2206Return zero only if flush is non-zero and info->cb() returns zero.
2207ie. if it fails.
2208
2209=cut
2210*/
2211
b33c08f8 2212int i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2213{
2214 int result = !flush ||
2215 info->filledto == 0 ||
2216 info->cb(info->userdata, info->buffer, info->filledto);
2217 myfree(info);
2218
2219 return result;
2220}
2221
8b302e44
TC
2222struct magic_entry {
2223 unsigned char *magic;
2224 size_t magic_size;
2225 char *name;
2226 unsigned char *mask;
2227};
2228
2229static int
2230test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
2231 if (length < magic->magic_size)
2232 return 0;
2233 if (magic->mask) {
2234 int i;
2235 unsigned char *bufp = buffer,
2236 *maskp = magic->mask,
2237 *magicp = magic->magic;
e10bf46e 2238
8b302e44
TC
2239 for (i = 0; i < magic->magic_size; ++i) {
2240 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
2241 ++maskp;
2242
2243 if ((*bufp++ & mask) != (*magicp++ & mask))
2244 return 0;
2245 }
2246
2247 return 1;
2248 }
2249 else {
2250 return !memcmp(magic->magic, buffer, magic->magic_size);
2251 }
2252}
e10bf46e 2253
84e51293
AMH
2254/*
2255=item i_test_format_probe(io_glue *data, int length)
2256
676d5bb5 2257Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
2258
2259=cut
2260*/
e10bf46e 2261
db7a8754
TC
2262#define FORMAT_ENTRY(magic, type) \
2263 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 2264#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 2265 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
2266
2267const char *
2268i_test_format_probe(io_glue *data, int length) {
8b302e44 2269 static const struct magic_entry formats[] = {
db7a8754
TC
2270 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
2271 FORMAT_ENTRY("GIF87a", "gif"),
2272 FORMAT_ENTRY("GIF89a", "gif"),
2273 FORMAT_ENTRY("MM\0*", "tiff"),
2274 FORMAT_ENTRY("II*\0", "tiff"),
2275 FORMAT_ENTRY("BM", "bmp"),
2276 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
2277 FORMAT_ENTRY("P1", "pnm"),
2278 FORMAT_ENTRY("P2", "pnm"),
2279 FORMAT_ENTRY("P3", "pnm"),
2280 FORMAT_ENTRY("P4", "pnm"),
2281 FORMAT_ENTRY("P5", "pnm"),
2282 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
2283 FORMAT_ENTRY("/* XPM", "xpm"),
2284 FORMAT_ENTRY("\x8aMNG", "mng"),
2285 FORMAT_ENTRY("\x8aJNG", "jng"),
2286 /* SGI RGB - with various possible parameters to avoid false positives
2287 on similar files
2288 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
2289 */
d5477d3d
TC
2290 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
2291 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
2292 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
2293 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
2294
2295 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
2296
2297 /* different versions of PCX format
2298 http://www.fileformat.info/format/pcx/
2299 */
2300 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 2301 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
2302 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
2303 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
2304 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
2305
2306 /* FITS - http://fits.gsfc.nasa.gov/ */
2307 FORMAT_ENTRY("SIMPLE =", "fits"),
2308
2309 /* PSD - Photoshop */
2310 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
2311
2312 /* EPS - Encapsulated Postscript */
2313 /* only reading 18 chars, so we don't include the F in EPSF */
2314 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
2315
2316 /* Utah RLE */
2317 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
2318
2319 /* GZIP compressed, only matching deflate for now */
2320 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
2321
2322 /* bzip2 compressed */
2323 FORMAT_ENTRY("BZh", "bzip2"),
e10bf46e 2324 };
8b302e44 2325 static const struct magic_entry more_formats[] = {
681d28fc
TC
2326 /* these were originally both listed as ico, but cur files can
2327 include hotspot information */
2328 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
2329 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
2330 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
2331 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 2332 };
db7a8754 2333
e10bf46e 2334 unsigned int i;
db7a8754 2335 unsigned char head[18];
84e51293 2336 ssize_t rc;
e10bf46e
AMH
2337
2338 io_glue_commit_types(data);
84e51293
AMH
2339 rc = data->readcb(data, head, 18);
2340 if (rc == -1) return NULL;
2341 data->seekcb(data, -rc, SEEK_CUR);
e10bf46e
AMH
2342
2343 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
2344 struct magic_entry const *entry = formats + i;
2345
2346 if (test_magic(head, rc, entry))
2347 return entry->name;
e10bf46e
AMH
2348 }
2349
ea1136fc 2350 if ((rc == 18) &&
db7a8754
TC
2351 tga_header_verify(head))
2352 return "tga";
2353
ea1136fc 2354 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
2355 struct magic_entry const *entry = more_formats + i;
2356
2357 if (test_magic(head, rc, entry))
2358 return entry->name;
ea1136fc
TC
2359 }
2360
2361 return NULL;
e10bf46e
AMH
2362}
2363
9c106321
TC
2364/*
2365=item i_img_is_monochrome(img, &zero_is_white)
2366
2367Tests an image to check it meets our monochrome tests.
2368
2369The idea is that a file writer can use this to test where it should
2370write the image in whatever bi-level format it uses, eg. pbm for pnm.
2371
2372For performance of encoders we require monochrome images:
2373
2374=over
2375
2376=item *
e10bf46e 2377
9c106321 2378be paletted
e10bf46e 2379
9c106321
TC
2380=item *
2381
2382have a palette of two colors, containing only (0,0,0) and
2383(255,255,255) in either order.
2384
2385=back
2386
2387zero_is_white is set to non-zero iff the first palette entry is white.
2388
2389=cut
2390*/
2391
2392int
2393i_img_is_monochrome(i_img *im, int *zero_is_white) {
2394 if (im->type == i_palette_type
2395 && i_colorcount(im) == 2) {
2396 i_color colors[2];
2397 i_getcolors(im, 0, colors, 2);
2398 if (im->channels == 3) {
2399 if (colors[0].rgb.r == 255 &&
2400 colors[0].rgb.g == 255 &&
2401 colors[0].rgb.b == 255 &&
2402 colors[1].rgb.r == 0 &&
2403 colors[1].rgb.g == 0 &&
2404 colors[1].rgb.b == 0) {
bd8052a6 2405 *zero_is_white = 1;
9c106321
TC
2406 return 1;
2407 }
2408 else if (colors[0].rgb.r == 0 &&
2409 colors[0].rgb.g == 0 &&
2410 colors[0].rgb.b == 0 &&
2411 colors[1].rgb.r == 255 &&
2412 colors[1].rgb.g == 255 &&
2413 colors[1].rgb.b == 255) {
bd8052a6 2414 *zero_is_white = 0;
9c106321
TC
2415 return 1;
2416 }
2417 }
2418 else if (im->channels == 1) {
2419 if (colors[0].channel[0] == 255 &&
bd8052a6
TC
2420 colors[1].channel[0] == 0) {
2421 *zero_is_white = 1;
9c106321
TC
2422 return 1;
2423 }
2424 else if (colors[0].channel[0] == 0 &&
bd8052a6
TC
2425 colors[1].channel[0] == 255) {
2426 *zero_is_white = 0;
9c106321
TC
2427 return 1;
2428 }
2429 }
2430 }
2431
2432 *zero_is_white = 0;
2433 return 0;
2434}
e10bf46e 2435
6e4af7d4
TC
2436/*
2437=item i_get_file_background(im, &bg)
2438
2439Retrieve the file write background color tag from the image.
2440
2441If not present, returns black.
2442
2443=cut
2444*/
2445
2446void
2447i_get_file_background(i_img *im, i_color *bg) {
2448 if (!i_tags_get_color(&im->tags, "i_background", 0, bg)) {
2449 /* black default */
2450 bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
2451 }
2452 /* always full alpha */
2453 bg->channel[3] = 255;
2454}
2455
02d1d628
AMH
2456/*
2457=back
2458
b8c2033e
AMH
2459=head1 AUTHOR
2460
2461Arnar M. Hrafnkelsson <addi@umich.edu>
2462
2463Tony Cook <tony@develop-help.com>
2464
02d1d628
AMH
2465=head1 SEE ALSO
2466
2467L<Imager>, L<gif.c>
2468
2469=cut
2470*/