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