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