oops, forgot to free the memory I allocated
[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 670 }
1f235e0d 671 myfree(pv);
02d1d628
AMH
672}
673
674
675/*
676=item i_rubthru(im, src, tx, ty)
677
678Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
679
680The alpha channel of each pixel in I<src> is used to control how much
681the existing colour in I<im> is replaced, if it is 255 then the colour
682is completely replaced, if it is 0 then the original colour is left
683unmodified.
684
685=cut
686*/
142c26ff 687
02d1d628
AMH
688void
689i_rubthru(i_img *im,i_img *src,int tx,int ty) {
4cac9410
AMH
690 i_color pv, orig, dest;
691 int x, y, ttx, tty;
02d1d628 692
4cac9410 693 mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
02d1d628 694
4cac9410 695 if (im->channels != 3) { fprintf(stderr,"Destination is not in rgb mode.\n"); exit(3); }
02d1d628
AMH
696 if (src->channels != 4) { fprintf(stderr,"Source is not in rgba mode.\n"); exit(3); }
697
4cac9410
AMH
698 ttx = tx;
699 for(x=0; x<src->xsize; x++) {
700 tty=ty;
701 for(y=0;y<src->ysize;y++) {
702 /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
703 i_gpix(src, x, y, &pv);
704 i_gpix(im, ttx, tty, &orig);
705 dest.rgb.r = (pv.rgba.a*pv.rgba.r+(255-pv.rgba.a)*orig.rgb.r)/255;
706 dest.rgb.g = (pv.rgba.a*pv.rgba.g+(255-pv.rgba.a)*orig.rgb.g)/255;
707 dest.rgb.b = (pv.rgba.a*pv.rgba.b+(255-pv.rgba.a)*orig.rgb.b)/255;
708 i_ppix(im, ttx, tty, &dest);
709 tty++;
02d1d628 710 }
4cac9410
AMH
711 ttx++;
712 }
02d1d628
AMH
713}
714
142c26ff
AMH
715
716/*
717=item i_flipxy(im, axis)
718
719Flips the image inplace around the axis specified.
720Returns 0 if parameters are invalid.
721
722 im - Image pointer
723 axis - 0 = x, 1 = y, 2 = both
724
725=cut
726*/
727
728undef_int
729i_flipxy(i_img *im, int direction) {
730 int x, x2, y, y2, xm, ym;
731 int xs = im->xsize;
732 int ys = im->ysize;
733
734 mm_log((1, "i_flipxy(im %p, direction %d)\n", im, direction ));
735
736 if (!im) return 0;
737
738 switch (direction) {
739 case XAXIS: /* Horizontal flip */
740 xm = xs/2;
741 ym = ys;
742 for(y=0; y<ym; y++) {
743 x2 = xs-1;
744 for(x=0; x<xm; x++) {
745 i_color val1, val2;
746 i_gpix(im, x, y, &val1);
747 i_gpix(im, x2, y, &val2);
748 i_ppix(im, x, y, &val2);
749 i_ppix(im, x2, y, &val1);
750 x2--;
751 }
752 }
753 break;
390cd725 754 case YAXIS: /* Vertical flip */
142c26ff
AMH
755 xm = xs;
756 ym = ys/2;
757 y2 = ys-1;
758 for(y=0; y<ym; y++) {
759 for(x=0; x<xm; x++) {
760 i_color val1, val2;
761 i_gpix(im, x, y, &val1);
762 i_gpix(im, x, y2, &val2);
763 i_ppix(im, x, y, &val2);
764 i_ppix(im, x, y2, &val1);
765 }
766 y2--;
767 }
768 break;
390cd725 769 case XYAXIS: /* Horizontal and Vertical flip */
142c26ff
AMH
770 xm = xs/2;
771 ym = ys/2;
772 y2 = ys-1;
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, y2, &val2);
779 i_ppix(im, x, y, &val2);
780 i_ppix(im, x2, y2, &val1);
781
782 i_gpix(im, x2, y, &val1);
783 i_gpix(im, x, y2, &val2);
784 i_ppix(im, x2, y, &val2);
785 i_ppix(im, x, y2, &val1);
786 x2--;
787 }
788 y2--;
789 }
390cd725
AMH
790 if (xm*2 != xs) { /* odd number of column */
791 mm_log((1, "i_flipxy: odd number of columns\n"));
792 x = xm;
793 y2 = ys-1;
794 for(y=0; y<ym; y++) {
795 i_color val1, val2;
796 i_gpix(im, x, y, &val1);
797 i_gpix(im, x, y2, &val2);
798 i_ppix(im, x, y, &val2);
799 i_ppix(im, x, y2, &val1);
800 y2--;
801 }
802 }
803 if (ym*2 != ys) { /* odd number of rows */
804 mm_log((1, "i_flipxy: odd number of rows\n"));
805 y = ym;
806 x2 = xs-1;
807 for(x=0; x<xm; x++) {
808 i_color val1, val2;
809 i_gpix(im, x, y, &val1);
810 i_gpix(im, x2, y, &val2);
811 i_ppix(im, x, y, &val2);
812 i_ppix(im, x2, y, &val1);
813 x2--;
814 }
815 }
142c26ff
AMH
816 break;
817 default:
818 mm_log((1, "i_flipxy: direction is invalid\n" ));
819 return 0;
820 }
821 return 1;
822}
823
824
825
826
827
828static
02d1d628
AMH
829float
830Lanczos(float x) {
831 float PIx, PIx2;
832
833 PIx = PI * x;
834 PIx2 = PIx / 2.0;
835
836 if ((x >= 2.0) || (x <= -2.0)) return (0.0);
837 else if (x == 0.0) return (1.0);
838 else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
839}
840
841/*
842=item i_scaleaxis(im, value, axis)
843
844Returns a new image object which is I<im> scaled by I<value> along
845wither the x-axis (I<axis> == 0) or the y-axis (I<axis> == 1).
846
847=cut
848*/
849
850i_img*
851i_scaleaxis(i_img *im, float Value, int Axis) {
852 int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
853 int LanczosWidthFactor;
854 float *l0, *l1, OldLocation;
855 int T, TempJump1, TempJump2;
856 float F, PictureValue[MAXCHANNELS];
857 short psave;
858 i_color val,val1,val2;
859 i_img *new_img;
860
861 mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
862
863 if (Axis == XAXIS) {
864 hsize = (int) ((float) im->xsize * Value);
865 vsize = im->ysize;
866
867 jEnd = hsize;
868 iEnd = vsize;
869
870 TempJump1 = (hsize - 1) * 3;
871 TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
872 } else {
873 hsize = im->xsize;
874 vsize = (int) ((float) im->ysize * Value);
875
876 jEnd = vsize;
877 iEnd = hsize;
878
879 TempJump1 = 0;
880 TempJump2 = 0;
881 }
882
883 new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
884
885 if (Value >=1) LanczosWidthFactor = 1;
886 else LanczosWidthFactor = (int) (1.0/Value);
887
888 lMax = LanczosWidthFactor << 1;
889
890 l0 = (float *) mymalloc(lMax * sizeof(float));
891 l1 = (float *) mymalloc(lMax * sizeof(float));
892
893 for (j=0; j<jEnd; j++) {
894 OldLocation = ((float) j) / Value;
895 T = (int) (OldLocation);
896 F = OldLocation - (float) T;
897
898 for (l = 0; l < lMax; l++) {
899 l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
900 l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
901 }
902
903 if (Axis== XAXIS) {
904
905 for (i=0; i<iEnd; i++) {
906 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
907 for (l=0; l < lMax; l++) {
908 i_gpix(im,T+l+1, i, &val1);
909 i_gpix(im,T-lMax+l+1, i, &val2);
910 for (k=0; k<im->channels; k++) {
911 PictureValue[k] += l1[l] * val1.channel[k];
912 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
913 }
914 }
915 for(k=0;k<im->channels;k++) {
916 psave = (short)( PictureValue[k] / LanczosWidthFactor);
917 val.channel[k]=minmax(0,255,psave);
918 }
919 i_ppix(new_img,j,i,&val);
920 }
921
922 } else {
923
924 for (i=0; i<iEnd; i++) {
925 for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
926 for (l=0; l < lMax; l++) {
927 i_gpix(im,i, T+l+1, &val1);
928 i_gpix(im,i, T-lMax+l+1, &val2);
929 for (k=0; k<im->channels; k++) {
930 PictureValue[k] += l1[l] * val1.channel[k];
931 PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
932 }
933 }
934 for (k=0; k<im->channels; k++) {
935 psave = (short)( PictureValue[k] / LanczosWidthFactor);
936 val.channel[k]=minmax(0,255,psave);
937 }
938 i_ppix(new_img,i,j,&val);
939 }
940
941 }
942 }
943 myfree(l0);
944 myfree(l1);
945
946 mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
947
948 return new_img;
949}
950
951
952/*
953=item i_scale_nn(im, scx, scy)
954
955Scale by using nearest neighbor
956Both axes scaled at the same time since
957nothing is gained by doing it in two steps
958
959=cut
960*/
961
962
963i_img*
964i_scale_nn(i_img *im, float scx, float scy) {
965
966 int nxsize,nysize,nx,ny;
967 i_img *new_img;
968 i_color val;
969
970 mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
971
972 nxsize = (int) ((float) im->xsize * scx);
973 nysize = (int) ((float) im->ysize * scy);
974
975 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
976
977 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
978 i_gpix(im,((float)nx)/scx,((float)ny)/scy,&val);
979 i_ppix(new_img,nx,ny,&val);
980 }
981
982 mm_log((1,"(0x%x) <- i_scale_nn\n",new_img));
983
984 return new_img;
985}
986
987
988/*
989=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
990
991Spatially transforms I<im> returning a new image.
992
993opx for a length of opxl and opy for a length of opy are arrays of
994operators that modify the x and y positions to retreive the pixel data from.
995
996parm and parmlen define extra parameters that the operators may use.
997
998Note that this function is largely superseded by the more flexible
999L<transform.c/i_transform2>.
1000
1001Returns the new image.
1002
1003The operators for this function are defined in L<stackmach.c>.
1004
1005=cut
1006*/
1007i_img*
1008i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int parmlen) {
1009 double rx,ry;
1010 int nxsize,nysize,nx,ny;
1011 i_img *new_img;
1012 i_color val;
1013
1014 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));
1015
1016 nxsize = im->xsize;
1017 nysize = im->ysize ;
1018
1019 new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
1020 /* fprintf(stderr,"parm[2]=%f\n",parm[2]); */
1021 for(ny=0;ny<nysize;ny++) for(nx=0;nx<nxsize;nx++) {
1022 /* parm[parmlen-2]=(double)nx;
1023 parm[parmlen-1]=(double)ny; */
1024
1025 parm[0]=(double)nx;
1026 parm[1]=(double)ny;
1027
1028 /* fprintf(stderr,"(%d,%d) ->",nx,ny); */
1029 rx=op_run(opx,opxl,parm,parmlen);
1030 ry=op_run(opy,opyl,parm,parmlen);
1031 /* fprintf(stderr,"(%f,%f)\n",rx,ry); */
1032 i_gpix(im,rx,ry,&val);
1033 i_ppix(new_img,nx,ny,&val);
1034 }
1035
1036 mm_log((1,"(0x%x) <- i_transform\n",new_img));
1037 return new_img;
1038}
1039
1040/*
1041=item i_img_diff(im1, im2)
1042
1043Calculates the sum of the squares of the differences between
1044correspoding channels in two images.
1045
1046If the images are not the same size then only the common area is
1047compared, hence even if images are different sizes this function
1048can return zero.
1049
1050=cut
1051*/
1052float
1053i_img_diff(i_img *im1,i_img *im2) {
1054 int x,y,ch,xb,yb,chb;
1055 float tdiff;
1056 i_color val1,val2;
1057
1058 mm_log((1,"i_img_diff(im1 0x%x,im2 0x%x)\n",im1,im2));
1059
1060 xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
1061 yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
1062 chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
1063
1064 mm_log((1,"i_img_diff: xb=%d xy=%d chb=%d\n",xb,yb,chb));
1065
1066 tdiff=0;
1067 for(y=0;y<yb;y++) for(x=0;x<xb;x++) {
1068 i_gpix(im1,x,y,&val1);
1069 i_gpix(im2,x,y,&val2);
1070
1071 for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
1072 }
1073 mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
1074 return tdiff;
1075}
1076
1077/* just a tiny demo of haar wavelets */
1078
1079i_img*
1080i_haar(i_img *im) {
1081 int mx,my;
1082 int fx,fy;
1083 int x,y;
1084 int ch,c;
1085 i_img *new_img,*new_img2;
1086 i_color val1,val2,dval1,dval2;
1087
1088 mx=im->xsize;
1089 my=im->ysize;
1090 fx=(mx+1)/2;
1091 fy=(my+1)/2;
1092
1093
1094 /* horizontal pass */
1095
1096 new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1097 new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
1098
1099 c=0;
1100 for(y=0;y<my;y++) for(x=0;x<fx;x++) {
1101 i_gpix(im,x*2,y,&val1);
1102 i_gpix(im,x*2+1,y,&val2);
1103 for(ch=0;ch<im->channels;ch++) {
1104 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1105 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1106 }
1107 i_ppix(new_img,x,y,&dval1);
1108 i_ppix(new_img,x+fx,y,&dval2);
1109 }
1110
1111 for(y=0;y<fy;y++) for(x=0;x<mx;x++) {
1112 i_gpix(new_img,x,y*2,&val1);
1113 i_gpix(new_img,x,y*2+1,&val2);
1114 for(ch=0;ch<im->channels;ch++) {
1115 dval1.channel[ch]=(val1.channel[ch]+val2.channel[ch])/2;
1116 dval2.channel[ch]=(255+val1.channel[ch]-val2.channel[ch])/2;
1117 }
1118 i_ppix(new_img2,x,y,&dval1);
1119 i_ppix(new_img2,x,y+fy,&dval2);
1120 }
1121
1122 i_img_destroy(new_img);
1123 return new_img2;
1124}
1125
1126/*
1127=item i_count_colors(im, maxc)
1128
1129returns number of colors or -1
1130to indicate that it was more than max colors
1131
1132=cut
1133*/
1134int
1135i_count_colors(i_img *im,int maxc) {
1136 struct octt *ct;
1137 int x,y;
1138 int xsize,ysize;
1139 i_color val;
1140 int colorcnt;
1141
1142 mm_log((1,"i_count_colors(im 0x%08X,maxc %d)\n"));
1143
1144 xsize=im->xsize;
1145 ysize=im->ysize;
1146 ct=octt_new();
1147
1148 colorcnt=0;
1149 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
1150 i_gpix(im,x,y,&val);
1151 colorcnt+=octt_add(ct,val.rgb.r,val.rgb.g,val.rgb.b);
1152 if (colorcnt > maxc) { octt_delete(ct); return -1; }
1153 }
1154 octt_delete(ct);
1155 return colorcnt;
1156}
1157
1158
1159symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
1160 i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
1161 i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
1162 i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
1163
1164
1165/*
1166=item i_gen_reader(i_gen_read_data *info, char *buf, int length)
1167
1168Performs general read buffering for file readers that permit reading
1169to be done through a callback.
1170
1171The final callback gets two parameters, a I<need> value, and a I<want>
1172value, where I<need> is the amount of data that the file library needs
1173to read, and I<want> is the amount of space available in the buffer
1174maintained by these functions.
1175
1176This means if you need to read from a stream that you don't know the
1177length of, you can return I<need> bytes, taking the performance hit of
1178possibly expensive callbacks (eg. back to perl code), or if you are
1179reading from a stream where it doesn't matter if some data is lost, or
1180if the total length of the stream is known, you can return I<want>
1181bytes.
1182
1183=cut
1184*/
1185
1186int
1187i_gen_reader(i_gen_read_data *gci, char *buf, int length) {
1188 int total;
1189
1190 if (length < gci->length - gci->cpos) {
1191 /* simplest case */
1192 memcpy(buf, gci->buffer+gci->cpos, length);
1193 gci->cpos += length;
1194 return length;
1195 }
1196
1197 total = 0;
1198 memcpy(buf, gci->buffer+gci->cpos, gci->length-gci->cpos);
1199 total += gci->length - gci->cpos;
1200 length -= gci->length - gci->cpos;
1201 buf += gci->length - gci->cpos;
1202 if (length < (int)sizeof(gci->buffer)) {
1203 int did_read;
1204 int copy_size;
1205 while (length
1206 && (did_read = (gci->cb)(gci->userdata, gci->buffer, length,
1207 sizeof(gci->buffer))) > 0) {
1208 gci->cpos = 0;
1209 gci->length = did_read;
1210
1211 copy_size = min(length, gci->length);
1212 memcpy(buf, gci->buffer, copy_size);
1213 gci->cpos += copy_size;
1214 buf += copy_size;
1215 total += copy_size;
1216 length -= copy_size;
1217 }
1218 }
1219 else {
1220 /* just read the rest - too big for our buffer*/
1221 int did_read;
1222 while ((did_read = (gci->cb)(gci->userdata, buf, length, length)) > 0) {
1223 length -= did_read;
1224 total += did_read;
1225 buf += did_read;
1226 }
1227 }
1228 return total;
1229}
1230
1231/*
1232=item i_gen_read_data_new(i_read_callback_t cb, char *userdata)
1233
1234For use by callback file readers to initialize the reader buffer.
1235
1236Allocates, initializes and returns the reader buffer.
1237
1238See also L<image.c/free_gen_read_data> and L<image.c/i_gen_reader>.
1239
1240=cut
1241*/
1242i_gen_read_data *
1243i_gen_read_data_new(i_read_callback_t cb, char *userdata) {
1244 i_gen_read_data *self = mymalloc(sizeof(i_gen_read_data));
1245 self->cb = cb;
1246 self->userdata = userdata;
1247 self->length = 0;
1248 self->cpos = 0;
1249
1250 return self;
1251}
1252
1253/*
1254=item free_gen_read_data(i_gen_read_data *)
1255
1256Cleans up.
1257
1258=cut
1259*/
1260void free_gen_read_data(i_gen_read_data *self) {
1261 myfree(self);
1262}
1263
1264/*
1265=item i_gen_writer(i_gen_write_data *info, char const *data, int size)
1266
1267Performs write buffering for a callback based file writer.
1268
1269Failures are considered fatal, if a write fails then data will be
1270dropped.
1271
1272=cut
1273*/
1274int
1275i_gen_writer(
1276i_gen_write_data *self,
1277char const *data,
1278int size)
1279{
1280 if (self->filledto && self->filledto+size > self->maxlength) {
1281 if (self->cb(self->userdata, self->buffer, self->filledto)) {
1282 self->filledto = 0;
1283 }
1284 else {
1285 self->filledto = 0;
1286 return 0;
1287 }
1288 }
1289 if (self->filledto+size <= self->maxlength) {
1290 /* just save it */
1291 memcpy(self->buffer+self->filledto, data, size);
1292 self->filledto += size;
1293 return 1;
1294 }
1295 /* doesn't fit - hand it off */
1296 return self->cb(self->userdata, data, size);
1297}
1298
1299/*
1300=item i_gen_write_data_new(i_write_callback_t cb, char *userdata, int max_length)
1301
1302Allocates and initializes the data structure used by i_gen_writer.
1303
1304This should be released with L<image.c/free_gen_write_data>
1305
1306=cut
1307*/
1308i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb,
1309 char *userdata, int max_length)
1310{
1311 i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
1312 self->cb = cb;
1313 self->userdata = userdata;
1314 self->maxlength = min(max_length, sizeof(self->buffer));
1315 if (self->maxlength < 0)
1316 self->maxlength = sizeof(self->buffer);
1317 self->filledto = 0;
1318
1319 return self;
1320}
1321
1322/*
1323=item free_gen_write_data(i_gen_write_data *info, int flush)
1324
1325Cleans up the write buffer.
1326
1327Will flush any left-over data if I<flush> is non-zero.
1328
1329Returns non-zero if flush is zero or if info->cb() returns non-zero.
1330
1331Return zero only if flush is non-zero and info->cb() returns zero.
1332ie. if it fails.
1333
1334=cut
1335*/
1336
1337int free_gen_write_data(i_gen_write_data *info, int flush)
1338{
1339 int result = !flush ||
1340 info->filledto == 0 ||
1341 info->cb(info->userdata, info->buffer, info->filledto);
1342 myfree(info);
1343
1344 return result;
1345}
1346
1347/*
1348=back
1349
1350=head1 SEE ALSO
1351
1352L<Imager>, L<gif.c>
1353
1354=cut
1355*/