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