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