API documentation (mostly)
[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;
1005 scx = 1 / im->xsize;
1006 }
02d1d628 1007 nysize = (int) ((float) im->ysize * scy);
1501d9b3
TC
1008 if (nysize < 1) {
1009 nysize = 1;
1010 scy = 1 / im->ysize;
1011 }
02d1d628
AMH
1012
1013 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1014
1015 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1016 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1017 i_ppix(new_img,nx,ny,&val);
1018 }
1019
1020 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1021
1022 return new_img;
1023}
1024
faa9b3e7
TC
1025/*
1026=item i_sametype(i_img *im, int xsize, int ysize)
1027
9167a5c6
TC
1028=category Image creation/destruction
1029=synopsis i_img *img = i_sametype(src, width, height);
92bda632 1030
faa9b3e7
TC
1031Returns an image of the same type (sample size, channels, paletted/direct).
1032
1033For paletted images the palette is copied from the source.
1034
1035=cut
1036*/
1037
1038i_img *i_sametype(i_img *src, int xsize, int ysize) {
1039 if (src->type == i_direct_type) {
1040 if (src->bits == 8) {
1041 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1042 }
af3c2450 1043 else if (src->bits == i_16_bits) {
faa9b3e7
TC
1044 return i_img_16_new(xsize, ysize, src->channels);
1045 }
af3c2450
TC
1046 else if (src->bits == i_double_bits) {
1047 return i_img_double_new(xsize, ysize, src->channels);
1048 }
faa9b3e7
TC
1049 else {
1050 i_push_error(0, "Unknown image bits");
1051 return NULL;
1052 }
1053 }
1054 else {
1055 i_color col;
1056 int i;
1057
1058 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1059 for (i = 0; i < i_colorcount(src); ++i) {
1060 i_getcolors(src, i, &col, 1);
1061 i_addcolors(targ, &col, 1);
1062 }
1063
1064 return targ;
1065 }
1066}
02d1d628 1067
dff75dee
TC
1068/*
1069=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
1070
9167a5c6
TC
1071=category Image creation/destruction
1072=synopsis i_img *img = i_sametype_chans(src, width, height, channels);
92bda632 1073
dff75dee
TC
1074Returns an image of the same type (sample size).
1075
1076For paletted images the equivalent direct type is returned.
1077
1078=cut
1079*/
1080
1081i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
1082 if (src->bits == 8) {
1083 return i_img_empty_ch(NULL, xsize, ysize, channels);
1084 }
1085 else if (src->bits == i_16_bits) {
1086 return i_img_16_new(xsize, ysize, channels);
1087 }
1088 else if (src->bits == i_double_bits) {
1089 return i_img_double_new(xsize, ysize, channels);
1090 }
1091 else {
1092 i_push_error(0, "Unknown image bits");
1093 return NULL;
1094 }
1095}
1096
02d1d628
AMH
1097/*
1098=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1099
1100Spatially transforms I<im> returning a new image.
1101
1102opx for a length of opxl and opy for a length of opy are arrays of
1103operators that modify the x and y positions to retreive the pixel data from.
1104
1105parm and parmlen define extra parameters that the operators may use.
1106
1107Note that this function is largely superseded by the more flexible
1108L<transform.c/i_transform2>.
1109
1110Returns the new image.
1111
1112The operators for this function are defined in L<stackmach.c>.
1113
1114=cut
1115*/
1116i_img*
1117i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1118 double rx,ry;
1119 int nxsize,nysize,nx,ny;
1120 i_img *new_img;
1121 i_color val;
1122
1123 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));
1124
1125 nxsize = im->xsize;
1126 nysize = im->ysize ;
1127
1128 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1129 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1130 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1131 /* parm[parmlen-2]=(double)nx;
1132 parm[parmlen-1]=(double)ny; */
1133
1134 parm[0]=(double)nx;
1135 parm[1]=(double)ny;
1136
1137 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
b33c08f8
TC
1138 rx=i_op_run(opx,opxl,parm,parmlen);
1139 ry=i_op_run(opy,opyl,parm,parmlen);
02d1d628
AMH
1140 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1141 i_gpix(im,rx,ry,&val);
1142 i_ppix(new_img,nx,ny,&val);
1143 }
1144
1145 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1146 return new_img;
1147}
1148
1149/*
1150=item i_img_diff(im1, im2)
1151
1152Calculates the sum of the squares of the differences between
1153correspoding channels in two images.
1154
1155If the images are not the same size then only the common area is
1156compared, hence even if images are different sizes this function
1157can return zero.
1158
1159=cut
1160*/
1161float
1162i_img_diff(i_img *im1,i_img *im2) {
1163 int x,y,ch,xb,yb,chb;
1164 float tdiff;
1165 i_color val1,val2;
1166
1167 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1168
1169 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1170 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1171 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1172
1173 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1174
1175 tdiff=0;
1176 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1177 i_gpix(im1,x,y,&val1);
1178 i_gpix(im2,x,y,&val2);
1179
1180 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1181 }
1182 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1183 return tdiff;
1184}
1185
1186/* just a tiny demo of haar wavelets */
1187
1188i_img*
1189i_haar(i_img *im) {
1190 int mx,my;
1191 int fx,fy;
1192 int x,y;
1193 int ch,c;
1194 i_img *new_img,*new_img2;
1195 i_color val1,val2,dval1,dval2;
1196
1197 mx=im->xsize;
1198 my=im->ysize;
1199 fx=(mx+1)/2;
1200 fy=(my+1)/2;
1201
1202
1203 /* horizontal pass */
1204
1205 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1206 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1207
1208 c=0;
1209 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1210 i_gpix(im,x*2,y,&val1);
1211 i_gpix(im,x*2+1,y,&val2);
1212 for(ch=0;ch<im->channels;ch++) {
1213 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1214 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1215 }
1216 i_ppix(new_img,x,y,&dval1);
1217 i_ppix(new_img,x+fx,y,&dval2);
1218 }
1219
1220 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1221 i_gpix(new_img,x,y*2,&val1);
1222 i_gpix(new_img,x,y*2+1,&val2);
1223 for(ch=0;ch<im->channels;ch++) {
1224 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1225 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1226 }
1227 i_ppix(new_img2,x,y,&dval1);
1228 i_ppix(new_img2,x,y+fy,&dval2);
1229 }
1230
1231 i_img_destroy(new_img);
1232 return new_img2;
1233}
1234
1235/*
1236=item i_count_colors(im, maxc)
1237
1238returns number of colors or -1
1239to indicate that it was more than max colors
1240
1241=cut
1242*/
fe622da1
TC
1243/* This function has been changed and is now faster. It's using
1244 * i_gsamp instead of i_gpix */
02d1d628
AMH
1245int
1246i_count_colors(i_img *im,int maxc) {
1247 struct octt *ct;
1248 int x,y;
02d1d628 1249 int colorcnt;
fe622da1
TC
1250 int channels[3];
1251 int *samp_chans;
1252 i_sample_t * samp;
fe622da1
TC
1253 int xsize = im->xsize;
1254 int ysize = im->ysize;
a60905e4
TC
1255 int samp_cnt = 3 * xsize;
1256
fe622da1
TC
1257 if (im->channels >= 3) {
1258 samp_chans = NULL;
1259 }
1260 else {
1261 channels[0] = channels[1] = channels[2] = 0;
1262 samp_chans = channels;
02d1d628 1263 }
a60905e4 1264
fe622da1
TC
1265 ct = octt_new();
1266
1267 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1268
1269 colorcnt = 0;
1270 for(y = 0; y < ysize; ) {
1271 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1272 for(x = 0; x < samp_cnt; ) {
1273 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1274 x += 3;
1275 if (colorcnt > maxc) {
1276 octt_delete(ct);
1277 return -1;
1278 }
1279 }
1280 }
1281 myfree(samp);
02d1d628
AMH
1282 octt_delete(ct);
1283 return colorcnt;
1284}
1285
fe622da1
TC
1286/* sorts the array ra[0..n-1] into increasing order using heapsort algorithm
1287 * (adapted from the Numerical Recipes)
1288 */
1289/* Needed by get_anonymous_color_histo */
a60905e4
TC
1290static void
1291hpsort(unsigned int n, unsigned *ra) {
fe622da1
TC
1292 unsigned int i,
1293 ir,
1294 j,
1295 l,
1296 rra;
1297
1298 if (n < 2) return;
1299 l = n >> 1;
1300 ir = n - 1;
1301 for(;;) {
1302 if (l > 0) {
1303 rra = ra[--l];
1304 }
1305 else {
1306 rra = ra[ir];
1307 ra[ir] = ra[0];
1308 if (--ir == 0) {
1309 ra[0] = rra;
1310 break;
1311 }
1312 }
1313 i = l;
1314 j = 2 * l + 1;
1315 while (j <= ir) {
1316 if (j < ir && ra[j] < ra[j+1]) j++;
1317 if (rra < ra[j]) {
1318 ra[i] = ra[j];
1319 i = j;
1320 j++; j <<= 1; j--;
1321 }
1322 else break;
1323 }
1324 ra[i] = rra;
1325 }
1326}
1327
1328/* This function constructs an ordered list which represents how much the
1329 * different colors are used. So for instance (100, 100, 500) means that one
1330 * color is used for 500 pixels, another for 100 pixels and another for 100
1331 * pixels. It's tuned for performance. You might not like the way I've hardcoded
1332 * the maxc ;-) and you might want to change the name... */
1333/* Uses octt_histo */
1334int
a60905e4
TC
1335i_get_anonymous_color_histo(i_img *im, unsigned int **col_usage, int maxc) {
1336 struct octt *ct;
1337 int x,y;
1338 int colorcnt;
1339 unsigned int *col_usage_it;
1340 i_sample_t * samp;
1341 int channels[3];
1342 int *samp_chans;
1343
1344 int xsize = im->xsize;
1345 int ysize = im->ysize;
1346 int samp_cnt = 3 * xsize;
1347 ct = octt_new();
1348
1349 samp = (i_sample_t *) mymalloc( xsize * 3 * sizeof(i_sample_t));
1350
1351 if (im->channels >= 3) {
1352 samp_chans = NULL;
1353 }
1354 else {
1355 channels[0] = channels[1] = channels[2] = 0;
1356 samp_chans = channels;
1357 }
1358
1359 colorcnt = 0;
1360 for(y = 0; y < ysize; ) {
1361 i_gsamp(im, 0, xsize, y++, samp, samp_chans, 3);
1362 for(x = 0; x < samp_cnt; ) {
1363 colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
1364 x += 3;
1365 if (colorcnt > maxc) {
1366 octt_delete(ct);
1367 return -1;
1368 }
fe622da1 1369 }
a60905e4
TC
1370 }
1371 myfree(samp);
1372 /* Now that we know the number of colours... */
1373 col_usage_it = *col_usage = (unsigned int *) mymalloc(colorcnt * sizeof(unsigned int));
1374 octt_histo(ct, &col_usage_it);
1375 hpsort(colorcnt, *col_usage);
1376 octt_delete(ct);
1377 return colorcnt;
fe622da1
TC
1378}
1379
02d1d628 1380/*
faa9b3e7
TC
1381=back
1382
1383=head2 8-bit per sample image internal functions
1384
1385These are the functions installed in an 8-bit per sample image.
1386
1387=over
1388
1389=item i_ppix_d(im, x, y, col)
1390
1391Internal function.
1392
1393This is the function kept in the i_f_ppix member of an i_img object.
1394It does a normal store of a pixel into the image with range checking.
1395
1396Returns 0 if the pixel could be set, -1 otherwise.
1397
1398=cut
1399*/
63b018fd 1400static
faa9b3e7 1401int
97ac0a96 1402i_ppix_d(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
1403 int ch;
1404
1405 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1406 for(ch=0;ch<im->channels;ch++)
1407 if (im->ch_mask&(1<<ch))
1408 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1409 return 0;
1410 }
1411 return -1; /* error was clipped */
1412}
1413
1414/*
1415=item i_gpix_d(im, x, y, &col)
1416
1417Internal function.
1418
1419This is the function kept in the i_f_gpix member of an i_img object.
1420It does normal retrieval of a pixel from the image with range checking.
1421
1422Returns 0 if the pixel could be set, -1 otherwise.
1423
1424=cut
1425*/
63b018fd 1426static
faa9b3e7
TC
1427int
1428i_gpix_d(i_img *im, int x, int y, i_color *val) {
1429 int ch;
1430 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1431 for(ch=0;ch<im->channels;ch++)
9982a307 1432 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
faa9b3e7
TC
1433 return 0;
1434 }
0bcbaf60 1435 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
faa9b3e7
TC
1436 return -1; /* error was cliped */
1437}
1438
1439/*
1440=item i_glin_d(im, l, r, y, vals)
1441
1442Reads a line of data from the image, storing the pixels at vals.
1443
1444The line runs from (l,y) inclusive to (r,y) non-inclusive
1445
1446vals should point at space for (r-l) pixels.
1447
1448l should never be less than zero (to avoid confusion about where to
1449put the pixels in vals).
1450
1451Returns the number of pixels copied (eg. if r, l or y is out of range)
1452
1453=cut
1454*/
63b018fd 1455static
faa9b3e7
TC
1456int
1457i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1458 int ch, count, i;
1459 unsigned char *data;
1460 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1461 if (r > im->xsize)
1462 r = im->xsize;
1463 data = im->idata + (l+y*im->xsize) * im->channels;
1464 count = r - l;
1465 for (i = 0; i < count; ++i) {
1466 for (ch = 0; ch < im->channels; ++ch)
1467 vals[i].channel[ch] = *data++;
1468 }
1469 return count;
1470 }
1471 else {
1472 return 0;
1473 }
1474}
1475
1476/*
1477=item i_plin_d(im, l, r, y, vals)
1478
1479Writes a line of data into the image, using the pixels at vals.
1480
1481The line runs from (l,y) inclusive to (r,y) non-inclusive
1482
1483vals should point at (r-l) pixels.
1484
1485l should never be less than zero (to avoid confusion about where to
1486get the pixels in vals).
1487
1488Returns the number of pixels copied (eg. if r, l or y is out of range)
1489
1490=cut
1491*/
63b018fd 1492static
faa9b3e7 1493int
97ac0a96 1494i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
1495 int ch, count, i;
1496 unsigned char *data;
1497 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1498 if (r > im->xsize)
1499 r = im->xsize;
1500 data = im->idata + (l+y*im->xsize) * im->channels;
1501 count = r - l;
1502 for (i = 0; i < count; ++i) {
1503 for (ch = 0; ch < im->channels; ++ch) {
1504 if (im->ch_mask & (1 << ch))
1505 *data = vals[i].channel[ch];
1506 ++data;
1507 }
1508 }
1509 return count;
1510 }
1511 else {
1512 return 0;
1513 }
1514}
1515
1516/*
1517=item i_ppixf_d(im, x, y, val)
1518
1519=cut
1520*/
63b018fd 1521static
faa9b3e7 1522int
97ac0a96 1523i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
1524 int ch;
1525
1526 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1527 for(ch=0;ch<im->channels;ch++)
1528 if (im->ch_mask&(1<<ch)) {
1529 im->idata[(x+y*im->xsize)*im->channels+ch] =
1530 SampleFTo8(val->channel[ch]);
1531 }
1532 return 0;
1533 }
1534 return -1; /* error was clipped */
1535}
1536
1537/*
1538=item i_gpixf_d(im, x, y, val)
1539
1540=cut
1541*/
63b018fd 1542static
faa9b3e7
TC
1543int
1544i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1545 int ch;
1546 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1547 for(ch=0;ch<im->channels;ch++) {
1548 val->channel[ch] =
1549 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1550 }
1551 return 0;
1552 }
1553 return -1; /* error was cliped */
1554}
1555
1556/*
1557=item i_glinf_d(im, l, r, y, vals)
1558
1559Reads a line of data from the image, storing the pixels at vals.
1560
1561The line runs from (l,y) inclusive to (r,y) non-inclusive
1562
1563vals should point at space for (r-l) pixels.
1564
1565l should never be less than zero (to avoid confusion about where to
1566put the pixels in vals).
1567
1568Returns the number of pixels copied (eg. if r, l or y is out of range)
1569
1570=cut
1571*/
63b018fd 1572static
faa9b3e7
TC
1573int
1574i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1575 int ch, count, i;
1576 unsigned char *data;
1577 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1578 if (r > im->xsize)
1579 r = im->xsize;
1580 data = im->idata + (l+y*im->xsize) * im->channels;
1581 count = r - l;
1582 for (i = 0; i < count; ++i) {
1583 for (ch = 0; ch < im->channels; ++ch)
6607600c 1584 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1585 }
1586 return count;
1587 }
1588 else {
1589 return 0;
1590 }
1591}
1592
1593/*
1594=item i_plinf_d(im, l, r, y, vals)
1595
1596Writes a line of data into the image, using the pixels at vals.
1597
1598The line runs from (l,y) inclusive to (r,y) non-inclusive
1599
1600vals should point at (r-l) pixels.
1601
1602l should never be less than zero (to avoid confusion about where to
1603get the pixels in vals).
1604
1605Returns the number of pixels copied (eg. if r, l or y is out of range)
1606
1607=cut
1608*/
63b018fd 1609static
faa9b3e7 1610int
97ac0a96 1611i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
1612 int ch, count, i;
1613 unsigned char *data;
1614 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1615 if (r > im->xsize)
1616 r = im->xsize;
1617 data = im->idata + (l+y*im->xsize) * im->channels;
1618 count = r - l;
1619 for (i = 0; i < count; ++i) {
1620 for (ch = 0; ch < im->channels; ++ch) {
1621 if (im->ch_mask & (1 << ch))
6607600c 1622 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1623 ++data;
1624 }
1625 }
1626 return count;
1627 }
1628 else {
1629 return 0;
1630 }
1631}
1632
1633/*
1634=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1635
1636Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1637for the channels specified by chans, an array of int with chan_count
1638elements.
1639
1640Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1641
1642=cut
1643*/
63b018fd
AMH
1644static
1645int
1646i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 1647 const int *chans, int chan_count) {
faa9b3e7
TC
1648 int ch, count, i, w;
1649 unsigned char *data;
1650
1651 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1652 if (r > im->xsize)
1653 r = im->xsize;
1654 data = im->idata + (l+y*im->xsize) * im->channels;
1655 w = r - l;
1656 count = 0;
1657
1658 if (chans) {
1659 /* make sure we have good channel numbers */
1660 for (ch = 0; ch < chan_count; ++ch) {
1661 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1662 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1663 return 0;
1664 }
1665 }
1666 for (i = 0; i < w; ++i) {
1667 for (ch = 0; ch < chan_count; ++ch) {
1668 *samps++ = data[chans[ch]];
1669 ++count;
1670 }
1671 data += im->channels;
1672 }
1673 }
1674 else {
c7481ae1
TC
1675 if (chan_count <= 0 || chan_count > im->channels) {
1676 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1677 chan_count);
1678 return 0;
1679 }
faa9b3e7
TC
1680 for (i = 0; i < w; ++i) {
1681 for (ch = 0; ch < chan_count; ++ch) {
1682 *samps++ = data[ch];
1683 ++count;
1684 }
1685 data += im->channels;
1686 }
1687 }
1688
1689 return count;
1690 }
1691 else {
1692 return 0;
1693 }
1694}
1695
1696/*
1697=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1698
1699Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1700for the channels specified by chan_mask, where bit 0 is the first
1701channel.
1702
1703Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1704
1705=cut
1706*/
63b018fd
AMH
1707static
1708int
1709i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 1710 const int *chans, int chan_count) {
faa9b3e7
TC
1711 int ch, count, i, w;
1712 unsigned char *data;
1713 for (ch = 0; ch < chan_count; ++ch) {
1714 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1715 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1716 }
1717 }
1718 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1719 if (r > im->xsize)
1720 r = im->xsize;
1721 data = im->idata + (l+y*im->xsize) * im->channels;
1722 w = r - l;
1723 count = 0;
1724
1725 if (chans) {
1726 /* make sure we have good channel numbers */
1727 for (ch = 0; ch < chan_count; ++ch) {
1728 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1729 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1730 return 0;
1731 }
1732 }
1733 for (i = 0; i < w; ++i) {
1734 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1735 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1736 ++count;
1737 }
1738 data += im->channels;
1739 }
1740 }
1741 else {
c7481ae1
TC
1742 if (chan_count <= 0 || chan_count > im->channels) {
1743 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
1744 chan_count);
1745 return 0;
1746 }
faa9b3e7
TC
1747 for (i = 0; i < w; ++i) {
1748 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1749 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1750 ++count;
1751 }
1752 data += im->channels;
1753 }
1754 }
1755 return count;
1756 }
1757 else {
1758 return 0;
1759 }
1760}
1761
1762/*
1763=back
1764
1765=head2 Image method wrappers
1766
1767These functions provide i_fsample_t functions in terms of their
1768i_sample_t versions.
1769
1770=over
1771
1772=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1773
1774=cut
1775*/
1776
97ac0a96 1777int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
faa9b3e7
TC
1778 i_color temp;
1779 int ch;
1780
1781 for (ch = 0; ch < im->channels; ++ch)
1782 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1783
1784 return i_ppix(im, x, y, &temp);
1785}
1786
1787/*
1788=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1789
1790=cut
1791*/
1792int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1793 i_color temp;
1794 int ch;
1795
1796 if (i_gpix(im, x, y, &temp)) {
1797 for (ch = 0; ch < im->channels; ++ch)
1798 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1799 return 0;
1800 }
1801 else
1802 return -1;
1803}
1804
1805/*
1806=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1807
1808=cut
1809*/
97ac0a96 1810int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
faa9b3e7
TC
1811 i_color *work;
1812
1813 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1814 if (r > im->xsize)
1815 r = im->xsize;
1816 if (r > l) {
1817 int ret;
1818 int i, ch;
1819 work = mymalloc(sizeof(i_color) * (r-l));
1820 for (i = 0; i < r-l; ++i) {
1821 for (ch = 0; ch < im->channels; ++ch)
1822 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1823 }
1824 ret = i_plin(im, l, r, y, work);
1825 myfree(work);
1826
1827 return ret;
1828 }
1829 else {
1830 return 0;
1831 }
1832 }
1833 else {
1834 return 0;
1835 }
1836}
1837
1838/*
1839=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1840
1841=cut
1842*/
1843int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1844 i_color *work;
1845
1846 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1847 if (r > im->xsize)
1848 r = im->xsize;
1849 if (r > l) {
1850 int ret;
1851 int i, ch;
1852 work = mymalloc(sizeof(i_color) * (r-l));
1853 ret = i_plin(im, l, r, y, work);
1854 for (i = 0; i < r-l; ++i) {
1855 for (ch = 0; ch < im->channels; ++ch)
1856 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1857 }
1858 myfree(work);
1859
1860 return ret;
1861 }
1862 else {
1863 return 0;
1864 }
1865 }
1866 else {
1867 return 0;
1868 }
1869}
1870
1871/*
1872=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1873
1874=cut
1875*/
1876int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
18accb2a 1877 int const *chans, int chan_count) {
faa9b3e7
TC
1878 i_sample_t *work;
1879
1880 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1881 if (r > im->xsize)
1882 r = im->xsize;
1883 if (r > l) {
1884 int ret;
1885 int i;
1886 work = mymalloc(sizeof(i_sample_t) * (r-l));
1887 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1888 for (i = 0; i < ret; ++i) {
1889 samp[i] = Sample8ToF(work[i]);
1890 }
1891 myfree(work);
1892
1893 return ret;
1894 }
1895 else {
1896 return 0;
1897 }
1898 }
1899 else {
1900 return 0;
1901 }
1902}
1903
1904/*
1905=back
1906
1907=head2 Palette wrapper functions
1908
1909Used for virtual images, these forward palette calls to a wrapped image,
1910assuming the wrapped image is the first pointer in the structure that
1911im->ext_data points at.
1912
1913=over
1914
97ac0a96 1915=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
faa9b3e7
TC
1916
1917=cut
1918*/
97ac0a96 1919int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
faa9b3e7
TC
1920 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1921}
1922
1923/*
1924=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1925
1926=cut
1927*/
1928int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1929 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1930}
1931
1932/*
97ac0a96 1933=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
faa9b3e7
TC
1934
1935=cut
1936*/
97ac0a96 1937int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
faa9b3e7
TC
1938 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1939}
1940
1941/*
1942=item i_colorcount_forward(i_img *im)
1943
1944=cut
1945*/
1946int i_colorcount_forward(i_img *im) {
1947 return i_colorcount(*(i_img **)im->ext_data);
1948}
1949
1950/*
1951=item i_maxcolors_forward(i_img *im)
1952
1953=cut
1954*/
1955int i_maxcolors_forward(i_img *im) {
1956 return i_maxcolors(*(i_img **)im->ext_data);
1957}
1958
1959/*
97ac0a96 1960=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
faa9b3e7
TC
1961
1962=cut
1963*/
97ac0a96 1964int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
faa9b3e7
TC
1965 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1966}
1967
1968/*
1969=back
1970
bd8052a6
TC
1971=head2 Fallback handler
1972
1973=over
1974
1975=item i_gsamp_bits_fb
1976
1977=cut
1978*/
1979
1980int
1981i_gsamp_bits_fb(i_img *im, int l, int r, int y, unsigned *samps,
1982 const int *chans, int chan_count, int bits) {
1983 if (bits < 1 || bits > 32) {
1984 i_push_error(0, "Invalid bits, must be 1..32");
1985 return -1;
1986 }
1987
1988 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1989 double scale;
1990 int ch, count, i, w;
1991
1992 if (bits == 32)
1993 scale = 4294967295.0;
1994 else
1995 scale = (double)(1 << bits) - 1;
1996
1997 if (r > im->xsize)
1998 r = im->xsize;
1999 w = r - l;
2000 count = 0;
2001
2002 if (chans) {
2003 /* make sure we have good channel numbers */
2004 for (ch = 0; ch < chan_count; ++ch) {
2005 if (chans[ch] < 0 || chans[ch] >= im->channels) {
2006 i_push_errorf(0, "No channel %d in this image", chans[ch]);
2007 return -1;
2008 }
2009 }
2010 for (i = 0; i < w; ++i) {
2011 i_fcolor c;
2012 i_gpixf(im, l+i, y, &c);
2013 for (ch = 0; ch < chan_count; ++ch) {
2014 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2015 ++count;
2016 }
2017 }
2018 }
2019 else {
2020 if (chan_count <= 0 || chan_count > im->channels) {
2021 i_push_error(0, "Invalid channel count");
2022 return -1;
2023 }
2024 for (i = 0; i < w; ++i) {
2025 i_fcolor c;
2026 i_gpixf(im, l+i, y, &c);
2027 for (ch = 0; ch < chan_count; ++ch) {
2028 *samps++ = (unsigned)(c.channel[ch] * scale + 0.5);
2029 ++count;
2030 }
2031 }
2032 }
2033
2034 return count;
2035 }
2036 else {
2037 i_push_error(0, "Image position outside of image");
2038 return -1;
2039 }
2040}
2041
2042/*
2043=back
2044
faa9b3e7
TC
2045=head2 Stream reading and writing wrapper functions
2046
2047=over
2048
02d1d628
AMH
2049=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
2050
2051Performs general read buffering for file readers that permit reading
2052to be done through a callback.
2053
2054The final callback gets two parameters, a I<need> value, and a I<want>
2055value, where I<need> is the amount of data that the file library needs
2056to read, and I<want> is the amount of space available in the buffer
2057maintained by these functions.
2058
2059This means if you need to read from a stream that you don't know the
2060length of, you can return I<need> bytes, taking the performance hit of
2061possibly expensive callbacks (eg. back to perl code), or if you are
2062reading from a stream where it doesn't matter if some data is lost, or
2063if the total length of the stream is known, you can return I<want>
2064bytes.
2065
2066=cut
2067*/
2068
2069int
2070i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
2071 int total;
2072
2073 if (length < gci->length - gci->cpos) {
2074 /* simplest case */
2075 memcpy(buf, gci->buffer+gci->cpos, length);
2076 gci->cpos += length;
2077 return length;
2078 }
2079
2080 total = 0;
2081 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
2082 total += gci->length - gci->cpos;
2083 length -= gci->length - gci->cpos;
2084 buf += gci->length - gci->cpos;
2085 if (length < (int)sizeof(gci->buffer)) {
2086 int did_read;
2087 int copy_size;
2088 while (length
2089 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
2090 sizeof(gci->buffer))) > 0) {
2091 gci->cpos = 0;
2092 gci->length = did_read;
2093
b33c08f8 2094 copy_size = i_min(length, gci->length);
02d1d628
AMH
2095 memcpy(buf, gci->buffer, copy_size);
2096 gci->cpos += copy_size;
2097 buf += copy_size;
2098 total += copy_size;
2099 length -= copy_size;
2100 }
2101 }
2102 else {
2103 /* just read the rest - too big for our buffer*/
2104 int did_read;
2105 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
2106 length -= did_read;
2107 total += did_read;
2108 buf += did_read;
2109 }
2110 }
2111 return total;
2112}
2113
2114/*
2115=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
2116
2117For use by callback file readers to initialize the reader buffer.
2118
2119Allocates, initializes and returns the reader buffer.
2120
2121See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
2122
2123=cut
2124*/
2125i_gen_read_data *
2126i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
2127 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
2128 self->cb = cb;
2129 self->userdata = userdata;
2130 self->length = 0;
2131 self->cpos = 0;
2132
2133 return self;
2134}
2135
2136/*
b33c08f8 2137=item i_free_gen_read_data(i_gen_read_data *)
02d1d628
AMH
2138
2139Cleans up.
2140
2141=cut
2142*/
b33c08f8 2143void i_free_gen_read_data(i_gen_read_data *self) {
02d1d628
AMH
2144 myfree(self);
2145}
2146
2147/*
2148=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
2149
2150Performs write buffering for a callback based file writer.
2151
2152Failures are considered fatal, if a write fails then data will be
2153dropped.
2154
2155=cut
2156*/
2157int
2158i_gen_writer(
2159i_gen_write_data *self,
2160char const *data,
2161int size)
2162{
2163 if (self->filledto && self->filledto+size > self->maxlength) {
2164 if (self->cb(self->userdata, self->buffer, self->filledto)) {
2165 self->filledto = 0;
2166 }
2167 else {
2168 self->filledto = 0;
2169 return 0;
2170 }
2171 }
2172 if (self->filledto+size <= self->maxlength) {
2173 /* just save it */
2174 memcpy(self->buffer+self->filledto, data, size);
2175 self->filledto += size;
2176 return 1;
2177 }
2178 /* doesn't fit - hand it off */
2179 return self->cb(self->userdata, data, size);
2180}
2181
2182/*
2183=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2184
2185Allocates and initializes the data structure used by i_gen_writer.
2186
b33c08f8 2187This should be released with L<image.c/i_free_gen_write_data>
02d1d628
AMH
2188
2189=cut
2190*/
2191i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2192 char *userdata, int max_length)
2193{
2194 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2195 self->cb = cb;
2196 self->userdata = userdata;
b33c08f8 2197 self->maxlength = i_min(max_length, sizeof(self->buffer));
02d1d628
AMH
2198 if (self->maxlength < 0)
2199 self->maxlength = sizeof(self->buffer);
2200 self->filledto = 0;
2201
2202 return self;
2203}
2204
2205/*
b33c08f8 2206=item i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2207
2208Cleans up the write buffer.
2209
2210Will flush any left-over data if I<flush> is non-zero.
2211
2212Returns non-zero if flush is zero or if info->cb() returns non-zero.
2213
2214Return zero only if flush is non-zero and info->cb() returns zero.
2215ie. if it fails.
2216
2217=cut
2218*/
2219
b33c08f8 2220int i_free_gen_write_data(i_gen_write_data *info, int flush)
02d1d628
AMH
2221{
2222 int result = !flush ||
2223 info->filledto == 0 ||
2224 info->cb(info->userdata, info->buffer, info->filledto);
2225 myfree(info);
2226
2227 return result;
2228}
2229
8b302e44
TC
2230struct magic_entry {
2231 unsigned char *magic;
2232 size_t magic_size;
2233 char *name;
2234 unsigned char *mask;
2235};
2236
2237static int
2238test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
8b302e44
TC
2239 if (length < magic->magic_size)
2240 return 0;
2241 if (magic->mask) {
2242 int i;
2243 unsigned char *bufp = buffer,
2244 *maskp = magic->mask,
2245 *magicp = magic->magic;
e10bf46e 2246
8b302e44
TC
2247 for (i = 0; i < magic->magic_size; ++i) {
2248 int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
2249 ++maskp;
2250
2251 if ((*bufp++ & mask) != (*magicp++ & mask))
2252 return 0;
2253 }
2254
2255 return 1;
2256 }
2257 else {
2258 return !memcmp(magic->magic, buffer, magic->magic_size);
2259 }
2260}
e10bf46e 2261
84e51293
AMH
2262/*
2263=item i_test_format_probe(io_glue *data, int length)
2264
676d5bb5 2265Check the beginning of the supplied file for a 'magic number'
84e51293
AMH
2266
2267=cut
2268*/
e10bf46e 2269
db7a8754
TC
2270#define FORMAT_ENTRY(magic, type) \
2271 { (unsigned char *)(magic ""), sizeof(magic)-1, type }
8b302e44 2272#define FORMAT_ENTRY2(magic, type, mask) \
c0f79ae6 2273 { (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
ea1136fc
TC
2274
2275const char *
2276i_test_format_probe(io_glue *data, int length) {
8b302e44 2277 static const struct magic_entry formats[] = {
db7a8754
TC
2278 FORMAT_ENTRY("\xFF\xD8", "jpeg"),
2279 FORMAT_ENTRY("GIF87a", "gif"),
2280 FORMAT_ENTRY("GIF89a", "gif"),
2281 FORMAT_ENTRY("MM\0*", "tiff"),
2282 FORMAT_ENTRY("II*\0", "tiff"),
2283 FORMAT_ENTRY("BM", "bmp"),
2284 FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
2285 FORMAT_ENTRY("P1", "pnm"),
2286 FORMAT_ENTRY("P2", "pnm"),
2287 FORMAT_ENTRY("P3", "pnm"),
2288 FORMAT_ENTRY("P4", "pnm"),
2289 FORMAT_ENTRY("P5", "pnm"),
2290 FORMAT_ENTRY("P6", "pnm"),
8b302e44
TC
2291 FORMAT_ENTRY("/* XPM", "xpm"),
2292 FORMAT_ENTRY("\x8aMNG", "mng"),
2293 FORMAT_ENTRY("\x8aJNG", "jng"),
2294 /* SGI RGB - with various possible parameters to avoid false positives
2295 on similar files
2296 values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
2297 */
d5477d3d
TC
2298 FORMAT_ENTRY("\x01\xDA\x00\x01", "sgi"),
2299 FORMAT_ENTRY("\x01\xDA\x00\x02", "sgi"),
2300 FORMAT_ENTRY("\x01\xDA\x01\x01", "sgi"),
2301 FORMAT_ENTRY("\x01\xDA\x01\x02", "sgi"),
8b302e44
TC
2302
2303 FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
2304
2305 /* different versions of PCX format
2306 http://www.fileformat.info/format/pcx/
2307 */
2308 FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
681d28fc 2309 FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
8b302e44
TC
2310 FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
2311 FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
2312 FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
2313
2314 /* FITS - http://fits.gsfc.nasa.gov/ */
2315 FORMAT_ENTRY("SIMPLE =", "fits"),
2316
2317 /* PSD - Photoshop */
2318 FORMAT_ENTRY("8BPS\x00\x01", "psd"),
2319
2320 /* EPS - Encapsulated Postscript */
2321 /* only reading 18 chars, so we don't include the F in EPSF */
2322 FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
681d28fc
TC
2323
2324 /* Utah RLE */
2325 FORMAT_ENTRY("\x52\xCC", "utah"),
33fc0c9e
TC
2326
2327 /* GZIP compressed, only matching deflate for now */
2328 FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
2329
2330 /* bzip2 compressed */
2331 FORMAT_ENTRY("BZh", "bzip2"),
e10bf46e 2332 };
8b302e44 2333 static const struct magic_entry more_formats[] = {
681d28fc
TC
2334 /* these were originally both listed as ico, but cur files can
2335 include hotspot information */
2336 FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
2337 FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
603dfac7
TC
2338 FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
2339 "xwd", " xxxx"), /* X Windows Dump */
ea1136fc 2340 };
db7a8754 2341
e10bf46e 2342 unsigned int i;
db7a8754 2343 unsigned char head[18];
84e51293 2344 ssize_t rc;
e10bf46e
AMH
2345
2346 io_glue_commit_types(data);
84e51293
AMH
2347 rc = data->readcb(data, head, 18);
2348 if (rc == -1) return NULL;
2349 data->seekcb(data, -rc, SEEK_CUR);
e10bf46e
AMH
2350
2351 for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
8b302e44
TC
2352 struct magic_entry const *entry = formats + i;
2353
2354 if (test_magic(head, rc, entry))
2355 return entry->name;
e10bf46e
AMH
2356 }
2357
ea1136fc 2358 if ((rc == 18) &&
db7a8754
TC
2359 tga_header_verify(head))
2360 return "tga";
2361
ea1136fc 2362 for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
8b302e44
TC
2363 struct magic_entry const *entry = more_formats + i;
2364
2365 if (test_magic(head, rc, entry))
2366 return entry->name;
ea1136fc
TC
2367 }
2368
2369 return NULL;
e10bf46e
AMH
2370}
2371
9c106321
TC
2372/*
2373=item i_img_is_monochrome(img, &zero_is_white)
2374
2375Tests an image to check it meets our monochrome tests.
2376
2377The idea is that a file writer can use this to test where it should
2378write the image in whatever bi-level format it uses, eg. pbm for pnm.
2379
2380For performance of encoders we require monochrome images:
2381
2382=over
2383
2384=item *
e10bf46e 2385
9c106321 2386be paletted
e10bf46e 2387
9c106321
TC
2388=item *
2389
2390have a palette of two colors, containing only (0,0,0) and
2391(255,255,255) in either order.
2392
2393=back
2394
2395zero_is_white is set to non-zero iff the first palette entry is white.
2396
2397=cut
2398*/
2399
2400int
2401i_img_is_monochrome(i_img *im, int *zero_is_white) {
2402 if (im->type == i_palette_type
2403 && i_colorcount(im) == 2) {
2404 i_color colors[2];
2405 i_getcolors(im, 0, colors, 2);
2406 if (im->channels == 3) {
2407 if (colors[0].rgb.r == 255 &&
2408 colors[0].rgb.g == 255 &&
2409 colors[0].rgb.b == 255 &&
2410 colors[1].rgb.r == 0 &&
2411 colors[1].rgb.g == 0 &&
2412 colors[1].rgb.b == 0) {
bd8052a6 2413 *zero_is_white = 1;
9c106321
TC
2414 return 1;
2415 }
2416 else if (colors[0].rgb.r == 0 &&
2417 colors[0].rgb.g == 0 &&
2418 colors[0].rgb.b == 0 &&
2419 colors[1].rgb.r == 255 &&
2420 colors[1].rgb.g == 255 &&
2421 colors[1].rgb.b == 255) {
bd8052a6 2422 *zero_is_white = 0;
9c106321
TC
2423 return 1;
2424 }
2425 }
2426 else if (im->channels == 1) {
2427 if (colors[0].channel[0] == 255 &&
bd8052a6
TC
2428 colors[1].channel[0] == 0) {
2429 *zero_is_white = 1;
9c106321
TC
2430 return 1;
2431 }
2432 else if (colors[0].channel[0] == 0 &&
bd8052a6
TC
2433 colors[1].channel[0] == 255) {
2434 *zero_is_white = 0;
9c106321
TC
2435 return 1;
2436 }
2437 }
2438 }
2439
2440 *zero_is_white = 0;
2441 return 0;
2442}
e10bf46e 2443
6e4af7d4
TC
2444/*
2445=item i_get_file_background(im, &bg)
2446
2447Retrieve the file write background color tag from the image.
2448
2449If not present, returns black.
2450
2451=cut
2452*/
2453
2454void
2455i_get_file_background(i_img *im, i_color *bg) {
2456 if (!i_tags_get_color(&im->tags, "i_background", 0, bg)) {
2457 /* black default */
2458 bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
2459 }
2460 /* always full alpha */
2461 bg->channel[3] = 255;
2462}
2463
fa90de94
TC
2464/*
2465=item i_get_file_backgroundf(im, &bg)
2466
2467Retrieve the file write background color tag from the image as a
2468floating point color.
2469
2470Implemented in terms of i_get_file_background().
2471
2472If not present, returns black.
2473
2474=cut
2475*/
2476
2477void
2478i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
2479 i_color bg;
2480
2481 i_get_file_background(im, &bg);
2482 fbg->rgba.r = Sample8ToF(bg.rgba.r);
2483 fbg->rgba.g = Sample8ToF(bg.rgba.g);
2484 fbg->rgba.b = Sample8ToF(bg.rgba.b);
2485 fbg->rgba.a = 1.0;
2486}
2487
02d1d628
AMH
2488/*
2489=back
2490
b8c2033e
AMH
2491=head1 AUTHOR
2492
2493Arnar M. Hrafnkelsson <addi@umich.edu>
2494
2495Tony Cook <tony@develop-help.com>
2496
02d1d628
AMH
2497=head1 SEE ALSO
2498
2499L<Imager>, L<gif.c>
2500
2501=cut
2502*/