1 /*
2 * Utah RLE Toolkit library routines.
3 *
4 * Read image support only.
5 *
6 * Cobbled from Utah RLE include and library source files.
7 *
8 * By Graeme Gill
9 * 30/5/90
10 *
11 */
12
13 #include <stdio.h>
14 #include <math.h>
15 #include <ctype.h>
16
17 #include "image.h" /* need ZFILE definition */
18 #include "rle.h"
19 #include "rlelib.h"
20
21 /* SUPPRESS 530 */
22 /* SUPPRESS 558 */
23 /* SUPPRESS 590 */
24
25 #define zeof(zfp) feof((zfp)->stream)
26 #define zclearerr(zfp) clearerr((zfp)->stream)
27
28 /*
29 * This software is copyrighted as noted below. It may be freely copied,
30 * modified, and redistributed, provided that the copyright notice is
31 * preserved on all copies.
32 *
33 * There is no warranty or other guarantee of fitness for this software,
34 * it is provided solely "as is". Bug reports or fixes may be sent
35 * to the author, who may or may not act on them as he desires.
36 *
37 * You may not include this software in a program or other software product
38 * without supplying the source, or without informing the end-user that the
39 * source is available for no extra charge.
40 *
41 * If you modify this software, you should include a notice giving the
42 * name of the person performing the modification, the date of modification,
43 * and the reason for such modification.
44 */
45 /*
46 * Runsv.h - Definitions for Run Length Encoding.
47 *
48 * Author: Spencer W. Thomas
49 * Computer Science Dept.
50 * University of Utah
51 * Date: Mon Aug 9 1982
52 * Copyright (c) 1982 Spencer W. Thomas
53 */
54
55 #ifndef XTNDRUNSV
56 #define XTNDRUNSV
57
58 /*
59 * Opcode definitions
60 */
61
62 #define LONG 0x40
63 #define RSkipLinesOp 1
64 #define RSetColorOp 2
65 #define RSkipPixelsOp 3
66 #define RByteDataOp 5
67 #define RRunDataOp 6
68 #define REOFOp 7
69
70 #define H_CLEARFIRST 0x1 /* clear framebuffer flag */
71 #define H_NO_BACKGROUND 0x2 /* if set, no bg color supplied */
72 #define H_ALPHA 0x4 /* if set, alpha channel (-1) present */
73 #define H_COMMENT 0x8 /* if set, comments present */
74
75 struct XtndRsetup
76 {
77 short h_xpos,
78 h_ypos,
79 h_xlen,
80 h_ylen;
81 char h_flags,
82 h_ncolors,
83 h_pixelbits,
84 h_ncmap,
85 h_cmaplen;
86 };
87 #define SETUPSIZE ((4*2)+5)
88
89 /* "Old" RLE format magic numbers */
90 #define RMAGIC ('R' << 8) /* top half of magic number */
91 #define WMAGIC ('W' << 8) /* black&white rle image */
92
93 #define XtndRMAGIC ((short)0xcc52) /* RLE file magic number */
94
95 #endif /* XTNDRUNSV */
96
97 /* "svfb.h" */
98 /*
99 * This software is copyrighted as noted below. It may be freely copied,
100 * modified, and redistributed, provided that the copyright notice is
101 * preserved on all copies.
102 *
103 * There is no warranty or other guarantee of fitness for this software,
104 * it is provided solely "as is". Bug reports or fixes may be sent
105 * to the author, who may or may not act on them as he desires.
106 *
107 * You may not include this software in a program or other software product
108 * without supplying the source, or without informing the end-user that the
109 * source is available for no extra charge.
110 *
111 * If you modify this software, you should include a notice giving the
112 * name of the person performing the modification, the date of modification,
113 * and the reason for such modification.
114 */
115 /*
116 * svfb.h - Definitions and a few global variables for svfb.
117 *
118 * Author: Spencer W. Thomas
119 * Computer Science Dept.
120 * University of Utah
121 * Date: Mon Aug 9 1982
122 * Copyright (c) 1982 Spencer W. Thomas
123 */
124
125 /* ****************************************************************
126 * Dispatch table for different output types.
127 */
128 typedef void sv_fn();
129 struct sv_dispatch_tab {
130 char *magic; /* magic type flags */
131 sv_fn *setup, /* startup function */
132 *skipBlankLines,
133 *setColor,
134 *skipPixels,
135 *newScanLine,
136 *putdat, /* put a set of differing pixels */
137 *putrn, /* put a run all the same */
138 *blockHook, /* hook called at start of new */
139 /* output block */
140 *putEof; /* write EOF marker (if possible) */
141 };
142
143 /*
144 * These definitions presume the existence of a variable called
145 * "fileptr", declared "long * fileptr". *fileptr should be
146 * initialized to 0 before calling Setup().
147 * A pointer "globals" declared "struct sv_globals * globals" is also
148 * presumed to exist.
149 */
150 #define sv_magic (sv_DTable[(int)globals->sv_dispatch].magic)
151 #define Setup() (*sv_DTable[(int)globals->sv_dispatch].setup)(globals)
152 #define SkipBlankLines(n) (*sv_DTable[(int)globals->sv_dispatch].skipBlankLines)(n, globals)
153 #define SetColor(c) (*sv_DTable[(int)globals->sv_dispatch].setColor)(c, globals)
154 #define SkipPixels(n, l, r) (*sv_DTable[(int)globals->sv_dispatch].skipPixels)(n,l,r, globals)
155 #define NewScanLine(flag) (*sv_DTable[(int)globals->sv_dispatch].newScanLine)(flag, globals)
156 #define putdata(buf, len) (*sv_DTable[(int)globals->sv_dispatch].putdat)(buf, len, globals)
157 #define putrun(val, len, f) (*sv_DTable[(int)globals->sv_dispatch].putrn)(val,len,f, globals)
158 #define BlockHook() (*sv_DTable[(int)globals->sv_dispatch].blockHook)(globals)
159 #define PutEof() (*sv_DTable[(int)globals->sv_dispatch].putEof)(globals)
160
161 /*
162 * States for run detection
163 */
164 #define DATA 0
165 #define RUN2 1
166 #define RUN3 2
167 #define RUN4 3
168 #define INRUN -1
169
170 /*
171 * This software is copyrighted as noted below. It may be freely copied,
172 * modified, and redistributed, provided that the copyright notice is
173 * preserved on all copies.
174 *
175 * There is no warranty or other guarantee of fitness for this software,
176 * it is provided solely "as is". Bug reports or fixes may be sent
177 * to the author, who may or may not act on them as he desires.
178 *
179 * You may not include this software in a program or other software product
180 * without supplying the source, or without informing the end-user that the
181 * source is available for no extra charge.
182 *
183 * If you modify this software, you should include a notice giving the
184 * name of the person performing the modification, the date of modification,
185 * and the reason for such modification.
186 *
187 * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
188 * to have all "void" functions so declared.
189 */
190 /*
191 * svfb_global.c - Global variable initialization for svfb routines.
192 *
193 * Author: Spencer W. Thomas
194 * Computer Science Dept.
195 * University of Utah
196 * Date: Thu Apr 25 1985
197 * Copyright (c) 1985,1986 Spencer W. Thomas
198 */
199
200
201 void RunSetup(),
202 RunSkipBlankLines(),
203 RunSetColor(),
204 RunSkipPixels(),
205 RunNewScanLine(),
206 Runputdata(),
207 Runputrun(),
208 RunputEof();
209
210 void DefaultBlockHook();
211 void NullputEof();
212
213 struct sv_dispatch_tab sv_DTable[10] = {
214 {
215 " OB",
216 RunSetup,
217 RunSkipBlankLines,
218 RunSetColor,
219 RunSkipPixels,
220 RunNewScanLine,
221 Runputdata,
222 Runputrun,
223 DefaultBlockHook,
224 RunputEof
225 },
226 };
227
228 static int sv_bg_color[3] = { 0, 0, 0 };
229
230 struct sv_globals sv_globals = {
231 RUN_DISPATCH, /* dispatch value */
232 3, /* 3 colors */
233 sv_bg_color, /* background color */
234 0, /* (alpha) if 1, save alpha channel */
235 2, /* (background) 0->just save pixels, */
236 /* 1->overlay, 2->clear to bg first */
237 0, 511, /* (xmin, xmax) X bounds to save */
238 0, 479, /* (ymin, ymax) Y bounds to save */
239 0, /* ncmap (if != 0, save color map) */
240 8, /* cmaplen (log2 of length of color map) */
241 NULL, /* pointer to color map */
242 NULL, /* pointer to comment strings */
243 NULL, /* output file */
244 { 7 } /* RGB channels only */
245 /* Can't initialize the union */
246 };
247
248 /* ARGSUSED */
249 void
NullputEof(globals)250 NullputEof(globals)
251 struct sv_globals * globals;
252 {
253 /* do nothing */
254 }
255
256 /*
257 * This software is copyrighted as noted below. It may be freely copied,
258 * modified, and redistributed, provided that the copyright notice is
259 * preserved on all copies.
260 *
261 * There is no warranty or other guarantee of fitness for this software,
262 * it is provided solely "as is". Bug reports or fixes may be sent
263 * to the author, who may or may not act on them as he desires.
264 *
265 * You may not include this software in a program or other software product
266 * without supplying the source, or without informing the end-user that the
267 * source is available for no extra charge.
268 *
269 * If you modify this software, you should include a notice giving the
270 * name of the person performing the modification, the date of modification,
271 * and the reason for such modification.
272 *
273 * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
274 * to have all "void" functions so declared.
275 */
276 /*
277 * Runsv.c - General purpose Run Length Encoding for svfb.
278 *
279 * Author: Spencer W. Thomas
280 * Computer Science Dept.
281 * University of Utah
282 * Date: Mon Aug 9 1982
283 * Copyright (c) 1982,1986 Spencer W. Thomas
284 */
285
286 /* THIS IS WAY OUT OF DATE. See rle.5.
287 * The output file format is:
288 *
289 * Word 0: A "magic" number. The top byte of the word contains
290 * the letter 'R' or the letter 'W'. 'W' indicates that
291 * only black and white information was saved. The bottom
292 * byte is one of the following:
293 * ' ': Means a straight "box" save, -S flag was given.
294 * 'B': Image saved with background color, clear screen to
295 * background before restoring image.
296 * 'O': Image saved in overlay mode.
297 *
298 * Words 1-6: The structure
299 * { short xpos, * Lower left corner
300 * ypos,
301 * xsize, * Size of saved box
302 * ysize;
303 * char rgb[3]; * Background color
304 * char map; * flag for map presence
305 * }
306 *
307 * If the map flag is non-zero, then the color map will follow as
308 * 3*256 16 bit words, first the red map, then the green map, and
309 * finally the blue map.
310 *
311 * Following the setup information is the Run Length Encoded image.
312 * Each instruction consists of a 4-bit opcode, a 12-bit datum and
313 * possibly one or more following words (all words are 16 bits). The
314 * instruction opcodes are:
315 *
316 * SkipLines (1): The bottom 10 bits are an unsigned number to be added to
317 * current Y position.
318 *
319 * SetColor (2): The datum indicates which color is to be loaded with
320 * the data described by the following ByteData and
321 * RunData instructions. 0->red, 1->green, 2->blue. The
322 * operation also resets the X position to the initial
323 * X (i.e. a carriage return operation is performed).
324 *
325 * SkipPixels (3): The bottom 10 bits are an unsigned number to be
326 * added to the current X position.
327 *
328 * ByteData (5): The datum is one less than the number of bytes of
329 * color data following. If the number of bytes is
330 * odd, a filler byte will be appended to the end of
331 * the byte string to make an integral number of 16-bit
332 * words. The bytes are in PDP-11 order. The X
333 * position is incremented to follow the last byte of
334 * data.
335 *
336 * RunData (6): The datum is one less than the run length. The
337 * following word contains (in its lower 8 bits) the
338 * color of the run. The X position is incremented to
339 * follow the last byte in the run.
340 */
341
342 #define UPPER 255 /* anything bigger ain't a byte */
343
344 /* Predefine LITTLE_ENDIAN for vax and pdp11 machines */
345 #if defined(vax) || defined(pdp11)
346 #define LITTLE_ENDIAN
347 #endif
348
349 /*
350 * Macros to make writing instructions with correct byte order easier.
351 */
352 union { short s; char c[2]; } arg;
353 #ifdef LITTLE_ENDIAN
354 #define put16(a) arg.s=a,putc(arg.c[0],sv_fd), putc(arg.c[1],sv_fd)
355 #else
356 #define put16(a) arg.s=a,putc(arg.c[1],sv_fd), putc(arg.c[0],sv_fd)
357 #endif
358
359 /* short instructions */
360 #define mk_short_1(oper,a1) /* one argument short */ \
361 putc(oper,sv_fd), putc((char)a1,sv_fd)
362
363 #define mk_short_2(oper,a1,a2) /* two argument short */ \
364 putc(oper,sv_fd), putc((char)a1,sv_fd), put16(a2)
365
366 /* long instructions */
367 #define mk_long_1(oper,a1) /* one argument long */ \
368 putc((char)(LONG|oper),sv_fd), putc('\0', sv_fd), put16(a1)
369
370 #define mk_long_2(oper,a1,a2) /* two argument long */ \
371 putc((char)(LONG|oper),sv_fd), putc('\0', sv_fd), \
372 put16(a1), put16(a2)
373
374 /* choose between long and short format instructions */
375 /* NOTE: these macros can only be used where a STATEMENT is legal */
376
377 #define mk_inst_1(oper,a1) /* one argument inst */ \
378 if (a1>UPPER) (mk_long_1(oper,a1)); else (mk_short_1(oper,a1))
379
380 #define mk_inst_2(oper,a1,a2) /* two argument inst */ \
381 if (a1>UPPER) (mk_long_2(oper,a1,a2)); else (mk_short_2(oper,a1,a2))
382
383 /*
384 * Opcode definitions
385 */
386 #define RSkipLines(n) mk_inst_1(RSkipLinesOp,(n))
387
388 #define RSetColor(c) mk_short_1(RSetColorOp,(c))
389 /* has side effect of performing */
390 /* "carriage return" action */
391
392 #define RSkipPixels(n) mk_inst_1(RSkipPixelsOp,(n))
393
394 #define RNewLine RSkipLines(1)
395
396 #define RByteData(n) mk_inst_1(RByteDataOp,n)
397 /* followed by ((n+1)/2)*2 bytes */
398 /* of data. If n is odd, last */
399 /* byte will be ignored */
400 /* "cursor" is left at pixel */
401 /* following last pixel written */
402
403 #define RRunData(n,c) mk_inst_2(RRunDataOp,(n),(c))
404 /* next word contains color data */
405 /* "cursor" is left at pixel after */
406 /* end of run */
407
408 #define REOF mk_inst_1(REOFOp,0)
409 /* Really opcode only */
410
411 /*****************************************************************
412 * TAG( RunSetup )
413 * Put out initial setup data for RLE svfb files.
414 */
415 void
RunSetup(globals)416 RunSetup(globals)
417 register struct sv_globals * globals;
418 {
419 }
420
421 /*****************************************************************
422 * TAG( RunSkipBlankLines )
423 * Skip one or more blank lines in the RLE file.
424 */
425 void
RunSkipBlankLines(nblank,globals)426 RunSkipBlankLines(nblank, globals)
427 register struct sv_globals * globals;
428 {
429 }
430
431 /*****************************************************************
432 * TAG( RunSetColor )
433 * Select a color and do carriage return.
434 * color: 0 = Red, 1 = Green, 2 = Blue.
435 */
436 void
RunSetColor(c,globals)437 RunSetColor(c, globals)
438 register struct sv_globals * globals;
439 {
440 }
441
442 /*****************************************************************
443 * TAG( RunSkipPixels )
444 * Skip a run of background.
445 */
446
447 /* ARGSUSED */
448 void
RunSkipPixels(nskip,last,wasrun,globals)449 RunSkipPixels(nskip, last, wasrun, globals)
450 register struct sv_globals * globals;
451 {
452 }
453
454 /*****************************************************************
455 * TAG( RunNewScanLine )
456 * Perform a newline action. Since CR is implied by the Set Color
457 * operation, only generate code if the newline flag is true.
458 */
459 void
RunNewScanLine(flag,globals)460 RunNewScanLine(flag, globals)
461 register struct sv_globals * globals;
462 {
463 }
464
465 /*****************************************************************
466 * TAG( Runputdata )
467 * Put one or more pixels of byte data into the output file.
468 */
469 void
Runputdata(buf,n,globals)470 Runputdata(buf, n, globals)
471 rle_pixel * buf;
472 register struct sv_globals * globals;
473 {
474 }
475
476 /*****************************************************************
477 * TAG( Runputrun )
478 * Output a single color run.
479 */
480
481 /* ARGSUSED */
482 void
Runputrun(color,n,last,globals)483 Runputrun(color, n, last, globals)
484 register struct sv_globals * globals;
485 {
486 }
487
488
489 /*****************************************************************
490 * TAG( RunputEof )
491 * Output an EOF opcode
492 */
493 void
RunputEof(globals)494 RunputEof( globals )
495 register struct sv_globals * globals;
496 {
497 }
498
499 /*ARGSUSED*/
500 void
DefaultBlockHook(globals)501 DefaultBlockHook(globals)
502 struct sv_globals * globals;
503 {
504 }
505
506
507 /*
508 * This software is copyrighted as noted below. It may be freely copied,
509 * modified, and redistributed, provided that the copyright notice is
510 * preserved on all copies.
511 *
512 * There is no warranty or other guarantee of fitness for this software,
513 * it is provided solely "as is". Bug reports or fixes may be sent
514 * to the author, who may or may not act on them as he desires.
515 *
516 * You may not include this software in a program or other software product
517 * without supplying the source, or without informing the end-user that the
518 * source is available for no extra charge.
519 *
520 * If you modify this software, you should include a notice giving the
521 * name of the person performing the modification, the date of modification,
522 * and the reason for such modification.
523 */
524 /*
525 * buildmap.c - Build a color map from the RLE file color map.
526 *
527 * Author: Spencer W. Thomas
528 * Computer Science Dept.
529 * University of Utah
530 * Date: Sat Jan 24 1987
531 * Copyright (c) 1987, University of Utah
532 */
533
534 /*****************************************************************
535 * TAG( buildmap )
536 *
537 * Returns a color map that can easily be used to map the pixel values in
538 * an RLE file. Map is built from the color map in the input file.
539 * Inputs:
540 * globals: sv_globals structure containing color map.
541 * minmap: Minimum number of channels in output map.
542 * gamma: Adjust color map for this image gamma value
543 * (1.0 means no adjustment).
544 * Outputs:
545 * Returns an array of pointers to arrays of rle_pixels. The array
546 * of pointers contains max(sv_ncolors, sv_ncmap) elements, each
547 * array of pixels contains 2^sv_cmaplen elements. The pixel arrays
548 * should be considered read-only.
549 * Assumptions:
550 * [None]
551 * Algorithm:
552 * Ensure that there are at least sv_ncolors rows in the map, and
553 * that each has at least 256 elements in it (largest map that can
554 * be addressed by an rle_pixel).
555 */
556 rle_pixel **
buildmap(globals,minmap,gamma)557 buildmap( globals, minmap, gamma )
558 struct sv_globals *globals;
559 int minmap;
560 double gamma;
561 {
562 rle_pixel ** cmap, * gammap;
563 register int i, j;
564 int maplen, cmaplen, ncmap, nmap;
565
566 if ( globals->sv_ncmap == 0 ) /* make identity map */
567 {
568 nmap = (minmap < globals->sv_ncolors) ? globals->sv_ncolors : minmap;
569 cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
570 cmap[0] = (rle_pixel *)lmalloc( 256 * sizeof(rle_pixel) );
571 for ( i = 0; i < 256; i++ )
572 cmap[0][i] = i;
573 for ( i = 1; i < nmap; i++ )
574 cmap[i] = cmap[0];
575 maplen = 256;
576 ncmap = 1; /* number of unique rows */
577 }
578 else /* make map from globals */
579 {
580 /* Map is at least 256 long */
581 cmaplen = (1 << globals->sv_cmaplen);
582 if ( cmaplen < 256 )
583 maplen = 256;
584 else
585 maplen = cmaplen;
586
587 if ( globals->sv_ncmap == 1 ) /* make "b&w" map */
588 {
589 nmap = (minmap < globals->sv_ncolors) ?
590 globals->sv_ncolors : minmap;
591 cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
592 cmap[0] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
593 for ( i = 0; i < maplen; i++ )
594 if ( i < cmaplen )
595 cmap[0][i] = globals->sv_cmap[i] >> 8;
596 else
597 cmap[0][i] = i;
598 for ( i = 1; i < nmap; i++ )
599 cmap[i] = cmap[0];
600 ncmap = 1;
601 }
602 else if ( globals->sv_ncolors <= globals->sv_ncmap )
603 {
604 nmap = (minmap < globals->sv_ncmap) ? globals->sv_ncmap : minmap;
605 cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
606 for ( j = 0; j < globals->sv_ncmap; j++ )
607 {
608 cmap[j] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
609 for ( i = 0; i < maplen; i++ )
610 if ( i < cmaplen )
611 cmap[j][i] = globals->sv_cmap[j*cmaplen + i] >> 8;
612 else
613 cmap[j][i] = i;
614 }
615 for ( i = j, j--; i < nmap; i++ )
616 cmap[i] = cmap[j];
617 ncmap = globals->sv_ncmap;
618 }
619 else /* ncolors > ncmap */
620 {
621 nmap = (minmap < globals->sv_ncolors) ?
622 globals->sv_ncolors : minmap;
623 cmap = (rle_pixel **)lmalloc( nmap * sizeof(rle_pixel *) );
624 for ( j = 0; j < globals->sv_ncmap; j++ )
625 {
626 cmap[j] = (rle_pixel *)lmalloc( maplen * sizeof(rle_pixel) );
627 for ( i = 0; i < maplen; i++ )
628 if ( i < cmaplen )
629 cmap[j][i] = globals->sv_cmap[j*cmaplen + i] >> 8;
630 else
631 cmap[j][i] = i;
632 }
633 for( i = j, j--; i < nmap; i++ )
634 cmap[i] = cmap[j];
635 ncmap = globals->sv_ncmap;
636 }
637 }
638
639 /* Gamma compensate if requested */
640 if ( gamma != 1.0 )
641 {
642 gammap = (rle_pixel *)lmalloc( 256 * sizeof(rle_pixel) );
643 for ( i = 0; i < 256; i++ )
644 {
645 #ifdef BYTEBUG
646 int byteb1;
647 byteb1 = (int)(0.5 + 255.0 * pow( i / 255.0, gamma ));
648 gammap[i] = byteb1;
649 #else
650 gammap[i] = (int)(0.5 + 255.0 * pow( i / 255.0, gamma ));
651 #endif
652 }
653 for ( i = 0; i < ncmap; i++ )
654 for ( j = 0; j < maplen; j++ )
655 cmap[i][j] = gammap[cmap[i][j]];
656 }
657
658 return cmap;
659 }
660
661 /*
662 * This software is copyrighted as noted below. It may be freely copied,
663 * modified, and redistributed, provided that the copyright notice is
664 * preserved on all copies.
665 *
666 * There is no warranty or other guarantee of fitness for this software,
667 * it is provided solely "as is". Bug reports or fixes may be sent
668 * to the author, who may or may not act on them as he desires.
669 *
670 * You may not include this software in a program or other software product
671 * without supplying the source, or without informing the end-user that the
672 * source is available for no extra charge.
673 *
674 * If you modify this software, you should include a notice giving the
675 * name of the person performing the modification, the date of modification,
676 * and the reason for such modification.
677 */
678 /*
679 * rle_getcom.c - Get specific comments from globals structure.
680 *
681 * Author: Spencer W. Thomas
682 * Computer Science Dept.
683 * University of Utah
684 * Date: Sun Jan 25 1987
685 * Copyright (c) 1987, University of Utah
686 */
687
688 /*****************************************************************
689 * TAG( match )
690 *
691 * Match a name against a test string for "name=value" or "name".
692 * If it matches name=value, return pointer to value part, if just
693 * name, return pointer to NUL at end of string. If no match, return NULL.
694 *
695 * Inputs:
696 * n: Name to match. May also be "name=value" to make it easier
697 * to replace comments.
698 * v: Test string.
699 * Outputs:
700 * Returns pointer as above.
701 * Assumptions:
702 * [None]
703 * Algorithm:
704 * [None]
705 */
706 static char *
match(n,v)707 match( n, v )
708 register char *n;
709 register char *v;
710 {
711 for ( ; *n != '\0' && *n != '=' && *n == *v; n++, v++ )
712 ;
713 if (*n == '\0' || *n == '=') {
714 if ( *v == '\0' )
715 return v;
716 else if ( *v == '=' )
717 return ++v;
718 }
719
720 return NULL;
721 }
722
723 /*****************************************************************
724 * TAG( rle_getcom )
725 *
726 * Return a pointer to the value part of a name=value pair in the comments.
727 * Inputs:
728 * name: Name part of the comment to search for.
729 * globals: sv_globals structure.
730 * Outputs:
731 * Returns pointer to value part of comment or NULL if no match.
732 * Assumptions:
733 * [None]
734 * Algorithm:
735 * [None]
736 */
737 char *
rle_getcom(name,globals)738 rle_getcom( name, globals )
739 char *name;
740 struct sv_globals *globals;
741 {
742 char ** cp;
743 char * v;
744
745 if ( globals->sv_comments == NULL )
746 return NULL;
747
748 for ( cp = globals->sv_comments; *cp; cp++ )
749 if ( (v = match( name, *cp )) != NULL )
750 return v;
751
752 return NULL;
753 }
754
755 /*
756 * This software is copyrighted as noted below. It may be freely copied,
757 * modified, and redistributed, provided that the copyright notice is
758 * preserved on all copies.
759 *
760 * There is no warranty or other guarantee of fitness for this software,
761 * it is provided solely "as is". Bug reports or fixes may be sent
762 * to the author, who may or may not act on them as he desires.
763 *
764 * You may not include this software in a program or other software product
765 * without supplying the source, or without informing the end-user that the
766 * source is available for no extra charge.
767 *
768 * If you modify this software, you should include a notice giving the
769 * name of the person performing the modification, the date of modification,
770 * and the reason for such modification.
771 *
772 * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
773 * to have all "void" functions so declared.
774 */
775 /*
776 * rle_getrow.c - Read an RLE file in.
777 *
778 * Author: Spencer W. Thomas
779 * Computer Science Dept.
780 * University of Utah
781 * Date: Wed Apr 10 1985
782 * Copyright (c) 1985 Spencer W. Thomas
783 *
784 */
785 /*
786 * Automatically define LITTLE_ENDIAN on vax and pdp11 machines
787 */
788 #if defined(vax) || defined(pdp11)
789 #define LITTLE_ENDIAN
790 #endif
791
792 struct inst {
793 unsigned opcode:8, datum:8;
794 };
795
796 #define BREAD(type, var, len)\
797 zread( infile, (byte *)&var,len )
798 #define OPCODE(inst) (inst.opcode & ~LONG)
799 #define LONGP(inst) (inst.opcode & LONG)
800 #define DATUM(inst) (0x00ff & inst.datum)
801
802 static int debug_f; /* if non-zero, print debug info */
803 static void bfill();
804
805 /*****************************************************************
806 * TAG( rle_get_setup )
807 *
808 * Read the initialization information from an RLE file.
809 * Inputs:
810 * globals: Contains pointer to the input file.
811 * Outputs:
812 * globals: Initialized with information from the
813 * input file.
814 * Returns 0 on success, -1 if the file is not an RLE file,
815 * -2 if malloc of the color map failed, -3 if an immediate EOF
816 * is hit (empty input file), and -4 if an EOF is encountered reading
817 * the setup information.
818 * Assumptions:
819 * infile points to the "magic" number in an RLE file (usually
820 * byte 0 in the file).
821 * Algorithm:
822 * Read in the setup info and fill in sv_globals.
823 */
rle_get_setup(globals)824 int rle_get_setup( globals )
825 struct sv_globals * globals;
826 {
827 struct XtndRsetup setup;
828 short magic; /* assume 16 bits */
829 register ZFILE *infile = globals->svfb_fd;
830 rle_pixel * bg_color;
831 register int i;
832 char * comment_buf;
833
834 zclearerr(infile);
835 BREAD( short, magic, sizeof magic );
836 SWAB(magic);
837 if ( zeof( infile ) )
838 return -3;
839 if ( magic != XtndRMAGIC )
840 return -1;
841 BREAD( struct XtndRsetup, setup, SETUPSIZE ); /* assume VAX packing */
842 if ( zeof( infile ) )
843 return -4;
844 SWAB( setup.h_xpos );
845 SWAB( setup.h_ypos );
846 SWAB( setup.h_xlen );
847 SWAB( setup.h_ylen );
848
849 /* Extract information from setup */
850 globals->sv_ncolors = setup.h_ncolors;
851 for ( i = 0; i < globals->sv_ncolors; i++ )
852 SV_SET_BIT( *globals, i );
853
854 if ( !(setup.h_flags & H_NO_BACKGROUND) )
855 {
856 globals->sv_bg_color = (int *)lmalloc(
857 (unsigned)(sizeof(int) * setup.h_ncolors) );
858 bg_color = (rle_pixel *)lmalloc(
859 (unsigned)(1 + (setup.h_ncolors / 2) * 2) );
860 zread( infile, (byte *)bg_color, 1 + (setup.h_ncolors / 2) * 2 );
861 for ( i = 0; i < setup.h_ncolors; i++ )
862 globals->sv_bg_color[i] = bg_color[i];
863 lfree( bg_color );
864 }
865 else
866 zgetc( infile ); /* skip filler byte */
867
868 if ( setup.h_flags & H_NO_BACKGROUND )
869 globals->sv_background = 0;
870 else if ( setup.h_flags & H_CLEARFIRST )
871 globals->sv_background = 2;
872 else
873 globals->sv_background = 1;
874 if ( setup.h_flags & H_ALPHA )
875 {
876 globals->sv_alpha = 1;
877 SV_SET_BIT( *globals, SV_ALPHA );
878 }
879 else
880 globals->sv_alpha = 0;
881
882 globals->sv_xmin = setup.h_xpos;
883 globals->sv_ymin = setup.h_ypos;
884 globals->sv_xmax = globals->sv_xmin + setup.h_xlen - 1;
885 globals->sv_ymax = globals->sv_ymin + setup.h_ylen - 1;
886
887 globals->sv_ncmap = setup.h_ncmap;
888 globals->sv_cmaplen = setup.h_cmaplen;
889 if ( globals->sv_ncmap > 0 )
890 {
891 register int maplen =
892 globals->sv_ncmap * (1 << globals->sv_cmaplen);
893 globals->sv_cmap = (rle_map *)lmalloc(
894 (unsigned)(sizeof(rle_map) * maplen) );
895 if ( globals->sv_cmap == NULL )
896 {
897 fprintf( stderr,
898 "Malloc failed for color map of size %d*%d in rle_get_setup\n",
899 globals->sv_ncmap, (1 << globals->sv_cmaplen) );
900 return -2;
901 }
902 zread( infile, (byte *)globals->sv_cmap, sizeof(short) * maplen );
903 #ifndef LITTLE_ENDIAN
904 /* Swap bytes on bigendian machines
905 */
906 for ( i = 0; i < maplen; i++ )
907 SWAB( globals->sv_cmap[i] );
908 #endif
909 }
910
911 /* Check for comments */
912 if ( setup.h_flags & H_COMMENT )
913 {
914 short comlen, evenlen;
915 register char * cp;
916
917 BREAD( short, comlen, sizeof comlen ); /* get comment length */
918 SWAB( comlen );
919 evenlen = (comlen + 1) & ~1; /* make it even */
920 comment_buf = (char *)lmalloc( (unsigned) evenlen );
921 if ( comment_buf == NULL )
922 {
923 fprintf( stderr,
924 "Malloc failed for comment buffer of size %d in rle_get_setup\n",
925 comlen );
926 return -2;
927 }
928 zread( infile, (byte *)comment_buf, evenlen );
929 /* Count the comments */
930 for ( i = 0, cp = comment_buf; cp < comment_buf + comlen; cp++ )
931 if ( *cp == 0 )
932 i++;
933 i++; /* extra for NULL pointer at end */
934 /* Get space to put pointers to comments */
935 globals->sv_comments =
936 (char **)lmalloc( (unsigned)(i * sizeof(char *)) );
937 if ( globals->sv_comments == NULL )
938 {
939 fprintf( stderr,
940 "Malloc failed for %d comment pointers in rle_get_setup\n",
941 i );
942 return -2;
943 }
944 /* Get pointers to the comments */
945 *globals->sv_comments = comment_buf;
946 for ( i = 1, cp = comment_buf + 1; cp < comment_buf + comlen; cp++ )
947 if ( *(cp - 1) == 0 )
948 globals->sv_comments[i++] = cp;
949 globals->sv_comments[i] = NULL;
950 }
951 else
952 globals->sv_comments = NULL;
953
954 /* Initialize state for rle_getrow */
955 globals->sv_private.get.scan_y = globals->sv_ymin;
956 globals->sv_private.get.vert_skip = 0;
957 globals->sv_private.get.is_eof = 0;
958 globals->sv_private.get.is_seek = 0; /* Can't do seek on zfile */
959 debug_f = 0;
960
961 if ( !zeof( infile ) )
962 return 0; /* success! */
963 else
964 {
965 globals->sv_private.get.is_eof = 1;
966 return -4;
967 }
968 }
969
970
971 /*****************************************************************
972 * TAG( rle_get_error )
973 *
974 * Print an error message for the return code from rle_get_setup
975 * Inputs:
976 * code: The return code from rle_get_setup.
977 * pgmname: Name of this program (argv[0]).
978 * fname: Name of the input file.
979 * Outputs:
980 * Prints an error message on standard output.
981 * Returns code.
982 */
983
rle_get_error(code,pgmname,fname)984 int rle_get_error( code, pgmname, fname )
985 int code;
986 char *pgmname;
987 char *fname;
988 {
989 switch( code )
990 {
991 case 0: /* success */
992 break;
993
994 case -1: /* Not an RLE file */
995 fprintf( stderr, "%s: %s is not an RLE file\n",
996 pgmname, fname );
997 break;
998
999 case -2: /* malloc failed */
1000 fprintf( stderr,
1001 "%s: Malloc failed reading header of file %s\n",
1002 pgmname, fname );
1003 break;
1004
1005 case -3:
1006 fprintf( stderr, "%s: %s is an empty file\n", pgmname, fname );
1007 break;
1008
1009 case -4:
1010 fprintf( stderr,
1011 "%s: RLE header of %s is incomplete (premature EOF)\n",
1012 pgmname, fname );
1013 break;
1014
1015 default:
1016 fprintf( stderr, "%s: Error encountered reading header of %s\n",
1017 pgmname, fname );
1018 break;
1019 }
1020 return code;
1021 }
1022
1023
1024 /*****************************************************************
1025 * TAG( rle_get_setup_ok )
1026 *
1027 * Read the initialization information from an RLE file.
1028 * Inputs:
1029 * globals: Contains pointer to the input file.
1030 * prog_name: Program name to be printed in the error message.
1031 * file_name: File name to be printed in the error message.
1032 * If NULL, the string "stdin" is generated.
1033 * Outputs:
1034 * globals: Initialized with information from the
1035 * input file.
1036 * If reading the globals fails, it prints an error message
1037 * and exits with the appropriate status code.
1038 * Algorithm:
1039 * sv_get_setup does all the work.
1040 */
1041 void
rle_get_setup_ok(globals,prog_name,file_name)1042 rle_get_setup_ok( globals, prog_name, file_name )
1043 struct sv_globals * globals;
1044 char *prog_name;
1045 char *file_name;
1046 {
1047 int code;
1048
1049 if (! file_name)
1050 file_name = "stdin";
1051
1052 code = rle_get_error( rle_get_setup( globals ), prog_name, file_name );
1053 if (code)
1054 exit( code );
1055 }
1056
1057
1058 /*****************************************************************
1059 * TAG( rle_debug )
1060 *
1061 * Turn RLE debugging on or off.
1062 * Inputs:
1063 * on_off: if 0, stop debugging, else start.
1064 * Outputs:
1065 * Sets internal debug flag.
1066 * Assumptions:
1067 * [None]
1068 * Algorithm:
1069 * [None]
1070 */
1071 void
rle_debug(on_off)1072 rle_debug( on_off )
1073 int on_off;
1074 {
1075 debug_f = on_off;
1076 }
1077
1078
1079 /*****************************************************************
1080 * TAG( rle_getrow )
1081 *
1082 * Get a scanline from the input file.
1083 * Inputs:
1084 * globals: sv_globals structure containing information about
1085 * the input file.
1086 * Outputs:
1087 * scanline: an array of pointers to the individual color
1088 * scanlines. Scanline is assumed to have
1089 * globals->sv_ncolors pointers to arrays of rle_pixel,
1090 * each of which is at least globals->sv_xmax+1 long.
1091 * Returns the current scanline number.
1092 * Assumptions:
1093 * rle_get_setup has already been called.
1094 * Algorithm:
1095 * If a vertical skip is being executed, and clear-to-background is
1096 * specified (globals->sv_background is true), just set the
1097 * scanlines to the background color. If clear-to-background is
1098 * not set, just increment the scanline number and return.
1099 *
1100 * Otherwise, read input until a vertical skip is encountered,
1101 * decoding the instructions into scanline data.
1102 */
1103
rle_getrow(globals,scanline)1104 int rle_getrow( globals, scanline )
1105 struct sv_globals * globals;
1106 rle_pixel *scanline[];
1107 {
1108 register rle_pixel * scanc;
1109 register int nc;
1110 register ZFILE *infile = globals->svfb_fd;
1111 int scan_x = globals->sv_xmin, /* current X position */
1112 channel = 0; /* current color channel */
1113 short word, long_data;
1114 struct inst inst;
1115
1116 /* Clear to background if specified */
1117 if ( globals->sv_background == 2 )
1118 {
1119 if ( globals->sv_alpha && SV_BIT( *globals, -1 ) )
1120 bfill( (char *)scanline[-1], globals->sv_xmax + 1, 0 );
1121 for ( nc = 0; nc < globals->sv_ncolors; nc++ )
1122 if ( SV_BIT( *globals, nc ) )
1123 bfill( (char *)scanline[nc], globals->sv_xmax+1,
1124 globals->sv_bg_color[nc] );
1125 }
1126
1127 /* If skipping, then just return */
1128 if ( globals->sv_private.get.vert_skip > 0 )
1129 {
1130 globals->sv_private.get.vert_skip--;
1131 globals->sv_private.get.scan_y++;
1132 if ( globals->sv_private.get.vert_skip > 0 )
1133 return globals->sv_private.get.scan_y;
1134 }
1135
1136 /* If EOF has been encountered, return also */
1137 if ( globals->sv_private.get.is_eof )
1138 return ++globals->sv_private.get.scan_y;
1139
1140 /* Otherwise, read and interpret instructions until a skipLines
1141 * instruction is encountered.
1142 */
1143 if ( SV_BIT( *globals, channel ) )
1144 scanc = scanline[channel] + scan_x;
1145 else
1146 scanc = NULL;
1147 for (;;)
1148 {
1149 BREAD(struct inst, inst, 2 );
1150 if ( zeof(infile) )
1151 {
1152 globals->sv_private.get.is_eof = 1;
1153 break; /* <--- one of the exits */
1154 }
1155
1156 switch( OPCODE(inst) )
1157 {
1158 case RSkipLinesOp:
1159 if ( LONGP(inst) )
1160 {
1161 BREAD( short, long_data, sizeof long_data );
1162 SWAB( long_data );
1163 globals->sv_private.get.vert_skip = long_data;
1164 }
1165 else
1166 globals->sv_private.get.vert_skip = DATUM(inst);
1167 if (debug_f)
1168 fprintf(stderr, "Skip %d Lines (to %d)\n",
1169 globals->sv_private.get.vert_skip,
1170 globals->sv_private.get.scan_y +
1171 globals->sv_private.get.vert_skip );
1172
1173 break; /* need to break for() here, too */
1174
1175 case RSetColorOp:
1176 channel = DATUM(inst); /* select color channel */
1177 if ( channel == 255 )
1178 channel = -1;
1179 scan_x = globals->sv_xmin;
1180 if ( SV_BIT( *globals, channel ) )
1181 scanc = scanline[channel]+scan_x;
1182 if ( debug_f )
1183 fprintf( stderr, "Set color to %d (reset x to %d)\n",
1184 channel, scan_x );
1185 break;
1186
1187 case RSkipPixelsOp:
1188 if ( LONGP(inst) )
1189 {
1190 BREAD( short, long_data, sizeof long_data );
1191 SWAB( long_data );
1192 scan_x += long_data;
1193 scanc += long_data;
1194 if ( debug_f )
1195 fprintf( stderr, "Skip %d pixels (to %d)\n",
1196 long_data, scan_x );
1197
1198 }
1199 else
1200 {
1201 scan_x += DATUM(inst);
1202 scanc += DATUM(inst);
1203 if ( debug_f )
1204 fprintf( stderr, "Skip %d pixels (to %d)\n",
1205 DATUM(inst), scan_x );
1206 }
1207 break;
1208
1209 case RByteDataOp:
1210 if ( LONGP(inst) )
1211 {
1212 BREAD( short, long_data, sizeof long_data );
1213 SWAB( long_data );
1214 nc = (int)long_data;
1215 }
1216 else
1217 nc = DATUM(inst);
1218 nc++;
1219 if ( SV_BIT( *globals, channel ) )
1220 {
1221 zread( infile, (byte *)scanc, nc );
1222 if ( nc & 1 )
1223 (void)zgetc( infile ); /* throw away odd byte */
1224 }
1225 else
1226 { /* Emulate a forward fseek */
1227 register int ii;
1228 for ( ii = ((nc + 1) / 2) * 2; ii > 0; ii-- )
1229 (void) zgetc( infile ); /* discard it */
1230 }
1231
1232 scanc += nc;
1233 scan_x += nc;
1234 if ( debug_f ) {
1235 if ( SV_BIT( *globals, channel ) )
1236 {
1237 rle_pixel * cp = scanc - nc;
1238 fprintf( stderr, "Pixel data %d (to %d):", nc, scan_x );
1239 for ( ; nc > 0; nc-- )
1240 fprintf( stderr, "%02x", *cp++ );
1241 putc( '\n', stderr );
1242 }
1243 else
1244 fprintf( stderr, "Pixel data %d (to %d)\n", nc, scan_x );
1245 }
1246 break;
1247
1248 case RRunDataOp:
1249 if ( LONGP(inst) )
1250 {
1251 BREAD( short, long_data, sizeof long_data );
1252 SWAB( long_data );
1253 nc = long_data;
1254 }
1255 else
1256 nc = DATUM(inst);
1257 scan_x += nc + 1;
1258
1259 BREAD( short, word, sizeof(short) );
1260 SWAB( word );
1261 if ( debug_f )
1262 fprintf( stderr, "Run length %d (to %d), data %02x\n",
1263 nc + 1, scan_x, word );
1264 if ( SV_BIT( *globals, channel ) )
1265 {
1266 if ( nc >= 10 ) /* break point for 785, anyway */
1267 {
1268 bfill( (char *)scanc, nc + 1, word );
1269 scanc += nc + 1;
1270 }
1271 else
1272 for ( ; nc >= 0; nc--, scanc++ )
1273 *scanc = word;
1274 }
1275 break;
1276
1277 case REOFOp:
1278 globals->sv_private.get.is_eof = 1;
1279 break;
1280
1281 default:
1282 fprintf( stderr,
1283 "rle_getrow: Unrecognized opcode: %d\n", inst.opcode );
1284 exit(1);
1285 }
1286 if ( OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp )
1287 break; /* <--- the other loop exit */
1288 }
1289
1290 return globals->sv_private.get.scan_y;
1291 }
1292
1293
1294 /* Fill buffer at s with n copies of character c. N must be <= 65535*/
1295 /* ARGSUSED */
bfill(s,n,c)1296 static void bfill( s, n, c )
1297 char *s;
1298 int n, c;
1299 {
1300 #if defined(vax) && !defined(VMS)
1301 asm(" movc5 $0,*4(ap),12(ap),8(ap),*4(ap)");
1302 #else
1303 while ( n-- > 0 )
1304 *s++ = c;
1305 #endif
1306 }
1307
1308 /*
1309 * This software is copyrighted as noted below. It may be freely copied,
1310 * modified, and redistributed, provided that the copyright notice is
1311 * preserved on all copies.
1312 *
1313 * There is no warranty or other guarantee of fitness for this software,
1314 * it is provided solely "as is". Bug reports or fixes may be sent
1315 * to the author, who may or may not act on them as he desires.
1316 *
1317 * You may not include this software in a program or other software product
1318 * without supplying the source, or without informing the end-user that the
1319 * source is available for no extra charge.
1320 *
1321 * If you modify this software, you should include a notice giving the
1322 * name of the person performing the modification, the date of modification,
1323 * and the reason for such modification.
1324 *
1325 * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
1326 * to have all "void" functions so declared.
1327 *
1328 * Modified to generate an apropriate size dither map (ie 2x2, 4x4, 8x8
1329 * or 16x16) rather than use fixed 16x16 map. Use a large enough map
1330 * to give a minimum of 128 effective levels rather than aiming for 256.
1331 * This should give less grainy pictures.
1332 * Two global variables can modify this:
1333 * dith_levels = 128 (default)
1334 * dith_np2 = 0 (default). Nonzero to enable non power of 2 dither mapping.
1335 * dith_size = actual dither matrix size chosen.
1336 *
1337 * Graeme Gill 3 June 88
1338 */
1339
1340 /*
1341 * dither.c - Functions for RGB color dithering.
1342 *
1343 * Author: Spencer W. Thomas
1344 * Computer Science Dept.
1345 * University of Utah
1346 * Date: Mon Feb 2 1987
1347 * Copyright (c) 1987, University of Utah
1348 */
1349
1350 void make_square();
1351
1352 /* dither globals */
1353 int dith_levels = 128;
1354 int dith_np2 = 0;
1355 int dith_size = 16;
1356
1357 /* basic dithering macro */
1358 #define DMAP(v,x,y) (modN[v]>magic[x][y] ? divN[v] + 1 : divN[v])
1359
1360 /*****************************************************************
1361 * TAG( dithermap )
1362 *
1363 * Create a color dithering map with a specified number of intensity levels.
1364 * Inputs:
1365 * levels: Intensity levels per primary.
1366 * gamma: Display gamma value.
1367 * Outputs:
1368 * rgbmap: Generated color map.
1369 * divN: "div" function for dithering.
1370 * modN: "mod" function for dithering.
1371 * Assumptions:
1372 * rgbmap will hold levels^3 entries.
1373 * Algorithm:
1374 * Compute gamma compensation map.
1375 * N = 255.0 / (levels - 1) is number of pixel values per level.
1376 * Compute rgbmap with red ramping fastest, green slower, and blue
1377 * slowest (treat it as if it were rgbmap[levels][levels][levels][3]).
1378 * Call make_square to get divN, modN, and magic
1379 *
1380 * Note:
1381 * Call dithergb( x, y, r, g, b, levels, divN, modN, magic ) to get index
1382 * into rgbmap for a given color/location pair, or use
1383 * row = y % 16; col = x % 16;
1384 * DMAP(v,col,row) =def (divN[v] + (modN[v]>magic[col][row] ? 1 : 0))
1385 * DMAP(r,col,row) + DMAP(g,col,row)*levels + DMAP(b,col,row)*levels^2
1386 * if you don't want function call overhead.
1387 */
1388 void
dithermap(levels,gamma,rgbmap,divN,modN,magic)1389 dithermap( levels, gamma, rgbmap, divN, modN, magic )
1390 double gamma;
1391 int rgbmap[][3];
1392 int divN[256];
1393 int modN[256];
1394 int magic[16][16];
1395 {
1396 double N;
1397 register int i;
1398 int levelsq, levelsc;
1399 int gammamap[256];
1400
1401 make_gamma(gamma,gammamap);
1402
1403 levelsq = levels*levels; /* squared */
1404 levelsc = levels*levelsq; /* and cubed */
1405
1406 N = 255.0 / (levels - 1); /* Get size of each step */
1407
1408 /*
1409 * Set up the color map entries.
1410 */
1411 for(i = 0; i < levelsc; i++) {
1412 rgbmap[i][0] = gammamap[(int)(0.5 + (i%levels) * N)];
1413 rgbmap[i][1] = gammamap[(int)(0.5 + ((i/levels)%levels) * N)];
1414 rgbmap[i][2] = gammamap[(int)(0.5 + ((i/levelsq)%levels) * N)];
1415 }
1416
1417 make_square( N, divN, modN, magic );
1418 }
1419
1420
1421 /*****************************************************************
1422 * TAG( bwdithermap )
1423 *
1424 * Create a color dithering map with a specified number of intensity levels.
1425 * Inputs:
1426 * levels: Intensity levels.
1427 * gamma: Display gamma value.
1428 * Outputs:
1429 * bwmap: Generated black & white map.
1430 * divN: "div" function for dithering.
1431 * modN: "mod" function for dithering.
1432 * Assumptions:
1433 * bwmap will hold levels entries.
1434 * Algorithm:
1435 * Compute gamma compensation map.
1436 * N = 255.0 / (levels - 1) is number of pixel values per level.
1437 * Compute bwmap for levels entries.
1438 * Call make_square to get divN, modN, and magic.
1439 * Note:
1440 * Call ditherbw( x, y, val, divN, modN, magic ) to get index into
1441 * bwmap for a given color/location pair, or use
1442 * row = y % 16; col = x % 16;
1443 * divN[val] + (modN[val]>magic[col][row] ? 1 : 0)
1444 * if you don't want function call overhead.
1445 * On a 1-bit display, use
1446 * divN[val] > magic[col][row] ? 1 : 0
1447 */
1448 void
bwdithermap(levels,gamma,bwmap,divN,modN,magic)1449 bwdithermap( levels, gamma, bwmap, divN, modN, magic )
1450 double gamma;
1451 int bwmap[];
1452 int divN[256];
1453 int modN[256];
1454 int magic[16][16];
1455 {
1456 double N;
1457 register int i;
1458 int gammamap[256];
1459
1460 make_gamma(gamma,gammamap);
1461
1462 N = 255.0 / (levels - 1); /* Get size of each step */
1463
1464 /*
1465 * Set up the color map entries.
1466 */
1467 for(i = 0; i < levels; i++)
1468 bwmap[i] = gammamap[(int)(0.5 + i * N)];
1469
1470 make_square( N, divN, modN, magic );
1471 }
1472
1473
1474 /*****************************************************************
1475 * TAG( make_square )
1476 *
1477 * Build the magic square for a given number of levels.
1478 * Inputs:
1479 * N: Pixel values per level (255.0 / (levels-1)).
1480 * (global) dith_levels = 128 (default) - number of effective levels to aim for
1481 * (global) dith_np2 = 0 (default) - non-zero if non power of two size is permissable.
1482 * Outputs:
1483 * divN: Integer value of pixval / N
1484 * modN: Integer remainder between pixval and divN[pixval]*N
1485 * magic: Magic square for dithering to N sublevels.
1486 * (global) dith_size = magic square size chosen.
1487 * Assumptions:
1488 *
1489 * Algorithm:
1490 * divN[pixval] = (int)(pixval / N) maps pixval to its appropriate level.
1491 * modN[pixval] = pixval - (int)(N * divN[pixval]) maps pixval to
1492 * its sublevel, and is used in the dithering computation.
1493 */
1494 void
make_square(N,divN,modN,magic)1495 make_square( N, divN, modN, magic )
1496 double N;
1497 int divN[256];
1498 int modN[256];
1499 int magic[16][16] ;
1500 {
1501 register int i, j, k, l;
1502 double magicfact;
1503
1504 for ( i = 0; i < 256; i++ )
1505 {
1506 divN[i] = (int)(i / N);
1507 modN[i] = i - (int)(N * divN[i]);
1508 }
1509 modN[255] = 0; /* always */
1510
1511 /* figure out how big a square will give */
1512 /* the desired number of levels */
1513 if(dith_np2)
1514 for(dith_size= 2;((dith_size * dith_size)+1)<((N*dith_levels)/256);dith_size++ );
1515 else
1516 for(dith_size= 2;((dith_size * dith_size)+1)<((N*dith_levels)/256);dith_size *=2);
1517
1518 /* make the basic square up */
1519 /* ( will have numbers 0 - size * size ) */
1520 make_magic(dith_size,magic);
1521
1522 /* divN gives 0 - levels-1 */
1523 /* modN gives 0 - N-1 */
1524 /* dither is if(modN(pix) > magic[][] so */
1525 /* scale magic it to have levels 0 to N-2 */
1526 /* (ie takes account of magic square size allows size * size +1 levels */
1527
1528 magicfact = (N-2)/((double)((dith_size * dith_size)-1));
1529 for(i=0;i<dith_size;i++)
1530 {
1531 for(j=0;j<dith_size;j++)
1532 {
1533 magic[i][j] = (int)(0.5 + magic[i][j] * magicfact);
1534 }
1535 }
1536
1537 if(!dith_np2) /* if we have power of 2 */
1538 {
1539 /* now replicate the size square we've chosen */
1540 /* (and use a brick pattern) */
1541 for(k=0;k<16;k += dith_size)
1542 {
1543 for(l=k>0?0:dith_size;l<16;l += dith_size)
1544 {
1545 for(i=0;i<dith_size;i++)
1546 {
1547 for(j=0;j<dith_size;j++)
1548 {
1549 magic[k+i][((l+k/2)+j)%16] = magic[i][j];
1550 }
1551 }
1552 }
1553 }
1554 }
1555 }
1556
1557 int magic16x16[16][16] =
1558 {
1559 {0,128,32,160,8,136,40,168,2,130,34,162,10,138,42,170},
1560 {192,64,224,96,200,72,232,104,194,66,226,98,202,74,234,106},
1561 {48,176,16,144,56,184,24,152,50,178,18,146,58,186,26,154},
1562 {240,112,208,80,248,120,216,88,242,114,210,82,250,122,218,90},
1563 {12,140,44,172,4,132,36,164,14,142,46,174,6,134,38,166},
1564 {204,76,236,108,196,68,228,100,206,78,238,110,198,70,230,102},
1565 {60,188,28,156,52,180,20,148,62,190,30,158,54,182,22,150},
1566 {252,124,220,92,244,116,212,84,254,126,222,94,246,118,214,86},
1567 {3,131,35,163,11,139,43,171,1,129,33,161,9,137,41,169},
1568 {195,67,227,99,203,75,235,107,193,65,225,97,201,73,233,105},
1569 {51,179,19,147,59,187,27,155,49,177,17,145,57,185,25,153},
1570 {243,115,211,83,251,123,219,91,241,113,209,81,249,121,217,89},
1571 {15,143,47,175,7,135,39,167,13,141,45,173,5,133,37,165},
1572 {207,79,239,111,199,71,231,103,205,77,237,109,197,69,229,101},
1573 {63,191,31,159,55,183,23,151,61,189,29,157,53,181,21,149},
1574 {255,127,223,95,247,119,215,87,253,125,221,93,245,117,213,85}
1575 };
1576
1577 /*****************************************************************
1578 * TAG( make_magic )
1579 *
1580 * Create the magic square.
1581 * Inputs:
1582 * size: Order of the square
1583 * magic: Address of 16 x 16 magic square.
1584 * Outputs:
1585 * Fills in the 16 x 16 magic square.
1586 * Assumptions:
1587 * size is between 2 and 16
1588 * Algorithm:
1589 * Chose sub cell of 16 by 16 magic square
1590 */
make_magic(size,magic)1591 void make_magic( size, magic )
1592 int size;
1593 int magic[16][16];
1594 {
1595 int j,i,li,bi,bx,by;
1596 int xx,yy;
1597 int total;
1598
1599 total = size * size;
1600
1601 i = bx = by = 0;
1602 li = -1;
1603 for(j=0;j<total;j++)
1604 {
1605 bi = 256;
1606
1607 for(xx=0;xx<size;xx++)
1608 {
1609 for(yy=0;yy<size;yy++)
1610 {
1611 if(magic16x16[xx][yy] >li && magic16x16[xx][yy] < bi)
1612 {
1613 bx = xx;
1614 by = yy;
1615 bi = magic16x16[xx][yy];
1616 }
1617 }
1618 }
1619 magic[bx][by] = i;
1620 i++;
1621 li = bi;
1622 }
1623 }
1624
1625 /*****************************************************************
1626 * TAG( make_gamma )
1627 *
1628 * Makes a gamma compenstation map.
1629 * Inputs:
1630 * gamma: desired gamma
1631 * gammamap: gamma mapping array
1632 * Outputs:
1633 * Changes gamma array entries.
1634 */
make_gamma(gamma,gammamap)1635 void make_gamma( gamma, gammamap )
1636 double gamma;
1637 int gammamap[256];
1638 {
1639 register int i;
1640
1641 for ( i = 0; i < 256; i++ )
1642 {
1643 #ifdef BYTEBUG
1644 int byteb1;
1645
1646 byteb1 = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
1647 gammamap[i] = byteb1;
1648 #else
1649 gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
1650 #endif
1651 }
1652 }
1653
1654 /*****************************************************************
1655 * TAG( dithergb )
1656 *
1657 * Return dithered RGB value.
1658 * Inputs:
1659 * x: X location on screen of this pixel.
1660 * y: Y location on screen of this pixel.
1661 * r, g, b: Color at this pixel (0 - 255 range).
1662 * levels: Number of levels in this map.
1663 * divN, modN: From dithermap.
1664 * magic: Magic square from dithermap.
1665 * Outputs:
1666 * Returns color map index for dithered pixelv value.
1667 * Assumptions:
1668 * divN, modN, magic were set up properly.
1669 * Algorithm:
1670 * see "Note:" in dithermap comment.
1671 */
dithergb(x,y,r,g,b,levels,divN,modN,magic)1672 int dithergb( x, y, r, g, b, levels, divN, modN, magic )
1673 int divN[256];
1674 int modN[256];
1675 int magic[16][16];
1676 {
1677 int col = x % 16, row = y % 16;
1678
1679 return DMAP(r, col, row) +
1680 DMAP(g, col, row) * levels +
1681 DMAP(b, col, row) * levels*levels;
1682 }
1683
1684
1685 /*****************************************************************
1686 * TAG( ditherbw )
1687 *
1688 * Return dithered black & white value.
1689 * Inputs:
1690 * x: X location on screen of this pixel.
1691 * y: Y location on screen of this pixel.
1692 * val: Intensity at this pixel (0 - 255 range).
1693 * divN, modN: From dithermap.
1694 * magic: Magic square from dithermap.
1695 * Outputs:
1696 * Returns color map index for dithered pixel value.
1697 * Assumptions:
1698 * divN, modN, magic were set up properly.
1699 * Algorithm:
1700 * see "Note:" in bwdithermap comment.
1701 */
ditherbw(x,y,val,divN,modN,magic)1702 int ditherbw( x, y, val, divN, modN, magic )
1703 int divN[256];
1704 int modN[256];
1705 int magic[16][16];
1706 {
1707 int col = x % 16, row = y % 16;
1708
1709 return DMAP(val, col, row);
1710 }
1711