1 /*
2 * ppmqscale.c
3 *
4 * Copyright (C) Peter Schlaile - February 2001
5 *
6 * This file is part of libdv, a free DV (IEC 61834/SMPTE 314M)
7 * codec.
8 *
9 * libdv is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser Public License as published by
11 * the Free Software Foundation; either version 2.1, or (at your
12 * option) any later version.
13 *
14 * libdv is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser Public License
20 * along with libdv; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * The libdv homepage is http://libdv.sourceforge.net/.
24 */
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include "libdv/dv_types.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
read_ppm_stream(FILE * f,int * width,int * height)35 unsigned char* read_ppm_stream(FILE* f, int * width, int * height)
36 {
37 char line[200];
38 unsigned char* res;
39 fgets(line, sizeof(line), f);
40 do {
41 fgets(line, sizeof(line), f); /* P6 */
42 } while ((line[0] == '#') && !feof(f));
43 if (feof(f)) {
44 exit(0);
45 }
46 if (sscanf(line, "%d %d\n", width, height) != 2) {
47 fprintf(stderr, "Bad PPM file!\n");
48 exit(1);
49 }
50 fgets(line, sizeof(line), f); /* 255 */
51
52 res = (unsigned char*) malloc(*width * *height * 3);
53
54 fread(res, 1, 3 * *width * *height, f);
55 return res;
56 }
57
write_ppm(FILE * f,unsigned char * outbuf,int width,int height)58 void write_ppm(FILE * f, unsigned char* outbuf, int width, int height)
59 {
60 fprintf(f, "P6\n# CREATOR: ppmqscale V0.0.2\n%d %d\n255\n",
61 width, height);
62 fwrite(outbuf, 3, width * height, f);
63 }
64
65
enlarge_picture(unsigned char * src,unsigned char * dst,int src_width,int src_height,int dst_width,int dst_height)66 void enlarge_picture(unsigned char* src, unsigned char* dst, int src_width,
67 int src_height, int dst_width, int dst_height)
68 {
69 double ratiox = (double) (dst_width) / (double) (src_width);
70 double ratioy = (double) (dst_height) / (double) (src_height);
71 double ratio;
72 unsigned long x_src, dx_src, x_dst;
73 unsigned long y_src, dy_src, y_dst;
74 unsigned long dst_scaled_width;
75 unsigned long dst_scaled_height;
76
77 if (ratiox > ratioy) {
78 ratio = ratioy;
79 dst += ((int) ((dst_width - ratio * src_width) / 2)) * 3;
80 #if 0
81 fprintf(stderr, "Choosing Y ratio: %g, %d\n", ratio,
82 (int) (((dst_width - ratio * src_width) / 2) * 3));
83 #endif
84 } else {
85 ratio = ratiox;
86 dst += ((int) ((dst_height - ratio * src_height)
87 * dst_width / 2)) * 3;
88 #if 0
89 fprintf(stderr, "Choosing X ratio: %g, %d\n", ratio,
90 ((int) ((dst_height - ratio * src_height)
91 * dst_width / 2)) * 3);
92 #endif
93 }
94
95 dx_src = 65536.0 / ratio;
96 dy_src = 65536.0 / ratio;
97 dst_scaled_width = ratio * src_width;
98 dst_scaled_height = ratio * src_height;
99 y_src = 0;
100 for (y_dst = 0; y_dst < dst_scaled_height; y_dst++) {
101 unsigned char* line1 = src + (y_src >> 16) * 3 * src_width;
102 unsigned char* line2 = line1 + 3 * src_width;
103 unsigned long weight1y = 65536 - (y_src & 0xffff);
104 unsigned long weight2y = 65536 - weight1y;
105
106 x_src = 0;
107 for (x_dst = 0; x_dst < dst_scaled_width; x_dst++) {
108 unsigned long weight1x = 65536 - (x_src & 0xffff);
109 unsigned long weight2x = 65536 - weight1x;
110
111 unsigned long x = (x_src >> 16) * 3;
112
113 #if 0
114 *dst++ = line1[x];
115 *dst++ = line1[x + 1];
116 *dst++ = line1[x + 2];
117 #else
118 *dst++ = ((((line1[x] * weight1y) >> 16)
119 * weight1x) >> 16)
120 + ((((line2[x] * weight2y) >> 16)
121 * weight1x) >> 16)
122 + ((((line1[3 + x] * weight1y) >> 16)
123 * weight2x) >> 16)
124 + ((((line2[3 + x] * weight2y) >> 16)
125 * weight2x) >> 16);
126 *dst++ = ((((line1[x + 1] * weight1y) >> 16)
127 * weight1x) >> 16)
128 + ((((line2[x + 1] * weight2y) >> 16)
129 * weight1x) >> 16)
130 + ((((line1[3 + x + 1] * weight1y) >> 16)
131 * weight2x) >> 16)
132 + ((((line2[3 + x + 1] * weight2y) >> 16)
133 * weight2x) >> 16);
134 *dst++ = ((((line1[x + 2] * weight1y) >> 16)
135 * weight1x) >> 16)
136 + ((((line2[x + 2] * weight2y) >> 16)
137 * weight1x) >> 16)
138 + ((((line1[3 + x + 2] * weight1y) >> 16)
139 * weight2x) >> 16)
140 + ((((line2[3 + x + 2] * weight2y) >> 16)
141 * weight2x) >> 16);
142 #endif
143 x_src += dx_src;
144 }
145 y_src += dy_src;
146 dst += (dst_width - dst_scaled_width) * 3;
147 }
148 }
149
150 struct outpix {
151 unsigned long r;
152 unsigned long g;
153 unsigned long b;
154
155 unsigned long weight;
156 };
157
158
159
shrink_picture(unsigned char * src,unsigned char * dst,int src_width,int src_height,int dst_width,int dst_height)160 void shrink_picture(unsigned char* src, unsigned char* dst, int src_width,
161 int src_height, int dst_width, int dst_height)
162 {
163 double ratiox = (double) (dst_width) / (double) (src_width);
164 double ratioy = (double) (dst_height) / (double) (src_height);
165 double ratio;
166 unsigned long x_src, dx_dst, x_dst;
167 unsigned long y_src, dy_dst, y_dst;
168 long y_counter;
169
170 unsigned long dst_scaled_width;
171 unsigned long dst_scaled_height;
172
173 static struct outpix * dst_line1 = NULL;
174 static struct outpix * dst_line2 = NULL;
175
176 if (!dst_line1) {
177 dst_line1 = (struct outpix*) malloc(
178 (dst_width + 1) * sizeof(struct outpix));
179 dst_line2 = (struct outpix*) malloc(
180 (dst_width + 1) * sizeof(struct outpix));
181 }
182
183 if (ratiox > ratioy) {
184 ratio = ratioy;
185 dst += ((int) ((dst_width - ratio * src_width) / 2)) * 3;
186 #if 0
187 fprintf(stderr, "Choosing Y ratio: %g, %d\n", ratio,
188 ((int) ((dst_width - ratio * src_width) / 2)) * 3);
189 #endif
190 } else {
191 ratio = ratiox;
192 dst += ((int) ((dst_height - ratio * src_height)
193 * dst_width / 2)) * 3;
194
195 #if 0
196 fprintf(stderr, "Choosing X ratio: %g, %d\n", ratio,
197 ((int) ((dst_height - ratio * src_height)
198 * dst_width / 2)) * 3);
199 #endif
200 }
201
202 dx_dst = 65536.0 * ratio;
203 dy_dst = 65536.0 * ratio;
204 dst_scaled_width = ratio * src_width;
205 dst_scaled_height = ratio * src_height;
206
207 memset(dst_line1, 0, dst_scaled_width * sizeof(struct outpix));
208 memset(dst_line2, 0, dst_scaled_width * sizeof(struct outpix));
209 y_dst = 0;
210 y_counter = 65536;
211 for (y_src = 0; y_src < src_height; y_src++) {
212 unsigned char* line = src + y_src * 3 * src_width;
213 unsigned long weight1y = 65536 - (y_dst & 0xffff);
214 unsigned long weight2y = 65536 - weight1y;
215 x_dst = 0;
216 for (x_src = 0; x_src < src_width; x_src++) {
217 unsigned long weight1x = 65536 - (x_dst & 0xffff);
218 unsigned long weight2x = 65536 - weight1x;
219
220 unsigned long x = x_dst >> 16;
221
222 unsigned long w;
223
224 w = (weight1y * weight1x) >> 16;
225
226 dst_line1[x].r += (line[0] * w) >> 16;
227 dst_line1[x].g += (line[1] * w) >> 16;
228 dst_line1[x].b += (line[2] * w) >> 16;
229 dst_line1[x].weight += w;
230
231 w = (weight2y * weight1x) >> 16;
232
233 dst_line2[x].r += (line[0] * w) >> 16;
234 dst_line2[x].g += (line[1] * w) >> 16;
235 dst_line2[x].b += (line[2] * w) >> 16;
236 dst_line2[x].weight += w;
237
238 w = (weight1y * weight2x) >> 16;
239
240 dst_line1[x+1].r += (line[0] * w) >> 16;
241 dst_line1[x+1].g += (line[1] * w) >> 16;
242 dst_line1[x+1].b += (line[2] * w) >> 16;
243 dst_line1[x+1].weight += w;
244
245 w = (weight2y * weight2x) >> 16;
246
247 dst_line2[x+1].r += (line[0] * w) >> 16;
248 dst_line2[x+1].g += (line[1] * w) >> 16;
249 dst_line2[x+1].b += (line[2] * w) >> 16;
250 dst_line2[x+1].weight += w;
251
252 x_dst += dx_dst;
253 line += 3;
254 }
255
256 y_dst += dy_dst;
257 y_counter -= dy_dst;
258 if (y_counter < 0) {
259 unsigned long x;
260 struct outpix * temp;
261
262 y_counter += 65536;
263
264 for (x=0; x < dst_scaled_width; x++) {
265 unsigned long f = 0x80000000UL
266 / dst_line1[x].weight;
267 *dst++ = (dst_line1[x].r * f) >> 15;
268 *dst++ = (dst_line1[x].g * f) >> 15;
269 *dst++ = (dst_line1[x].b * f) >> 15;
270 }
271 dst += (dst_width - dst_scaled_width) * 3;
272 memset(dst_line1, 0, dst_scaled_width *
273 sizeof(struct outpix));
274 temp = dst_line1;
275 dst_line1 = dst_line2;
276 dst_line2 = temp;
277 }
278 }
279 {
280 unsigned long x;
281 for (x = 0; x < dst_scaled_width; x++) {
282 unsigned long f = 0x80000000UL / dst_line1[x].weight;
283 *dst++ = (dst_line1[x].r * f) >> 15;
284 *dst++ = (dst_line1[x].g * f) >> 15;
285 *dst++ = (dst_line1[x].b * f) >> 15;
286 }
287 }
288 }
289
290
fast_scale(unsigned char * in,unsigned char * out,int in_width,int in_height,int dst_width,int dst_height)291 void fast_scale(unsigned char* in, unsigned char* out, int in_width,
292 int in_height, int dst_width, int dst_height)
293 {
294 memset(out, 0, dst_height * dst_width * 3);
295
296 if (dst_width > in_width && dst_height > in_height) {
297 enlarge_picture(in, out, in_width, in_height,
298 dst_width, dst_height);
299 } else if (dst_width == in_width && dst_height == in_height) {
300 memcpy(out, in, dst_height * dst_width * 3);
301 } else {
302 shrink_picture(in, out, in_width, in_height,
303 dst_width, dst_height);
304 }
305 }
306
main(int argc,const char ** argv)307 int main(int argc, const char** argv)
308 {
309 int out_width, out_height;
310 int in_width, in_height;
311 unsigned char* in_pic;
312 unsigned char* out_pic;
313
314 if (argc < 3) {
315 fprintf(stderr, "Usage: ppmqscale out_width out_height\n");
316 exit(-1);
317 }
318
319 out_width = atoi(argv[1]);
320 out_height = atoi(argv[2]);
321
322 out_pic = (unsigned char*) malloc(out_width * out_height * 3);
323
324 for (;;) {
325 in_pic = read_ppm_stream(stdin, &in_width, &in_height);
326
327 fast_scale(in_pic, out_pic, in_width, in_height,
328 out_width, out_height);
329 write_ppm(stdout, out_pic, out_width, out_height);
330 free(in_pic);
331 }
332 }
333
334
335