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