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