home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
cprog
/
newprt10.zip
/
GRAFPRNT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-17
|
16KB
|
615 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;
void * graphics_printer::allocate_graphics_printer(int pixels_per_line)
{
void *printer_ptr;
//figure out which kind of printer to create
switch(printer_type)
{
case 1:
printer_ptr = new epson_24_graphics_printer(pixels_per_line);
break;
case 2:
printer_ptr = new hp_laser_graphics_printer(pixels_per_line);
break;
}
return printer_ptr;
}
void graphics_printer::line_feed()
{
char feed[3] = {0x0a,0x0d};
send_print_buffer(feed,2);
}
extern int bbprinter_number;
int send_cmd( char *line_buffer, int length );
int opn_prt(char * path ,int i);
int cls_prt(int flag);
int flush_buf(void);
void epson_24_graphics_printer::open_graphics_printer()
{
port_handle = 4; //prn device
bbprinter_number = 0;
opn_prt("lpt1", 0);
//send it the appropriate string for turn on
char turn_on_string[6]={0x1b,0x40,0x1b,0x33,0x18};
send_print_buffer(turn_on_string, 5);
}
void hp_laser_graphics_printer::open_graphics_printer()
{
port_handle = 4; //prn device
bbprinter_number = 0;
opn_prt("lpt1", 0);
//set it to 300 dpi and prepare for graphics
send_print_buffer("\x1b*t300R", strlen("\x1b*t300R"));
send_print_buffer("\x1b*r0A", strlen("\x1b*r0A"));
}
void epson_24_graphics_printer::close_graphics_printer()
{
//send it the appropriate string for turn on
char turn_off_string[6]={0xC};
send_print_buffer(turn_off_string, 1);
}
void hp_laser_graphics_printer::close_graphics_printer()
{
//send it the appropriate string for turn off
send_print_buffer("\x1b*rB", strlen("\x1b*rB"));
send_print_buffer("\x0c", strlen("\x0c"));
}
void graphics_printer::send_print_buffer(char * line_buffer, int length)
{
send_cmd(line_buffer, length);
}
void epson_24_graphics_printer::send_graphics_buffer(char * line_buffer, int length)
{
//for an epson, the width is in dot columns
//in this case three bytes for each column
int temp = length / 3;
char n1 = temp % 256;
char n2 = temp / 256;
//send the epson prelude to a graphics line
char turn_on_graphics_string[6]={0x1B,0x2A,0x27};
turn_on_graphics_string[3]=n1;
turn_on_graphics_string[4]=n2;
send_print_buffer(turn_on_graphics_string, 5);
send_print_buffer(line_buffer, length);
//do a line feed
char turn_off_graphics_string[6]={0xD,0xA};
send_print_buffer(turn_off_graphics_string, 2);
}
void hp_laser_graphics_printer::send_graphics_buffer(unsigned char * line_buffer, int length)
{
//for an HP, the width is in dot columns
//in this case three bytes for each column
//send the hp prelude to a graphics line
char turn_on_graphics[20];
sprintf(turn_on_graphics,"\x1b*b%dW", length);
send_print_buffer(turn_on_graphics, strlen(turn_on_graphics));
//send the data itself. no line feed is necessary
send_print_buffer((char *)line_buffer, length);
}
//this is the entry to the printer from the graphics file object
//a generic grey scaled line is passed to this method. The
//printer object will then dither and print this line according
//to the scaling factors required for the printer resolution and
//page size.
void graphics_printer::print_grey_line(char * buffer, int buffer_length)
{
//Set the object variables
grey_line_buffer = buffer;
grey_line_count = buffer_length;
expand_grey_line();
//send the expanded grey info to the ditherer a line at a time,
//then convert
//the dithered line to a line of bits, then send the line of bits
//to the printer
int i;
for(i = 0; i < expansion_factor_y; i++)
{
//send a line to the ditherer, it will produce a dithered line
dither_expanded_line(i);
//send the line to the bits converter, produces a bits line
convert_dithered_line_to_bits();
//send the bits line to the printer
bits_to_printer();
}
}
//constructor
//pass it the width of the pcx graphic so it can allocae buffers
epson_24_graphics_printer::epson_24_graphics_printer(int pixels_per_line)
{
//set the expansion factors
expansion_factor_x = 2;
expansion_factor_y = 2;
//init pin counter counts from 0 to 23 pins on this 24 pin ptr
pin_number = 0;
//and the length of each line
len_expanded_lines = expansion_factor_x * pixels_per_line;
//allocate memory for the various buffers
//allocate memory for the expansion buffer
for( int j = 0; j < expansion_factor_y; j++)
{
expansion_buffer[j] = mem_malloc(len_expanded_lines);
if(expansion_buffer[j] ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
}
//and for the dither buffer
for( j = 0; j < 2; j++)
{
dither_buffer[j] = mem_malloc(len_expanded_lines + 10);
if(dither_buffer[j] ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
//set the dither buffer to all 129s so it will be white with
//very little error in the first line
memset(dither_buffer[j], 255, len_expanded_lines);
}
completed_dither_buffer = mem_malloc(len_expanded_lines);
if(completed_dither_buffer ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
bits_buffer = mem_malloc(((len_expanded_lines) / 8) + 1);
if(bits_buffer ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
//and for the printer buffer itself.
printer_buffer = mem_malloc(len_expanded_lines * 3);
if(printer_buffer ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
//clear it
memset(printer_buffer, 0, len_expanded_lines * 3);
open_graphics_printer();
}
//destructor
void epson_24_graphics_printer::deallocate_graphics_printer(void)
{
int j;
//deallocate the memory for the buffers
for( j = 0; j < expansion_factor_y; j++)
{
mem_free(expansion_buffer[j]);
}
//deallocate the memory for the buffers
for( j = 0; j < 2; j++)
{
mem_free(dither_buffer[j]);
}
mem_free(completed_dither_buffer);
mem_free(bits_buffer);
mem_free(printer_buffer);
close_graphics_printer();
}
//constructor
//pass it the width of the pcx graphic so it can allocae buffers
hp_laser_graphics_printer::hp_laser_graphics_printer(int pixels_per_line)
{
//set the expansion factors
expansion_factor_x = 3;
expansion_factor_y = 3;
//and the length of each line
len_expanded_lines = expansion_factor_x * pixels_per_line;
//allocate memory for the various buffers
//allocate memory for the expansion buffer
for( int j = 0; j < expansion_factor_y; j++)
{
expansion_buffer[j] = mem_malloc(pixels_per_line * expansion_factor_x);
if(expansion_buffer[j] ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
}
//and for the dither buffer
for( j = 0; j < 2; j++)
{
dither_buffer[j] = mem_malloc(pixels_per_line * expansion_factor_x + 10);
if(dither_buffer[j] ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
//set the dither buffer to all 129s so it will be white with
//very little error in the first line
memset(dither_buffer[j], 255, len_expanded_lines);
}
completed_dither_buffer = mem_malloc(len_expanded_lines);
if(completed_dither_buffer == NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
//and for the bits buffer. no printer buffer is needed
//as this is the final step
bits_buffer = mem_malloc(((len_expanded_lines) / 8) + 1);
if(bits_buffer ==NULL)
{
error_message("Not enough memory for print buffer.",NONFATAL);
deallocate_graphics_printer();
return;
}
open_graphics_printer();
}
//destructor
void hp_laser_graphics_printer::deallocate_graphics_printer(void)
{
int j;
//deallocate the memory for the buffers
for( j = 0; j < expansion_factor_y; j++)
{
mem_free(expansion_buffer[j]);
}
//deallocate the memory for the buffers
for( j = 0; j < 2; j++)
{
mem_free(dither_buffer[j]);
}
mem_free(completed_dither_buffer);
mem_free(bits_buffer);
close_graphics_printer();
}
//generic grey line expander. Given the x and y expansion
//factors, we can expand the grey line into the expand buffer
void graphics_printer::expand_grey_line()
{
//currently we can only handle integral expansion factors
int i,j,k;
//for each and every byte in the grey line...
for( i = 0; i < grey_line_count; i++)
{
//expand the number of times specified in the y direction
for( j = 0; j < expansion_factor_y; j++)
{
//expand the number of times specified in the x direction
for( k = 0; k < expansion_factor_x; k++)
{
expansion_buffer[j][(i * expansion_factor_x) + k] =
grey_line_buffer[i];
}
}
}
}
void graphics_printer::dither_expanded_line(int line_number)
{
//takes the specified expanded line and puts it into the
//bottom of the dither buffer. Then runs the Floyd Steinberg
//dither algorithm on the three lines in the buffer. When
//done, takes the top line and copies it into the completed
//dithered line buffer.
//copy the second line into the first
memcpy(dither_buffer[0], dither_buffer[1], len_expanded_lines);
//and the new one into the second
memcpy(dither_buffer[1], expansion_buffer[line_number], len_expanded_lines);
int error;
//apply Floyd Steinberg dither to the dither buffer
//go along the top row and diffuse the errors that are seen
//however, do a serpentine scan. Dither from the left
//to right one time, then right to left the next time
if(serpentine == 0)
{ //left to right
serpentine = 1;
for( int i = 1; i < len_expanded_lines - 2; i++)
{
if(dither_buffer[0][i] > 128) //it will be white
{
//calculate the error (since its not quite white)
error = dither_buffer[0][i] - 255;
}
else //it will be a black dot
{
//calculate the error (since its not quite black)
error = dither_buffer[0][i];
}
//Now distribute the error.
//see Rimmer P.391
dither_buffer[0][i + 1] += (7 * error) / 16;
dither_buffer[1][i - 1] += (3 * error) / 16;
dither_buffer[1][i] += (5 * error) / 16;
dither_buffer[1][i + 1] += (1 * error) / 16;
}
}
else //dither right to left
{
serpentine = 0;
for( int i = len_expanded_lines; i > 2; i--)
{
if(dither_buffer[0][i] > 128) //it will be white
{
//calculate the error (since its not quite white)
error = dither_buffer[0][i] - 255;
}
else //it will be a black dot
{
//calculate the error (since its not quite black)
error = dither_buffer[0][i];
}
//Now distribute the error.
//see Rimmer P.391
dither_buffer[0][i + 1] += (7 * error) / 16;
dither_buffer[1][i - 1] += (3 * error) / 16;
dither_buffer[1][i] += (5 * error) / 16;
dither_buffer[1][i + 1] += (1 * error) / 16;
}
}
//Copy the completed first line to the completed dither buffer
memcpy(completed_dither_buffer, dither_buffer[0], len_expanded_lines);
}
void graphics_printer::convert_dithered_line_to_bits(void)
{
//takes the dithered line buffer and converts it to
//a single line of bits using a threshold of 128
char set_byte;
//clear the bits buffer to all zeros
memset(bits_buffer, 0 , (len_expanded_lines / 8)+1);
for( int i = 0; i < len_expanded_lines; i++)
{
if(completed_dither_buffer[i] > 128)
{
//its white, so dont print it (0)
//(nothing needs to be done)
}
else //its black, so print it (1)
{
set_byte = 1; //start with one
set_byte = set_byte << (i % 8); //left shift to get it in the right spot
bits_buffer[i / 8] |= set_byte; //Or it to set the right bit
}
}
}
void graphics_printer::bits_to_printer(void)
{
//takes the line of bits and sends it to the printer. If its
//a dot matrix, this is a little more complicated, but
//eventually the printer prints out a line made of these bits.
//laser printers are really easy!
}
void epson_24_graphics_printer::bits_to_printer(void)
{
//takes the line of bits and sends it to the printer.
//In this case, the orientation of the pins on the printer
//and how they are addressed assume primary proportion
//In a 24 pin printer, there are three bytes for each
//24 pin impact. What we will do is set the bits for
//the top pin all the way across the paper, then the
//second pin the next time this routine is called etc.
//when we've done this 24 times, we ship the whole thing
//out to the printer.
//we're dealing with the same pin all the way across the swath
int pin_row_byte = pin_number / 8;
int pin_row_bit = pin_number % 8;
//Top pin is the MSBit
unsigned char pin_row_set_bit = 0x80 >> pin_row_bit;
for( int i = 0; i < len_expanded_lines; i++)
{
//see if the ith bit is 1 or 0 and
//set the corresponding bit in the printer buffer
unsigned char set_byte = 0x01; //start with one
set_byte = set_byte << (i % 8); //left shift to get it in the right spot
//Note that the least significant bit in the
//3 byte word controls the bottom pin, the most
//significant bit controls the top pin
if(bits_buffer[i / 8] & set_byte) //set or not?
{
//its a one!
//so set the pin in the swath . This is the final step
//before printing
printer_buffer[( i * 3 ) + pin_row_byte ] |= pin_row_set_bit;
}
else
{//do nothing
}
}
if(++pin_number >= 24)
{
//print the swath
send_graphics_buffer(printer_buffer,len_expanded_lines * 3);
// printf("Swath printed.\n");
//clear out the printer buffer
memset(printer_buffer, 0, len_expanded_lines * 3);
//reset the pin counter
pin_number = 0;
}
}
void reverse_bytes_in_buffer(unsigned char *buffer, int len);
void hp_laser_graphics_printer::bits_to_printer(void)
{
//takes the line of bits and sends it to the printer.
//In this case, the orientation of the pins on the printer
//and how they are addressed assume primary proportion
//In a laser printer, there is one bit for each dot
//just ship them out the way they are in the dot buffer
//reverse the bytes, then ship them out
reverse_bytes_in_buffer(bits_buffer, len_expanded_lines / 8);
send_graphics_buffer(bits_buffer, len_expanded_lines / 8);
}
//for each byte in the buffer, reverse the bit order
void reverse_bytes_in_buffer(unsigned char *buffer, int len)
{
//for each byte in the buffer, reverse the bit order
for(int i = 0; i < len; i ++)
{
char temp_char = buffer[i];
char temp_char2 = 0;
for (int j=0; j < 8; j++)
{
temp_char2 = temp_char2 << 1;
if(temp_char & 1 == 1)
{
//or a one to the the end result
temp_char2 |= 1;
}
//left shift the end result and right shift the temp
temp_char = temp_char >> 1;
}
buffer[i] = temp_char2;
}
}