home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
cprog
/
newprt10.zip
/
GRAFFILE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-17
|
15KB
|
581 lines
//Copyright 1991-1992 Roger Bedell All rights reserved
//See the attached readme file for licensing information.
#include "time.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "io.h"
#include "grafprnt.hpp"
#include "graffile.hpp"
#include "mem.h"
//global printer error flag set to 1 on a printer error
extern int printer_error_flag;
int check_for_user_input(void); //external function for allowing user abort
//Constructor for the base class.
graphics_file::graphics_file(char * filename)
{
//open the file and save its file pointer
file_ptr = fopen(filename,"rb");
if(file_ptr == NULL)
{
error_message("Could not open .PCX file",NONFATAL);
}
}
//Constructor for the derived class.
//pass the filename to the base class constructor
pcx_graphics_file::pcx_graphics_file(char * filename):graphics_file(filename)
{
}
//derived class for pcx file printing
void pcx_graphics_file::print_file(void)
{
//in this case its a PCX file
//read the PCX header and decide on how we are going to approach
//it (16 or 256 color etc...)
if(fread((char *)&pcx_header, 1, sizeof(PCX_HEAD), file_ptr) != sizeof(PCX_HEAD))
{
//couldnt read the header
error_message("couldnt read pcx header", NONFATAL);
return;
}
//check for reasonable values in the header
if(pcx_header.manufacturer != 0x0a)
{
error_message("Bad PCX header", NONFATAL);
return;
}
//allocate memory for the grey buffer.
//The grey buffer will hold one line of grey data,
//one byte per pixel.
grey_buffer_ptr = mem_malloc(pcx_header.xmax - pcx_header.xmin + 100);
//figure out how to handle it,whether its a 256 or 16 color
//bitmap
if(pcx_header.bits_per_pixel == 8)
{
//print the body object
print_256_body();
}
else if(pcx_header.bits_per_pixel == 1 && pcx_header.color_planes == 4)
{
//print the body object
print_16_body();
}
else
{
error_message("Bad PCX header", NONFATAL);
return;
}
mem_free( grey_buffer_ptr);
}
//body print for 256 color PCX files
//Note, this hasn't been fully tested
void pcx_graphics_file::print_256_body(void)
{
//read the palette (256 colors)
if(read_256_palette() == -1)
{
return;
}
//go to the start of the real data.
int return_code = fseek(file_ptr, 128L, SEEK_SET);
if (return_code != 0)
{
error_message("Could not seek to image data",NONFATAL);
return;
}
long temp = ftell(file_ptr);
//create a printer object.
//get a pointer that will be of the correct printer type
//pass it the pixels per line so it knows how big to
//allocate its buffers
printer = graphics_printer::allocate_graphics_printer(pcx_header.bytes_per_line);
//read in each line, expanding the compression,
//and calculating the grey value from the palette as we go
//and put the results in the grey buffer.
int i,j;
int dup_count;
int dup_byte;
int read_byte; //byte read in from the file
int num_lines = pcx_header.ymax - pcx_header.ymin;
int depth = pcx_header.ymax - pcx_header.ymin;
int buffer_count;
char *carry_buffer; //carries stuff from the end of the line to another
int carry_count = 0;
//carry buffer. Runs cant be longer than 256
carry_buffer = mem_malloc( 256 );
for( i = 0; i < depth; i++)
{
buffer_count = 0; //how far we are in the buffer
//put the stuff left over from the last run into the buffer
for( j = 0; j < carry_count; j ++)
{
grey_buffer_ptr[buffer_count] = carry_buffer[j];
buffer_count++;
}
carry_count = 0;
do //until we've unpacked a line
{
//get a byte.
read_byte = fgetc(file_ptr);
temp = ftell(file_ptr);
if(read_byte == EOF)
{
error_message("Unexpected end of data", NONFATAL);
break;
}
//trim off any upper stuff left over
read_byte &= 0xff;
//see if it is a run of bytes indicator (a 0xC0)
if( (read_byte & 0xc0) == 0xc0 )
{
//figure out how many bytes to duplicate
dup_count = read_byte & 0x3f;
//get the byte to duplicate
dup_byte = fgetc(file_ptr);
//convert the byte to the proper grey scale value
dup_byte = grey_convert_256(dup_byte);
//add the dup byte to the output buffer dup_count times
while(dup_count--)
{
if(buffer_count >= pcx_header.bytes_per_line - 1)
{ //overflow of the line buffer. carry it over
//to the next line
carry_buffer[carry_count++] = (char)dup_byte;
}
else //normal, add to the output buffer
{
grey_buffer_ptr[buffer_count++]=(char)dup_byte;
}
}
}
else //only one byte, convert and save it in the buffer
{
read_byte = grey_convert_256(read_byte);
grey_buffer_ptr[buffer_count++] = read_byte;
}
} while ( buffer_count < pcx_header.bytes_per_line );
//at the end of each line, send it out to the printer
printer -> print_grey_line(grey_buffer_ptr, pcx_header.bytes_per_line);
//check the printer error status
if(printer_error_flag == 1)
{
printer_error_flag = 0;
break;
}
//check for user input
//This allows the user to abort a print in mid-stream
if(check_for_user_input() == 1)
{
break;
}
}
//deallocate the printer object. Call a pseudo-destructor
//explicitly to make sure the right one is called (there may
//be a more elegant way to do this...)
printer->deallocate_graphics_printer();
delete printer;
//deallocate carry buffer.
mem_free(carry_buffer);
}
int pcx_graphics_file::read_256_palette(void)
{
//create a temporary rgb palette
unsigned char temp_palette[768];
//go to the end, then back 769 bytes
fseek(file_ptr,-769L,SEEK_END);
long temp2 = ftell(file_ptr);
//make sure the palette is there
int temp = fgetc(file_ptr);
temp2 = ftell(file_ptr);
if(temp != 0x0c)
{
error_message("Could not read 256 color palette",NONFATAL);
return -1;
}
//read the palette into the palette array
temp = fread(temp_palette, 1, 768, file_ptr);
temp2 = ftell(file_ptr);
if(temp != 768)
{
error_message("Could not read 256 color palette",NONFATAL);
return -1;
}
// Convert the RGB values to a grey scale number from 0-255
//See S.Rimmer, page 386
int i;
for( i = 0; i < 256; i++)
{
double red = 0.30 * double(temp_palette[i * 3]);
double green = 0.59 * double(temp_palette[(i * 3) +1]);
double blue = 0.11 * double(temp_palette[(i * 3) + 2]);
double total = red + green + blue;
unsigned char temp = unsigned char(total);
palette_256[i] = temp;
}
return 0;
}
//now, a little contrast needs to be added via a lookup
//table (Rimmer P388) to get a better looking image
unsigned char greymap[256] =
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21,
0x22, 0x23, 0x23, 0x24, 0x25, 0x27, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5a, 0x5b, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6a, 0x6b,
0x6c, 0x6e, 0x70, 0x72, 0x73, 0x74, 0x76, 0x78,
0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88,
0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x98, 0x9a,
0x9c, 0x9f, 0xa1, 0xa4, 0xa6, 0xa9, 0xab, 0xae,
0xb0, 0xb2, 0xb3, 0xb5, 0xb7, 0xb9, 0xba, 0xbc,
0xbd, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca,
0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd9, 0xdb,
0xdd, 0xe0, 0xe3, 0xe6, 0xe8, 0xeb, 0xed, 0xef,
0xf2, 0xf5, 0xf8, 0xfb, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe
};
int pcx_graphics_file::grey_convert_256(int convert_char)
{
//the input is an index into the palette
//we just need to convert it to a grey scale value
unsigned char grey_value = palette_256[convert_char];
//brighten it up a little
int temp = grey_value + 30;
if(temp > 255)
{
temp = 255;
}
grey_value = char(temp);
//substitute the lookup grey value for the one derived from
//the palette
return greymap[grey_value];
}
//body print for 16 color PCX files
//These are in planes, a little different to decode and transform
void pcx_graphics_file::print_16_body(void)
{
//read the palette (16 colors)
if(read_16_palette() == -1)
{
return;
}
//we should be already at the start of the data
long temp = ftell(file_ptr);
//create a printer object.
//get a pointer that will be of the correct printer type
//pass it the pixels per line so it knows how big to
//allocate its buffers
pixels_per_line = pcx_header.xmax - pcx_header.xmin;
printer = graphics_printer::allocate_graphics_printer(pixels_per_line);
//read in each line, expanding the compression,
//4 color pcx files are a little weird, the first line
//has the msbit of the palette index, the fourth line has
//the lsbit of the palett index etc So we need to read in
//four lines at a time, then convert to a grey line to
//output to the printer object
//and put the results in the grey buffer.
int i,j;
int dup_count;
int dup_byte;
int read_byte; //byte read in from the file
int num_lines = pcx_header.ymax - pcx_header.ymin;
int depth = pcx_header.ymax - pcx_header.ymin;
int buffer_count = 0;
int temp_line_count = 0;
char *temp_buffer[4]; //temporarily keeps the four lines
char *carry_buffer; //carries stuff from the end of the line to another
int carry_count = 0;
FILE * testfile = fopen("testout.out","w");
//allocate room for the temp buffers
for(i = 0; i < 4; i++)
{
temp_buffer[i] = mem_malloc( pcx_header.bytes_per_line + 256);
}
//carry buffer. Runs cant be longer than 256
carry_buffer = mem_malloc( 256 );
for( i = 0; i < depth; i++)
{
//do four lines at a time (four planes)
for(temp_line_count = 0; temp_line_count < 4; temp_line_count++)
{
buffer_count = 0;
//put the stuff left over from the last run into the buffer
for( j = 0; j < carry_count; j ++)
{
temp_buffer[temp_line_count][buffer_count] = carry_buffer[j];
buffer_count++;
}
carry_count = 0;
do //until we've unpacked a line
{
//get a byte.
read_byte = fgetc(file_ptr);
temp = ftell(file_ptr);
if(read_byte == EOF)
{
error_message("Unexpected end of data", NONFATAL);
break;
}
//trim off any upper stuff left over
read_byte &= 0xff;
//see if it is a run of bytes indicator (a 0xC0)
if( (read_byte & 0xc0) == 0xc0 )
{
//figure out how many bytes to duplicate
dup_count = read_byte & 0x3f;
//get the byte to duplicate
dup_byte = fgetc(file_ptr);
//add the dup byte to the output buffer dup_count times
while(dup_count--)
{
if(buffer_count >= pcx_header.bytes_per_line -1 )
{ //overflow of the line buffer. carry it over
//to the next line
carry_buffer[carry_count++] = (char)dup_byte;
}
else //normal, add to the output buffer
{
temp_buffer[temp_line_count][buffer_count++]=
(char)dup_byte;
}
}
}
else //only one byte, convert and save it in the buffer
{
temp_buffer[temp_line_count][buffer_count++]=(char)read_byte;
}
} while ( buffer_count < pcx_header.bytes_per_line );
}//end for
//convert the 4 plane lines to one grey line
grey_convert_16(temp_buffer);
//at the end of each line, send it out to the printer
printer -> print_grey_line(grey_buffer_ptr, pixels_per_line);
//check the printer error status
if(printer_error_flag == 1)
{
printer_error_flag = 0;
break;
}
//check for user input
//This allows the user to abort a print in mid-stream
if(check_for_user_input() == 1)
{
break;
}
}
//deallocate the printer object. Call a pseudo-destructor
//explicitly to make sure the right one is called (there may
//be a more elegant way to do this...)
printer->deallocate_graphics_printer();
delete printer;
//deallocate room for the temp buffers
for(i = 0; i < 4; i++)
{
mem_free(temp_buffer[i]);
}
//deallocate carry buffer.
mem_free(carry_buffer);
}
//converts the 4 plane lines to one grey line
int pcx_graphics_file::grey_convert_16(char * temp_buffer[4])
{
int temp_palette_index = 0;
for(int i = 0; i < pixels_per_line; i++)
{
temp_palette_index = 0;
for(int j = 0; j < 4; j ++)
{
//which bit?
int bit_in_byte = 0x80 >> (i % 8 );
int byte_num = i / 8;
//construct a palette index from the bits in each plane
//get the bit and put it in the temp palette index
//see if its a one or a zero
if(bit_in_byte & temp_buffer[j][byte_num])
{ //its a one
temp_palette_index |= 1 << j;
}
//else its a zero, so do nothing.
}
//so now we have the palette index, look up the grey palette
//and assign a grey 8 bit value to it and stick it in
//the grey buffer.
int temp_int = palette_16[temp_palette_index];
if(temp_int > 255)
{
temp_int = 255;
}
grey_buffer_ptr[i] = temp_int;
}
return 0;
}
//doesnt actually read anything, but sets up the
//grey 16 color palette
int pcx_graphics_file::read_16_palette(void)
{
// Convert the RGB values to a grey scale number from 0-255
//See S.Rimmer, page 386
int i;
for( i = 0; i < 16; i++)
{
double red = 0.30 * double(pcx_header.palette[i * 3]);
double green = 0.59 * double(pcx_header.palette[(i * 3) +1]);
double blue = 0.11 * double(pcx_header.palette[(i * 3) + 2]);
double total = red + green + blue;
unsigned char temp = unsigned char(total);
palette_16[i] = temp;
}
return 0;
}