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