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
*src
, unsigned new_width
, unsigned new_height
)
59 unsigned char *sr
, *sg
, *sb
, *sa
;
60 unsigned char *dr
, *dg
, *db
, *da
;
65 dst
= RCreateImage(new_width
, new_height
, src
->data
[3]!=NULL
);
68 ee
= (ddy
/2) - dst
->height
;
73 e
= (src
->width
/2)-xd
;
87 for (yd
= 0; yd
< new_height
; yd
++) {
90 sr
= src
->data
[0] + ys
* src
->width
;
91 sg
= src
->data
[1] + ys
* src
->width
;
92 sb
= src
->data
[2] + ys
* src
->width
;
94 for (x
= 0; x
< xd
; x
++) {
114 for (yd
= 0; yd
< new_height
; yd
++) {
117 sr
= src
->data
[0] + ys
* src
->width
;
118 sg
= src
->data
[1] + ys
* src
->width
;
119 sb
= src
->data
[2] + ys
* src
->width
;
120 sa
= src
->data
[3] + ys
* src
->width
;
122 for (x
= 0; x
< xd
; x
++) {
152 * Filtered Image Rescaling code copy/pasted from
154 * Public Domain 1991 by Dale Schumacher
159 * filter function definitions
162 #define filter_support (1.0)
168 /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
170 if(t
< 1.0) return((2.0 * t
- 3.0) * t
* t
+ 1.0);
174 #define box_support (0.5)
180 if((t
> -0.5) && (t
<= 0.5)) return(1.0);
184 #define triangle_support (1.0)
191 if(t
< 1.0) return(1.0 - t
);
195 #define bell_support (1.5)
198 bell_filter(t
) /* box (*) box (*) box */
202 if(t
< .5) return(.75 - (t
* t
));
205 return(.5 * (t
* t
));
210 #define B_spline_support (2.0)
213 B_spline_filter(t
) /* box (*) box (*) box (*) box */
221 return((.5 * tt
* t
) - tt
+ (2.0 / 3.0));
224 return((1.0 / 6.0) * (t
* t
* t
));
234 if(x
!= 0) return(sin(x
) / x
);
238 #define Lanczos3_support (3.0)
245 if(t
< 3.0) return(sinc(t
) * sinc(t
/3.0));
249 #define Mitchell_support (2.0)
251 #define B (1.0 / 3.0)
252 #define C (1.0 / 3.0)
263 t
= (((12.0 - 9.0 * B
- 6.0 * C
) * (t
* tt
))
264 + ((-18.0 + 12.0 * B
+ 6.0 * C
) * tt
)
268 t
= (((-1.0 * B
- 6.0 * C
) * (t
* tt
))
269 + ((6.0 * B
+ 30.0 * C
) * tt
)
270 + ((-12.0 * B
- 48.0 * C
) * t
)
271 + (8.0 * B
+ 24 * C
));
277 static double (*filterf
)() = Mitchell_filter
;
278 static double fwidth
= Mitchell_support
;
281 _wraster_change_filter(int type
)
285 filterf
= box_filter
;
286 fwidth
= box_support
;
288 case RTriangleFilter
:
289 filterf
= triangle_filter
;
290 fwidth
= triangle_support
;
293 filterf
= bell_filter
;
294 fwidth
= bell_support
;
297 filterf
= B_spline_filter
;
298 fwidth
= B_spline_support
;
300 case RLanczos3Filter
:
301 filterf
= Lanczos3_filter
;
302 fwidth
= Lanczos3_support
;
305 case RMitchellFilter
:
306 filterf
= Mitchell_filter
;
307 fwidth
= Mitchell_support
;
314 * image rescaling routine
323 int n
; /* number of contributors */
324 CONTRIB
*p
; /* pointer to list of contributions */
327 CLIST
*contrib
; /* array of contribution lists */
329 /* clamp the input to the specified range */
330 #define CLAMP(v,l,h) ((v)<(l) ? (l) : (v) > (h) ? (h) : v)
334 RSmoothScaleImage(RImage
*src
, unsigned new_width
, unsigned new_height
)
336 RImage
*tmp
; /* intermediate image */
337 double xscale
, yscale
; /* zoom scale factors */
338 int i
, j
, k
; /* loop variables */
339 int n
; /* pixel number */
340 double center
, left
, right
; /* filter calculation variables */
341 double width
, fscale
; /* filter calculation variables */
342 double rweight
, gweight
, bweight
;
344 unsigned char *rp
, *gp
, *bp
;
345 unsigned char *rsp
, *gsp
, *bsp
;
347 dst
= RCreateImage(new_width
, new_height
, False
);
349 /* create intermediate image to hold horizontal zoom */
350 tmp
= RCreateImage(dst
->width
, src
->height
, False
);
351 xscale
= (double)new_width
/ (double)src
->width
;
352 yscale
= (double)new_height
/ (double)src
->height
;
354 /* pre-calculate filter contributions for a row */
355 contrib
= (CLIST
*)calloc(new_width
, sizeof(CLIST
));
357 width
= fwidth
/ xscale
;
358 fscale
= 1.0 / xscale
;
359 for (i
= 0; i
< new_width
; ++i
) {
361 contrib
[i
].p
= (CONTRIB
*)calloc((int)(width
* 2 + 1),
363 center
= (double) i
/ xscale
;
364 left
= ceil(center
- width
);
365 right
= floor(center
+ width
);
366 for(j
= left
; j
<= right
; ++j
) {
367 rweight
= center
- (double) j
;
368 rweight
= (*filterf
)(rweight
/ fscale
) / fscale
;
371 } else if(j
>= src
->width
) {
372 n
= (src
->width
- j
) + src
->width
- 1;
377 contrib
[i
].p
[k
].pixel
= n
;
378 contrib
[i
].p
[k
].weight
= rweight
;
382 for(i
= 0; i
< new_width
; ++i
) {
384 contrib
[i
].p
= (CONTRIB
*)calloc((int) (fwidth
* 2 + 1),
386 center
= (double) i
/ xscale
;
387 left
= ceil(center
- fwidth
);
388 right
= floor(center
+ fwidth
);
389 for(j
= left
; j
<= right
; ++j
) {
390 rweight
= center
- (double) j
;
391 rweight
= (*filterf
)(rweight
);
394 } else if(j
>= src
->width
) {
395 n
= (src
->width
- j
) + src
->width
- 1;
400 contrib
[i
].p
[k
].pixel
= n
;
401 contrib
[i
].p
[k
].weight
= rweight
;
406 /* apply filter to zoom horizontally from src to tmp */
411 for(k
= 0; k
< tmp
->height
; ++k
) {
412 rsp
= src
->data
[0] + src
->width
*k
;
413 gsp
= src
->data
[1] + src
->width
*k
;
414 bsp
= src
->data
[2] + src
->width
*k
;
416 for(i
= 0; i
< tmp
->width
; ++i
) {
417 rweight
= gweight
= bweight
= 0.0;
418 for(j
= 0; j
< contrib
[i
].n
; ++j
) {
419 rweight
+= rsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
420 gweight
+= gsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
421 bweight
+= bsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
423 *rp
++ = CLAMP(rweight
, 0, 255);
424 *gp
++ = CLAMP(gweight
, 0, 255);
425 *bp
++ = CLAMP(bweight
, 0, 255);
429 /* free the memory allocated for horizontal filter weights */
430 for(i
= 0; i
< tmp
->width
; ++i
) {
435 /* pre-calculate filter contributions for a column */
436 contrib
= (CLIST
*)calloc(dst
->height
, sizeof(CLIST
));
438 width
= fwidth
/ yscale
;
439 fscale
= 1.0 / yscale
;
440 for(i
= 0; i
< dst
->height
; ++i
) {
442 contrib
[i
].p
= (CONTRIB
*)calloc((int) (width
* 2 + 1),
444 center
= (double) i
/ yscale
;
445 left
= ceil(center
- width
);
446 right
= floor(center
+ width
);
447 for(j
= left
; j
<= right
; ++j
) {
448 rweight
= center
- (double) j
;
449 rweight
= (*filterf
)(rweight
/ fscale
) / fscale
;
452 } else if(j
>= tmp
->height
) {
453 n
= (tmp
->height
- j
) + tmp
->height
- 1;
458 contrib
[i
].p
[k
].pixel
= n
;
459 contrib
[i
].p
[k
].weight
= rweight
;
463 for(i
= 0; i
< dst
->height
; ++i
) {
465 contrib
[i
].p
= (CONTRIB
*)calloc((int) (fwidth
* 2 + 1),
467 center
= (double) i
/ yscale
;
468 left
= ceil(center
- fwidth
);
469 right
= floor(center
+ fwidth
);
470 for(j
= left
; j
<= right
; ++j
) {
471 rweight
= center
- (double) j
;
472 rweight
= (*filterf
)(rweight
);
475 } else if(j
>= tmp
->height
) {
476 n
= (tmp
->height
- j
) + tmp
->height
- 1;
481 contrib
[i
].p
[k
].pixel
= n
;
482 contrib
[i
].p
[k
].weight
= rweight
;
487 /* apply filter to zoom vertically from tmp to dst */
488 rsp
= malloc(tmp
->height
);
489 gsp
= malloc(tmp
->height
);
490 bsp
= malloc(tmp
->height
);
492 for(k
= 0; k
< new_width
; ++k
) {
493 rp
= dst
->data
[0] + k
;
494 gp
= dst
->data
[1] + k
;
495 bp
= dst
->data
[2] + k
;
497 /* copy a column into a row */
500 unsigned char *p
, *d
;
503 for(i
= tmp
->height
, p
= tmp
->data
[0] + k
; i
-- > 0;
508 for(i
= tmp
->height
, p
= tmp
->data
[1] + k
; i
-- > 0;
513 for(i
= tmp
->height
, p
= tmp
->data
[2] + k
; i
-- > 0;
518 for(i
= 0; i
< new_height
; ++i
) {
519 rweight
= gweight
= bweight
= 0.0;
520 for(j
= 0; j
< contrib
[i
].n
; ++j
) {
521 rweight
+= rsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
522 gweight
+= gsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
523 bweight
+= bsp
[contrib
[i
].p
[j
].pixel
] * contrib
[i
].p
[j
].weight
;
525 *rp
= CLAMP(rweight
, 0, 255);
526 *gp
= CLAMP(gweight
, 0, 255);
527 *bp
= CLAMP(bweight
, 0, 255);
537 /* free the memory allocated for vertical filter weights */
538 for(i
= 0; i
< dst
->height
; ++i
) {