Removed unused version of RScaleImage() in wrlib/scale.c
[wmaker-crm.git] / wrlib / scale.c
blob7e49074423ecdc87548ed51a881a459ea97679d1
1 /* scale.c - image scaling
3 * Raster graphics library
5 * Copyright (c) 1997-2003 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.
22 #include <config.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include <math.h>
30 #ifndef PI
31 #define PI 3.14159265358979323846
32 #endif
34 #include <assert.h>
36 #include "wraster.h"
39 *----------------------------------------------------------------------
40 * RScaleImage--
41 * Creates a scaled copy of an image.
43 * Returns:
44 * The new scaled image.
46 *----------------------------------------------------------------------
48 RImage *RScaleImage(RImage * image, unsigned new_width, unsigned new_height)
50 int ox;
51 int px, py;
52 register int x, y, t;
53 int dx, dy;
54 unsigned char *s;
55 unsigned char *d;
56 RImage *img;
58 assert(new_width >= 0 && new_height >= 0);
60 if (new_width == image->width && new_height == image->height)
61 return RCloneImage(image);
63 img = RCreateImage(new_width, new_height, image->format == RRGBAFormat);
65 if (!img)
66 return NULL;
68 /* fixed point math idea taken from Imlib by
69 * Carsten Haitzler (Rasterman) */
70 dx = (image->width << 16) / new_width;
71 dy = (image->height << 16) / new_height;
73 py = 0;
75 d = img->data;
77 if (image->format == RRGBAFormat) {
78 for (y = 0; y < new_height; y++) {
79 t = image->width * (py >> 16);
81 s = image->data + (t << 2); /* image->data+t*4 */
83 ox = 0;
84 px = 0;
85 for (x = 0; x < new_width; x++) {
86 px += dx;
88 *(d++) = *(s);
89 *(d++) = *(s + 1);
90 *(d++) = *(s + 2);
91 *(d++) = *(s + 3);
93 t = (px - ox) >> 16;
94 ox += t << 16;
96 s += t << 2; /* t*4 */
98 py += dy;
100 } else {
101 for (y = 0; y < new_height; y++) {
102 t = image->width * (py >> 16);
104 s = image->data + (t << 1) + t; /* image->data+t*3 */
106 ox = 0;
107 px = 0;
108 for (x = 0; x < new_width; x++) {
109 px += dx;
111 *(d++) = *(s);
112 *(d++) = *(s + 1);
113 *(d++) = *(s + 2);
115 t = (px - ox) >> 16;
116 ox += t << 16;
118 s += (t << 1) + t; /* t*3 */
120 py += dy;
124 return img;
128 * Filtered Image Rescaling code copy/pasted from
129 * Graphics Gems III
130 * Public Domain 1991 by Dale Schumacher
134 * filter function definitions
136 #if 0
137 #define filter_support (1.0)
139 static double filter(double t)
141 /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
142 if (t < 0.0)
143 t = -t;
144 if (t < 1.0)
145 return ((2.0 * t - 3.0) * t * t + 1.0);
146 return (0.0);
148 #endif
149 #define box_support (0.5)
151 static double box_filter(double t)
153 if ((t > -0.5) && (t <= 0.5))
154 return (1.0);
155 return (0.0);
158 #define triangle_support (1.0)
160 static double triangle_filter(double t)
162 if (t < 0.0)
163 t = -t;
164 if (t < 1.0)
165 return (1.0 - t);
166 return (0.0);
169 #define bell_support (1.5)
171 static double bell_filter(double t) /* box (*) box (*) box */
173 if (t < 0)
174 t = -t;
175 if (t < .5)
176 return (.75 - (t * t));
177 if (t < 1.5) {
178 t = (t - 1.5);
179 return (.5 * (t * t));
181 return (0.0);
184 #define B_spline_support (2.0)
186 static double B_spline_filter(double t) /* box (*) box (*) box (*) box */
188 double tt;
190 if (t < 0)
191 t = -t;
192 if (t < 1) {
193 tt = t * t;
194 return ((.5 * tt * t) - tt + (2.0 / 3.0));
195 } else if (t < 2) {
196 t = 2 - t;
197 return ((1.0 / 6.0) * (t * t * t));
199 return (0.0);
202 static double sinc(double x)
204 x *= PI;
205 if (x != 0)
206 return (sin(x) / x);
207 return (1.0);
210 #define Lanczos3_support (3.0)
212 static double Lanczos3_filter(double t)
214 if (t < 0)
215 t = -t;
216 if (t < 3.0)
217 return (sinc(t) * sinc(t / 3.0));
218 return (0.0);
221 #define Mitchell_support (2.0)
223 #define B (1.0 / 3.0)
224 #define C (1.0 / 3.0)
226 static double Mitchell_filter(double t)
228 double tt;
230 tt = t * t;
231 if (t < 0)
232 t = -t;
233 if (t < 1.0) {
234 t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt))
235 + ((-18.0 + 12.0 * B + 6.0 * C) * tt)
236 + (6.0 - 2 * B));
237 return (t / 6.0);
238 } else if (t < 2.0) {
239 t = (((-1.0 * B - 6.0 * C) * (t * tt))
240 + ((6.0 * B + 30.0 * C) * tt)
241 + ((-12.0 * B - 48.0 * C) * t)
242 + (8.0 * B + 24 * C));
243 return (t / 6.0);
245 return (0.0);
248 static double (*filterf)(double) = Mitchell_filter;
249 static double fwidth = Mitchell_support;
251 void _wraster_change_filter(int type)
253 switch (type) {
254 case RBoxFilter:
255 filterf = box_filter;
256 fwidth = box_support;
257 break;
258 case RTriangleFilter:
259 filterf = triangle_filter;
260 fwidth = triangle_support;
261 break;
262 case RBellFilter:
263 filterf = bell_filter;
264 fwidth = bell_support;
265 break;
266 case RBSplineFilter:
267 filterf = B_spline_filter;
268 fwidth = B_spline_support;
269 break;
270 case RLanczos3Filter:
271 filterf = Lanczos3_filter;
272 fwidth = Lanczos3_support;
273 break;
274 default:
275 case RMitchellFilter:
276 filterf = Mitchell_filter;
277 fwidth = Mitchell_support;
278 break;
283 * image rescaling routine
286 typedef struct {
287 int pixel;
288 double weight;
289 } CONTRIB;
291 typedef struct {
292 int n; /* number of contributors */
293 CONTRIB *p; /* pointer to list of contributions */
294 } CLIST;
296 CLIST *contrib; /* array of contribution lists */
298 /* clamp the input to the specified range */
299 #define CLAMP(v,l,h) ((v)<(l) ? (l) : (v) > (h) ? (h) : v)
301 /* return of calloc is not checked if NULL in the function below! */
302 RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
304 RImage *tmp; /* intermediate image */
305 double xscale, yscale; /* zoom scale factors */
306 int i, j, k; /* loop variables */
307 int n; /* pixel number */
308 double center, left, right; /* filter calculation variables */
309 double width, fscale; /* filter calculation variables */
310 double rweight, gweight, bweight;
311 RImage *dst;
312 unsigned char *p;
313 unsigned char *sp;
314 int sch = src->format == RRGBAFormat ? 4 : 3;
316 dst = RCreateImage(new_width, new_height, False);
318 /* create intermediate image to hold horizontal zoom */
319 tmp = RCreateImage(dst->width, src->height, False);
320 xscale = (double)new_width / (double)src->width;
321 yscale = (double)new_height / (double)src->height;
323 /* pre-calculate filter contributions for a row */
324 contrib = (CLIST *) calloc(new_width, sizeof(CLIST));
325 if (xscale < 1.0) {
326 width = fwidth / xscale;
327 fscale = 1.0 / xscale;
328 for (i = 0; i < new_width; ++i) {
329 contrib[i].n = 0;
330 contrib[i].p = (CONTRIB *) calloc((int)(width * 2 + 1), sizeof(CONTRIB));
331 center = (double)i / xscale;
332 left = ceil(center - width);
333 right = floor(center + width);
334 for (j = left; j <= right; ++j) {
335 rweight = center - (double)j;
336 rweight = (*filterf) (rweight / fscale) / fscale;
337 if (j < 0) {
338 n = -j;
339 } else if (j >= src->width) {
340 n = (src->width - j) + src->width - 1;
341 } else {
342 n = j;
344 k = contrib[i].n++;
345 contrib[i].p[k].pixel = n * sch;
346 contrib[i].p[k].weight = rweight;
349 } else {
351 for (i = 0; i < new_width; ++i) {
352 contrib[i].n = 0;
353 contrib[i].p = (CONTRIB *) calloc((int)(fwidth * 2 + 1), sizeof(CONTRIB));
354 center = (double)i / xscale;
355 left = ceil(center - fwidth);
356 right = floor(center + fwidth);
357 for (j = left; j <= right; ++j) {
358 rweight = center - (double)j;
359 rweight = (*filterf) (rweight);
360 if (j < 0) {
361 n = -j;
362 } else if (j >= src->width) {
363 n = (src->width - j) + src->width - 1;
364 } else {
365 n = j;
367 k = contrib[i].n++;
368 contrib[i].p[k].pixel = n * sch;
369 contrib[i].p[k].weight = rweight;
374 /* apply filter to zoom horizontally from src to tmp */
375 p = tmp->data;
377 for (k = 0; k < tmp->height; ++k) {
378 CONTRIB *pp;
380 sp = src->data + src->width * k * sch;
382 for (i = 0; i < tmp->width; ++i) {
383 rweight = gweight = bweight = 0.0;
385 pp = contrib[i].p;
387 for (j = 0; j < contrib[i].n; ++j) {
388 rweight += sp[pp[j].pixel] * pp[j].weight;
389 gweight += sp[pp[j].pixel + 1] * pp[j].weight;
390 bweight += sp[pp[j].pixel + 2] * pp[j].weight;
392 *p++ = CLAMP(rweight, 0, 255);
393 *p++ = CLAMP(gweight, 0, 255);
394 *p++ = CLAMP(bweight, 0, 255);
398 /* free the memory allocated for horizontal filter weights */
399 for (i = 0; i < tmp->width; ++i) {
400 free(contrib[i].p);
402 free(contrib);
404 /* pre-calculate filter contributions for a column */
405 contrib = (CLIST *) calloc(dst->height, sizeof(CLIST));
406 if (yscale < 1.0) {
407 width = fwidth / yscale;
408 fscale = 1.0 / yscale;
409 for (i = 0; i < dst->height; ++i) {
410 contrib[i].n = 0;
411 contrib[i].p = (CONTRIB *) calloc((int)(width * 2 + 1), sizeof(CONTRIB));
412 center = (double)i / yscale;
413 left = ceil(center - width);
414 right = floor(center + width);
415 for (j = left; j <= right; ++j) {
416 rweight = center - (double)j;
417 rweight = (*filterf) (rweight / fscale) / fscale;
418 if (j < 0) {
419 n = -j;
420 } else if (j >= tmp->height) {
421 n = (tmp->height - j) + tmp->height - 1;
422 } else {
423 n = j;
425 k = contrib[i].n++;
426 contrib[i].p[k].pixel = n * 3;
427 contrib[i].p[k].weight = rweight;
430 } else {
431 for (i = 0; i < dst->height; ++i) {
432 contrib[i].n = 0;
433 contrib[i].p = (CONTRIB *) calloc((int)(fwidth * 2 + 1), sizeof(CONTRIB));
434 center = (double)i / yscale;
435 left = ceil(center - fwidth);
436 right = floor(center + fwidth);
437 for (j = left; j <= right; ++j) {
438 rweight = center - (double)j;
439 rweight = (*filterf) (rweight);
440 if (j < 0) {
441 n = -j;
442 } else if (j >= tmp->height) {
443 n = (tmp->height - j) + tmp->height - 1;
444 } else {
445 n = j;
447 k = contrib[i].n++;
448 contrib[i].p[k].pixel = n * 3;
449 contrib[i].p[k].weight = rweight;
454 /* apply filter to zoom vertically from tmp to dst */
455 sp = malloc(tmp->height * 3);
457 for (k = 0; k < new_width; ++k) {
458 CONTRIB *pp;
460 p = dst->data + k * 3;
462 /* copy a column into a row */
464 int i;
465 unsigned char *p, *d;
467 d = sp;
468 for (i = tmp->height, p = tmp->data + k * 3; i-- > 0; p += tmp->width * 3) {
469 *d++ = *p;
470 *d++ = *(p + 1);
471 *d++ = *(p + 2);
474 for (i = 0; i < new_height; ++i) {
475 rweight = gweight = bweight = 0.0;
477 pp = contrib[i].p;
479 for (j = 0; j < contrib[i].n; ++j) {
480 rweight += sp[pp[j].pixel] * pp[j].weight;
481 gweight += sp[pp[j].pixel + 1] * pp[j].weight;
482 bweight += sp[pp[j].pixel + 2] * pp[j].weight;
484 *p = CLAMP(rweight, 0, 255);
485 *(p + 1) = CLAMP(gweight, 0, 255);
486 *(p + 2) = CLAMP(bweight, 0, 255);
487 p += new_width * 3;
490 free(sp);
492 /* free the memory allocated for vertical filter weights */
493 for (i = 0; i < dst->height; ++i) {
494 free(contrib[i].p);
496 free(contrib);
498 RReleaseImage(tmp);
500 return dst;