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