Fixes to the scale function so that edges are handled by extending the edges
[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 */
205 ~0, /* ch_mask */
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*/
1313int
1314i_ppix_d(i_img *im, int x, int y, i_color *val) {
1315 int ch;
1316
1317 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1318 for(ch=0;ch<im->channels;ch++)
1319 if (im->ch_mask&(1<<ch))
1320 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1321 return 0;
1322 }
1323 return -1; /* error was clipped */
1324}
1325
1326/*
1327=item i_gpix_d(im, x, y, &col)
1328
1329Internal function.
1330
1331This is the function kept in the i_f_gpix member of an i_img object.
1332It does normal retrieval of a pixel from the image with range checking.
1333
1334Returns 0 if the pixel could be set, -1 otherwise.
1335
1336=cut
1337*/
1338int
1339i_gpix_d(i_img *im, int x, int y, i_color *val) {
1340 int ch;
1341 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1342 for(ch=0;ch<im->channels;ch++)
1343 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1344 return 0;
1345 }
0bcbaf60 1346 for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
faa9b3e7
TC
1347 return -1; /* error was cliped */
1348}
1349
1350/*
1351=item i_glin_d(im, l, r, y, vals)
1352
1353Reads a line of data from the image, storing the pixels at vals.
1354
1355The line runs from (l,y) inclusive to (r,y) non-inclusive
1356
1357vals should point at space for (r-l) pixels.
1358
1359l should never be less than zero (to avoid confusion about where to
1360put the pixels in vals).
1361
1362Returns the number of pixels copied (eg. if r, l or y is out of range)
1363
1364=cut
1365*/
1366int
1367i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1368 int ch, count, i;
1369 unsigned char *data;
1370 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1371 if (r > im->xsize)
1372 r = im->xsize;
1373 data = im->idata + (l+y*im->xsize) * im->channels;
1374 count = r - l;
1375 for (i = 0; i < count; ++i) {
1376 for (ch = 0; ch < im->channels; ++ch)
1377 vals[i].channel[ch] = *data++;
1378 }
1379 return count;
1380 }
1381 else {
1382 return 0;
1383 }
1384}
1385
1386/*
1387=item i_plin_d(im, l, r, y, vals)
1388
1389Writes a line of data into the image, using the pixels at vals.
1390
1391The line runs from (l,y) inclusive to (r,y) non-inclusive
1392
1393vals should point at (r-l) pixels.
1394
1395l should never be less than zero (to avoid confusion about where to
1396get the pixels in vals).
1397
1398Returns the number of pixels copied (eg. if r, l or y is out of range)
1399
1400=cut
1401*/
1402int
1403i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
1404 int ch, count, i;
1405 unsigned char *data;
1406 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1407 if (r > im->xsize)
1408 r = im->xsize;
1409 data = im->idata + (l+y*im->xsize) * im->channels;
1410 count = r - l;
1411 for (i = 0; i < count; ++i) {
1412 for (ch = 0; ch < im->channels; ++ch) {
1413 if (im->ch_mask & (1 << ch))
1414 *data = vals[i].channel[ch];
1415 ++data;
1416 }
1417 }
1418 return count;
1419 }
1420 else {
1421 return 0;
1422 }
1423}
1424
1425/*
1426=item i_ppixf_d(im, x, y, val)
1427
1428=cut
1429*/
1430int
1431i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
1432 int ch;
1433
1434 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1435 for(ch=0;ch<im->channels;ch++)
1436 if (im->ch_mask&(1<<ch)) {
1437 im->idata[(x+y*im->xsize)*im->channels+ch] =
1438 SampleFTo8(val->channel[ch]);
1439 }
1440 return 0;
1441 }
1442 return -1; /* error was clipped */
1443}
1444
1445/*
1446=item i_gpixf_d(im, x, y, val)
1447
1448=cut
1449*/
1450int
1451i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1452 int ch;
1453 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1454 for(ch=0;ch<im->channels;ch++) {
1455 val->channel[ch] =
1456 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1457 }
1458 return 0;
1459 }
1460 return -1; /* error was cliped */
1461}
1462
1463/*
1464=item i_glinf_d(im, l, r, y, vals)
1465
1466Reads a line of data from the image, storing the pixels at vals.
1467
1468The line runs from (l,y) inclusive to (r,y) non-inclusive
1469
1470vals should point at space for (r-l) pixels.
1471
1472l should never be less than zero (to avoid confusion about where to
1473put the pixels in vals).
1474
1475Returns the number of pixels copied (eg. if r, l or y is out of range)
1476
1477=cut
1478*/
1479int
1480i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1481 int ch, count, i;
1482 unsigned char *data;
1483 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1484 if (r > im->xsize)
1485 r = im->xsize;
1486 data = im->idata + (l+y*im->xsize) * im->channels;
1487 count = r - l;
1488 for (i = 0; i < count; ++i) {
1489 for (ch = 0; ch < im->channels; ++ch)
6607600c 1490 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1491 }
1492 return count;
1493 }
1494 else {
1495 return 0;
1496 }
1497}
1498
1499/*
1500=item i_plinf_d(im, l, r, y, vals)
1501
1502Writes a line of data into the image, using the pixels at vals.
1503
1504The line runs from (l,y) inclusive to (r,y) non-inclusive
1505
1506vals should point at (r-l) pixels.
1507
1508l should never be less than zero (to avoid confusion about where to
1509get the pixels in vals).
1510
1511Returns the number of pixels copied (eg. if r, l or y is out of range)
1512
1513=cut
1514*/
1515int
1516i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1517 int ch, count, i;
1518 unsigned char *data;
1519 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1520 if (r > im->xsize)
1521 r = im->xsize;
1522 data = im->idata + (l+y*im->xsize) * im->channels;
1523 count = r - l;
1524 for (i = 0; i < count; ++i) {
1525 for (ch = 0; ch < im->channels; ++ch) {
1526 if (im->ch_mask & (1 << ch))
6607600c 1527 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1528 ++data;
1529 }
1530 }
1531 return count;
1532 }
1533 else {
1534 return 0;
1535 }
1536}
1537
1538/*
1539=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1540
1541Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1542for the channels specified by chans, an array of int with chan_count
1543elements.
1544
1545Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1546
1547=cut
1548*/
1549int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
1550 int *chans, int chan_count) {
1551 int ch, count, i, w;
1552 unsigned char *data;
1553
1554 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1555 if (r > im->xsize)
1556 r = im->xsize;
1557 data = im->idata + (l+y*im->xsize) * im->channels;
1558 w = r - l;
1559 count = 0;
1560
1561 if (chans) {
1562 /* make sure we have good channel numbers */
1563 for (ch = 0; ch < chan_count; ++ch) {
1564 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1565 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1566 return 0;
1567 }
1568 }
1569 for (i = 0; i < w; ++i) {
1570 for (ch = 0; ch < chan_count; ++ch) {
1571 *samps++ = data[chans[ch]];
1572 ++count;
1573 }
1574 data += im->channels;
1575 }
1576 }
1577 else {
1578 for (i = 0; i < w; ++i) {
1579 for (ch = 0; ch < chan_count; ++ch) {
1580 *samps++ = data[ch];
1581 ++count;
1582 }
1583 data += im->channels;
1584 }
1585 }
1586
1587 return count;
1588 }
1589 else {
1590 return 0;
1591 }
1592}
1593
1594/*
1595=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1596
1597Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1598for the channels specified by chan_mask, where bit 0 is the first
1599channel.
1600
1601Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1602
1603=cut
1604*/
1605int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
1606 int *chans, int chan_count) {
1607 int ch, count, i, w;
1608 unsigned char *data;
1609 for (ch = 0; ch < chan_count; ++ch) {
1610 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1611 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1612 }
1613 }
1614 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1615 if (r > im->xsize)
1616 r = im->xsize;
1617 data = im->idata + (l+y*im->xsize) * im->channels;
1618 w = r - l;
1619 count = 0;
1620
1621 if (chans) {
1622 /* make sure we have good channel numbers */
1623 for (ch = 0; ch < chan_count; ++ch) {
1624 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1625 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1626 return 0;
1627 }
1628 }
1629 for (i = 0; i < w; ++i) {
1630 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1631 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1632 ++count;
1633 }
1634 data += im->channels;
1635 }
1636 }
1637 else {
1638 for (i = 0; i < w; ++i) {
1639 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1640 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1641 ++count;
1642 }
1643 data += im->channels;
1644 }
1645 }
1646 return count;
1647 }
1648 else {
1649 return 0;
1650 }
1651}
1652
1653/*
1654=back
1655
1656=head2 Image method wrappers
1657
1658These functions provide i_fsample_t functions in terms of their
1659i_sample_t versions.
1660
1661=over
1662
1663=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1664
1665=cut
1666*/
1667
1668int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1669 i_color temp;
1670 int ch;
1671
1672 for (ch = 0; ch < im->channels; ++ch)
1673 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1674
1675 return i_ppix(im, x, y, &temp);
1676}
1677
1678/*
1679=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1680
1681=cut
1682*/
1683int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1684 i_color temp;
1685 int ch;
1686
1687 if (i_gpix(im, x, y, &temp)) {
1688 for (ch = 0; ch < im->channels; ++ch)
1689 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1690 return 0;
1691 }
1692 else
1693 return -1;
1694}
1695
1696/*
1697=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1698
1699=cut
1700*/
1701int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1702 i_color *work;
1703
1704 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1705 if (r > im->xsize)
1706 r = im->xsize;
1707 if (r > l) {
1708 int ret;
1709 int i, ch;
1710 work = mymalloc(sizeof(i_color) * (r-l));
1711 for (i = 0; i < r-l; ++i) {
1712 for (ch = 0; ch < im->channels; ++ch)
1713 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1714 }
1715 ret = i_plin(im, l, r, y, work);
1716 myfree(work);
1717
1718 return ret;
1719 }
1720 else {
1721 return 0;
1722 }
1723 }
1724 else {
1725 return 0;
1726 }
1727}
1728
1729/*
1730=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1731
1732=cut
1733*/
1734int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1735 i_color *work;
1736
1737 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1738 if (r > im->xsize)
1739 r = im->xsize;
1740 if (r > l) {
1741 int ret;
1742 int i, ch;
1743 work = mymalloc(sizeof(i_color) * (r-l));
1744 ret = i_plin(im, l, r, y, work);
1745 for (i = 0; i < r-l; ++i) {
1746 for (ch = 0; ch < im->channels; ++ch)
1747 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1748 }
1749 myfree(work);
1750
1751 return ret;
1752 }
1753 else {
1754 return 0;
1755 }
1756 }
1757 else {
1758 return 0;
1759 }
1760}
1761
1762/*
1763=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1764
1765=cut
1766*/
1767int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
1768 int *chans, int chan_count) {
1769 i_sample_t *work;
1770
1771 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1772 if (r > im->xsize)
1773 r = im->xsize;
1774 if (r > l) {
1775 int ret;
1776 int i;
1777 work = mymalloc(sizeof(i_sample_t) * (r-l));
1778 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1779 for (i = 0; i < ret; ++i) {
1780 samp[i] = Sample8ToF(work[i]);
1781 }
1782 myfree(work);
1783
1784 return ret;
1785 }
1786 else {
1787 return 0;
1788 }
1789 }
1790 else {
1791 return 0;
1792 }
1793}
1794
1795/*
1796=back
1797
1798=head2 Palette wrapper functions
1799
1800Used for virtual images, these forward palette calls to a wrapped image,
1801assuming the wrapped image is the first pointer in the structure that
1802im->ext_data points at.
1803
1804=over
1805
1806=item i_addcolors_forward(i_img *im, i_color *colors, int count)
1807
1808=cut
1809*/
1810int i_addcolors_forward(i_img *im, i_color *colors, int count) {
1811 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1812}
1813
1814/*
1815=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1816
1817=cut
1818*/
1819int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1820 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1821}
1822
1823/*
1824=item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
1825
1826=cut
1827*/
1828int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
1829 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1830}
1831
1832/*
1833=item i_colorcount_forward(i_img *im)
1834
1835=cut
1836*/
1837int i_colorcount_forward(i_img *im) {
1838 return i_colorcount(*(i_img **)im->ext_data);
1839}
1840
1841/*
1842=item i_maxcolors_forward(i_img *im)
1843
1844=cut
1845*/
1846int i_maxcolors_forward(i_img *im) {
1847 return i_maxcolors(*(i_img **)im->ext_data);
1848}
1849
1850/*
1851=item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
1852
1853=cut
1854*/
1855int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
1856 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1857}
1858
1859/*
1860=back
1861
1862=head2 Stream reading and writing wrapper functions
1863
1864=over
1865
02d1d628
AMH
1866=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1867
1868Performs general read buffering for file readers that permit reading
1869to be done through a callback.
1870
1871The final callback gets two parameters, a I<need> value, and a I<want>
1872value, where I<need> is the amount of data that the file library needs
1873to read, and I<want> is the amount of space available in the buffer
1874maintained by these functions.
1875
1876This means if you need to read from a stream that you don't know the
1877length of, you can return I<need> bytes, taking the performance hit of
1878possibly expensive callbacks (eg. back to perl code), or if you are
1879reading from a stream where it doesn't matter if some data is lost, or
1880if the total length of the stream is known, you can return I<want>
1881bytes.
1882
1883=cut
1884*/
1885
1886int
1887i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1888 int total;
1889
1890 if (length < gci->length - gci->cpos) {
1891 /* simplest case */
1892 memcpy(buf, gci->buffer+gci->cpos, length);
1893 gci->cpos += length;
1894 return length;
1895 }
1896
1897 total = 0;
1898 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1899 total += gci->length - gci->cpos;
1900 length -= gci->length - gci->cpos;
1901 buf += gci->length - gci->cpos;
1902 if (length < (int)sizeof(gci->buffer)) {
1903 int did_read;
1904 int copy_size;
1905 while (length
1906 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1907 sizeof(gci->buffer))) > 0) {
1908 gci->cpos = 0;
1909 gci->length = did_read;
1910
1911 copy_size = min(length, gci->length);
1912 memcpy(buf, gci->buffer, copy_size);
1913 gci->cpos += copy_size;
1914 buf += copy_size;
1915 total += copy_size;
1916 length -= copy_size;
1917 }
1918 }
1919 else {
1920 /* just read the rest - too big for our buffer*/
1921 int did_read;
1922 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1923 length -= did_read;
1924 total += did_read;
1925 buf += did_read;
1926 }
1927 }
1928 return total;
1929}
1930
1931/*
1932=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1933
1934For use by callback file readers to initialize the reader buffer.
1935
1936Allocates, initializes and returns the reader buffer.
1937
1938See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1939
1940=cut
1941*/
1942i_gen_read_data *
1943i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1944 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1945 self->cb = cb;
1946 self->userdata = userdata;
1947 self->length = 0;
1948 self->cpos = 0;
1949
1950 return self;
1951}
1952
1953/*
1954=item free_gen_read_data(i_gen_read_data *)
1955
1956Cleans up.
1957
1958=cut
1959*/
1960void free_gen_read_data(i_gen_read_data *self) {
1961 myfree(self);
1962}
1963
1964/*
1965=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1966
1967Performs write buffering for a callback based file writer.
1968
1969Failures are considered fatal, if a write fails then data will be
1970dropped.
1971
1972=cut
1973*/
1974int
1975i_gen_writer(
1976i_gen_write_data *self,
1977char const *data,
1978int size)
1979{
1980 if (self->filledto && self->filledto+size > self->maxlength) {
1981 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1982 self->filledto = 0;
1983 }
1984 else {
1985 self->filledto = 0;
1986 return 0;
1987 }
1988 }
1989 if (self->filledto+size <= self->maxlength) {
1990 /* just save it */
1991 memcpy(self->buffer+self->filledto, data, size);
1992 self->filledto += size;
1993 return 1;
1994 }
1995 /* doesn't fit - hand it off */
1996 return self->cb(self->userdata, data, size);
1997}
1998
1999/*
2000=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
2001
2002Allocates and initializes the data structure used by i_gen_writer.
2003
2004This should be released with L<image.c/free_gen_write_data>
2005
2006=cut
2007*/
2008i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
2009 char *userdata, int max_length)
2010{
2011 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
2012 self->cb = cb;
2013 self->userdata = userdata;
2014 self->maxlength = min(max_length, sizeof(self->buffer));
2015 if (self->maxlength < 0)
2016 self->maxlength = sizeof(self->buffer);
2017 self->filledto = 0;
2018
2019 return self;
2020}
2021
2022/*
2023=item free_gen_write_data(i_gen_write_data *info, int flush)
2024
2025Cleans up the write buffer.
2026
2027Will flush any left-over data if I<flush> is non-zero.
2028
2029Returns non-zero if flush is zero or if info->cb() returns non-zero.
2030
2031Return zero only if flush is non-zero and info->cb() returns zero.
2032ie. if it fails.
2033
2034=cut
2035*/
2036
2037int free_gen_write_data(i_gen_write_data *info, int flush)
2038{
2039 int result = !flush ||
2040 info->filledto == 0 ||
2041 info->cb(info->userdata, info->buffer, info->filledto);
2042 myfree(info);
2043
2044 return result;
2045}
2046
2047/*
2048=back
2049
2050=head1 SEE ALSO
2051
2052L<Imager>, L<gif.c>
2053
2054=cut
2055*/