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