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