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