1 /* scale.c - image scaling
3 * Raster graphics library
5 * Copyright (c) 1997, 1988, 1999 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41 *----------------------------------------------------------------------
43 * Creates a scaled copy of an image.
46 * The new scaled image.
48 *----------------------------------------------------------------------
51 RScaleImage(RImage
*image
, unsigned new_width
, unsigned new_height
)
57 unsigned char *sr
, *sg
, *sb
, *sa
;
58 unsigned char *dr
, *dg
, *db
, *da
;
61 assert(new_width
>= 0 && new_height
>= 0);
63 if (new_width
== image
->width
&& new_height
== image
->height
)
64 return RCloneImage(image
);
66 img
= RCreateImage(new_width
, new_height
, image
->data
[3]!=NULL
);
71 /* fixed point math idea taken from Imlib by
72 * Carsten Haitzler (Rasterman) */
73 dx
= (image
->width
<<16)/new_width
;
74 dy
= (image
->height
<<16)/new_height
;
83 if (image
->data
[3]!=NULL
) {
86 for (y
=0; y
<new_height
; y
++) {
87 t
= image
->width
*(py
>>16);
89 sr
= image
->data
[0]+t
;
90 sg
= image
->data
[1]+t
;
91 sb
= image
->data
[2]+t
;
92 sa
= image
->data
[3]+t
;
97 for (x
=0; x
<new_width
; x
++) {
118 for (y
=0; y
<new_height
; y
++) {
119 t
= image
->width
*(py
>>16);
121 sr
= image
->data
[0]+t
;
122 sg
= image
->data
[1]+t
;
123 sb
= image
->data
[2]+t
;
128 for (x
=0; x
<new_width
; x
++) {
153 * Filtered Image Rescaling code copy/pasted from
155 * Public Domain 1991 by Dale Schumacher
160 * filter function definitions
163 #define filter_support (1.0)
169 /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
171 if(t
< 1.0) return((2.0 * t
- 3.0) * t
* t
+ 1.0);
175 #define box_support (0.5)
181 if((t
> -0.5) && (t
<= 0.5)) return(1.0);
185 #define triangle_support (1.0)
192 if(t
< 1.0) return(1.0 - t
);
196 #define bell_support (1.5)
199 bell_filter(t
) /* box (*) box (*) box */
203 if(t
< .5) return(.75 - (t
* t
));
206 return(.5 * (t
* t
));
211 #define B_spline_support (2.0)
214 B_spline_filter(t
) /* box (*) box (*) box (*) box */
222 return((.5 * tt
* t
) - tt
+ (2.0 / 3.0));
225 return((1.0 / 6.0) * (t
* t
* t
));
235 if(x
!= 0) return(sin(x
) / x
);
239 #define Lanczos3_support (3.0)
246 if(t
< 3.0) return(sinc(t
) * sinc(t
/3.0));
250 #define Mitchell_support (2.0)
252 #define B (1.0 / 3.0)
253 #define C (1.0 / 3.0)
264 t
= (((12.0 - 9.0 * B
- 6.0 * C
) * (t
* tt
))
265 + ((-18.0 + 12.0 * B
+ 6.0 * C
) * tt
)
269 t
= (((-1.0 * B
- 6.0 * C
) * (t
* tt
))
270 + ((6.0 * B
+ 30.0 * C
) * tt
)
271 + ((-12.0 * B
- 48.0 * C
) * t
)
272 + (8.0 * B
+ 24 * C
));
278 static double (*filterf
)() = Mitchell_filter
;
279 static double fwidth
= Mitchell_support
;
282 _wraster_change_filter(int type
)
286 filterf
= box_filter
;
287 fwidth
= box_support
;
289 case RTriangleFilter
:
290 filterf
= triangle_filter
;
291 fwidth
= triangle_support
;
294 filterf
= bell_filter
;
295 fwidth
= bell_support
;
298 filterf
= B_spline_filter
;
299 fwidth
= B_spline_support
;
301 case RLanczos3Filter
:
302 filterf
= Lanczos3_filter
;
303 fwidth
= Lanczos3_support
;
306 case RMitchellFilter
:
307 filterf
= Mitchell_support
;
308 fwidth
= Mitchell_filter
;
315 * image rescaling routine
324 int n
; /* number of contributors */
325 CONTRIB
*p
; /* pointer to list of contributions */
328 CLIST
*contrib
; /* array of contribution lists */
330 /* clamp the input to the specified range */
331 #define CLAMP(v,l,h) ((v)<(l) ? (l) : (v) > (h) ? (h) : v)
335 RSmoothScaleImage(RImage
*src
, int newWidth
, int newHeight
)
337 RImage
*tmp
; /* intermediate image */
338 double xscale
, yscale
; /* zoom scale factors */
339 int i
, j
, k
; /* loop variables */
340 int n
; /* pixel number */
341 double center
, left
, right
; /* filter calculation variables */
342 double width
, fscale
; /* filter calculation variables */
343 double rweight
, gweight
, bweight
;
345 unsigned char *rp
, *gp
, *bp
;
346 unsigned char *rsp
, *gsp
, *bsp
;
348 dst
= RCreateImage(newWidth
, newHeight
, False
);
350 /* create intermediate image to hold horizontal zoom */
351 tmp
= RCreateImage(dst
->width
, src
->height
, False
);
352 xscale
= (double)newWidth
/ (double)src
->width
;
353 yscale
= (double)newHeight
/ (double)src
->height
;
355 /* pre-calculate filter contributions for a row */
356 contrib
= (CLIST
*)calloc(newWidth
, sizeof(CLIST
));
358 width
= fwidth
/ xscale
;
359 fscale
= 1.0 / xscale
;
360 for (i
= 0; i
< newWidth
; ++i
) {
362 contrib
[i
].p
= (CONTRIB
*)calloc((int)(width
* 2 + 1),
364 center
= (double) i
/ xscale
;
365 left
= ceil(center
- width
);
366 right
= floor(center
+ width
);
367 for(j
= left
; j
<= right
; ++j
) {
368 rweight
= center
- (double) j
;
369 rweight
= (*filterf
)(rweight
/ fscale
) / fscale
;
372 } else if(j
>= src
->width
) {
373 n
= (src
->width
- j
) + src
->width
- 1;
378 contrib
[i
].p
[k
].pixel
= n
;
379 contrib
[i
].p
[k
].weight
= rweight
;
383 for(i
= 0; i
< newWidth
; ++i
) {
385 contrib
[i
].p
= (CONTRIB
*)calloc((int) (fwidth
* 2 + 1),
387 center
= (double) i
/ xscale
;
388 left
= ceil(center
- fwidth
);
389 right
= floor(center
+ fwidth
);
390 for(j
= left
; j
<= right
; ++j
) {
391 rweight
= center
- (double) j
;
392 rweight
= (*filterf
)(rweight
);
395 } else if(j
>= src
->width
) {
396 n
= (src
->width
- j
) + src
->width
- 1;
401 contrib
[i
].p
[k
].pixel
= n
;
402 contrib
[i
].p
[k
].weight
= rweight
;
407 /* apply filter to zoom horizontally from src to tmp */
412 for(k
= 0; k
< tmp
->height
; ++k
) {
413 rsp
= src
->data
[0] + src
->width
*k
;
414 gsp
= src
->data
[1] + src
->width
*k
;
415 bsp
= src
->data
[2] + src
->width
*k
;
417 for(i
= 0; i
< tmp
->width
; ++i
) {
418 rweight
= gweight
= bweight
= 0.0;
419 for(j
= 0; j
< contrib
[i
].n
; ++j
) {
420 rweight
+= rsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
421 gweight
+= gsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
422 bweight
+= bsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
424 *rp
++ = CLAMP(rweight
, 0, 255);
425 *gp
++ = CLAMP(gweight
, 0, 255);
426 *bp
++ = CLAMP(bweight
, 0, 255);
430 /* free the memory allocated for horizontal filter weights */
431 for(i
= 0; i
< tmp
->width
; ++i
) {
436 /* pre-calculate filter contributions for a column */
437 contrib
= (CLIST
*)calloc(dst
->height
, sizeof(CLIST
));
439 width
= fwidth
/ yscale
;
440 fscale
= 1.0 / yscale
;
441 for(i
= 0; i
< dst
->height
; ++i
) {
443 contrib
[i
].p
= (CONTRIB
*)calloc((int) (width
* 2 + 1),
445 center
= (double) i
/ yscale
;
446 left
= ceil(center
- width
);
447 right
= floor(center
+ width
);
448 for(j
= left
; j
<= right
; ++j
) {
449 rweight
= center
- (double) j
;
450 rweight
= (*filterf
)(rweight
/ fscale
) / fscale
;
453 } else if(j
>= tmp
->height
) {
454 n
= (tmp
->height
- j
) + tmp
->height
- 1;
459 contrib
[i
].p
[k
].pixel
= n
;
460 contrib
[i
].p
[k
].weight
= rweight
;
464 for(i
= 0; i
< dst
->height
; ++i
) {
466 contrib
[i
].p
= (CONTRIB
*)calloc((int) (fwidth
* 2 + 1),
468 center
= (double) i
/ yscale
;
469 left
= ceil(center
- fwidth
);
470 right
= floor(center
+ fwidth
);
471 for(j
= left
; j
<= right
; ++j
) {
472 rweight
= center
- (double) j
;
473 rweight
= (*filterf
)(rweight
);
476 } else if(j
>= tmp
->height
) {
477 n
= (tmp
->height
- j
) + tmp
->height
- 1;
482 contrib
[i
].p
[k
].pixel
= n
;
483 contrib
[i
].p
[k
].weight
= rweight
;
488 /* apply filter to zoom vertically from tmp to dst */
489 rsp
= malloc(tmp
->height
);
490 gsp
= malloc(tmp
->height
);
491 bsp
= malloc(tmp
->height
);
493 for(k
= 0; k
< newWidth
; ++k
) {
494 rp
= dst
->data
[0] + k
;
495 gp
= dst
->data
[1] + k
;
496 bp
= dst
->data
[2] + k
;
498 /* copy a column into a row */
501 unsigned char *p
, *d
;
504 for(i
= tmp
->height
, p
= tmp
->data
[0] + k
; i
-- > 0;
509 for(i
= tmp
->height
, p
= tmp
->data
[1] + k
; i
-- > 0;
514 for(i
= tmp
->height
, p
= tmp
->data
[2] + k
; i
-- > 0;
519 for(i
= 0; i
< newHeight
; ++i
) {
520 rweight
= gweight
= bweight
= 0.0;
521 for(j
= 0; j
< contrib
[i
].n
; ++j
) {
522 rweight
+= rsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
523 gweight
+= gsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
524 bweight
+= bsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
526 *rp
= CLAMP(rweight
, 0, 255);
527 *gp
= CLAMP(gweight
, 0, 255);
528 *bp
= CLAMP(bweight
, 0, 255);
538 /* free the memory allocated for vertical filter weights */
539 for(i
= 0; i
< dst
->height
; ++i
) {