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