Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
rletoabA62.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1988 Research Institute for Advanced Computer Science.
3  * All rights reserved. The RIACS Software Policy contains specific
4  * terms and conditions on the use of this software, and must be
5  * distributed with any copies. This file may be redistributed. This
6  * copyright and notice must be preserved in all copies made of this file.
7  */
8 
9 /*
10  * rletoabA62
11  * ----------
12  *
13  * This program converts Utah Raster Toolkit files into the dump format of the
14  * Abekas A62 video storage disk.
15  *
16  * Options:
17  * -N ... do no digital filtering.
18  * -n N ... N specifies the number for frames to write
19  * -f N ... N specifies the first frame number (1-4) to write.
20  * -b R G B ... clear background to this color
21  *
22  * Author/Status:
23  * Bob Brown rlb@riacs.edu
24  * First write: 29 Jan 1988
25  *
26  * The interface to the particular raster format used is mostly separated from
27  * the logic of the conversion code. Two routines define the interface:
28  *
29  * rasterInit(fd, width, height)
30  *
31  * This specifies the integer file descriptor for the input file,
32  * the width and the height of the image. It is called exactly once.
33  *
34  * rasterGetRow(red, green, blue)
35  *
36  * This is called to return the next row of the raster. The parameters
37  * point to arrays of unsigned char to hold the RGB values.
38  */
39 static char rcsid[] = "$Header: /l/spencer/src/urt/cnv/rletoabA62/RCS/rletoabA62.c,v 3.0.1.1 1992/04/30 14:15:19 spencer Exp $";
40 /*
41 rletoabA62() Tag the file.
42 */
43 
44 #include <stdio.h>
45 
46 #ifndef TRUE
47 #define TRUE 1
48 #define FALSE 0
49 #endif
50 typedef char bool;
51 
52 /*
53  * Dimensions of the raster image within the A62
54  */
55 
56 #define WIDTH 768
57 #define HEIGHT 512
58 
59 /*
60  * Global variables are always capitalized.
61  *
62  * These are globals set by program arguments. The static initializations are
63  * the default values.
64  */
65 
66 int Width = WIDTH; /* Width of the output image */
67 int Height = HEIGHT; /* Height of the output image */
68 int Debug = 0;
70 int Frame = 1;
71 int NumFrames = 2;
72 int BkgRed = 0;
73 int BkgBlue = 0;
74 int BkgGreen= 0;
75 
76 extern char *optarg; /* interface to getopt() */
77 extern int optind; /* interface to getopt() */
78 
79 typedef struct {
80  char y, i, q;
81 } yiq_t;
82 
83 #ifdef USE_PROTOTYPES
84 extern void rasterInit(int fd, int width, int height);
85 extern void rasterRowGet(unsigned char *red, unsigned char *green, unsigned char *blue);
86 extern void rasterDone(void);
87 extern void filterY(float *yVal, float c0, float c1, float c2);
88 extern void filterIQ(float *iqVal, float c0, float c1, float c2, int start, int stride);
89 extern void dump1(register yiq_t **raster, int start);
90 extern void dump2(register yiq_t **raster, int start);
91 #else
92 extern void rasterInit();
93 extern void rasterRowGet(), rasterDone();
94 extern void filterY();
95 extern void filterIQ();
96 extern void dump1();
97 extern void dump2();
98 #endif
99 
100 /*
101  * Main entry...
102  */
103 
104 void
106 int argc;
107 char **argv;
108 {
109  register int i, j;
110  int errors, c, file;
111  float rTOy[256], gTOy[256], bTOy[256];
112  float rTOi[256], gTOi[256], bTOi[256];
113  float rTOq[256], gTOq[256], bTOq[256];
114  float *iVal, *yVal, *qVal, *tmpVal;
115  unsigned char *red, *green, *blue;
116  int r, g, b;
117  yiq_t **raster;
118 
119  /*
120  * Parse program arguments...
121  *
122  * The -w and -h args should actually not be used.
123  */
124 
125  errors = 0;
126  while ((c = getopt(argc, argv, "Nn:f:w:h:d:D:b")) != EOF) {
127  switch (c) {
128  case 'b':
129  BkgRed = atoi(argv[optind++]);
130  BkgGreen = atoi(argv[optind++]);
131  BkgBlue = atoi(argv[optind++]);
132  break;
133  case 'N':
134  NoFilter = TRUE;
135  break;
136  case 'w':
137  Width = atoi(optarg);
138  break;
139  case 'f':
140  Frame = atoi(optarg);
141  break;
142  case 'n':
143  NumFrames = atoi(optarg);
144  break;
145  case 'h':
146  Height = atoi(optarg);
147  break;
148  case 'D':
149  Debug = atoi(optarg);
150  break;
151  case '?':
152  errors++;
153  }
154  }
155  if (errors > 0) {
156  fprintf(stderr, "Usage: %s [-n] [-D debug-level] [file]\n", argv[0]);
157  exit(1);
158  }
159  if (optind < argc) {
160  if ((file = open(argv[optind], 0)) == -1) {
161  perror(argv[optind]);
162  exit(1);
163  }
164  } else {
165  file = 0;
166  }
167 
168  /*
169  * Initialize the type manager for Utah RLE files
170  */
171 
172  rasterInit(file, Width, Height, BkgRed, BkgGreen, BkgBlue);
173 
174  /*
175  * Allocate storage for the RGB inputs, the computed YIQ, and the
176  * results. This is all dynamically allocated because the dimensions of
177  * the framestore are only decided at run time.
178  *
179  * The YIQ arrays are extended two entries at either end to simplify the
180  * filtering code. The effect is that the iVal and qVal arrays can be
181  * indexed [-2 .. Width+2] and yVal [-4 .. Width+4] (the stuff at the
182  * end of the yVal array isn't used).
183  */
184 
185  red = (unsigned char *) calloc(Width, sizeof *red);
186  green = (unsigned char *) calloc(Width, sizeof *green);
187  blue = (unsigned char *) calloc(Width, sizeof *blue);
188 
189  tmpVal = (float *) calloc(Width + 8, sizeof *yVal);
190  yVal = tmpVal + 4;
191  tmpVal = (float *) calloc(Width + 4, sizeof *iVal);
192  iVal = tmpVal + 2;
193  tmpVal = (float *) calloc(Width + 4, sizeof *qVal);
194  qVal = tmpVal + 2;
195 
196  /*
197  * Allocate storage to hold the 8-bit YIQ values for the entire
198  * picture.
199  */
200 
201  raster = (yiq_t **) calloc(Height, sizeof *raster);
202  for (i = 0; i < Height; i++) {
203  raster[i] = (yiq_t *) calloc(Width, sizeof **raster);
204  }
205 
206  /*
207  * Build the mappings from R,G,B to Y,I,Q. The pedastal is factored
208  * into this mapping.
209  */
210 
211  for (i = 0; i < 256; i++) {
212  rTOy[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.299;
213  gTOy[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.587;
214  bTOy[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.114;
215 
216  rTOi[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.596;
217  gTOi[i] = ((float) i / 255.0 * 0.925 + 0.075) * -0.274;
218  bTOi[i] = ((float) i / 255.0 * 0.925 + 0.075) * -0.322;
219 
220  rTOq[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.211;
221  gTOq[i] = ((float) i / 255.0 * 0.925 + 0.075) * -0.523;
222  bTOq[i] = ((float) i / 255.0 * 0.925 + 0.075) * 0.312;
223  }
224 
225  /*
226  * process the input raster line by raster line
227  */
228 
229  for (i = 0; i < Height; i++) {
230  rasterRowGet(red, green, blue);
231  yVal[-4] = yVal[-3] = yVal[-2] = yVal[-1] = 0;
232  iVal[-2] = iVal[-1] = 0;
233  qVal[-2] = qVal[-1] = 0;
234  yVal[Width + 3] = yVal[Width + 2] = yVal[Width + 1] = yVal[Width + 0] = 0;
235  iVal[Width + 0] = iVal[Width + 1] = 0;
236  qVal[Width + 0] = qVal[Width + 1] = 0;
237 
238  /*
239  * Convert RGB to YIQ. The multiplication is done by table lookup
240  * into the [rgb]TO[yiq] arrays.
241  */
242 
243  for (j = 0; j < Width; j++) {
244  r = red[j];
245  g = green[j];
246  b = blue[j];
247  yVal[j] = rTOy[r] + gTOy[g] + bTOy[b];
248  iVal[j] = rTOi[r] + gTOi[g] + bTOi[b];
249  qVal[j] = rTOq[r] + gTOq[g] + bTOq[b];
250  }
251  if (!NoFilter) {
252  filterY(yVal, 0.62232, 0.21732, -0.02848);
253  filterIQ(iVal, 0.42354, 0.25308, 0.03515, 0, 2);
254  filterIQ(qVal, 0.34594, 0.25122, 0.07581, 1, 2);
255  }
256  /*
257  * Build the YIQ raster
258  */
259 
260  for (j = 0; j < Width; j++) {
261  raster[Height - i - 1][j].y = yVal[j] * 140.0;
262  raster[Height - i - 1][j].i = iVal[j] * 140.0;
263  raster[Height - i - 1][j].q = qVal[j] * 140.0;
264  }
265  }
266 
267  /*
268  * Dump the raster as four color fields.
269  *
270  * Assert that Width%4 ==0 and Height%4 == 0
271  *
272  * Despite what the A62 SCSI manual says, for frames I and IV, the even
273  * numbered lines (starting with line 0) begin Y-I and the others begin
274  * Y+I.
275  */
276 
277  for (i = 0; i < NumFrames; i++) {
278  switch ((i + Frame - 1) % 4 + 1) {
279  case 1:
280  dump2(raster, 0); /* even lines, starts Y-I */
281  break;
282  case 2:
283  dump1(raster, 1); /* odd lines, starts Y+I */
284  break;
285  case 3:
286  dump1(raster, 0); /* even lines, starts Y+I */
287  break;
288  case 4:
289  dump2(raster, 1); /* odd lines, starts Y-I */
290  break;
291  }
292  }
293  exit(0);
294 }
295 
296 /*
297  * filterY
298  * -------
299  *
300  * Apply and RIF filter to the luminance data. The signal is shifted two pixels
301  * to the right in the process.
302  *
303  * The multiplier arrays m0, m1, and m2 exist to reduce the number of floating
304  * point multiplications and to allow the filtering to occur in place.
305  */
306 void
307 filterY(yVal, c0, c1, c2)
308 float *yVal, c0, c1, c2;
309 {
310  static float *m0 = NULL;
311  static float *m1 = NULL;
312  static float *m2 = NULL;
313  register int i;
314 
315  if (m1 == NULL) {
316  m0 = (float *) calloc(Width + 8, sizeof(float));
317  m1 = (float *) calloc(Width + 8, sizeof(float));
318  m2 = (float *) calloc(Width + 8, sizeof(float));
319  }
320  for (i = -4; i < Width + 4; i++) {
321  m0[i] = c0 * yVal[i];
322  m1[i] = c1 * yVal[i];
323  m2[i] = c2 * yVal[i];
324  }
325  for (i = 0; i < Width; i++) {
326  yVal[i] = m2[i - 4] + m1[i - 3] + m0[i - 2] + m1[i - 1] + m2[i];
327  }
328 }
329 /*
330  * filterIQ
331  * --------
332  *
333  * Apply and RIF filter to the color difference data.
334  *
335  * The multiplier arrays m0, m1, and m2 exist to reduce the number of floating
336  * point multiplications and to allow the filtering to occur in place.
337  *
338  * The "start" and "stride" parameters are used to reduce the number of
339  * computations because I and Q are only used every other pixel.
340  *
341  * This is different from the manual in than the filtering is done on adjacent
342  * pixels, rather than every other pixel. This may be a problem...
343  */
344 void
345 filterIQ(iqVal, c0, c1, c2, start, stride)
346 float *iqVal, c0, c1, c2;
347 int start, stride;
348 {
349  static float *m0 = NULL;
350  static float *m1 = NULL;
351  static float *m2 = NULL;
352  register int i;
353 
354  if (m1 == NULL) {
355  m0 = (float *) calloc(Width + 4, sizeof(float));
356  m1 = (float *) calloc(Width + 4, sizeof(float));
357  m2 = (float *) calloc(Width + 4, sizeof(float));
358  }
359  for (i = -2; i < Width + 2; i++) {
360  m0[i] = c0 * iqVal[i];
361  m1[i] = c1 * iqVal[i];
362  m2[i] = c2 * iqVal[i];
363  }
364  for (i = start; i < Width; i += stride) {
365  iqVal[i] = m2[i - 2] + m1[i - 1] + m0[i] + m1[i + 1] + m2[i + 2];
366  }
367 }
368 
369 /*
370  * dump1
371  * -----
372  *
373  * Dumps the raster starting with the sequence Y+I Y+Q Y-I Y-Q
374  *
375  * This routine also adds 60 to put the data in the 60 .. 200 range.
376  */
377 
378 #define OUT(y, OP, iq) putc((char) (raster[i][j + 0].y OP raster[i][j + 0].iq + 60), stdout);
379 void
380 dump1(raster, start)
381 register yiq_t **raster;
382 int start;
383 {
384  register int i, j;
385 
386  for (i = start; i < Height; i += 4) { /* field I */
387  for (j = 0; j < Width; j += 4) {
388  putc((char) (raster[i][j + 0].y + raster[i][j + 0].i + 60), stdout);
389  putc((char) (raster[i][j + 1].y + raster[i][j + 1].q + 60), stdout);
390  putc((char) (raster[i][j + 2].y - raster[i][j + 2].i + 60), stdout);
391  putc((char) (raster[i][j + 3].y - raster[i][j + 3].q + 60), stdout);
392  }
393  for (j = 0; j < Width; j += 4) {
394  putc((char) (raster[i + 2][j + 0].y - raster[i + 2][j + 0].i + 60), stdout);
395  putc((char) (raster[i + 2][j + 1].y - raster[i + 2][j + 1].q + 60), stdout);
396  putc((char) (raster[i + 2][j + 2].y + raster[i + 2][j + 2].i + 60), stdout);
397  putc((char) (raster[i + 2][j + 3].y + raster[i + 2][j + 3].q + 60), stdout);
398  }
399  }
400 }
401 
402 /*
403  * dump2
404  * -----
405  *
406  * Dumps the raster starting with the sequence Y-I Y-Q Y+I Y+Q
407  *
408  * This routine also adds 60 to put the data in the 60 .. 200 range.
409  */
410 
411 void
412 dump2(raster, start)
413 register yiq_t **raster;
414 int start;
415 {
416  register int i, j;
417 
418  for (i = start; i < Height; i += 4) { /* field I */
419  for (j = 0; j < Width; j += 4) {
420  putc((char) (raster[i][j + 0].y - raster[i][j + 0].i + 60), stdout);
421  putc((char) (raster[i][j + 1].y - raster[i][j + 1].q + 60), stdout);
422  putc((char) (raster[i][j + 2].y + raster[i][j + 2].i + 60), stdout);
423  putc((char) (raster[i][j + 3].y + raster[i][j + 3].q + 60), stdout);
424  }
425  for (j = 0; j < Width; j += 4) {
426  putc((char) (raster[i + 2][j + 0].y + raster[i + 2][j + 0].i + 60), stdout);
427  putc((char) (raster[i + 2][j + 1].y + raster[i + 2][j + 1].q + 60), stdout);
428  putc((char) (raster[i + 2][j + 2].y - raster[i + 2][j + 2].i + 60), stdout);
429  putc((char) (raster[i + 2][j + 3].y - raster[i + 2][j + 3].q + 60), stdout);
430  }
431  }
432 }
static char rcsid[]
Definition: rletoabA62.c:39
char y
Definition: rletoabA62.c:80
void main(int argc, char **argv)
Definition: aliastorle.c:121
#define FALSE
Definition: giftorle.c:39
int optind
Definition: getopt.c:30
char q
Definition: rletoabA62.c:80
int BkgBlue
Definition: rletoabA62.c:73
char bool
Definition: rletoabA62.c:50
int BkgGreen
Definition: rletoabA62.c:74
#define TRUE
Definition: giftorle.c:38
#define HEIGHT
Definition: rletoabA62.c:57
int Frame
Definition: rletoabA62.c:70
int BkgRed
Definition: rletoabA62.c:72
#define WIDTH
Definition: rletoabA62.c:56
int NumFrames
Definition: rletoabA62.c:71
int Height
Definition: rletoabA62.c:67
bool Debug
Definition: rleClock.c:116
bool NoFilter
Definition: rletoabA62.c:69
char * optarg
Definition: getopt.c:29
int Width
Definition: rletoabA62.c:66
char i
Definition: rletoabA62.c:80