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