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