Text rendering library
[jpcrr.git] / streamtools / rawtorgb.c
blob04a2c6902608c886650808c13676fa8940cd501c
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2009 H. Ilari Liusvaara
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as published by
9 the Free Software Foundation.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 Based on JPC x86 PC Hardware emulator,
21 A project from the Physics Dept, The University of Oxford
23 Details about original JPC can be found at:
25 www-jpc.physics.ox.ac.uk
30 #include "frame.h"
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <assert.h>
38 #define MAXCOEFFICIENTS 256
40 typedef signed long long position_t;
42 enum algorithm
44 ALGO_AVERAGE,
45 ALGO_LANCZOS1,
46 ALGO_LANCZOS2,
47 ALGO_LANCZOS3,
48 ALGO_LANCZOS4,
49 ALGO_LANCZOS5
52 struct framelist_entry
54 unsigned long fe_first;
55 unsigned long fe_last; //0 is unbounded.
56 struct framelist_entry* fe_next;
59 unsigned long read_number(const char* value, const char* name, int zero_ok, char sep)
61 unsigned long x;
62 char* end;
64 x = strtoul(value, &end, 10);
65 if((*end && *end != sep) || (x == 0 && !zero_ok)) {
66 fprintf(stderr, "Invalid %s: '%s'\n", name, value);
67 exit(1);
69 return x;
72 struct framelist_entry* parse_framelist(const char* list)
74 const char* next;
75 const char* split;
76 struct framelist_entry* entry;
77 unsigned long first, last;
78 if(!list || !*list)
79 return NULL;
80 next = strchr(list, ',');
81 if(!next)
82 next = list + strlen(list);
83 else
84 next++;
86 entry = malloc(sizeof(struct framelist_entry));
87 if(!entry) {
88 fprintf(stderr, "Out of memory!\n");
89 exit(1);
92 split = strchr(list, '-');
93 if(split)
94 split++;
96 if(split && !*split) {
97 first = read_number(list, "framelist start", 0, '-');
98 last = 0;
99 } else if(!split || split > next)
100 first = last = read_number(list, "framelist entry", 0, ',');
101 else {
102 first = read_number(list, "framelist start", 0, '-');
103 last = read_number(split, "framelist end", 0, ',');
106 if(first > last && last != 0) {
107 fprintf(stderr, "Bad framelist range %lu-%lu!\n", first, last);
108 exit(1);
111 entry->fe_first = first;
112 entry->fe_last = last;
113 entry->fe_next = parse_framelist(next);
114 return entry;
117 #define LANZCOS_A 2
119 void compute_coefficients_lanczos(float* coeffs, position_t num, position_t denum, position_t width,
120 unsigned* count, unsigned* base, unsigned a)
122 signed lowbound, highbound, scan;
124 if(num % denum == 0) {
125 coeffs[0] = 1;
126 *count = 1;
127 *base = num / denum;
128 return;
131 if(a == 0) {
132 fprintf(stderr, "Error: Parameter alpha must be positive in lanczos resizer.",
133 2 * a + 1, MAXCOEFFICIENTS);
134 exit(1);
137 if(2 * a + 1 <= a) {
138 fprintf(stderr, "Error: Parameter alpha way too large in lanczos resizer.",
139 2 * a + 1, MAXCOEFFICIENTS);
140 exit(1);
143 if(2 * a + 1 > MAXCOEFFICIENTS) {
144 fprintf(stderr, "Error: Conversion would require %u coefficients, but only up to %u coefficients are supported.",
145 2 * a + 1, MAXCOEFFICIENTS);
146 exit(1);
149 lowbound = num - a * denum;
150 highbound = num + a * denum;
151 if(lowbound < 0)
152 lowbound = 0;
153 if(highbound > width * denum)
154 highbound = width * denum - denum;
156 scan = lowbound + (denum - lowbound % denum) % denum;
157 *base = scan / denum;
158 *count = 0;
159 while(scan <= highbound) {
160 float difference = (float)(num - scan) / denum;
161 if(num == scan)
162 coeffs[(*count)++] = 1;
163 else
164 coeffs[(*count)++] = a * sin(M_PI*difference) * sin(M_PI*difference/2) /
165 (M_PI * M_PI * difference * difference);
167 scan = scan + denum;
171 void compute_coefficients_average(float* coeffs, position_t num, position_t denum, position_t width,
172 unsigned* count, unsigned* base)
174 signed lowbound, highbound, scan;
176 lowbound = num;
177 highbound = num + width;
178 scan = lowbound - lowbound % denum;
180 if((width + denum - 1) / denum > MAXCOEFFICIENTS) {
181 fprintf(stderr, "Error: Conversion would require %lli coefficients, but only up to %u coefficients are supported.",
182 (width + denum - 1) / denum, MAXCOEFFICIENTS);
183 exit(1);
186 *base = scan / denum;
187 *coeffs = (scan + denum) - lowbound;
188 *count = 1;
189 scan = scan + denum;
190 while(scan < highbound) {
191 if(scan + denum > highbound)
192 coeffs[(*count)++] = highbound - scan;
193 else
194 coeffs[(*count)++] = denum;
196 scan = scan + denum;
200 // The coodinate space is such that range is [0, srclength] and is given as fraction
201 // num / denum, where denumerator is destination length. Thus source pixel spacing
202 // is unity.
203 void compute_coefficients(float* coeffs, position_t num, position_t denum, position_t width,
204 unsigned* count, unsigned* base, enum algorithm algo)
206 float sum = 0;
207 switch(algo) {
208 case ALGO_AVERAGE:
209 return compute_coefficients_average(coeffs, num, denum, width, count, base);
210 case ALGO_LANCZOS1:
211 return compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 1);
212 case ALGO_LANCZOS2:
213 return compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 2);
214 case ALGO_LANCZOS3:
215 return compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 3);
216 case ALGO_LANCZOS4:
217 return compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 4);
218 case ALGO_LANCZOS5:
219 return compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 5);
220 default:
221 fprintf(stderr, "Error: Unknown algorithm #%i.", algo);
222 exit(1);
225 /* Normalize the coefficients. */
226 for(int i = 0; i < *count; i++)
227 sum += coeffs[i];
228 for(int i = 0; i < *count; i++)
229 coeffs[i] /= sum;
233 //Read the frame data in src (swidth x sheight) and resize it to dest (dwidth x dheight).
234 void resize_frame(unsigned char* dest, unsigned dwidth, unsigned dheight, uint32_t* src, unsigned swidth,
235 unsigned sheight, enum algorithm algo)
237 float coeffs[MAXCOEFFICIENTS];
238 unsigned trap = 0xCAFEFACE;
239 unsigned count;
240 unsigned base;
241 float* interm;
243 interm = calloc(3 * sizeof(float), dwidth * sheight);
244 if(!interm) {
245 fprintf(stderr, "Out of memory!\n");
246 exit(1);
249 for(unsigned x = 0; x < dwidth; x++) {
250 count = 0xDEADBEEF;
251 base = 0xDEADBEEF;
252 compute_coefficients(coeffs, (position_t)x * swidth, dwidth, swidth, &count, &base, algo);
253 assert(trap == 0xCAFEFACE);
254 for(unsigned y = 0; y < sheight; y++) {
255 float vr = 0, vg = 0, vb = 0;
256 for(unsigned k = 0; k < count; k++) {
257 uint32_t sample = src[y * swidth + k + base];
258 vr += coeffs[k] * ((sample >> 16) & 0xFF);
259 vg += coeffs[k] * ((sample >> 8) & 0xFF);
260 vb += coeffs[k] * (sample & 0xFF);
262 interm[y * 3 * dwidth + 3 * x + 0] = vr;
263 interm[y * 3 * dwidth + 3 * x + 1] = vg;
264 interm[y * 3 * dwidth + 3 * x + 2] = vb;
268 for(unsigned y = 0; y < dheight; y++) {
269 count = 0;
270 base = 0;
271 compute_coefficients(coeffs, (position_t)y * sheight, dheight, sheight, &count, &base, algo);
272 assert(trap == 0xCAFEFACE);
273 for(unsigned x = 0; x < dwidth; x++) {
274 float vr = 0, vg = 0, vb = 0;
275 for(unsigned k = 0; k < count; k++) {
276 vr += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 0];
277 vg += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 1];
278 vb += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 2];
280 int wr = (int)vr;
281 int wg = (int)vg;
282 int wb = (int)vb;
283 wr = (wr < 0) ? 0 : ((wr > 255) ? 255 : wr);
284 wg = (wg < 0) ? 0 : ((wg > 255) ? 255 : wg);
285 wb = (wb < 0) ? 0 : ((wb > 255) ? 255 : wb);
287 dest[y * 4 * dwidth + 4 * x] = (unsigned char)wr;
288 dest[y * 4 * dwidth + 4 * x + 1] = (unsigned char)wg;
289 dest[y * 4 * dwidth + 4 * x + 2] = (unsigned char)wb;
290 dest[y * 4 * dwidth + 4 * x + 3] = 0;
294 free(interm);
297 void dump_frame(FILE* out, unsigned width, unsigned height, struct frame* frame, enum algorithm algo)
299 static int dnum = 1;
300 unsigned char* buffer = calloc(4 * width, height);
301 if(!buffer) {
302 fprintf(stderr, "Out of memory!\n");
303 exit(1);
306 if(frame) {
307 resize_frame(buffer, width, height, frame->f_framedata, frame->f_width, frame->f_height,
308 algo);
309 printf("Destination frame %i: Timeseq=%llu.\n", dnum, frame->f_timeseq);
310 } else
311 printf("Destination frame %i: Blank.\n", dnum);
314 if(fwrite(buffer, 4 * width, height, out) < height) {
315 fprintf(stderr, "Can't write frame to output file!\n");
316 exit(1);
318 free(buffer);
319 dnum++;
322 int main(int argc, char** argv)
324 struct framelist_entry frame_default_list = {1, 0, NULL};
325 struct framelist_entry* current_block = &frame_default_list;
326 enum algorithm algo;
328 if(argc < 7 || argc > 8) {
329 fprintf(stderr, "usage: %s <in> <out> <algo> <width> <height> <framegap> [<frames>]\n", argv[0]);
330 fprintf(stderr, "Read stream from <in> and dump the raw RGBx output to <out>. The\n");
331 fprintf(stderr, "dumped frames are scaled to be <width>x<height> and frame is read\n");
332 fprintf(stderr, "every <framegap> ns. If <frames> is given, it lists frames to\n");
333 fprintf(stderr, "include, in form '1,6,62-122,244-'. If not specified, default is\n");
334 fprintf(stderr, "'1-' (dump every frame). Frame numbers are 1-based.\n");
335 fprintf(stderr, "<algo> gives the algorithm used. Following are supported:\n");
336 fprintf(stderr, "average: Weighted average of covering pixels\n");
337 fprintf(stderr, "lanczos1: Lanczos with alpha = 1\n");
338 fprintf(stderr, "lanczos2: Lanczos with alpha = 2\n");
339 fprintf(stderr, "lanczos3: Lanczos with alpha = 3\n");
340 fprintf(stderr, "lanczos4: Lanczos with alpha = 4\n");
341 fprintf(stderr, "lanczos5: Lanczos with alpha = 5\n");
342 return 1;
344 struct frame_input_stream* in = fis_open(argv[1]);
345 FILE* out = fopen(argv[2], "wb");
346 struct frame* frame;
347 struct frame* aframe = NULL;
348 int num = 1;
350 if(!out) {
351 fprintf(stderr, "Can't open %s\n", argv[2]);
352 exit(1);
355 unsigned long width = read_number(argv[4], "width", 0, 0);
356 unsigned long height = read_number(argv[5], "height", 0, 0);
357 unsigned long framegap = read_number(argv[6], "framegap", 0, 0);
358 uint64_t lastdumped = 0;
360 if(!strcasecmp(argv[3], "average"))
361 algo = ALGO_AVERAGE;
362 else if(!strcasecmp(argv[3], "lanczos1"))
363 algo = ALGO_LANCZOS1;
364 else if(!strcasecmp(argv[3], "lanczos2"))
365 algo = ALGO_LANCZOS2;
366 else if(!strcasecmp(argv[3], "lanczos3"))
367 algo = ALGO_LANCZOS3;
368 else if(!strcasecmp(argv[3], "lanczos4"))
369 algo = ALGO_LANCZOS4;
370 else if(!strcasecmp(argv[3], "lanczos5"))
371 algo = ALGO_LANCZOS5;
372 else {
373 fprintf(stderr, "Error: Unknown resize algorithm '%s'\n", argv[3]);
374 exit(1);
377 if(argc == 8)
378 current_block = parse_framelist(argv[7]);
380 while(1) {
381 struct frame* old_aframe = aframe;
382 frame = fis_next_frame(in);
383 if(!frame) {
384 if(aframe)
385 in_next_block2:
386 if(!current_block || current_block->fe_first > num)
388 else if(current_block->fe_last + 1 == num && num > 1) {
389 current_block = current_block->fe_next;
390 goto in_next_block2;
391 } else
392 dump_frame(out, width, height, aframe, algo);
393 break;
396 old_aframe = aframe;
397 aframe = frame;
398 while(frame->f_timeseq > lastdumped + framegap) {
399 //Check that frame is in list of frames to include.
400 in_next_block:
401 if(!current_block || current_block->fe_first > num)
403 else if(current_block->fe_last + 1 == num && num > 1) {
404 current_block = current_block->fe_next;
405 goto in_next_block;
406 } else {
407 dump_frame(out, width, height, old_aframe, algo);
409 lastdumped += framegap;
410 num++;
412 if(old_aframe)
413 frame_release(old_aframe);
417 if(aframe)
418 frame_release(aframe);
419 fis_close(in);
420 if(fclose(out)) {
421 fprintf(stderr, "Can't close output file!\n");
422 exit(1);