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