1 /*
2  * swiggle - le's simple web image gallery generator
3  *
4  * This module is responsible for the scaling of images.
5  *
6  * Copyright (c) 2003
7  *  Lukas Ertl <l.ertl@univie.ac.at>.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *  This product includes software developed by the University of
20  *  California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *
38  * $Id: resize.c,v 1.11 2004/10/23 20:57:02 le Exp $
39  *
40  */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #ifdef AIX
46 #include <strings.h>
47 #endif
48 
49 #include <jpeglib.h>
50 
51 #include "swiggle.h"
52 
53 /*
54  * Scales image (with pixels given in "p") according to the settings in
55  * "dinfo" (the source image) and "cinfo" (the target image) and stores
56  * the result in "o".
57  * Scaling is done with a bicubic algorithm (stolen from ImageMagick :-)).
58  */
59 int
resize_bicubic(struct jpeg_decompress_struct * dinfo,struct jpeg_compress_struct * cinfo,const unsigned char * p,unsigned char ** o)60 resize_bicubic(struct jpeg_decompress_struct *dinfo,
61     struct jpeg_compress_struct *cinfo, const unsigned char *p,
62     unsigned char **o)
63 {
64 	unsigned char *q, *x_vector;
65 	int comp, i, next_col, next_row, num_rows;
66 	int s_row_width, ty, t_row_width, x, y;
67 	double factor, *s, *scanline, *scale_scanline;
68 	double *t, x_scale, x_span, y_scale, y_span, *y_vector;
69 
70 	q = NULL;
71 
72 	/* RGB images have 3 components, grayscale images have only one. */
73 	comp = dinfo->num_components;
74 	s_row_width = dinfo->output_width * comp;
75 	t_row_width = cinfo->image_width  * comp;
76 	factor = (double)cinfo->image_width / (double)dinfo->output_width;
77 
78 	if ( *o == NULL )
79 		return (-1);
80 
81 	/* No scaling needed. */
82 	if (dinfo->output_width == cinfo->image_width) {
83 		memcpy(*o, p, s_row_width * dinfo->output_height);
84 		return (0);
85 	}
86 
87 	x_vector = malloc(s_row_width * SIZE_UCHAR);
88 	if (x_vector == NULL)
89 		return (-1);
90 	y_vector = malloc(s_row_width * sizeof(double));
91 	if (y_vector == NULL)
92 		return (-1);
93 	scanline = malloc(s_row_width * sizeof(double));
94 	if (scanline == NULL)
95 		return (-1);
96 	scale_scanline = malloc((t_row_width + comp) * sizeof(double));
97 	if (scale_scanline == NULL)
98 		return (-1);
99 
100 	num_rows = 0;
101 	next_row = 1;
102 	y_span = 1.0;
103 	y_scale = factor;
104 	i = 0;
105 
106 	for (y = 0; y < cinfo->image_height; y++) {
107 		ty = y * t_row_width;
108 		q = *o;
109 
110 		bzero(y_vector, s_row_width * sizeof(double));
111 		bzero(scale_scanline, t_row_width * sizeof(double));
112 
113 		/* Scale Y-dimension. */
114 		while (y_scale < y_span) {
115 			if (next_row && num_rows < dinfo->output_height) {
116 				/* Read a new scanline.  */
117 				memcpy(x_vector, p, s_row_width);
118 				p += s_row_width;
119 				num_rows++;
120 			}
121 			for (x = 0; x < s_row_width; x++)
122 				y_vector[x] += y_scale * (double)x_vector[x];
123 			y_span  -= y_scale;
124 			y_scale  = factor;
125 			next_row = 1;
126 		}
127 		if (next_row && num_rows < dinfo->output_height) {
128 			/* Read a new scanline.  */
129 			memcpy(x_vector, p, s_row_width);
130 			p += s_row_width;
131 			num_rows++;
132 			next_row = 0;
133 		}
134 		s = scanline;
135 		for (x = 0; x < s_row_width; x++) {
136 			y_vector[x] += y_span * (double) x_vector[x];
137 			*s = y_vector[x];
138 			s++;
139 		}
140 		y_scale -= y_span;
141 		if (y_scale <= 0) {
142 			y_scale  = factor;
143 			next_row = 1;
144 		}
145 		y_span = 1.0;
146 
147 		next_col = 0;
148 		x_span   = 1.0;
149 		s = scanline;
150 		t = scale_scanline;
151 
152 		/* Scale X dimension. */
153 		for (x = 0; x < dinfo->output_width; x++) {
154 			x_scale = factor;
155 			while (x_scale >= x_span) {
156 				if (next_col)
157 					t += comp;
158 				t[0] += x_span * s[0];
159 				if (comp != 1) {
160 					t[1] += x_span * s[1];
161 					t[2] += x_span * s[2];
162 				}
163 				x_scale -= x_span;
164 				x_span   = 1.0;
165 				next_col = 1;
166 			}
167 			if (x_scale > 0) {
168 				if (next_col) {
169 					next_col = 0;
170 					t += comp;
171 				}
172 				t[0] += x_scale * s[0];
173 				if (comp != 1) {
174 					t[1] += x_scale * s[1];
175 					t[2] += x_scale * s[2];
176 				}
177 				x_span -= x_scale;
178 			}
179 			s += comp;
180 		}
181 
182 		/* Copy scanline to target. */
183 		t = scale_scanline;
184 		for (x = 0; x < t_row_width; x++)
185 			q[ty+x] = (unsigned char)t[x];
186 	}
187 
188 	free(x_vector);
189 	free(y_vector);
190 	free(scanline);
191 	free(scale_scanline);
192 
193 	return (0);
194 }
195 
196 /*
197  * Scales image (with pixels given in "p") according to the settings in
198  * "dinfo" (the source image) and "cinfo" (the target image) and stores
199  * the result in "o".
200  * Scaling is done with a bilinear algorithm.
201  */
202 int
resize_bilinear(struct jpeg_decompress_struct * dinfo,struct jpeg_compress_struct * cinfo,const unsigned char * p,unsigned char ** o)203 resize_bilinear(struct jpeg_decompress_struct *dinfo,
204     struct jpeg_compress_struct *cinfo, const unsigned char *p,
205     unsigned char **o)
206 {
207 	double factor, fraction_x, fraction_y, one_minus_x, one_minus_y;
208 	int ceil_x, ceil_y, floor_x, floor_y, s_row_width;
209 	int tcx, tcy, tfx, tfy, tx, ty, t_row_width, x, y;
210 	unsigned char *q;
211 
212 	/* RGB images have 3 components, grayscale images have only one. */
213 	s_row_width = dinfo->num_components * dinfo->output_width;
214 	t_row_width = dinfo->num_components * cinfo->image_width;
215 
216 	factor = (double)dinfo->output_width / (double)cinfo->image_width;
217 
218 	if (*o == NULL)
219 		return (-1);
220 
221 	/* No scaling needed. */
222 	if (dinfo->output_width == cinfo->image_width) {
223 		memcpy(*o, p, s_row_width * dinfo->output_height);
224 		return (0);
225 	}
226 
227 	q = *o;
228 
229 	for (y = 0; y < cinfo->image_height; y++) {
230 		for (x = 0; x < cinfo->image_width; x++) {
231 			floor_x = (int)(x * factor);
232 			floor_y = (int)(y * factor);
233 			ceil_x = (floor_x + 1 > cinfo->image_width)
234 			    ? floor_x
235 			    : floor_x + 1;
236 			ceil_y = (floor_y + 1 > cinfo->image_height)
237 			    ? floor_y
238 			    : floor_y + 1;
239 			fraction_x = (x * factor) - floor_x;
240 			fraction_y = (y * factor) - floor_y;
241 			one_minus_x = 1.0 - fraction_x;
242 			one_minus_y = 1.0 - fraction_y;
243 
244 			tx  = x * dinfo->num_components;
245 			ty  = y * t_row_width;
246 			tfx = floor_x * dinfo->num_components;
247 			tfy = floor_y * s_row_width;
248 			tcx = ceil_x * dinfo->num_components;
249 			tcy = ceil_y * s_row_width;
250 
251 			q[tx + ty] = one_minus_y *
252 			    (one_minus_x * p[tfx + tfy] +
253 			    fraction_x * p[tcx + tfy]) +
254 			    fraction_y * (one_minus_x * p[tfx + tcy] +
255 			    fraction_x  * p[tcx + tcy]);
256 
257 			if (dinfo->num_components != 1) {
258 				q[tx + ty + 1] = one_minus_y *
259 				    (one_minus_x * p[tfx + tfy + 1] +
260 				    fraction_x * p[tcx + tfy + 1]) +
261 				    fraction_y * (one_minus_x *
262 				    p[tfx + tcy + 1] + fraction_x *
263 				    p[tcx + tcy + 1]);
264 
265 				q[tx + ty + 2] = one_minus_y *
266 				    (one_minus_x * p[tfx + tfy + 2] +
267 				    fraction_x * p[tcx + tfy + 2]) +
268 				    fraction_y * (one_minus_x *
269 				    p[tfx + tcy + 2] + fraction_x *
270 				    p[tcx + tcy + 2]);
271 			}
272 		}
273 	}
274 
275 	return (0);
276 }
277