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