1 /*
2 * getbob.c - Read RLE files onto hp bobcat screens.
3 *
4 * Author: Mark Bloomenthal
5 * Computer Science Dept.
6 * University of Utah
7 * Date: Fri Oct 17 1986
8 * Copyright (c) 1986, University of Utah
9 *
10 * Most code lifted from J W. Peterson.
11 *
12 * Flags are:
13 * -l Linear map
14 * -g gam Gammap map, use gamma of gam (floating point number)
15 * -d device Use the device specified.
16 * -x driver Use the driver specified.
17 * -p x y Position image lower left hand corner on the display. The
18 * x and y position is given in pixels with the origin taken as
19 * the lower left hand corner of the display. This flag is only
20 * useful with the -D, -d, and/or -x flags.
21 *
22 */
23
24 #include "starbase.c.h"
25 #include <stdio.h>
26 #include <math.h>
27 #include <fcntl.h>
28 #include "rle.h"
29
30 typedef char * string; /* Character Strings. */
31 typedef int boolean; /* Logical vars or values. */
32 #define TRUE 1 /* Logical constants. */
33 #define FALSE 0
34 typedef float single;
35 #define MAX(i,j) ( (i) > (j) ? (i) : (j) )
36
37
38 /* Some starbase type definitions. */
39 typedef single starbase_color_type[3];
40 typedef unsigned char starbase_color_index_type;
41
42 #define RASTERSIZE_LIM 1023
43
44 /* Standard color map offset. */
45 #define COLMAP_OFFSET 8
46
47 /* Color modes. */
48 #define MONOCHROME_MODE 1
49 #define EIGHT_BIT_COLOR_MODE 2
50
51 /* Scanline storage & RLE row pointers */
52 unsigned char scanline[4][RASTERSIZE_LIM], *rows[4];
53
54 /* Scanline to be written to device. */
55 starbase_color_index_type dest_pixels[RASTERSIZE_LIM]; /* avoid bludging stack */
56
57 /* Dither matrix. */
58 int dm16[16][16];
59
60 /* Tables for quantization. */
61 int errN[256], divN[256];
62
63 /* The gamma map and default gamma. */
64 int gammamap[256];
65 float gam = 2.0;
66
67 /* Input filename. */
68 string infname = NULL;
69
70 /* Image header. */
71 rle_hdr hdr;
72
73 /* Color map flags. */
74 boolean linear_flag = FALSE;
75 boolean gamma_flag = FALSE;
76
77 boolean dummy;
78
79 /* The default device and device driver. */
80 string display_name = "/dev/crt";
81 string driver_name = "hp98705";
82
83 /* For positioning the image on the display. */
84 boolean pos_flag;
85 int pic_x = 0;
86 int pic_y = 0;
87
88 /* How many bits in the devices color map. */
89 int dev_color_map_size;
90
91 /* What mode to dither into. Either 8 bit color or monochrome. */
92 int put_mode;
93
94 /* Color map to be written to device. */
95 int n_colmap_colors;
96 static starbase_color_type colmap[216];
97
98 /* The color to be used in case we do monochrome. */
99 float r_base_color = 1.0;
100 float g_base_color = 1.0;
101 float b_base_color = 1.0;
102
103 /* Starbase file descriptor for device where the picture goes. */
104 int picture_fd;
105
106
main(argc,argv)107 main( argc, argv)
108 int argc; char *argv[];
109 {
110 int i;
111 int row;
112 boolean bw_flag = FALSE;
113
114 /* sbrk( 1000000 ); */
115
116 /* Get command line arguments. */
117 if ( scanargs( argc, argv,
118 "getbob l%- g%-gamma!f p%-pos!d!d d%-display!s x%-driver!s file%s",
119 &linear_flag, &gamma_flag, &gam,
120 &pos_flag, &pic_x, &pic_y,
121 &dummy, &display_name,
122 &dummy, &driver_name,
123 &infname ) == 0 )
124 exit( 1 );
125
126 /* Open file for reading, if no filename was specified, we'll read
127 * from stdin.
128 */
129 hdr = *rle_hdr_init( (rle_hdr *)NULL );
130 rle_names( &hdr, cmd_name( argv ), infname, 0 );
131 hdr.rle_file = rle_open_f(hdr.cmd, infname, "r");
132 /* Read header information from rle file. */
133 rle_get_setup_ok( &hdr, NULL, NULL );
134
135 RLE_CLR_BIT( hdr, RLE_ALPHA ); /* No alpha channel */
136
137 /* Set up gamma correction tables if need be. */
138 init_gamma_map();
139
140 direct_setup();
141
142 /* Set up rows to point to our copy of the scanline */
143 for ( i= 0; i < 4; i++ )
144 rows[i] = scanline[i];
145
146 /* Get the scanlines. */
147 for (i = hdr.ymin; i < hdr.ymax; i++)
148 {
149 rle_getrow( &hdr, rows );
150 if ( put_mode == MONOCHROME_MODE )
151 put_line_mono( i );
152 else
153 put_line_8( i );
154 }
155 }
156
157
158
159 /*****************************************************************
160 * TAG( init_gamma_map )
161 *
162 * Compute a gamma correction map.
163 */
164
init_gamma_map()165 init_gamma_map()
166 {
167 int i;
168
169 /* Compute a gamma correction map. */
170 for ( i = 0; i < 256; i++ )
171 {
172 if ( ! linear_flag )
173 {
174 gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gam ));
175 }
176 }
177 }
178
179
180
181 /*****************************************************************
182 * TAG( init_8_bit_color_map )
183 *
184 * Initialize the 8 bit color map.
185 */
186
init_8_bit_color_map()187 init_8_bit_color_map()
188 {
189 int i;
190
191 /*
192 * Set up the color map entries. We will use 216 colors.
193 */
194 n_colmap_colors = 216; /* Fill out the global. */
195
196 for ( i = 0; i < n_colmap_colors; i++ )
197 {
198 colmap[i][0] = ((i%6) * 51) / 255.0;
199 colmap[i][1] = (((i/6)%6) * 51) / 255.0;
200 colmap[i][2] = (((i/36)%6) * 51) / 255.0;
201 }
202
203 make_square( 6.0, divN, errN, dm16 );
204 }
205
206
207
208 /*****************************************************************
209 * TAG( init_monochrome_color_map )
210 *
211 * Initialize the monochrome color map. This is for devices with
212 * color maps too small to do good color dithering. The argument
213 * ncolors is the number of colors of the devices color map that
214 * may be used for dithering.
215 */
216
init_monochrome_color_map(ncolors)217 init_monochrome_color_map( ncolors )
218 int ncolors;
219 {
220 int k;
221 int color_val;
222
223 /* Set up the color map entries into a single grayscale ramp. */
224 n_colmap_colors = ncolors; /* Fill out the global. */
225
226 for ( k = 0; k < ncolors; k++ )
227 {
228 color_val = (k * 255) / (ncolors - 1);
229 colmap[k][0] = (color_val * r_base_color) / 255.;
230 colmap[k][1] = (color_val * g_base_color) / 255.;
231 colmap[k][2] = (color_val * b_base_color) / 255.;
232 }
233
234 /* Make dithering tables. */
235 make_square( (double)ncolors, divN, errN, dm16 );
236 }
237
238
239
240 #define DMAP(v,x,y) (errN[v]>dm16[x][y] ? divN[v] + 1 : divN[v])
241
242 /*****************************************************************
243 * TAG( put_line_8 )
244 *
245 * Map a 24 bit scanline to 8 bits through the dither matrix.
246 */
247
put_line_8(y)248 put_line_8( y )
249 int y;
250 {
251 register unsigned char *r, *g, *b;
252 register int i, dither_col, dither_row;
253 register starbase_color_index_type *dest_pixel_ptr;
254 int xmax = hdr.xmax;
255 int g_offset, b_offset;
256
257
258 /* In case we have less than 3 color channels. */
259 for (i = 2; i >= hdr.ncolors; i--)
260 bcopy(rows[0], rows[i], hdr.xmax - hdr.xmin);
261
262 dither_row = y % 16;
263 dither_col = 0;
264 r = rows[0];
265 g = rows[1];
266 b = rows[2];
267 dest_pixel_ptr = &dest_pixels[0];
268
269 /* Linear map. */
270 if ( linear_flag )
271 for ( i = 0; i < xmax; i++, r++, g++, b++,
272 dither_col = ((dither_col + 1) & 15),
273 dest_pixel_ptr++ )
274 *dest_pixel_ptr =
275 DMAP( *r, dither_col, dither_row ) +
276 DMAP( *g, dither_col, dither_row ) * 6 +
277 DMAP( *b, dither_col, dither_row ) * 36 +
278 COLMAP_OFFSET;
279
280 /* RLE file with color map. */
281 else if ( hdr.ncmap )
282 {
283 /* Compute offsets to the green and blue sections of the color map. */
284 g_offset = 1 << hdr.cmaplen;
285 b_offset = 2 * g_offset;
286
287 for ( i = 0; i < xmax; i++, r++, g++, b++,
288 dither_col = ((dither_col + 1) & 15),
289 dest_pixel_ptr++ )
290 *dest_pixel_ptr =
291 DMAP( hdr.cmap[*r], dither_col, dither_row ) +
292 DMAP( hdr.cmap[*g + g_offset],
293 dither_col, dither_row ) * 6 +
294 DMAP( hdr.cmap[*b + b_offset],
295 dither_col, dither_row ) * 36 +
296 COLMAP_OFFSET;
297 }
298
299 /* Gamma correction is the default. */
300 else
301 for ( i = 0; i < xmax; i++, r++, g++, b++,
302 dither_col = ((dither_col + 1) & 15),
303 dest_pixel_ptr++ )
304 *dest_pixel_ptr =
305 DMAP( gammamap[*r], dither_col, dither_row ) +
306 DMAP( gammamap[*g], dither_col, dither_row ) * 6 +
307 DMAP( gammamap[*b], dither_col, dither_row ) * 36 +
308 COLMAP_OFFSET;
309
310 /* Write this scanline to the device. */
311 write_scanline( y );
312 }
313
314
315
316 /*****************************************************************
317 * TAG( put_line_mono )
318 *
319 * For small color maps. Dither into monochrome.
320 */
321
put_line_mono(y)322 put_line_mono( y )
323 int y;
324 {
325 register unsigned char *r, *g, *b;
326 register int i, dither_col, dither_row;
327 register starbase_color_index_type *dest_pixel_ptr;
328 int xmax = hdr.xmax;
329 int bw_val;
330 int g_offset, b_offset;
331
332 /* In case we have less than 3 color channels. */
333 for (i = 2; i >= hdr.ncolors; i--)
334 bcopy(rows[0], rows[i], hdr.xmax - hdr.xmin);
335
336 dither_row = y % 16;
337 dither_col = 0;
338 r = rows[0];
339 g = rows[1];
340 b = rows[2];
341 dest_pixel_ptr = &dest_pixels[0];
342
343 /* Linear map. */
344 if ( linear_flag )
345 for ( i = 0; i < xmax; i++, r++, g++, b++,
346 dither_col = ((dither_col + 1) & 15),
347 dest_pixel_ptr++ )
348 {
349 bw_val =
350 (35*(*r) + 55*(*g) + 10*(*b)) / 100;
351 *dest_pixel_ptr =
352 DMAP( bw_val, dither_col, dither_row ) + COLMAP_OFFSET;
353 }
354
355 /* RLE file with color map. */
356 else if ( hdr.ncmap )
357 {
358 /* Compute offsets to the green and blue sections of the color map. */
359 g_offset = 1 << hdr.cmaplen;
360 b_offset = 2 * g_offset;
361
362 for ( i = 0; i < xmax; i++, r++, g++, b++,
363 dither_col = ((dither_col + 1) & 15),
364 dest_pixel_ptr++ )
365 {
366 bw_val =
367 ( 35 * hdr.cmap[*r] +
368 55 * hdr.cmap[*g + g_offset] +
369 10 * hdr.cmap[*b + b_offset] ) / 100;
370 *dest_pixel_ptr =
371 DMAP( bw_val, dither_col, dither_row ) + COLMAP_OFFSET;
372 }
373 }
374
375 /* Gamma correction is the default. */
376 else
377 for ( i = 0; i < xmax; i++, r++, g++, b++,
378 dither_col = ((dither_col + 1) & 15),
379 dest_pixel_ptr++ )
380 {
381 bw_val =
382 (35*gammamap[*r] + 55*gammamap[*g] + 10*gammamap[*b]) / 100;
383 *dest_pixel_ptr =
384 DMAP( bw_val, dither_col, dither_row ) + COLMAP_OFFSET;
385 }
386
387 /* Write this scanline to the device. */
388 write_scanline( y );
389 }
390
391
392
393 /*****************************************************************
394 * TAG( direct_setup )
395 *
396 * Use starbase to talk directly to graphics device.
397 */
398
direct_setup()399 direct_setup()
400 {
401 single p_lim[2][3], res[3], p1[3], p2[3];
402 int map_size;
403 int dev_xmax, dev_ymax;
404
405 picture_fd = gopen( display_name, OUTDEV, driver_name, 0 );
406 if ( picture_fd < 0 )
407 {
408 fprintf( stderr, "Can't open device.\n" );
409 exit( 1 );
410 }
411
412 /* Find out info about this device. */
413 inquire_sizes( picture_fd, p_lim, res, p1, p2, &map_size );
414
415 if ( map_size >= 256 )
416 {
417 put_mode = EIGHT_BIT_COLOR_MODE;
418 init_8_bit_color_map();
419 }
420 else
421 {
422 put_mode = MONOCHROME_MODE;
423 init_monochrome_color_map( map_size - COLMAP_OFFSET );
424 }
425
426 write_color_map( picture_fd );
427
428 /* Set the screen limits in pixels so we can use starbase in a device
429 * independent way.
430 *
431 * It is assumed that the p_lim values returned by inquire_sizes are the
432 * lower left screen coordinates in (float) pixels and the upper right
433 * screen coordinates in (float) pixels. It is also assumed that the
434 * range of values in x and y coordinates are given from 0 to some
435 * positive maximum value.
436 */
437 dev_xmax = MAX( p_lim[0][0], p_lim[1][0] );
438 dev_ymax = MAX( p_lim[0][1], p_lim[1][1] );
439
440 if ( hdr.xmax > dev_xmax )
441 hdr.xmax = dev_xmax;
442 if ( hdr.ymax > dev_ymax )
443 hdr.ymax = dev_ymax;
444
445 /* Make sure that the specified lower left hand corner of the image
446 * will keep the image in bounds.
447 */
448 if ( ( hdr.xmax + pic_x ) > dev_xmax )
449 pic_x = dev_xmax - hdr.xmax;
450 if ( ( hdr.ymax + pic_y ) > dev_ymax )
451 pic_y = dev_ymax - hdr.ymax;
452
453 /* Set to use the whole display surface. */
454 mapping_mode( picture_fd, DISTORT );
455
456 /* Set to address the pixels in a device independent way. */
457 vdc_extent( picture_fd, 0.0, 0.0, 0.0,
458 (single)dev_xmax, (single)dev_ymax, 0.0 );
459 clip_rectangle( picture_fd, 0.0, (single)dev_xmax, 0.0, (single)dev_ymax );
460
461 }
462
463
464
465 /*****************************************************************
466 * TAG( write_color_map )
467 *
468 * Write color map to device.
469 *
470 */
471
write_color_map(star_fd)472 write_color_map( star_fd )
473 int star_fd;
474 {
475 define_color_table( star_fd, COLMAP_OFFSET, n_colmap_colors, colmap );
476
477 }
478
479
480
481 /*****************************************************************
482 * TAG( write_scanline )
483 *
484 * Write scanline to device.
485 *
486 */
487
write_scanline(y)488 write_scanline( y )
489 int y;
490 {
491 block_write( picture_fd,
492 (single)(hdr.xmin + pic_x), (single)(y + pic_y),
493 hdr.xmax - hdr.xmin, 1,
494 dest_pixels, FALSE );
495 }
496
497
498 #ifdef NEED_BSTRING
499
500 /*****************************************************************
501 * TAG( bcopy )
502 *
503 * Move contents of a block to a new location.
504 * For systems without a bcopy system routine.
505 */
bcopy(src_ptr,dst_ptr,size)506 void bcopy( src_ptr, dst_ptr, size )
507 register int * src_ptr, * dst_ptr;
508 int size;
509 {
510 register int words;
511 register char * byte_src_ptr, * byte_dst_ptr;
512 register int bytes;
513
514 /* Tight word copy loop for most or all of the block. */
515 words=size/sizeof(int);
516 bytes = size - words*sizeof(int);
517 while ( words-- )
518 *dst_ptr++ = *src_ptr++;
519
520 /* Tight byte copy loop for the remainder. */
521 byte_src_ptr = (char *)src_ptr;
522 byte_dst_ptr = (char *)dst_ptr;
523 while ( bytes-- )
524 *byte_dst_ptr++ = *byte_src_ptr++;
525 }
526 #endif
527