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