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