convert t/t90cc.t to Test::More and actually test a bit more
[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;
1267
1268 int xsize = im->xsize;
1269 int ysize = im->ysize;
1270 if (im->channels >= 3) {
1271 samp_chans = NULL;
1272 }
1273 else {
1274 channels[0] = channels[1] = channels[2] = 0;
1275 samp_chans = channels;
02d1d628 1276 }
fe622da1
TC
1277 int samp_cnt = 3 * xsize;
1278 ct = octt_new();
1279
1280 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1281
1282 colorcnt = 0;
1283 for(y = 0; y < ysize; ) {
1284 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1285 for(x = 0; x < samp_cnt; ) {
1286 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1287 x += 3;
1288 if (colorcnt > maxc) {
1289 octt_delete(ct);
1290 return -1;
1291 }
1292 }
1293 }
1294 myfree(samp);
02d1d628
AMH
1295 octt_delete(ct);
1296 return colorcnt;
1297}
1298
fe622da1
TC
1299/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1300 * (adapted from the Numerical Recipes)
1301 */
1302/* Needed by get_anonymous_color_histo */
1303void hpsort(unsigned int n, int *ra) {
1304 unsigned int i,
1305 ir,
1306 j,
1307 l,
1308 rra;
1309
1310 if (n < 2) return;
1311 l = n >> 1;
1312 ir = n - 1;
1313 for(;;) {
1314 if (l > 0) {
1315 rra = ra[--l];
1316 }
1317 else {
1318 rra = ra[ir];
1319 ra[ir] = ra[0];
1320 if (--ir == 0) {
1321 ra[0] = rra;
1322 break;
1323 }
1324 }
1325 i = l;
1326 j = 2 * l + 1;
1327 while (j <= ir) {
1328 if (j < ir && ra[j] < ra[j+1]) j++;
1329 if (rra < ra[j]) {
1330 ra[i] = ra[j];
1331 i = j;
1332 j++; j <<= 1; j--;
1333 }
1334 else break;
1335 }
1336 ra[i] = rra;
1337 }
1338}
1339
1340/* This function constructs an ordered list which represents how much the
1341 * different colors are used. So for instance (100, 100, 500) means that one
1342 * color is used for 500 pixels, another for 100 pixels and another for 100
1343 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1344 * the maxc ;-) and you might want to change the name... */
1345/* Uses octt_histo */
1346int
1347get_anonymous_color_histo(i_img *im, unsigned int **col_usage) {
1348 struct octt *ct;
1349 int x,y,i;
1350 int colorcnt;
1351 int maxc = 10000000;
1352 unsigned int *col_usage_it;
1353 i_sample_t * samp;
1354
1355 int xsize = im->xsize;
1356 int ysize = im->ysize;
1357 int samp_cnt = 3 * xsize;
1358 ct = octt_new();
1359
1360 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1361
1362 colorcnt = 0;
1363 for(y = 0; y < ysize; ) {
1364 i_gsamp(im, 0, xsize, y++, samp, NULL, 3);
1365 for(x = 0; x < samp_cnt; ) {
1366 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1367 x += 3;
1368 if (colorcnt > maxc) {
1369 octt_delete(ct);
1370 return -1;
1371 }
1372 }
1373 }
1374 myfree(samp);
1375 /* Now that we know the number of colours... */
1376 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * 2 * sizeof(unsigned int));
1377 octt_histo(ct, &col_usage_it);
1378 hpsort(colorcnt, *col_usage);
1379 octt_delete(ct);
1380 return colorcnt;
1381}
1382
1383
1384
02d1d628 1385/*
faa9b3e7
TC
1386=back
1387
1388=head2 8-bit per sample image internal functions
1389
1390These are the functions installed in an 8-bit per sample image.
1391
1392=over
1393
1394=item i_ppix_d(im, x, y, col)
1395
1396Internal function.
1397
1398This is the function kept in the i_f_ppix member of an i_img object.
1399It does a normal store of a pixel into the image with range checking.
1400
1401Returns 0 if the pixel could be set, -1 otherwise.
1402
1403=cut
1404*/
63b018fd 1405static
faa9b3e7 1406int
97ac0a96 1407i_ppix_d(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
1408 int ch;
1409
1410 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1411 for(ch=0;ch<im->channels;ch++)
1412 if (im->ch_mask&(1<<ch))
1413 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1414 return 0;
1415 }
1416 return -1; /* error was clipped */
1417}
1418
1419/*
1420=item i_gpix_d(im, x, y, &col)
1421
1422Internal function.
1423
1424This is the function kept in the i_f_gpix member of an i_img object.
1425It does normal retrieval of a pixel from the image with range checking.
1426
1427Returns 0 if the pixel could be set, -1 otherwise.
1428
1429=cut
1430*/
63b018fd 1431static
faa9b3e7
TC
1432int
1433i_gpix_d(i_img *im, int x, int y, i_color *val) {
1434 int ch;
1435 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1436 for(ch=0;ch<im->channels;ch++)
9982a307 1437 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
faa9b3e7
TC
1438 return 0;
1439 }
0bcbaf60 1440 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
faa9b3e7
TC
1441 return -1; /* error was cliped */
1442}
1443
1444/*
1445=item i_glin_d(im, l, r, y, vals)
1446
1447Reads a line of data from the image, storing the pixels at vals.
1448
1449The line runs from (l,y) inclusive to (r,y) non-inclusive
1450
1451vals should point at space for (r-l) pixels.
1452
1453l should never be less than zero (to avoid confusion about where to
1454put the pixels in vals).
1455
1456Returns the number of pixels copied (eg. if r, l or y is out of range)
1457
1458=cut
1459*/
63b018fd 1460static
faa9b3e7
TC
1461int
1462i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1463 int ch, count, i;
1464 unsigned char *data;
1465 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1466 if (r > im->xsize)
1467 r = im->xsize;
1468 data = im->idata + (l+y*im->xsize) * im->channels;
1469 count = r - l;
1470 for (i = 0; i < count; ++i) {
1471 for (ch = 0; ch < im->channels; ++ch)
1472 vals[i].channel[ch] = *data++;
1473 }
1474 return count;
1475 }
1476 else {
1477 return 0;
1478 }
1479}
1480
1481/*
1482=item i_plin_d(im, l, r, y, vals)
1483
1484Writes a line of data into the image, using the pixels at vals.
1485
1486The line runs from (l,y) inclusive to (r,y) non-inclusive
1487
1488vals should point at (r-l) pixels.
1489
1490l should never be less than zero (to avoid confusion about where to
1491get the pixels in vals).
1492
1493Returns the number of pixels copied (eg. if r, l or y is out of range)
1494
1495=cut
1496*/
63b018fd 1497static
faa9b3e7 1498int
97ac0a96 1499i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
1500 int ch, count, i;
1501 unsigned char *data;
1502 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1503 if (r > im->xsize)
1504 r = im->xsize;
1505 data = im->idata + (l+y*im->xsize) * im->channels;
1506 count = r - l;
1507 for (i = 0; i < count; ++i) {
1508 for (ch = 0; ch < im->channels; ++ch) {
1509 if (im->ch_mask & (1 << ch))
1510 *data = vals[i].channel[ch];
1511 ++data;
1512 }
1513 }
1514 return count;
1515 }
1516 else {
1517 return 0;
1518 }
1519}
1520
1521/*
1522=item i_ppixf_d(im, x, y, val)
1523
1524=cut
1525*/
63b018fd 1526static
faa9b3e7 1527int
97ac0a96 1528i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
1529 int ch;
1530
1531 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1532 for(ch=0;ch<im->channels;ch++)
1533 if (im->ch_mask&(1<<ch)) {
1534 im->idata[(x+y*im->xsize)*im->channels+ch] =
1535 SampleFTo8(val->channel[ch]);
1536 }
1537 return 0;
1538 }
1539 return -1; /* error was clipped */
1540}
1541
1542/*
1543=item i_gpixf_d(im, x, y, val)
1544
1545=cut
1546*/
63b018fd 1547static
faa9b3e7
TC
1548int
1549i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1550 int ch;
1551 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1552 for(ch=0;ch<im->channels;ch++) {
1553 val->channel[ch] =
1554 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1555 }
1556 return 0;
1557 }
1558 return -1; /* error was cliped */
1559}
1560
1561/*
1562=item i_glinf_d(im, l, r, y, vals)
1563
1564Reads a line of data from the image, storing the pixels at vals.
1565
1566The line runs from (l,y) inclusive to (r,y) non-inclusive
1567
1568vals should point at space for (r-l) pixels.
1569
1570l should never be less than zero (to avoid confusion about where to
1571put the pixels in vals).
1572
1573Returns the number of pixels copied (eg. if r, l or y is out of range)
1574
1575=cut
1576*/
63b018fd 1577static
faa9b3e7
TC
1578int
1579i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1580 int ch, count, i;
1581 unsigned char *data;
1582 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1583 if (r > im->xsize)
1584 r = im->xsize;
1585 data = im->idata + (l+y*im->xsize) * im->channels;
1586 count = r - l;
1587 for (i = 0; i < count; ++i) {
1588 for (ch = 0; ch < im->channels; ++ch)
6607600c 1589 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1590 }
1591 return count;
1592 }
1593 else {
1594 return 0;
1595 }
1596}
1597
1598/*
1599=item i_plinf_d(im, l, r, y, vals)
1600
1601Writes a line of data into the image, using the pixels at vals.
1602
1603The line runs from (l,y) inclusive to (r,y) non-inclusive
1604
1605vals should point at (r-l) pixels.
1606
1607l should never be less than zero (to avoid confusion about where to
1608get the pixels in vals).
1609
1610Returns the number of pixels copied (eg. if r, l or y is out of range)
1611
1612=cut
1613*/
63b018fd 1614static
faa9b3e7 1615int
97ac0a96 1616i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
1617 int ch, count, i;
1618 unsigned char *data;
1619 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1620 if (r > im->xsize)
1621 r = im->xsize;
1622 data = im->idata + (l+y*im->xsize) * im->channels;
1623 count = r - l;
1624 for (i = 0; i < count; ++i) {
1625 for (ch = 0; ch < im->channels; ++ch) {
1626 if (im->ch_mask & (1 << ch))
6607600c 1627 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1628 ++data;
1629 }
1630 }
1631 return count;
1632 }
1633 else {
1634 return 0;
1635 }
1636}
1637
1638/*
1639=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1640
1641Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1642for the channels specified by chans, an array of int with chan_count
1643elements.
1644
1645Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1646
1647=cut
1648*/
63b018fd
AMH
1649static
1650int
1651i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 1652 const int *chans, int chan_count) {
faa9b3e7
TC
1653 int ch, count, i, w;
1654 unsigned char *data;
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) {
1673 *samps++ = data[chans[ch]];
1674 ++count;
1675 }
1676 data += im->channels;
1677 }
1678 }
1679 else {
1680 for (i = 0; i < w; ++i) {
1681 for (ch = 0; ch < chan_count; ++ch) {
1682 *samps++ = data[ch];
1683 ++count;
1684 }
1685 data += im->channels;
1686 }
1687 }
1688
1689 return count;
1690 }
1691 else {
1692 return 0;
1693 }
1694}
1695
1696/*
1697=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1698
1699Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1700for the channels specified by chan_mask, where bit 0 is the first
1701channel.
1702
1703Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1704
1705=cut
1706*/
63b018fd
AMH
1707static
1708int
1709i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 1710 const int *chans, int chan_count) {
faa9b3e7
TC
1711 int ch, count, i, w;
1712 unsigned char *data;
1713 for (ch = 0; ch < chan_count; ++ch) {
1714 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1715 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1716 }
1717 }
1718 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1719 if (r > im->xsize)
1720 r = im->xsize;
1721 data = im->idata + (l+y*im->xsize) * im->channels;
1722 w = r - l;
1723 count = 0;
1724
1725 if (chans) {
1726 /* make sure we have good channel numbers */
1727 for (ch = 0; ch < chan_count; ++ch) {
1728 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1729 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1730 return 0;
1731 }
1732 }
1733 for (i = 0; i < w; ++i) {
1734 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1735 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1736 ++count;
1737 }
1738 data += im->channels;
1739 }
1740 }
1741 else {
1742 for (i = 0; i < w; ++i) {
1743 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1744 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1745 ++count;
1746 }
1747 data += im->channels;
1748 }
1749 }
1750 return count;
1751 }
1752 else {
1753 return 0;
1754 }
1755}
1756
1757/*
1758=back
1759
1760=head2 Image method wrappers
1761
1762These functions provide i_fsample_t functions in terms of their
1763i_sample_t versions.
1764
1765=over
1766
1767=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1768
1769=cut
1770*/
1771
97ac0a96 1772int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
faa9b3e7
TC
1773 i_color temp;
1774 int ch;
1775
1776 for (ch = 0; ch < im->channels; ++ch)
1777 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1778
1779 return i_ppix(im, x, y, &temp);
1780}
1781
1782/*
1783=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1784
1785=cut
1786*/
1787int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1788 i_color temp;
1789 int ch;
1790
1791 if (i_gpix(im, x, y, &temp)) {
1792 for (ch = 0; ch < im->channels; ++ch)
1793 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1794 return 0;
1795 }
1796 else
1797 return -1;
1798}
1799
1800/*
1801=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1802
1803=cut
1804*/
97ac0a96 1805int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
faa9b3e7
TC
1806 i_color *work;
1807
1808 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1809 if (r > im->xsize)
1810 r = im->xsize;
1811 if (r > l) {
1812 int ret;
1813 int i, ch;
1814 work = mymalloc(sizeof(i_color) * (r-l));
1815 for (i = 0; i < r-l; ++i) {
1816 for (ch = 0; ch < im->channels; ++ch)
1817 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1818 }
1819 ret = i_plin(im, l, r, y, work);
1820 myfree(work);
1821
1822 return ret;
1823 }
1824 else {
1825 return 0;
1826 }
1827 }
1828 else {
1829 return 0;
1830 }
1831}
1832
1833/*
1834=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1835
1836=cut
1837*/
1838int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1839 i_color *work;
1840
1841 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1842 if (r > im->xsize)
1843 r = im->xsize;
1844 if (r > l) {
1845 int ret;
1846 int i, ch;
1847 work = mymalloc(sizeof(i_color) * (r-l));
1848 ret = i_plin(im, l, r, y, work);
1849 for (i = 0; i < r-l; ++i) {
1850 for (ch = 0; ch < im->channels; ++ch)
1851 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1852 }
1853 myfree(work);
1854
1855 return ret;
1856 }
1857 else {
1858 return 0;
1859 }
1860 }
1861 else {
1862 return 0;
1863 }
1864}
1865
1866/*
1867=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1868
1869=cut
1870*/
1871int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
18accb2a 1872 int const *chans, int chan_count) {
faa9b3e7
TC
1873 i_sample_t *work;
1874
1875 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1876 if (r > im->xsize)
1877 r = im->xsize;
1878 if (r > l) {
1879 int ret;
1880 int i;
1881 work = mymalloc(sizeof(i_sample_t) * (r-l));
1882 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1883 for (i = 0; i < ret; ++i) {
1884 samp[i] = Sample8ToF(work[i]);
1885 }
1886 myfree(work);
1887
1888 return ret;
1889 }
1890 else {
1891 return 0;
1892 }
1893 }
1894 else {
1895 return 0;
1896 }
1897}
1898
1899/*
1900=back
1901
1902=head2 Palette wrapper functions
1903
1904Used for virtual images, these forward palette calls to a wrapped image,
1905assuming the wrapped image is the first pointer in the structure that
1906im->ext_data points at.
1907
1908=over
1909
97ac0a96 1910=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1911
1912=cut
1913*/
97ac0a96 1914int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1915 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1916}
1917
1918/*
1919=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1920
1921=cut
1922*/
1923int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1924 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1925}
1926
1927/*
97ac0a96 1928=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1929
1930=cut
1931*/
97ac0a96 1932int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1933 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1934}
1935
1936/*
1937=item i_colorcount_forward(i_img *im)
1938
1939=cut
1940*/
1941int i_colorcount_forward(i_img *im) {
1942 return i_colorcount(*(i_img **)im->ext_data);
1943}
1944
1945/*
1946=item i_maxcolors_forward(i_img *im)
1947
1948=cut
1949*/
1950int i_maxcolors_forward(i_img *im) {
1951 return i_maxcolors(*(i_img **)im->ext_data);
1952}
1953
1954/*
97ac0a96 1955=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1956
1957=cut
1958*/
97ac0a96 1959int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1960 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1961}
1962
1963/*
1964=back
1965
1966=head2 Stream reading and writing wrapper functions
1967
1968=over
1969
02d1d628
AMH
1970=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1971
1972Performs general read buffering for file readers that permit reading
1973to be done through a callback.
1974
1975The final callback gets two parameters, a I<need> value, and a I<want>
1976value, where I<need> is the amount of data that the file library needs
1977to read, and I<want> is the amount of space available in the buffer
1978maintained by these functions.
1979
1980This means if you need to read from a stream that you don't know the
1981length of, you can return I<need> bytes, taking the performance hit of
1982possibly expensive callbacks (eg. back to perl code), or if you are
1983reading from a stream where it doesn't matter if some data is lost, or
1984if the total length of the stream is known, you can return I<want>
1985bytes.
1986
1987=cut
1988*/
1989
1990int
1991i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1992 int total;
1993
1994 if (length < gci->length - gci->cpos) {
1995 /* simplest case */
1996 memcpy(buf, gci->buffer+gci->cpos, length);
1997 gci->cpos += length;
1998 return length;
1999 }
2000
2001 total = 0;
2002 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
2003 total += gci->length - gci->cpos;
2004 length -= gci->length - gci->cpos;
2005 buf += gci->length - gci->cpos;
2006 if (length < (int)sizeof(gci->buffer)) {
2007 int did_read;
2008 int copy_size;
2009 while (length
2010 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
2011 sizeof(gci->buffer))) > 0) {
2012 gci->cpos = 0;
2013 gci->length = did_read;
2014
b33c08f8 2015 copy_size = i_min(length, gci->length);
02d1d628
AMH
2016 memcpy(buf, gci->buffer, copy_size);
2017 gci->cpos += copy_size;
2018 buf += copy_size;
2019 total += copy_size;
2020 length -= copy_size;
2021 }
2022 }
2023 else {
2024 /* just read the rest - too big for our buffer*/
2025 int did_read;
2026 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2027 length -= did_read;
2028 total += did_read;
2029 buf += did_read;
2030 }
2031 }
2032 return total;
2033}
2034
2035/*
2036=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2037
2038For use by callback file readers to initialize the reader buffer.
2039
2040Allocates, initializes and returns the reader buffer.
2041
2042See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2043
2044=cut
2045*/
2046i_gen_read_data *
2047i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2048 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2049 self->cb = cb;
2050 self->userdata = userdata;
2051 self->length = 0;
2052 self->cpos = 0;
2053
2054 return self;
2055}
2056
2057/*
b33c08f8 2058=item i_free_gen_read_data(i_gen_read_data *)
02d1d628
AMH
2059
2060Cleans up.
2061
2062=cut
2063*/
b33c08f8 2064void i_free_gen_read_data(i_gen_read_data *self) {
02d1d628
AMH
2065 myfree(self);
2066}
2067
2068/*
2069=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2070
2071Performs write buffering for a callback based file writer.
2072
2073Failures are considered fatal, if a write fails then data will be
2074dropped.
2075
2076=cut
2077*/
2078int
2079i_gen_writer(
2080i_gen_write_data *self,
2081char const *data,
2082int size)
2083{
2084 if (self->filledto && self->filledto+size > self->maxlength) {
2085 if (self->cb(self->userdata, self->buffer, self->filledto)) {
2086 self->filledto = 0;
2087 }
2088 else {
2089 self->filledto = 0;
2090 return 0;
2091 }
2092 }
2093 if (self->filledto+size <= self->maxlength) {
2094 /* just save it */
2095 memcpy(self->buffer+self->filledto, data, size);
2096 self->filledto += size;
2097 return 1;
2098 }
2099 /* doesn't fit - hand it off */
2100 return self->cb(self->userdata, data, size);
2101}
2102
2103/*
2104=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2105
2106Allocates and initializes the data structure used by i_gen_writer.
2107
b33c08f8 2108This should be released with L<image.c/i_free_gen_write_data>
02d1d628
AMH
2109
2110=cut
2111*/
2112i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2113 char *userdata, int max_length)
2114{
2115 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2116 self->cb = cb;
2117 self->userdata = userdata;
b33c08f8 2118 self->maxlength = i_min(max_length, sizeof(self->buffer));
02d1d628
AMH
2119 if (self->maxlength < 0)
2120 self->maxlength = sizeof(self->buffer);
2121 self->filledto = 0;
2122
2123 return self;
2124}
2125
2126/*
b33c08f8 2127=item i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2128
2129Cleans up the write buffer.
2130
2131Will flush any left-over data if I<flush> is non-zero.
2132
2133Returns non-zero if flush is zero or if info->cb() returns non-zero.
2134
2135Return zero only if flush is non-zero and info->cb() returns zero.
2136ie. if it fails.
2137
2138=cut
2139*/
2140
b33c08f8 2141int i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2142{
2143 int result = !flush ||
2144 info->filledto == 0 ||
2145 info->cb(info->userdata, info->buffer, info->filledto);
2146 myfree(info);
2147
2148 return result;
2149}
2150
8b302e44
TC
2151struct magic_entry {
2152 unsigned char *magic;
2153 size_t magic_size;
2154 char *name;
2155 unsigned char *mask;
2156};
2157
2158static int
2159test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
2160 if (length < magic->magic_size)
2161 return 0;
2162 if (magic->mask) {
2163 int i;
2164 unsigned char *bufp = buffer,
2165 *maskp = magic->mask,
2166 *magicp = magic->magic;
e10bf46e 2167
8b302e44
TC
2168 for (i = 0; i < magic->magic_size; ++i) {
2169 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
2170 ++maskp;
2171
2172 if ((*bufp++ & mask) != (*magicp++ & mask))
2173 return 0;
2174 }
2175
2176 return 1;
2177 }
2178 else {
2179 return !memcmp(magic->magic, buffer, magic->magic_size);
2180 }
2181}
e10bf46e 2182
84e51293
AMH
2183/*
2184=item i_test_format_probe(io_glue *data, int length)
2185
676d5bb5 2186Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
2187
2188=cut
2189*/
e10bf46e 2190
db7a8754
TC
2191#define FORMAT_ENTRY(magic, type) \
2192 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 2193#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 2194 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
2195
2196const char *
2197i_test_format_probe(io_glue *data, int length) {
8b302e44 2198 static const struct magic_entry formats[] = {
db7a8754
TC
2199 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
2200 FORMAT_ENTRY("GIF87a", "gif"),
2201 FORMAT_ENTRY("GIF89a", "gif"),
2202 FORMAT_ENTRY("MM\0*", "tiff"),
2203 FORMAT_ENTRY("II*\0", "tiff"),
2204 FORMAT_ENTRY("BM", "bmp"),
2205 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
2206 FORMAT_ENTRY("P1", "pnm"),
2207 FORMAT_ENTRY("P2", "pnm"),
2208 FORMAT_ENTRY("P3", "pnm"),
2209 FORMAT_ENTRY("P4", "pnm"),
2210 FORMAT_ENTRY("P5", "pnm"),
2211 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
2212 FORMAT_ENTRY("/* XPM", "xpm"),
2213 FORMAT_ENTRY("\x8aMNG", "mng"),
2214 FORMAT_ENTRY("\x8aJNG", "jng"),
2215 /* SGI RGB - with various possible parameters to avoid false positives
2216 on similar files
2217 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
2218 */
d5477d3d
TC
2219 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
2220 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
2221 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
2222 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
2223
2224 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
2225
2226 /* different versions of PCX format
2227 http://www.fileformat.info/format/pcx/
2228 */
2229 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 2230 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
2231 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
2232 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
2233 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
2234
2235 /* FITS - http://fits.gsfc.nasa.gov/ */
2236 FORMAT_ENTRY("SIMPLE =", "fits"),
2237
2238 /* PSD - Photoshop */
2239 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
2240
2241 /* EPS - Encapsulated Postscript */
2242 /* only reading 18 chars, so we don't include the F in EPSF */
2243 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
2244
2245 /* Utah RLE */
2246 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
2247
2248 /* GZIP compressed, only matching deflate for now */
2249 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
2250
2251 /* bzip2 compressed */
2252 FORMAT_ENTRY("BZh", "bzip2"),
e10bf46e 2253 };
8b302e44 2254 static const struct magic_entry more_formats[] = {
681d28fc
TC
2255 /* these were originally both listed as ico, but cur files can
2256 include hotspot information */
2257 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
2258 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
2259 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
2260 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 2261 };
db7a8754 2262
e10bf46e 2263 unsigned int i;
db7a8754 2264 unsigned char head[18];
84e51293 2265 ssize_t rc;
e10bf46e
AMH
2266
2267 io_glue_commit_types(data);
84e51293
AMH
2268 rc = data->readcb(data, head, 18);
2269 if (rc == -1) return NULL;
2270 data->seekcb(data, -rc, SEEK_CUR);
e10bf46e
AMH
2271
2272 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
2273 struct magic_entry const *entry = formats + i;
2274
2275 if (test_magic(head, rc, entry))
2276 return entry->name;
e10bf46e
AMH
2277 }
2278
ea1136fc 2279 if ((rc == 18) &&
db7a8754
TC
2280 tga_header_verify(head))
2281 return "tga";
2282
ea1136fc 2283 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
2284 struct magic_entry const *entry = more_formats + i;
2285
2286 if (test_magic(head, rc, entry))
2287 return entry->name;
ea1136fc
TC
2288 }
2289
2290 return NULL;
e10bf46e
AMH
2291}
2292
9c106321
TC
2293/*
2294=item i_img_is_monochrome(img, &zero_is_white)
2295
2296Tests an image to check it meets our monochrome tests.
2297
2298The idea is that a file writer can use this to test where it should
2299write the image in whatever bi-level format it uses, eg. pbm for pnm.
2300
2301For performance of encoders we require monochrome images:
2302
2303=over
2304
2305=item *
e10bf46e 2306
9c106321 2307be paletted
e10bf46e 2308
9c106321
TC
2309=item *
2310
2311have a palette of two colors, containing only (0,0,0) and
2312(255,255,255) in either order.
2313
2314=back
2315
2316zero_is_white is set to non-zero iff the first palette entry is white.
2317
2318=cut
2319*/
2320
2321int
2322i_img_is_monochrome(i_img *im, int *zero_is_white) {
2323 if (im->type == i_palette_type
2324 && i_colorcount(im) == 2) {
2325 i_color colors[2];
2326 i_getcolors(im, 0, colors, 2);
2327 if (im->channels == 3) {
2328 if (colors[0].rgb.r == 255 &&
2329 colors[0].rgb.g == 255 &&
2330 colors[0].rgb.b == 255 &&
2331 colors[1].rgb.r == 0 &&
2332 colors[1].rgb.g == 0 &&
2333 colors[1].rgb.b == 0) {
2334 *zero_is_white = 0;
2335 return 1;
2336 }
2337 else if (colors[0].rgb.r == 0 &&
2338 colors[0].rgb.g == 0 &&
2339 colors[0].rgb.b == 0 &&
2340 colors[1].rgb.r == 255 &&
2341 colors[1].rgb.g == 255 &&
2342 colors[1].rgb.b == 255) {
2343 *zero_is_white = 1;
2344 return 1;
2345 }
2346 }
2347 else if (im->channels == 1) {
2348 if (colors[0].channel[0] == 255 &&
2349 colors[1].channel[1] == 0) {
2350 *zero_is_white = 0;
2351 return 1;
2352 }
2353 else if (colors[0].channel[0] == 0 &&
2354 colors[0].channel[0] == 255) {
2355 *zero_is_white = 1;
2356 return 1;
2357 }
2358 }
2359 }
2360
2361 *zero_is_white = 0;
2362 return 0;
2363}
e10bf46e 2364
02d1d628
AMH
2365/*
2366=back
2367
b8c2033e
AMH
2368=head1 AUTHOR
2369
2370Arnar M. Hrafnkelsson <addi@umich.edu>
2371
2372Tony Cook <tony@develop-help.com>
2373
02d1d628
AMH
2374=head1 SEE ALSO
2375
2376L<Imager>, L<gif.c>
2377
2378=cut
2379*/