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