implementing read/put horizontal line of pixels
[imager.git] / image.c
CommitLineData
02d1d628
AMH
1#include "image.h"
2#include "io.h"
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
28=over 4
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 */
40void fake() { ceil(1); }
41
42/*
43=item ICL_new_internal(r, g, b, a)
44
45Return a new color object with values passed to it.
46
47 r - red component (range: 0 - 255)
48 g - green component (range: 0 - 255)
49 b - blue component (range: 0 - 255)
50 a - alpha component (range: 0 - 255)
51
52=cut
53*/
54
55i_color *
56ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
4cac9410 57 i_color *cl = NULL;
02d1d628 58
4cac9410 59 mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
02d1d628
AMH
60
61 if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
4cac9410
AMH
62 cl->rgba.r = r;
63 cl->rgba.g = g;
64 cl->rgba.b = b;
65 cl->rgba.a = a;
66 mm_log((1,"(%p) <- ICL_new_internal\n",cl));
02d1d628
AMH
67 return cl;
68}
69
70
71/*
72=item ICL_set_internal(cl, r, g, b, a)
73
74 Overwrite a color with new values.
75
76 cl - pointer to color object
77 r - red component (range: 0 - 255)
78 g - green component (range: 0 - 255)
79 b - blue component (range: 0 - 255)
80 a - alpha component (range: 0 - 255)
81
82=cut
83*/
84
85i_color *
86ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
4cac9410 87 mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
02d1d628
AMH
88 if (cl == NULL)
89 if ( (cl=mymalloc(sizeof(i_color))) == NULL)
90 m_fatal(2,"malloc() error\n");
91 cl->rgba.r=r;
92 cl->rgba.g=g;
93 cl->rgba.b=b;
94 cl->rgba.a=a;
4cac9410 95 mm_log((1,"(%p) <- ICL_set_internal\n",cl));
02d1d628
AMH
96 return cl;
97}
98
99
100/*
101=item ICL_add(dst, src, ch)
102
103Add src to dst inplace - dst is modified.
104
105 dst - pointer to destination color object
106 src - pointer to color object that is added
107 ch - number of channels
108
109=cut
110*/
111
112void
113ICL_add(i_color *dst,i_color *src,int ch) {
114 int tmp,i;
115 for(i=0;i<ch;i++) {
116 tmp=dst->channel[i]+src->channel[i];
117 dst->channel[i]= tmp>255 ? 255:tmp;
118 }
119}
120
121/*
122=item ICL_info(cl)
123
124Dump color information to log - strictly for debugging.
125
126 cl - pointer to color object
127
128=cut
129*/
130
131void
132ICL_info(i_color *cl) {
4cac9410 133 mm_log((1,"i_color_info(cl* %p)\n",cl));
02d1d628
AMH
134 mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
135}
136
137/*
138=item ICL_DESTROY
139
140Destroy ancillary data for Color object.
141
142 cl - pointer to color object
143
144=cut
145*/
146
147void
148ICL_DESTROY(i_color *cl) {
4cac9410 149 mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
02d1d628
AMH
150 myfree(cl);
151}
152
153/*
154=item IIM_new(x, y, ch)
155
156Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
157
158=cut
159*/
160
161
162i_img *
163IIM_new(int x,int y,int ch) {
164 i_img *im;
165 mm_log((1,"IIM_new(x %d,y %d,ch %d)\n",x,y,ch));
166
167 im=i_img_empty_ch(NULL,x,y,ch);
168
4cac9410 169 mm_log((1,"(%p) <- IIM_new\n",im));
02d1d628
AMH
170 return im;
171}
172
173
174void
175IIM_DESTROY(i_img *im) {
4cac9410 176 mm_log((1,"IIM_DESTROY(im* %p)\n",im));
02d1d628
AMH
177 /* myfree(cl); */
178}
179
180
181
182/*
183=item i_img_new()
184
185Create new image reference - notice that this isn't an object yet and
186this should be fixed asap.
187
188=cut
189*/
190
191
192i_img *
193i_img_new() {
194 i_img *im;
195
196 mm_log((1,"i_img_struct()\n"));
197 if ( (im=mymalloc(sizeof(i_img))) == NULL)
198 m_fatal(2,"malloc() error\n");
199
200 im->xsize=0;
201 im->ysize=0;
202 im->channels=3;
203 im->ch_mask=MAXINT;
204 im->bytes=0;
205 im->data=NULL;
206
207 im->i_f_ppix=i_ppix_d;
208 im->i_f_gpix=i_gpix_d;
7a0584ef
TC
209 im->i_f_plin=i_plin_d;
210 im->i_f_glin=i_glin_d;
02d1d628
AMH
211 im->ext_data=NULL;
212
4cac9410 213 mm_log((1,"(%p) <- i_img_struct\n",im));
02d1d628
AMH
214 return im;
215}
216
217/*
218=item i_img_empty(im, x, y)
219
220Re-new image reference (assumes 3 channels)
221
222 im - Image pointer
223 x - xsize of destination image
224 y - ysize of destination image
225
226=cut
227*/
228
229i_img *
230i_img_empty(i_img *im,int x,int y) {
4cac9410 231 mm_log((1,"i_img_empty(*im %p, x %d, y %d)\n",im, x, y));
02d1d628
AMH
232 if (im==NULL)
233 if ( (im=mymalloc(sizeof(i_img))) == NULL)
234 m_fatal(2,"malloc() error\n");
235
4cac9410
AMH
236 im->xsize = x;
237 im->ysize = y;
238 im->channels = 3;
239 im->ch_mask = MAXINT;
02d1d628 240 im->bytes=x*y*im->channels;
4cac9410
AMH
241 if ( (im->data = mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
242 memset(im->data, 0, (size_t)im->bytes);
02d1d628 243
4cac9410
AMH
244 im->i_f_ppix = i_ppix_d;
245 im->i_f_gpix = i_gpix_d;
7a0584ef
TC
246 im->i_f_plin = i_plin_d;
247 im->i_f_glin = i_glin_d;
4cac9410 248 im->ext_data = NULL;
02d1d628 249
4cac9410 250 mm_log((1,"(%p) <- i_img_empty\n", im));
02d1d628
AMH
251 return im;
252}
253
254/*
255=item i_img_empty_ch(im, x, y, ch)
256
257Re-new image reference
258
259 im - Image pointer
142c26ff
AMH
260 x - xsize of destination image
261 y - ysize of destination image
02d1d628
AMH
262 ch - number of channels
263
264=cut
265*/
266
267i_img *
268i_img_empty_ch(i_img *im,int x,int y,int ch) {
4cac9410
AMH
269 mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
270 if (im == NULL)
02d1d628
AMH
271 if ( (im=mymalloc(sizeof(i_img))) == NULL)
272 m_fatal(2,"malloc() error\n");
273
4cac9410
AMH
274 im->xsize = x;
275 im->ysize = y;
276 im->channels = ch;
277 im->ch_mask = MAXINT;
02d1d628
AMH
278 im->bytes=x*y*im->channels;
279 if ( (im->data=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
280 memset(im->data,0,(size_t)im->bytes);
281
4cac9410
AMH
282 im->i_f_ppix = i_ppix_d;
283 im->i_f_gpix = i_gpix_d;
7a0584ef
TC
284 im->i_f_plin = i_plin_d;
285 im->i_f_glin = i_glin_d;
4cac9410 286 im->ext_data = NULL;
02d1d628 287
4cac9410 288 mm_log((1,"(%p) <- i_img_empty_ch\n",im));
02d1d628
AMH
289 return im;
290}
291
292/*
293=item i_img_exorcise(im)
294
295Free image data.
296
297 im - Image pointer
298
299=cut
300*/
301
302void
303i_img_exorcise(i_img *im) {
304 mm_log((1,"i_img_exorcise(im* 0x%x)\n",im));
305 if (im->data != NULL) { myfree(im->data); }
4cac9410
AMH
306 im->data = NULL;
307 im->xsize = 0;
308 im->ysize = 0;
309 im->channels = 0;
02d1d628
AMH
310
311 im->i_f_ppix=i_ppix_d;
312 im->i_f_gpix=i_gpix_d;
7a0584ef
TC
313 im->i_f_plin=i_plin_d;
314 im->i_f_glin=i_glin_d;
02d1d628
AMH
315 im->ext_data=NULL;
316}
317
318/*
319=item i_img_destroy(im)
320
321Destroy image and free data via exorcise.
322
323 im - Image pointer
324
325=cut
326*/
327
328void
329i_img_destroy(i_img *im) {
330 mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
331 i_img_exorcise(im);
332 if (im) { myfree(im); }
333}
334
335/*
336=item i_img_info(im, info)
337
338Return image information
339
340 im - Image pointer
341 info - pointer to array to return data
342
343info is an array of 4 integers with the following values:
344
345 info[0] - width
346 info[1] - height
347 info[2] - channels
348 info[3] - channel mask
349
350=cut
351*/
352
353
354void
355i_img_info(i_img *im,int *info) {
356 mm_log((1,"i_img_info(im 0x%x)\n",im));
357 if (im != NULL) {
358 mm_log((1,"i_img_info: xsize=%d ysize=%d channels=%d mask=%ud\n",im->xsize,im->ysize,im->channels,im->ch_mask));
359 mm_log((1,"i_img_info: data=0x%d\n",im->data));
4cac9410
AMH
360 info[0] = im->xsize;
361 info[1] = im->ysize;
362 info[2] = im->channels;
363 info[3] = im->ch_mask;
02d1d628 364 } else {
4cac9410
AMH
365 info[0] = 0;
366 info[1] = 0;
367 info[2] = 0;
368 info[3] = 0;
02d1d628
AMH
369 }
370}
371
372/*
373=item i_img_setmask(im, ch_mask)
374
375Set the image channel mask for I<im> to I<ch_mask>.
376
377=cut
378*/
379void
380i_img_setmask(i_img *im,int ch_mask) { im->ch_mask=ch_mask; }
381
382
383/*
384=item i_img_getmask(im)
385
386Get the image channel mask for I<im>.
387
388=cut
389*/
390int
391i_img_getmask(i_img *im) { return im->ch_mask; }
392
393/*
394=item i_img_getchannels(im)
395
396Get the number of channels in I<im>.
397
398=cut
399*/
400int
401i_img_getchannels(i_img *im) { return im->channels; }
402
403
404/*
405=item i_ppix(im, x, y, col)
406
407Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
408
409Returns true if the pixel could be set, false if x or y is out of
410range.
411
412=cut
413*/
414int
4cac9410 415i_ppix(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
02d1d628
AMH
416
417/*
418=item i_gpix(im, x, y, &col)
419
420Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
421
422Returns true if the pixel could be retrieved, false otherwise.
423
424=cut
425*/
426int
4cac9410 427i_gpix(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
02d1d628
AMH
428
429/*
430=item i_ppix_d(im, x, y, col)
431
432Internal function.
433
434This is the function kept in the i_f_ppix member of an i_img object.
435It does a normal store of a pixel into the image with range checking.
436
437Returns true if the pixel could be set, false otherwise.
438
439=cut
440*/
441int
4cac9410 442i_ppix_d(i_img *im, int x, int y, i_color *val) {
02d1d628
AMH
443 int ch;
444
445 if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
446 for(ch=0;ch<im->channels;ch++)
447 if (im->ch_mask&(1<<ch))
448 im->data[(x+y*im->xsize)*im->channels+ch]=val->channel[ch];
449 return 0;
450 }
451 return -1; /* error was clipped */
452}
453
454/*
455=item i_gpix_d(im, x, y, &col)
456
457Internal function.
458
459This is the function kept in the i_f_gpix member of an i_img object.
460It does normal retrieval of a pixel from the image with range checking.
461
462Returns true if the pixel could be set, false otherwise.
463
464=cut
465*/
466int
4cac9410 467i_gpix_d(i_img *im, int x, int y, i_color *val) {
02d1d628
AMH
468 int ch;
469 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
470 for(ch=0;ch<im->channels;ch++)
471 val->channel[ch]=im->data[(x+y*im->xsize)*im->channels+ch];
472 return 0;
473 }
474 return -1; /* error was cliped */
475}
476
7a0584ef
TC
477/*
478=item i_glin_d(im, l, r, y, vals)
479
480Reads a line of data from the image, storing the pixels at vals.
481
482The line runs from (l,y) inclusive to (r,y) non-inclusive
483
484vals should point at space for (r-l) pixels.
485
486l should never be less than zero (to avoid confusion about where to
487put the pixels in vals).
488
489Returns the number of pixels copied (eg. if r, l or y is out of range)
490
491=cut */
492int
493i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
494 int x, ch;
495 int count;
496 int i;
497 unsigned char *data;
498 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
499 if (r > im->xsize)
500 r = im->xsize;
501 data = im->data + (l+y*im->xsize) * im->channels;
502 count = r - l;
503 for (i = 0; i < count; ++i) {
504 for (ch = 0; ch < im->channels; ++ch)
505 vals[i].channel[ch] = *data++;
506 }
507 return count;
508 }
509 else {
510 return 0;
511 }
512}
513/*
514=item i_plin_d(im, l, r, y, vals)
515
516Writes a line of data into the image, using the pixels at vals.
517
518The line runs from (l,y) inclusive to (r,y) non-inclusive
519
520vals should point at (r-l) pixels.
521
522l should never be less than zero (to avoid confusion about where to
523get the pixels in vals).
524
525Returns the number of pixels copied (eg. if r, l or y is out of range)
526
527=cut */
528int
529i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
530 int x, ch;
531 int count;
532 int i;
533 unsigned char *data;
534 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
535 if (r > im->xsize)
536 r = im->xsize;
537 data = im->data + (l+y*im->xsize) * im->channels;
538 count = r - l;
539 for (i = 0; i < count; ++i) {
540 for (ch = 0; ch < im->channels; ++ch) {
541 if (im->ch_mask & (1 << ch))
542 *data = vals[i].channel[ch];
543 ++data;
544 }
545 }
546 return count;
547 }
548 else {
549 return 0;
550 }
551}
552
02d1d628
AMH
553/*
554=item i_ppix_pch(im, x, y, ch)
555
556Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
557scaled to [0,1].
558
559Returns zero if x or y is out of range.
560
561Warning: this ignores the vptr interface for images.
562
563=cut
564*/
565float
566i_gpix_pch(i_img *im,int x,int y,int ch) {
567 if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->data[(x+y*im->xsize)*im->channels+ch]/255);
568 else return 0;
569}
570
571
572/*
573=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
574
575(x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
576(tx,ty) specifies the upper left corner for the target image.
577pass NULL in trans for non transparent i_colors.
578
579=cut
580*/
581
582void
583i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
584 i_color pv;
585 int x,y,t,ttx,tty,tt,ch;
586
4cac9410
AMH
587 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",
588 im, src, x1, y1, x2, y2, tx, ty, trans));
589
02d1d628
AMH
590 if (x2<x1) { t=x1; x1=x2; x2=t; }
591 if (y2<y1) { t=y1; y1=y2; y2=t; }
592
593 ttx=tx;
594 for(x=x1;x<x2;x++)
595 {
596 tty=ty;
597 for(y=y1;y<y2;y++)
598 {
599 i_gpix(src,x,y,&pv);
600 if ( trans != NULL)
601 {
602 tt=0;
603 for(ch=0;ch<im->channels;ch++) if (trans->channel[ch]!=pv.channel[ch]) tt++;
604 if (tt) i_ppix(im,ttx,tty,&pv);
605 } else i_ppix(im,ttx,tty,&pv);
606 tty++;
607 }
608 ttx++;
609 }
610}
611
612/*
613=item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
614
615Copies image data from the area (x1,y1)-[x2,y2] in the source image to
616a rectangle the same size with it's top-left corner at (tx,ty) in the
617destination image.
618
619If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped.
620
621=cut
622*/
623
624void
4cac9410 625i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) {
02d1d628 626 i_color pv;
4cac9410 627 int x, y, t, ttx, tty;
02d1d628
AMH
628
629 if (x2<x1) { t=x1; x1=x2; x2=t; }
630 if (y2<y1) { t=y1; y1=y2; y2=t; }
631
4cac9410
AMH
632 mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
633 im, src, x1, y1, x2, y2, tx, ty));
02d1d628 634
4cac9410
AMH
635 tty = ty;
636 for(y=y1; y<y2; y++) {
637 ttx = tx;
638 for(x=x1; x<x2; x++) {
639 i_gpix(src, x, y, &pv);
640 i_ppix(im, ttx, tty, &pv);
641 ttx++;
02d1d628
AMH
642 }
643 tty++;
644 }
645}
646
647/*
648=item i_copy(im, src)
649
650Copies the contents of the image I<src> over the image I<im>.
651
652=cut
653*/
654
655void
4cac9410 656i_copy(i_img *im, i_img *src) {
7a0584ef 657 i_color *pv;
02d1d628
AMH
658 int x,y,y1,x1;
659
4202e066 660 mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
02d1d628 661
4cac9410
AMH
662 x1 = src->xsize;
663 y1 = src->ysize;
664 i_img_empty_ch(im, x1, y1, src->channels);
7a0584ef 665 pv = mymalloc(sizeof(i_color) * x1);
02d1d628 666
7a0584ef
TC
667 for (y = 0; y < y1; ++y) {
668 i_glin(src, 0, x1, y, pv);
669 i_plin(im, 0, x1, y, pv);
02d1d628
AMH
670 }
671}
672
673
674/*
675=item i_rubthru(im, src, tx, ty)
676
677Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
678
679The alpha channel of each pixel in I<src> is used to control how much
680the existing colour in I<im> is replaced, if it is 255 then the colour
681is completely replaced, if it is 0 then the original colour is left
682unmodified.
683
684=cut
685*/
142c26ff 686
02d1d628
AMH
687void
688i_rubthru(i_img *im,i_img *src,int tx,int ty) {
4cac9410
AMH
689 i_color pv, orig, dest;
690 int x, y, ttx, tty;
02d1d628 691
4cac9410 692 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
02d1d628 693
4cac9410 694 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
02d1d628
AMH
695 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
696
4cac9410
AMH
697 ttx = tx;
698 for(x=0; x<src->xsize; x++) {
699 tty=ty;
700 for(y=0;y<src->ysize;y++) {
701 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
702 i_gpix(src, x, y, &pv);
703 i_gpix(im, ttx, tty, &orig);
704 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
705 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
706 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
707 i_ppix(im, ttx, tty, &dest);
708 tty++;
02d1d628 709 }
4cac9410
AMH
710 ttx++;
711 }
02d1d628
AMH
712}
713
142c26ff
AMH
714
715/*
716=item i_flipxy(im, axis)
717
718Flips the image inplace around the axis specified.
719Returns 0 if parameters are invalid.
720
721 im - Image pointer
722 axis - 0 = x, 1 = y, 2 = both
723
724=cut
725*/
726
727undef_int
728i_flipxy(i_img *im, int direction) {
729 int x, x2, y, y2, xm, ym;
730 int xs = im->xsize;
731 int ys = im->ysize;
732
733 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
734
735 if (!im) return 0;
736
737 switch (direction) {
738 case XAXIS: /* Horizontal flip */
739 xm = xs/2;
740 ym = ys;
741 for(y=0; y<ym; y++) {
742 x2 = xs-1;
743 for(x=0; x<xm; x++) {
744 i_color val1, val2;
745 i_gpix(im, x, y, &val1);
746 i_gpix(im, x2, y, &val2);
747 i_ppix(im, x, y, &val2);
748 i_ppix(im, x2, y, &val1);
749 x2--;
750 }
751 }
752 break;
390cd725 753 case YAXIS: /* Vertical flip */
142c26ff
AMH
754 xm = xs;
755 ym = ys/2;
756 y2 = ys-1;
757 for(y=0; y<ym; y++) {
758 for(x=0; x<xm; x++) {
759 i_color val1, val2;
760 i_gpix(im, x, y, &val1);
761 i_gpix(im, x, y2, &val2);
762 i_ppix(im, x, y, &val2);
763 i_ppix(im, x, y2, &val1);
764 }
765 y2--;
766 }
767 break;
390cd725 768 case XYAXIS: /* Horizontal and Vertical flip */
142c26ff
AMH
769 xm = xs/2;
770 ym = ys/2;
771 y2 = ys-1;
772 for(y=0; y<ym; y++) {
773 x2 = xs-1;
774 for(x=0; x<xm; x++) {
775 i_color val1, val2;
776 i_gpix(im, x, y, &val1);
777 i_gpix(im, x2, y2, &val2);
778 i_ppix(im, x, y, &val2);
779 i_ppix(im, x2, y2, &val1);
780
781 i_gpix(im, x2, y, &val1);
782 i_gpix(im, x, y2, &val2);
783 i_ppix(im, x2, y, &val2);
784 i_ppix(im, x, y2, &val1);
785 x2--;
786 }
787 y2--;
788 }
390cd725
AMH
789 if (xm*2 != xs) { /* odd number of column */
790 mm_log((1, "i_flipxy: odd number of columns\n"));
791 x = xm;
792 y2 = ys-1;
793 for(y=0; y<ym; y++) {
794 i_color val1, val2;
795 i_gpix(im, x, y, &val1);
796 i_gpix(im, x, y2, &val2);
797 i_ppix(im, x, y, &val2);
798 i_ppix(im, x, y2, &val1);
799 y2--;
800 }
801 }
802 if (ym*2 != ys) { /* odd number of rows */
803 mm_log((1, "i_flipxy: odd number of rows\n"));
804 y = ym;
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, y, &val2);
810 i_ppix(im, x, y, &val2);
811 i_ppix(im, x2, y, &val1);
812 x2--;
813 }
814 }
142c26ff
AMH
815 break;
816 default:
817 mm_log((1, "i_flipxy: direction is invalid\n" ));
818 return 0;
819 }
820 return 1;
821}
822
823
824
825
826
827static
02d1d628
AMH
828float
829Lanczos(float x) {
830 float PIx, PIx2;
831
832 PIx = PI * x;
833 PIx2 = PIx / 2.0;
834
835 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
836 else if (x == 0.0) return (1.0);
837 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
838}
839
840/*
841=item i_scaleaxis(im, value, axis)
842
843Returns a new image object which is I<im> scaled by I<value> along
844wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
845
846=cut
847*/
848
849i_img*
850i_scaleaxis(i_img *im, float Value, int Axis) {
851 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
852 int LanczosWidthFactor;
853 float *l0, *l1, OldLocation;
854 int T, TempJump1, TempJump2;
855 float F, PictureValue[MAXCHANNELS];
856 short psave;
857 i_color val,val1,val2;
858 i_img *new_img;
859
860 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
861
862 if (Axis == XAXIS) {
863 hsize = (int) ((float) im->xsize * Value);
864 vsize = im->ysize;
865
866 jEnd = hsize;
867 iEnd = vsize;
868
869 TempJump1 = (hsize - 1) * 3;
870 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
871 } else {
872 hsize = im->xsize;
873 vsize = (int) ((float) im->ysize * Value);
874
875 jEnd = vsize;
876 iEnd = hsize;
877
878 TempJump1 = 0;
879 TempJump2 = 0;
880 }
881
882 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
883
884 if (Value >=1) LanczosWidthFactor = 1;
885 else LanczosWidthFactor = (int) (1.0/Value);
886
887 lMax = LanczosWidthFactor << 1;
888
889 l0 = (float *) mymalloc(lMax * sizeof(float));
890 l1 = (float *) mymalloc(lMax * sizeof(float));
891
892 for (j=0; j<jEnd; j++) {
893 OldLocation = ((float) j) / Value;
894 T = (int) (OldLocation);
895 F = OldLocation - (float) T;
896
897 for (l = 0; l < lMax; l++) {
898 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
899 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
900 }
901
902 if (Axis== XAXIS) {
903
904 for (i=0; i<iEnd; i++) {
905 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
906 for (l=0; l < lMax; l++) {
907 i_gpix(im,T+l+1, i, &val1);
908 i_gpix(im,T-lMax+l+1, i, &val2);
909 for (k=0; k<im->channels; k++) {
910 PictureValue[k] += l1[l] * val1.channel[k];
911 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
912 }
913 }
914 for(k=0;k<im->channels;k++) {
915 psave = (short)( PictureValue[k] / LanczosWidthFactor);
916 val.channel[k]=minmax(0,255,psave);
917 }
918 i_ppix(new_img,j,i,&val);
919 }
920
921 } else {
922
923 for (i=0; i<iEnd; i++) {
924 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
925 for (l=0; l < lMax; l++) {
926 i_gpix(im,i, T+l+1, &val1);
927 i_gpix(im,i, T-lMax+l+1, &val2);
928 for (k=0; k<im->channels; k++) {
929 PictureValue[k] += l1[l] * val1.channel[k];
930 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
931 }
932 }
933 for (k=0; k<im->channels; k++) {
934 psave = (short)( PictureValue[k] / LanczosWidthFactor);
935 val.channel[k]=minmax(0,255,psave);
936 }
937 i_ppix(new_img,i,j,&val);
938 }
939
940 }
941 }
942 myfree(l0);
943 myfree(l1);
944
945 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
946
947 return new_img;
948}
949
950
951/*
952=item i_scale_nn(im, scx, scy)
953
954Scale by using nearest neighbor
955Both axes scaled at the same time since
956nothing is gained by doing it in two steps
957
958=cut
959*/
960
961
962i_img*
963i_scale_nn(i_img *im, float scx, float scy) {
964
965 int nxsize,nysize,nx,ny;
966 i_img *new_img;
967 i_color val;
968
969 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
970
971 nxsize = (int) ((float) im->xsize * scx);
972 nysize = (int) ((float) im->ysize * scy);
973
974 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
975
976 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
977 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
978 i_ppix(new_img,nx,ny,&val);
979 }
980
981 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
982
983 return new_img;
984}
985
986
987/*
988=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
989
990Spatially transforms I<im> returning a new image.
991
992opx for a length of opxl and opy for a length of opy are arrays of
993operators that modify the x and y positions to retreive the pixel data from.
994
995parm and parmlen define extra parameters that the operators may use.
996
997Note that this function is largely superseded by the more flexible
998L<transform.c/i_transform2>.
999
1000Returns the new image.
1001
1002The operators for this function are defined in L<stackmach.c>.
1003
1004=cut
1005*/
1006i_img*
1007i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1008 double rx,ry;
1009 int nxsize,nysize,nx,ny;
1010 i_img *new_img;
1011 i_color val;
1012
1013 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));
1014
1015 nxsize = im->xsize;
1016 nysize = im->ysize ;
1017
1018 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1019 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1020 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1021 /* parm[parmlen-2]=(double)nx;
1022 parm[parmlen-1]=(double)ny; */
1023
1024 parm[0]=(double)nx;
1025 parm[1]=(double)ny;
1026
1027 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1028 rx=op_run(opx,opxl,parm,parmlen);
1029 ry=op_run(opy,opyl,parm,parmlen);
1030 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1031 i_gpix(im,rx,ry,&val);
1032 i_ppix(new_img,nx,ny,&val);
1033 }
1034
1035 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1036 return new_img;
1037}
1038
1039/*
1040=item i_img_diff(im1, im2)
1041
1042Calculates the sum of the squares of the differences between
1043correspoding channels in two images.
1044
1045If the images are not the same size then only the common area is
1046compared, hence even if images are different sizes this function
1047can return zero.
1048
1049=cut
1050*/
1051float
1052i_img_diff(i_img *im1,i_img *im2) {
1053 int x,y,ch,xb,yb,chb;
1054 float tdiff;
1055 i_color val1,val2;
1056
1057 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1058
1059 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1060 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1061 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1062
1063 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1064
1065 tdiff=0;
1066 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1067 i_gpix(im1,x,y,&val1);
1068 i_gpix(im2,x,y,&val2);
1069
1070 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1071 }
1072 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1073 return tdiff;
1074}
1075
1076/* just a tiny demo of haar wavelets */
1077
1078i_img*
1079i_haar(i_img *im) {
1080 int mx,my;
1081 int fx,fy;
1082 int x,y;
1083 int ch,c;
1084 i_img *new_img,*new_img2;
1085 i_color val1,val2,dval1,dval2;
1086
1087 mx=im->xsize;
1088 my=im->ysize;
1089 fx=(mx+1)/2;
1090 fy=(my+1)/2;
1091
1092
1093 /* horizontal pass */
1094
1095 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1096 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1097
1098 c=0;
1099 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1100 i_gpix(im,x*2,y,&val1);
1101 i_gpix(im,x*2+1,y,&val2);
1102 for(ch=0;ch<im->channels;ch++) {
1103 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1104 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1105 }
1106 i_ppix(new_img,x,y,&dval1);
1107 i_ppix(new_img,x+fx,y,&dval2);
1108 }
1109
1110 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1111 i_gpix(new_img,x,y*2,&val1);
1112 i_gpix(new_img,x,y*2+1,&val2);
1113 for(ch=0;ch<im->channels;ch++) {
1114 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1115 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1116 }
1117 i_ppix(new_img2,x,y,&dval1);
1118 i_ppix(new_img2,x,y+fy,&dval2);
1119 }
1120
1121 i_img_destroy(new_img);
1122 return new_img2;
1123}
1124
1125/*
1126=item i_count_colors(im, maxc)
1127
1128returns number of colors or -1
1129to indicate that it was more than max colors
1130
1131=cut
1132*/
1133int
1134i_count_colors(i_img *im,int maxc) {
1135 struct octt *ct;
1136 int x,y;
1137 int xsize,ysize;
1138 i_color val;
1139 int colorcnt;
1140
1141 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1142
1143 xsize=im->xsize;
1144 ysize=im->ysize;
1145 ct=octt_new();
1146
1147 colorcnt=0;
1148 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1149 i_gpix(im,x,y,&val);
1150 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1151 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1152 }
1153 octt_delete(ct);
1154 return colorcnt;
1155}
1156
1157
1158symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1159 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1160 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1161 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1162
1163
1164/*
1165=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1166
1167Performs general read buffering for file readers that permit reading
1168to be done through a callback.
1169
1170The final callback gets two parameters, a I<need> value, and a I<want>
1171value, where I<need> is the amount of data that the file library needs
1172to read, and I<want> is the amount of space available in the buffer
1173maintained by these functions.
1174
1175This means if you need to read from a stream that you don't know the
1176length of, you can return I<need> bytes, taking the performance hit of
1177possibly expensive callbacks (eg. back to perl code), or if you are
1178reading from a stream where it doesn't matter if some data is lost, or
1179if the total length of the stream is known, you can return I<want>
1180bytes.
1181
1182=cut
1183*/
1184
1185int
1186i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1187 int total;
1188
1189 if (length < gci->length - gci->cpos) {
1190 /* simplest case */
1191 memcpy(buf, gci->buffer+gci->cpos, length);
1192 gci->cpos += length;
1193 return length;
1194 }
1195
1196 total = 0;
1197 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1198 total += gci->length - gci->cpos;
1199 length -= gci->length - gci->cpos;
1200 buf += gci->length - gci->cpos;
1201 if (length < (int)sizeof(gci->buffer)) {
1202 int did_read;
1203 int copy_size;
1204 while (length
1205 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1206 sizeof(gci->buffer))) > 0) {
1207 gci->cpos = 0;
1208 gci->length = did_read;
1209
1210 copy_size = min(length, gci->length);
1211 memcpy(buf, gci->buffer, copy_size);
1212 gci->cpos += copy_size;
1213 buf += copy_size;
1214 total += copy_size;
1215 length -= copy_size;
1216 }
1217 }
1218 else {
1219 /* just read the rest - too big for our buffer*/
1220 int did_read;
1221 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1222 length -= did_read;
1223 total += did_read;
1224 buf += did_read;
1225 }
1226 }
1227 return total;
1228}
1229
1230/*
1231=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1232
1233For use by callback file readers to initialize the reader buffer.
1234
1235Allocates, initializes and returns the reader buffer.
1236
1237See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1238
1239=cut
1240*/
1241i_gen_read_data *
1242i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1243 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1244 self->cb = cb;
1245 self->userdata = userdata;
1246 self->length = 0;
1247 self->cpos = 0;
1248
1249 return self;
1250}
1251
1252/*
1253=item free_gen_read_data(i_gen_read_data *)
1254
1255Cleans up.
1256
1257=cut
1258*/
1259void free_gen_read_data(i_gen_read_data *self) {
1260 myfree(self);
1261}
1262
1263/*
1264=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1265
1266Performs write buffering for a callback based file writer.
1267
1268Failures are considered fatal, if a write fails then data will be
1269dropped.
1270
1271=cut
1272*/
1273int
1274i_gen_writer(
1275i_gen_write_data *self,
1276char const *data,
1277int size)
1278{
1279 if (self->filledto && self->filledto+size > self->maxlength) {
1280 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1281 self->filledto = 0;
1282 }
1283 else {
1284 self->filledto = 0;
1285 return 0;
1286 }
1287 }
1288 if (self->filledto+size <= self->maxlength) {
1289 /* just save it */
1290 memcpy(self->buffer+self->filledto, data, size);
1291 self->filledto += size;
1292 return 1;
1293 }
1294 /* doesn't fit - hand it off */
1295 return self->cb(self->userdata, data, size);
1296}
1297
1298/*
1299=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1300
1301Allocates and initializes the data structure used by i_gen_writer.
1302
1303This should be released with L<image.c/free_gen_write_data>
1304
1305=cut
1306*/
1307i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1308 char *userdata, int max_length)
1309{
1310 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1311 self->cb = cb;
1312 self->userdata = userdata;
1313 self->maxlength = min(max_length, sizeof(self->buffer));
1314 if (self->maxlength < 0)
1315 self->maxlength = sizeof(self->buffer);
1316 self->filledto = 0;
1317
1318 return self;
1319}
1320
1321/*
1322=item free_gen_write_data(i_gen_write_data *info, int flush)
1323
1324Cleans up the write buffer.
1325
1326Will flush any left-over data if I<flush> is non-zero.
1327
1328Returns non-zero if flush is zero or if info->cb() returns non-zero.
1329
1330Return zero only if flush is non-zero and info->cb() returns zero.
1331ie. if it fails.
1332
1333=cut
1334*/
1335
1336int free_gen_write_data(i_gen_write_data *info, int flush)
1337{
1338 int result = !flush ||
1339 info->filledto == 0 ||
1340 info->cb(info->userdata, info->buffer, info->filledto);
1341 myfree(info);
1342
1343 return result;
1344}
1345
1346/*
1347=back
1348
1349=head1 SEE ALSO
1350
1351L<Imager>, L<gif.c>
1352
1353=cut
1354*/