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