                                                          November 6, 1991

     The Scanmap Image Format

     The  scanmap  image  data format is designed to allow the QNX Windows
     server to store fairly large bitmap images in less  memory  than  the
     full pixmap  would occupy. The compression algorithm is optimized for
     speed of decompression at the expense  of  maximum  compression.  The
     image  that  is  compressed  using a simple run length encoding (RLE)
     process optimized for rapid decoding by the graphics drivers.

     A  set  of  utilities to process gif files into scanmaps exist in the
     /windows/apps/Image directory.

     The data is arranged as follows:

     Byte 0					Byte 1

     7 6 5 4 3 2 1 0			7 6 5 4 3 2 1 0
     * * * * + + + +         + + + + + + + +
     Opcode  Arg				Arg or repeat byte 0

     If  the opcode is between 0x0 and 0x7 (SCAN_) then the second byte is
     the low byte of a 12 bit operand:

     Byte 0					Byte 1
     MSB		3 2 1 0			7 6 5 4 3 2 1 0	LSB

     If  the  opcode  is greater than 0x7 (SHORT_) then next byte is a new
     instruction.

     ----------------------------------------------------------- 	

     DECODING a scanmap:

     The following definitions will be necessary:

#define SCAN_MASK           0x0F

/* Opcodes */
#define SCAN_RUN            0x0	/* Draw a line x pixels long */
#define SCAN_ROW            0x1	/* Next row */
#define SCAN_COL            0x2	/* Next col */
#define SCAN_COLOR          0x3	/* New color */
#define SCAN_RUN_RETURN     0x4	/* Draw a line x pixels long and start new col */
#define SCAN_SKIP0          0x5	/* Skip x pixels */
#define SCAN_SKIP1          0x6
#define SCAN_SKIP2          0x7
#define SHORT_RUN           0x8
#define SHORT_ROW           0x9
#define SHORT_COL           0xA
#define SHORT_COLOR         0xB
#define SHORT_RUN_RETURN    0xC
#define SHORT_SKIP0         0xD
#define SHORT_SKIP1         0xE
#define SHORT_SKIP2         0xF


     EXAMPLES:


     EXAMPLE 1:	Generating a PostScript copy of a scanmap

/*
 	#define PV(x)	x * V_TPP
	#define PH(x)	x * H_TPP

	x_map == 1 tip in PostScript co-ords (horizontally)
	y_map == 1 tip in PostScript co-ords (vertically)

	bool mto;	/* We need to position the next line */
*/

draw_scanmap(element,image,def)
	HDR *element;
	IMAGE_ELEMENT *image;
	IMAGE_DEF *def;
{
	register unsigned char op;
	register unsigned arg;
	RECT_AREA pos;	
	unsigned colour;
	char *last, byte1, byte2;
	register unsigned *ptr;

	ptr = (opcode *)image->data + sizeof(IMAGE_DEF);
	pos.row = element->row;
	pos.col = element->col;
	mto = YES;
	colour = element->color;
	last = ptr + def->length;

	fprintf(outfp,"gsave %^.2f setlinewidth\n",PV(y_map));
	run_map = PH(x_map);

	do		
	{
		/* Upper bits are the opcode */

		op = (unsigned char )( (*ptr >> 4) & SCAN_MASK);

		if ( *ptr & 0x0080 )
		{
			/* Short calls */
			arg = *ptr & SCAN_MASK;
			ptr = (char *)ptr + 1;
		}
		else
		{
			/* Long calls */
			byte1 =  (char) (*ptr & SCAN_MASK );
			byte2 = (char) (*ptr >> 8);
			arg = (byte1 << 8) | byte2;
			++ptr;
		}

		switch (op) {
		case SHORT_RUN:
		case SCAN_RUN:
			fill_run(pos.row,pos.col, arg, colour);			
			pos.col += PH(arg);
			break;
		case SHORT_ROW:
		case SCAN_ROW:
			pos.row += PV(arg);
			mto = YES;
			break;
		case SHORT_COL:
		case SCAN_COL:
			pos.col += PH(arg);
			mto = YES;
			break;
		case SHORT_COLOR:
		case SCAN_COLOR:
			colour = arg + 1;
			break;
		case SHORT_RUN_RETURN:
		case SCAN_RUN_RETURN:
			fill_run(pos.row,pos.col,arg, colour);
			pos.col = element->col;
			pos.row += V_TPP;
			mto = YES;
			break;
		}

	} while ( *ptr );
	fprintf(outfp,"gsave\n");
}

/*

	NOTE: 	The PostScript commands SCNl, SCNr, SCNn are defined in the
			file QUIP.prolog.  SCNl corresponds to scan_run_return, 
			SCNl corresponds to scan_run and SCNn corresponds to a skip.

*/

fill_run(row,col,run_len,colour)
	unsigned row, col;
	int run_len, colour;
{
	float x, y;

	if (!run_len) return (0);

	if (mto)
		PS_point_map(&x,&y,col,row);

	if (colour == TRANSPARENT) 
	{
		if (mto)
		{
			fprintf(outfp,"%^.2f %^.2f Mto\n",x + run_len * run_map,y);			
			mto = NO;
		}
		else
			fprintf(outfp,"%^.2f SCNn\n",run_len * run_map);

		return(1);
	}
	
	if (mto)
	{
		fprintf(outfp,"CC%d %^.2f %^.2f %^.2f SCNr\n",colour,run_len * run_map,x,y);
		mto = NO;
	}
	else
		fprintf(outfp,"CC%d %^.2f SCNl\n",colour,run_len * run_map);
}
