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