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