Counter correction.
[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) {
412 mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
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;
926 int T, TempJump1, TempJump2;
927 float F, PictureValue[MAXCHANNELS];
928 short psave;
929 i_color val,val1,val2;
930 i_img *new_img;
931
932 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
933
934 if (Axis == XAXIS) {
935 hsize = (int) ((float) im->xsize * Value);
936 vsize = im->ysize;
937
938 jEnd = hsize;
939 iEnd = vsize;
940
941 TempJump1 = (hsize - 1) * 3;
942 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
943 } else {
944 hsize = im->xsize;
945 vsize = (int) ((float) im->ysize * Value);
946
947 jEnd = vsize;
948 iEnd = hsize;
949
950 TempJump1 = 0;
951 TempJump2 = 0;
952 }
953
954 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
955
956 if (Value >=1) LanczosWidthFactor = 1;
957 else LanczosWidthFactor = (int) (1.0/Value);
958
959 lMax = LanczosWidthFactor << 1;
960
961 l0 = (float *) mymalloc(lMax * sizeof(float));
962 l1 = (float *) mymalloc(lMax * sizeof(float));
963
964 for (j=0; j<jEnd; j++) {
965 OldLocation = ((float) j) / Value;
966 T = (int) (OldLocation);
967 F = OldLocation - (float) T;
968
969 for (l = 0; l < lMax; l++) {
970 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
971 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
972 }
973
974 if (Axis== XAXIS) {
975
976 for (i=0; i<iEnd; i++) {
977 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
978 for (l=0; l < lMax; l++) {
979 i_gpix(im,T+l+1, i, &val1);
980 i_gpix(im,T-lMax+l+1, i, &val2);
981 for (k=0; k<im->channels; k++) {
982 PictureValue[k] += l1[l] * val1.channel[k];
983 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
984 }
985 }
986 for(k=0;k<im->channels;k++) {
987 psave = (short)( PictureValue[k] / LanczosWidthFactor);
988 val.channel[k]=minmax(0,255,psave);
989 }
990 i_ppix(new_img,j,i,&val);
991 }
992
993 } else {
994
995 for (i=0; i<iEnd; i++) {
996 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
997 for (l=0; l < lMax; l++) {
998 i_gpix(im,i, T+l+1, &val1);
999 i_gpix(im,i, T-lMax+l+1, &val2);
1000 for (k=0; k<im->channels; k++) {
1001 PictureValue[k] += l1[l] * val1.channel[k];
1002 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
1003 }
1004 }
1005 for (k=0; k<im->channels; k++) {
1006 psave = (short)( PictureValue[k] / LanczosWidthFactor);
1007 val.channel[k]=minmax(0,255,psave);
1008 }
1009 i_ppix(new_img,i,j,&val);
1010 }
1011
1012 }
1013 }
1014 myfree(l0);
1015 myfree(l1);
1016
1017 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
1018
1019 return new_img;
1020}
1021
1022
1023/*
1024=item i_scale_nn(im, scx, scy)
1025
1026Scale by using nearest neighbor
1027Both axes scaled at the same time since
1028nothing is gained by doing it in two steps
1029
1030=cut
1031*/
1032
1033
1034i_img*
1035i_scale_nn(i_img *im, float scx, float scy) {
1036
1037 int nxsize,nysize,nx,ny;
1038 i_img *new_img;
1039 i_color val;
1040
1041 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
1042
1043 nxsize = (int) ((float) im->xsize * scx);
1044 nysize = (int) ((float) im->ysize * scy);
1045
1046 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1047
1048 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1049 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
1050 i_ppix(new_img,nx,ny,&val);
1051 }
1052
1053 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
1054
1055 return new_img;
1056}
1057
faa9b3e7
TC
1058/*
1059=item i_sametype(i_img *im, int xsize, int ysize)
1060
1061Returns an image of the same type (sample size, channels, paletted/direct).
1062
1063For paletted images the palette is copied from the source.
1064
1065=cut
1066*/
1067
1068i_img *i_sametype(i_img *src, int xsize, int ysize) {
1069 if (src->type == i_direct_type) {
1070 if (src->bits == 8) {
1071 return i_img_empty_ch(NULL, xsize, ysize, src->channels);
1072 }
af3c2450 1073 else if (src->bits == i_16_bits) {
faa9b3e7
TC
1074 return i_img_16_new(xsize, ysize, src->channels);
1075 }
af3c2450
TC
1076 else if (src->bits == i_double_bits) {
1077 return i_img_double_new(xsize, ysize, src->channels);
1078 }
faa9b3e7
TC
1079 else {
1080 i_push_error(0, "Unknown image bits");
1081 return NULL;
1082 }
1083 }
1084 else {
1085 i_color col;
1086 int i;
1087
1088 i_img *targ = i_img_pal_new(xsize, ysize, src->channels, i_maxcolors(src));
1089 for (i = 0; i < i_colorcount(src); ++i) {
1090 i_getcolors(src, i, &col, 1);
1091 i_addcolors(targ, &col, 1);
1092 }
1093
1094 return targ;
1095 }
1096}
02d1d628
AMH
1097
1098/*
1099=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
1100
1101Spatially transforms I<im> returning a new image.
1102
1103opx for a length of opxl and opy for a length of opy are arrays of
1104operators that modify the x and y positions to retreive the pixel data from.
1105
1106parm and parmlen define extra parameters that the operators may use.
1107
1108Note that this function is largely superseded by the more flexible
1109L<transform.c/i_transform2>.
1110
1111Returns the new image.
1112
1113The operators for this function are defined in L<stackmach.c>.
1114
1115=cut
1116*/
1117i_img*
1118i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1119 double rx,ry;
1120 int nxsize,nysize,nx,ny;
1121 i_img *new_img;
1122 i_color val;
1123
1124 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));
1125
1126 nxsize = im->xsize;
1127 nysize = im->ysize ;
1128
1129 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1130 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1131 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1132 /* parm[parmlen-2]=(double)nx;
1133 parm[parmlen-1]=(double)ny; */
1134
1135 parm[0]=(double)nx;
1136 parm[1]=(double)ny;
1137
1138 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1139 rx=op_run(opx,opxl,parm,parmlen);
1140 ry=op_run(opy,opyl,parm,parmlen);
1141 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1142 i_gpix(im,rx,ry,&val);
1143 i_ppix(new_img,nx,ny,&val);
1144 }
1145
1146 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1147 return new_img;
1148}
1149
1150/*
1151=item i_img_diff(im1, im2)
1152
1153Calculates the sum of the squares of the differences between
1154correspoding channels in two images.
1155
1156If the images are not the same size then only the common area is
1157compared, hence even if images are different sizes this function
1158can return zero.
1159
1160=cut
1161*/
1162float
1163i_img_diff(i_img *im1,i_img *im2) {
1164 int x,y,ch,xb,yb,chb;
1165 float tdiff;
1166 i_color val1,val2;
1167
1168 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1169
1170 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1171 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1172 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1173
1174 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1175
1176 tdiff=0;
1177 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1178 i_gpix(im1,x,y,&val1);
1179 i_gpix(im2,x,y,&val2);
1180
1181 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1182 }
1183 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1184 return tdiff;
1185}
1186
1187/* just a tiny demo of haar wavelets */
1188
1189i_img*
1190i_haar(i_img *im) {
1191 int mx,my;
1192 int fx,fy;
1193 int x,y;
1194 int ch,c;
1195 i_img *new_img,*new_img2;
1196 i_color val1,val2,dval1,dval2;
1197
1198 mx=im->xsize;
1199 my=im->ysize;
1200 fx=(mx+1)/2;
1201 fy=(my+1)/2;
1202
1203
1204 /* horizontal pass */
1205
1206 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1207 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1208
1209 c=0;
1210 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1211 i_gpix(im,x*2,y,&val1);
1212 i_gpix(im,x*2+1,y,&val2);
1213 for(ch=0;ch<im->channels;ch++) {
1214 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1215 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1216 }
1217 i_ppix(new_img,x,y,&dval1);
1218 i_ppix(new_img,x+fx,y,&dval2);
1219 }
1220
1221 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1222 i_gpix(new_img,x,y*2,&val1);
1223 i_gpix(new_img,x,y*2+1,&val2);
1224 for(ch=0;ch<im->channels;ch++) {
1225 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1226 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1227 }
1228 i_ppix(new_img2,x,y,&dval1);
1229 i_ppix(new_img2,x,y+fy,&dval2);
1230 }
1231
1232 i_img_destroy(new_img);
1233 return new_img2;
1234}
1235
1236/*
1237=item i_count_colors(im, maxc)
1238
1239returns number of colors or -1
1240to indicate that it was more than max colors
1241
1242=cut
1243*/
1244int
1245i_count_colors(i_img *im,int maxc) {
1246 struct octt *ct;
1247 int x,y;
1248 int xsize,ysize;
1249 i_color val;
1250 int colorcnt;
1251
1252 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1253
1254 xsize=im->xsize;
1255 ysize=im->ysize;
1256 ct=octt_new();
1257
1258 colorcnt=0;
1259 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1260 i_gpix(im,x,y,&val);
1261 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1262 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1263 }
1264 octt_delete(ct);
1265 return colorcnt;
1266}
1267
1268
1269symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1270 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1271 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1272 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1273
1274
1275/*
faa9b3e7
TC
1276=back
1277
1278=head2 8-bit per sample image internal functions
1279
1280These are the functions installed in an 8-bit per sample image.
1281
1282=over
1283
1284=item i_ppix_d(im, x, y, col)
1285
1286Internal function.
1287
1288This is the function kept in the i_f_ppix member of an i_img object.
1289It does a normal store of a pixel into the image with range checking.
1290
1291Returns 0 if the pixel could be set, -1 otherwise.
1292
1293=cut
1294*/
1295int
1296i_ppix_d(i_img *im, int x, int y, i_color *val) {
1297 int ch;
1298
1299 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1300 for(ch=0;ch<im->channels;ch++)
1301 if (im->ch_mask&(1<<ch))
1302 im->idata[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
1303 return 0;
1304 }
1305 return -1; /* error was clipped */
1306}
1307
1308/*
1309=item i_gpix_d(im, x, y, &col)
1310
1311Internal function.
1312
1313This is the function kept in the i_f_gpix member of an i_img object.
1314It does normal retrieval of a pixel from the image with range checking.
1315
1316Returns 0 if the pixel could be set, -1 otherwise.
1317
1318=cut
1319*/
1320int
1321i_gpix_d(i_img *im, int x, int y, i_color *val) {
1322 int ch;
1323 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1324 for(ch=0;ch<im->channels;ch++)
1325 val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
1326 return 0;
1327 }
1328 return -1; /* error was cliped */
1329}
1330
1331/*
1332=item i_glin_d(im, l, r, y, vals)
1333
1334Reads a line of data from the image, storing the pixels at vals.
1335
1336The line runs from (l,y) inclusive to (r,y) non-inclusive
1337
1338vals should point at space for (r-l) pixels.
1339
1340l should never be less than zero (to avoid confusion about where to
1341put the pixels in vals).
1342
1343Returns the number of pixels copied (eg. if r, l or y is out of range)
1344
1345=cut
1346*/
1347int
1348i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
1349 int ch, count, i;
1350 unsigned char *data;
1351 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1352 if (r > im->xsize)
1353 r = im->xsize;
1354 data = im->idata + (l+y*im->xsize) * im->channels;
1355 count = r - l;
1356 for (i = 0; i < count; ++i) {
1357 for (ch = 0; ch < im->channels; ++ch)
1358 vals[i].channel[ch] = *data++;
1359 }
1360 return count;
1361 }
1362 else {
1363 return 0;
1364 }
1365}
1366
1367/*
1368=item i_plin_d(im, l, r, y, vals)
1369
1370Writes a line of data into the image, using the pixels at vals.
1371
1372The line runs from (l,y) inclusive to (r,y) non-inclusive
1373
1374vals should point at (r-l) pixels.
1375
1376l should never be less than zero (to avoid confusion about where to
1377get the pixels in vals).
1378
1379Returns the number of pixels copied (eg. if r, l or y is out of range)
1380
1381=cut
1382*/
1383int
1384i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
1385 int ch, count, i;
1386 unsigned char *data;
1387 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1388 if (r > im->xsize)
1389 r = im->xsize;
1390 data = im->idata + (l+y*im->xsize) * im->channels;
1391 count = r - l;
1392 for (i = 0; i < count; ++i) {
1393 for (ch = 0; ch < im->channels; ++ch) {
1394 if (im->ch_mask & (1 << ch))
1395 *data = vals[i].channel[ch];
1396 ++data;
1397 }
1398 }
1399 return count;
1400 }
1401 else {
1402 return 0;
1403 }
1404}
1405
1406/*
1407=item i_ppixf_d(im, x, y, val)
1408
1409=cut
1410*/
1411int
1412i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
1413 int ch;
1414
1415 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
1416 for(ch=0;ch<im->channels;ch++)
1417 if (im->ch_mask&(1<<ch)) {
1418 im->idata[(x+y*im->xsize)*im->channels+ch] =
1419 SampleFTo8(val->channel[ch]);
1420 }
1421 return 0;
1422 }
1423 return -1; /* error was clipped */
1424}
1425
1426/*
1427=item i_gpixf_d(im, x, y, val)
1428
1429=cut
1430*/
1431int
1432i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
1433 int ch;
1434 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
1435 for(ch=0;ch<im->channels;ch++) {
1436 val->channel[ch] =
1437 Sample8ToF(im->idata[(x+y*im->xsize)*im->channels+ch]);
1438 }
1439 return 0;
1440 }
1441 return -1; /* error was cliped */
1442}
1443
1444/*
1445=item i_glinf_d(im, l, r, y, vals)
1446
1447Reads a line of data from the image, storing the pixels at vals.
1448
1449The line runs from (l,y) inclusive to (r,y) non-inclusive
1450
1451vals should point at space for (r-l) pixels.
1452
1453l should never be less than zero (to avoid confusion about where to
1454put the pixels in vals).
1455
1456Returns the number of pixels copied (eg. if r, l or y is out of range)
1457
1458=cut
1459*/
1460int
1461i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1462 int ch, count, i;
1463 unsigned char *data;
1464 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1465 if (r > im->xsize)
1466 r = im->xsize;
1467 data = im->idata + (l+y*im->xsize) * im->channels;
1468 count = r - l;
1469 for (i = 0; i < count; ++i) {
1470 for (ch = 0; ch < im->channels; ++ch)
6607600c 1471 vals[i].channel[ch] = Sample8ToF(*data++);
faa9b3e7
TC
1472 }
1473 return count;
1474 }
1475 else {
1476 return 0;
1477 }
1478}
1479
1480/*
1481=item i_plinf_d(im, l, r, y, vals)
1482
1483Writes a line of data into the image, using the pixels at vals.
1484
1485The line runs from (l,y) inclusive to (r,y) non-inclusive
1486
1487vals should point at (r-l) pixels.
1488
1489l should never be less than zero (to avoid confusion about where to
1490get the pixels in vals).
1491
1492Returns the number of pixels copied (eg. if r, l or y is out of range)
1493
1494=cut
1495*/
1496int
1497i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
1498 int ch, count, i;
1499 unsigned char *data;
1500 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1501 if (r > im->xsize)
1502 r = im->xsize;
1503 data = im->idata + (l+y*im->xsize) * im->channels;
1504 count = r - l;
1505 for (i = 0; i < count; ++i) {
1506 for (ch = 0; ch < im->channels; ++ch) {
1507 if (im->ch_mask & (1 << ch))
6607600c 1508 *data = SampleFTo8(vals[i].channel[ch]);
faa9b3e7
TC
1509 ++data;
1510 }
1511 }
1512 return count;
1513 }
1514 else {
1515 return 0;
1516 }
1517}
1518
1519/*
1520=item i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count)
1521
1522Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1523for the channels specified by chans, an array of int with chan_count
1524elements.
1525
1526Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1527
1528=cut
1529*/
1530int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
1531 int *chans, int chan_count) {
1532 int ch, count, i, w;
1533 unsigned char *data;
1534
1535 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1536 if (r > im->xsize)
1537 r = im->xsize;
1538 data = im->idata + (l+y*im->xsize) * im->channels;
1539 w = r - l;
1540 count = 0;
1541
1542 if (chans) {
1543 /* make sure we have good channel numbers */
1544 for (ch = 0; ch < chan_count; ++ch) {
1545 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1546 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1547 return 0;
1548 }
1549 }
1550 for (i = 0; i < w; ++i) {
1551 for (ch = 0; ch < chan_count; ++ch) {
1552 *samps++ = data[chans[ch]];
1553 ++count;
1554 }
1555 data += im->channels;
1556 }
1557 }
1558 else {
1559 for (i = 0; i < w; ++i) {
1560 for (ch = 0; ch < chan_count; ++ch) {
1561 *samps++ = data[ch];
1562 ++count;
1563 }
1564 data += im->channels;
1565 }
1566 }
1567
1568 return count;
1569 }
1570 else {
1571 return 0;
1572 }
1573}
1574
1575/*
1576=item i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count)
1577
1578Reads sample values from im for the horizontal line (l, y) to (r-1,y)
1579for the channels specified by chan_mask, where bit 0 is the first
1580channel.
1581
1582Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
1583
1584=cut
1585*/
1586int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
1587 int *chans, int chan_count) {
1588 int ch, count, i, w;
1589 unsigned char *data;
1590 for (ch = 0; ch < chan_count; ++ch) {
1591 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1592 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1593 }
1594 }
1595 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
1596 if (r > im->xsize)
1597 r = im->xsize;
1598 data = im->idata + (l+y*im->xsize) * im->channels;
1599 w = r - l;
1600 count = 0;
1601
1602 if (chans) {
1603 /* make sure we have good channel numbers */
1604 for (ch = 0; ch < chan_count; ++ch) {
1605 if (chans[ch] < 0 || chans[ch] >= im->channels) {
1606 i_push_errorf(0, "No channel %d in this image", chans[ch]);
1607 return 0;
1608 }
1609 }
1610 for (i = 0; i < w; ++i) {
1611 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1612 *samps++ = Sample8ToF(data[chans[ch]]);
faa9b3e7
TC
1613 ++count;
1614 }
1615 data += im->channels;
1616 }
1617 }
1618 else {
1619 for (i = 0; i < w; ++i) {
1620 for (ch = 0; ch < chan_count; ++ch) {
6607600c 1621 *samps++ = Sample8ToF(data[ch]);
faa9b3e7
TC
1622 ++count;
1623 }
1624 data += im->channels;
1625 }
1626 }
1627 return count;
1628 }
1629 else {
1630 return 0;
1631 }
1632}
1633
1634/*
1635=back
1636
1637=head2 Image method wrappers
1638
1639These functions provide i_fsample_t functions in terms of their
1640i_sample_t versions.
1641
1642=over
1643
1644=item i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1645
1646=cut
1647*/
1648
1649int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1650 i_color temp;
1651 int ch;
1652
1653 for (ch = 0; ch < im->channels; ++ch)
1654 temp.channel[ch] = SampleFTo8(pix->channel[ch]);
1655
1656 return i_ppix(im, x, y, &temp);
1657}
1658
1659/*
1660=item i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix)
1661
1662=cut
1663*/
1664int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
1665 i_color temp;
1666 int ch;
1667
1668 if (i_gpix(im, x, y, &temp)) {
1669 for (ch = 0; ch < im->channels; ++ch)
1670 pix->channel[ch] = Sample8ToF(temp.channel[ch]);
1671 return 0;
1672 }
1673 else
1674 return -1;
1675}
1676
1677/*
1678=item i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1679
1680=cut
1681*/
1682int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1683 i_color *work;
1684
1685 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1686 if (r > im->xsize)
1687 r = im->xsize;
1688 if (r > l) {
1689 int ret;
1690 int i, ch;
1691 work = mymalloc(sizeof(i_color) * (r-l));
1692 for (i = 0; i < r-l; ++i) {
1693 for (ch = 0; ch < im->channels; ++ch)
1694 work[i].channel[ch] = SampleFTo8(pix[i].channel[ch]);
1695 }
1696 ret = i_plin(im, l, r, y, work);
1697 myfree(work);
1698
1699 return ret;
1700 }
1701 else {
1702 return 0;
1703 }
1704 }
1705 else {
1706 return 0;
1707 }
1708}
1709
1710/*
1711=item i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix)
1712
1713=cut
1714*/
1715int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
1716 i_color *work;
1717
1718 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1719 if (r > im->xsize)
1720 r = im->xsize;
1721 if (r > l) {
1722 int ret;
1723 int i, ch;
1724 work = mymalloc(sizeof(i_color) * (r-l));
1725 ret = i_plin(im, l, r, y, work);
1726 for (i = 0; i < r-l; ++i) {
1727 for (ch = 0; ch < im->channels; ++ch)
1728 pix[i].channel[ch] = Sample8ToF(work[i].channel[ch]);
1729 }
1730 myfree(work);
1731
1732 return ret;
1733 }
1734 else {
1735 return 0;
1736 }
1737 }
1738 else {
1739 return 0;
1740 }
1741}
1742
1743/*
1744=item i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, int *chans, int chan_count)
1745
1746=cut
1747*/
1748int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
1749 int *chans, int chan_count) {
1750 i_sample_t *work;
1751
1752 if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
1753 if (r > im->xsize)
1754 r = im->xsize;
1755 if (r > l) {
1756 int ret;
1757 int i;
1758 work = mymalloc(sizeof(i_sample_t) * (r-l));
1759 ret = i_gsamp(im, l, r, y, work, chans, chan_count);
1760 for (i = 0; i < ret; ++i) {
1761 samp[i] = Sample8ToF(work[i]);
1762 }
1763 myfree(work);
1764
1765 return ret;
1766 }
1767 else {
1768 return 0;
1769 }
1770 }
1771 else {
1772 return 0;
1773 }
1774}
1775
1776/*
1777=back
1778
1779=head2 Palette wrapper functions
1780
1781Used for virtual images, these forward palette calls to a wrapped image,
1782assuming the wrapped image is the first pointer in the structure that
1783im->ext_data points at.
1784
1785=over
1786
1787=item i_addcolors_forward(i_img *im, i_color *colors, int count)
1788
1789=cut
1790*/
1791int i_addcolors_forward(i_img *im, i_color *colors, int count) {
1792 return i_addcolors(*(i_img **)im->ext_data, colors, count);
1793}
1794
1795/*
1796=item i_getcolors_forward(i_img *im, int i, i_color *color, int count)
1797
1798=cut
1799*/
1800int i_getcolors_forward(i_img *im, int i, i_color *color, int count) {
1801 return i_getcolors(*(i_img **)im->ext_data, i, color, count);
1802}
1803
1804/*
1805=item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
1806
1807=cut
1808*/
1809int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
1810 return i_setcolors(*(i_img **)im->ext_data, i, color, count);
1811}
1812
1813/*
1814=item i_colorcount_forward(i_img *im)
1815
1816=cut
1817*/
1818int i_colorcount_forward(i_img *im) {
1819 return i_colorcount(*(i_img **)im->ext_data);
1820}
1821
1822/*
1823=item i_maxcolors_forward(i_img *im)
1824
1825=cut
1826*/
1827int i_maxcolors_forward(i_img *im) {
1828 return i_maxcolors(*(i_img **)im->ext_data);
1829}
1830
1831/*
1832=item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
1833
1834=cut
1835*/
1836int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
1837 return i_findcolor(*(i_img **)im->ext_data, color, entry);
1838}
1839
1840/*
1841=back
1842
1843=head2 Stream reading and writing wrapper functions
1844
1845=over
1846
02d1d628
AMH
1847=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1848
1849Performs general read buffering for file readers that permit reading
1850to be done through a callback.
1851
1852The final callback gets two parameters, a I<need> value, and a I<want>
1853value, where I<need> is the amount of data that the file library needs
1854to read, and I<want> is the amount of space available in the buffer
1855maintained by these functions.
1856
1857This means if you need to read from a stream that you don't know the
1858length of, you can return I<need> bytes, taking the performance hit of
1859possibly expensive callbacks (eg. back to perl code), or if you are
1860reading from a stream where it doesn't matter if some data is lost, or
1861if the total length of the stream is known, you can return I<want>
1862bytes.
1863
1864=cut
1865*/
1866
1867int
1868i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1869 int total;
1870
1871 if (length < gci->length - gci->cpos) {
1872 /* simplest case */
1873 memcpy(buf, gci->buffer+gci->cpos, length);
1874 gci->cpos += length;
1875 return length;
1876 }
1877
1878 total = 0;
1879 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1880 total += gci->length - gci->cpos;
1881 length -= gci->length - gci->cpos;
1882 buf += gci->length - gci->cpos;
1883 if (length < (int)sizeof(gci->buffer)) {
1884 int did_read;
1885 int copy_size;
1886 while (length
1887 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1888 sizeof(gci->buffer))) > 0) {
1889 gci->cpos = 0;
1890 gci->length = did_read;
1891
1892 copy_size = min(length, gci->length);
1893 memcpy(buf, gci->buffer, copy_size);
1894 gci->cpos += copy_size;
1895 buf += copy_size;
1896 total += copy_size;
1897 length -= copy_size;
1898 }
1899 }
1900 else {
1901 /* just read the rest - too big for our buffer*/
1902 int did_read;
1903 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1904 length -= did_read;
1905 total += did_read;
1906 buf += did_read;
1907 }
1908 }
1909 return total;
1910}
1911
1912/*
1913=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1914
1915For use by callback file readers to initialize the reader buffer.
1916
1917Allocates, initializes and returns the reader buffer.
1918
1919See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1920
1921=cut
1922*/
1923i_gen_read_data *
1924i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1925 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1926 self->cb = cb;
1927 self->userdata = userdata;
1928 self->length = 0;
1929 self->cpos = 0;
1930
1931 return self;
1932}
1933
1934/*
1935=item free_gen_read_data(i_gen_read_data *)
1936
1937Cleans up.
1938
1939=cut
1940*/
1941void free_gen_read_data(i_gen_read_data *self) {
1942 myfree(self);
1943}
1944
1945/*
1946=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1947
1948Performs write buffering for a callback based file writer.
1949
1950Failures are considered fatal, if a write fails then data will be
1951dropped.
1952
1953=cut
1954*/
1955int
1956i_gen_writer(
1957i_gen_write_data *self,
1958char const *data,
1959int size)
1960{
1961 if (self->filledto && self->filledto+size > self->maxlength) {
1962 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1963 self->filledto = 0;
1964 }
1965 else {
1966 self->filledto = 0;
1967 return 0;
1968 }
1969 }
1970 if (self->filledto+size <= self->maxlength) {
1971 /* just save it */
1972 memcpy(self->buffer+self->filledto, data, size);
1973 self->filledto += size;
1974 return 1;
1975 }
1976 /* doesn't fit - hand it off */
1977 return self->cb(self->userdata, data, size);
1978}
1979
1980/*
1981=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1982
1983Allocates and initializes the data structure used by i_gen_writer.
1984
1985This should be released with L<image.c/free_gen_write_data>
1986
1987=cut
1988*/
1989i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1990 char *userdata, int max_length)
1991{
1992 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1993 self->cb = cb;
1994 self->userdata = userdata;
1995 self->maxlength = min(max_length, sizeof(self->buffer));
1996 if (self->maxlength < 0)
1997 self->maxlength = sizeof(self->buffer);
1998 self->filledto = 0;
1999
2000 return self;
2001}
2002
2003/*
2004=item free_gen_write_data(i_gen_write_data *info, int flush)
2005
2006Cleans up the write buffer.
2007
2008Will flush any left-over data if I<flush> is non-zero.
2009
2010Returns non-zero if flush is zero or if info->cb() returns non-zero.
2011
2012Return zero only if flush is non-zero and info->cb() returns zero.
2013ie. if it fails.
2014
2015=cut
2016*/
2017
2018int free_gen_write_data(i_gen_write_data *info, int flush)
2019{
2020 int result = !flush ||
2021 info->filledto == 0 ||
2022 info->cb(info->userdata, info->buffer, info->filledto);
2023 myfree(info);
2024
2025 return result;
2026}
2027
2028/*
2029=back
2030
2031=head1 SEE ALSO
2032
2033L<Imager>, L<gif.c>
2034
2035=cut
2036*/