[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
/*
 * Convert data format of figure
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bookfile_figure.h"	/* verify prototypes */
#include "bookreader_recdef.h"
struct bitstream {
    int words_filled;		/* Completed words */
    int bit_off;		/* bits written to current word */
    int (*flush)(void *,int,char *);
    void *flush_arg;
    unsigned long buffer[65];
};
static int add_bits ( struct bitstream *bs, int value, int size );
static int compress_data ( struct bitstream *bs, 
	int code_size, unsigned char *data, int width, int height );

/*  hdr[2] = section #, hdr[3] = x, hdr[4] = y, hdr[5] = w hdr[6] = h
 *  hdr[7] = picbytes, hdr[8]<0..7> = primitive
 *  data[4..5] col, data[6..7] = rows
 */
int LIB$INIT_TIMER(), LIB$SHOW_TIMER();
int bkg_convert_figure_to_gif ( 
	long hdr[10], 			/* Section header figure subrec */
	unsigned char *data, int datalen,   /* data read from section */
	int (*output)(void*, int, char *), /* User-supplied output function */
	void *outarg )			/* user-arg for output function */
{
    FILE* out;
    int i, j, k, width, height, value, mask, status;
    float aspect;
    short *cols, *rows;
    char trailer[2] = { 0, ';' };
    unsigned char *cur_row, *cur_col;
    unsigned char *pixel_row, *pixel_image;
    int size, count;
#ifdef __DECC
#pragma nomember_alignment
#endif
    struct gif_header {
	char signature[6];		/* GIF87a */
	short width, height;		/* little-endian */
	unsigned char flags;		/* <0..2> gct_size (2**(val+1)). */
					/* <3> color table sorted */
					/* <4..6> out device clr res (7)*/
					/* <7> Global color table if set */
	short aspect;			/* aspect ratio */
	unsigned char color_table[6];	/* 2-entry color table */
			/* Image header follows */
	char separator;			/* ',' */
	short left,top;			/* origin */
	short iwidth, iheight;		/* Image size */
	unsigned char iflags;		/* <0..2> pixel depth */
					/* <3..5> mbz */
					/* <6>  Interlace flag */
					/* <7> local color table */
	unsigned char code_size;	/* first byte of image data */
    } header;
#ifdef __DECC
#pragma member_alignment
#endif
    struct bitstream bs;
    /*
     * Get dimensions of image and move data point to start of image bits.
     */
    data += 4;
    cols = (short  *)&data[0]; rows = (short *) &data[2];
    datalen = datalen - 8;
    data += 4;		 /* skip origin and size info */
    width = *cols;
    height = *rows;
    /*
     * Build gif header in structure and output.
     */
    strcpy ( header.signature, "GIF87a" );
    header.width = *cols;
    header.height = *rows;
    header.flags = 0;			/* ASSUME 2^(0+1) = 2 BITS */
    header.flags = header.flags | 0x00080;	/* include GCT */
    header.aspect = 0;
    header.color_table[0] = header.color_table[1] = header.color_table[2] = 0;
    header.color_table[3] = header.color_table[4] = header.color_table[5] = 255;
    header.separator = ',';
    header.left = header.top = 0;
    header.iwidth = width;
    header.iheight = height;
    header.iflags = 0;
    header.code_size = 2;		/* first byte of raster data */

    status = output( outarg, sizeof(header), (char *) &header );
    if ( (status&1) == 0 ) return status;
    /*
     * Initialize data stream structure and do LZ compression on bits.
     * add bits automatically calls output routine when buffer fills.
     */
LIB$INIT_TIMER();
    bs.words_filled = 0;
    bs.bit_off = 8;			/* leave room for count byte. */
    bs.flush = output;
    bs.flush_arg = outarg;
    bs.buffer[0] = 0;

    status = compress_data ( &bs, 2, data, width, height );
    if ( (status&1) == 0 ) return status;
    /*
     * Flush remaining bits in buffer and add final trailer bytes.
     */
    count = bs.words_filled*4 + (bs.bit_off+7)/8;	/* include whole byte */
    if ( count > 1 ) {
	bs.buffer[0] |= (count-1);
        status = output ( outarg, count, (char *) bs.buffer );
	if ( (status&1) == 0 ) return status;
    }

    status = output ( outarg, 2, trailer );
    if ( (status&1) == 0 ) return status;
LIB$SHOW_TIMER();
    return status;
}
/*
 * GIF encoder.  
 *
 *     The Graphics Interchange Format(c) is the Copyright property of
 *     CompuServe Incorporated. GIF(sm) is a Service Mark property of 
 *     CompuServe Incorporated."
 *
 */


/*****************************************************************************/
static unsigned bmask[33] = { 
	0, 1, 3, 7, 15, 31, 63, 127, 255, 
	511, 1023, 2047, 4095, 8191, 0x03fff, 0x07fff, 0x0ffff, 
	0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff, 
	0x01fffff, 0x03ffff, 0x07ffff, 0x0ffffff,
	0x01ffffff, 0x03fffff, 0x07fffff, 0x0ffffff,
	0x1fffffff, 0x3ffffff, 0x7ffffff, 0xffffffff };


static int add_bits ( struct bitstream *bs, int value, int size )
{
    int cur, pos, off, ov_bits, status;
    unsigned low;

    cur = bs->words_filled;
    off = bs->bit_off;
#ifdef DEBUG
printf("<%d,%d=%d>", off, size, value );
#endif
    if ( off + size <= 32 ) {
	/*
	 * All fits in current longword of buffer.
	 */
	low = (value &bmask[size]);
	bs->buffer[cur] |= (low << off);
	bs->bit_off = off + size;
    } else {
	/*
	 * value straddles two longwords.
	 */
	ov_bits = size + off - 32;
	if ( ov_bits > 0 ) {
	    low = (value & bmask[size-ov_bits]);
	    bs->buffer[cur++] |= (low<<off);
	}
#ifdef DEBUG
printf("buf[%d]=%x\n", cur-1, bs->buffer[cur-1] );
#endif
	if ( cur > 62 ) {
	    long bcount;
	    bcount = cur*4;
	    bs->buffer[0] |= (bcount-1);	/* load first (low) byte */
	    
	    status = bs->flush ( bs->flush_arg, cur*4, (char *)bs->buffer );
	    if ( (status&1) == 0 ) return cur;
	    value = (value & (~bmask[size-ov_bits]));	/* zero field */
	    value = value << 8;   /* make room for count */
	    ov_bits += 8;
	    size += 8;
	    cur = 0;
	}

	low = value;
	low = (low>>(size-ov_bits));
	bs->buffer[cur] = (low & bmask[ov_bits]);
	bs->bit_off = ov_bits;
    }
    bs->words_filled = cur;
    return cur;
}

struct code_t_entry {
    short prefix, code, next_hash;
};

struct lz_state {
    int code_size;			/* Number of bits of input size */
    int clear;				/* value of clear code (2^code_size) */
    int eoi;				/* End-of-info code (clear+1); */
    int out_size;
    int max_code;			/* hight entry in code_table */
    int max_hash;
#define HASH_BITS 13
#define HASH_TABLE_SIZE 8192
    int hash_shift;			/* shift for charval in hash func */
    struct code_t_entry table[4096];	/* code table */
    short hash_table[HASH_TABLE_SIZE];
};
typedef struct lz_state *lzptr;

static int initialize_lz_state ( lzptr lz, int code_size )
{
    int i, max_code, max_hash;
    struct code_t_entry *table;
    short *hash;

    lz->code_size = code_size;
    lz->clear = 1;
    for ( i = 0; i < code_size; i++ ) lz->clear *= 2;
    lz->eoi = lz->clear+1;
    lz->out_size = code_size + 1;
    lz->max_code = max_code = lz->eoi;

    max_hash = HASH_TABLE_SIZE;
    lz->hash_shift = 12;
    while ( (code_size+lz->hash_shift) > HASH_BITS) {
	lz->hash_shift = lz->hash_shift - 1;
    }
    /* max_hash = bmask[code_size+lz->hash_shift]; * /
    max_hash = bmask[HASH_BITS];	/* optimize for 1 bit data */
    lz->max_hash = max_hash;
    /*
     * Initialize the tables.
     */
    table = lz->table;
    for ( i = 0; i <= max_code; i++ ) { 
	table[i].prefix = -1; table[i].code = i; table[i].next_hash = 0;
    }
    for ( ; i < 4096; i++ ) table[i].prefix = table[i].code = 0;

    hash = lz->hash_table;
    for ( i = 0; i < max_hash; i++ ) hash[i] = 0;

    return 1;
}


static int compress_data ( struct bitstream *bs, 
	int code_size, unsigned char *data, int width, int height )
{
    int code, prefix, current, new, out_size, i, j, hashval;
    int code_limit, value, mask;
    unsigned char *dptr, *data_end;
    struct code_t_entry *table;
    short *hash_table;
    struct lz_state lz;

    dptr = data;

    initialize_lz_state ( &lz, code_size );
    table = lz.table;
    hash_table = lz.hash_table;
    out_size = lz.out_size;
    code_limit = bmask[out_size];

    add_bits ( bs, lz.clear, out_size );
    value = *dptr++;
    prefix = (value&1) ? 0 : 1;		/* first bit */
    mask = 2;
    for ( i = 0; i < height; i++ ) {
    for ( j = (i==0) ? 1 : 0; j < width; j++ ) {
	/*
	 * Extract next bit from input bits.
	 */
	current = ((value&mask) != 0) ? 0 : 1;
	mask *= 2;
	if ( mask > 128 ) { mask = 1; value = *dptr++; }
	/* 
	 * Find prefix//current table entry 
	 */
	/* hashval = (lz.max_hash&((current<<lz.hash_shift) ^ prefix)); */
	hashval = (current << 12) |  prefix;   /* optimized */
	code = hash_table[hashval];
	while ( code  ) {
	    if ( (table[code].prefix == prefix) && 
		 (table[code].code == current) ) break;

	    code = table[code].next_hash;
	}
	/*
	 * If code is non-zero, current prefix//code found in table and i is
	 * the code.  Make it the prefix and continue loop;
	 */
	if ( code ) {
	    prefix = code;
	} else {
	    /*
	     * Entry not found, output current prefix.
	     */
	    add_bits ( bs, prefix, out_size );
	    /* prefix = current; */
	    /*
	     * Add new entry to table and update output size.
	     */
	    new = ++lz.max_code;
	    if ( new > code_limit ) {
	        out_size++;
	        code_limit = code_limit*2 + 1;
	    }
	    if ( new > 4092 ) {
		/* Reset so we don't overflow */
		add_bits ( bs, current, out_size );
		add_bits ( bs, lz.clear, out_size );
		current = lz.clear;
		initialize_lz_state ( &lz, code_size );
#ifdef DEBUG
printf("Reset code table, out_size %d, clear=%d\n", lz.out_size,  lz.clear );
#endif
		out_size = lz.out_size;
		code_limit = bmask[out_size];

		prefix = ((value&mask) != 0) ? 0 : 1;
		mask *= 2;
		if ( mask > 128 ) { mask = 1; value = *dptr++; }
		j++; if ( j >= width ) break;
	    } else {
	        lz.table[new].prefix = prefix;
	        lz.table[new].code = current;
	        lz.table[new].next_hash = hash_table[hashval];
	        lz.hash_table[hashval] = new;

		/* prefix for next value */
	        prefix = current;
	    }
	    
	}
    }
    if ( mask != 1 ) {	/* wrap to next byte at eol */
	mask = 1; value = *dptr++;;
    }
    }
    /*
     * Flush remaining to output.
     */
    add_bits ( bs, prefix, out_size );
    if ( i >= height ) { add_bits ( bs, lz.eoi, out_size ); return 1; }

    return 1;
}