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