////////////////////////////////////////////////////////// // pcl2bmp.cpp ////////////////////////////////////////////////////////// #include <ctype.h> #include <fstream.h> #include <iostream.h> #include <math.h> #ifdef __WATCOMC__ #include <mem.h> #else #include <memory.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include "bmpio.h" #include "pcl2bmp.h" #include "rasterop.h" #include "softfont.h" #include "util.h" static int px, py; static int rasterx, rastery; static int patternf; static int patternx, patterny; static int patternw, patternh; static FONTNODE *curfont[2]; // primary & secondary static int fontshift; static int fontid; static int charcode; static unsigned char bits[3300][300]; static int dirtybits; static BMPINFO bmpinfo; static int debugtrace, debugerror; int pcl2bmp( char *NamePcl, char *NameBmp ); int Execute( COMMAND& command, ifstream& ifPcl ); ///////////////////////////////////////////////////////////////// // main ///////////////////////////////////////////////////////////////// main( int argc, char *argv[] ) { bmpinfo.bits = (unsigned char *)bits; bmpinfo.width = 2400; bmpinfo.height = 3300; bmpinfo.colours = 2; bmpinfo.palette = NULL; bmpinfo.cropx = bmpinfo.cropy = 0; bmpinfo.scalex = bmpinfo.scaley = 1; for( int i=1; i<argc; i++ ) { if( argv[i][0] != '-' ) break; if( !stricmp(argv[i], "-c") ) bmpinfo.cropx = bmpinfo.cropy = 1; else if( !stricmp(argv[i], "-cx") ) bmpinfo.cropx = 1; else if( !stricmp(argv[i], "-cy") ) bmpinfo.cropy = 1; else if( !strnicmp(argv[i], "-sx", 3) ) bmpinfo.scalex = atoi( argv[i] + 3 ); else if( !strnicmp(argv[i], "-sy", 3) ) bmpinfo.scaley = atoi( argv[i] + 3 ); else if( !strnicmp(argv[i], "-s", 2) ) bmpinfo.scalex = bmpinfo.scaley = atoi( argv[i] + 2 ); else if( !stricmp(argv[i], "-trace") ) debugtrace = 1; else if( !stricmp(argv[i], "-debug") ) debugerror = 1; else cerr << "bmp2pcl: unknown option " << argv[i] << endl; } if( bmpinfo.scalex < 1 ) bmpinfo.scalex = 1; if( bmpinfo.scaley < 1 ) bmpinfo.scaley = 1; if( argc - i < 2 ) { cerr << endl; cerr << "pcl2bmp: convert HP LaserJet print file to bitmap" << endl << endl; cerr << " usage: pcl2bmp {options} infile.prn outfile" << endl; cerr << " the output file(s) will be named outfile1.bmp, outfile2.bmp, ..." << endl << endl; cerr << "options: -c crop top, bottom, left, and right edges" << endl; cerr << " -cx crop left and right edges" << endl; cerr << " -cy crop top and bottom edges" << endl; cerr << " -s# shrink width and height by factor of '#'" << endl; cerr << " -sx# shrink width by factor of '#'" << endl; cerr << " -sy# shrink height by factor of '#'" << endl << endl; cerr << " -trace output trace log to stdout" << endl; cerr << " -debug output error log to stderr" << endl; return 1; } pcl2bmp( argv[i], argv[i+1] ); return 0; } int pcl2bmp( char *NamePcl, char *NameBmp ) { ifstream ifPcl( NamePcl, ios::in | ios::binary | ios::nocreate ); ifPcl.setf( ios::binary, ios::binary | ios::skipws ); int PageNo = 1; char PageNameBmp[1024]; static COMMAND command0; COMMAND command; int phase = 0; int ch; ch = ifPcl.get(); while( ch != EOF ) { switch( phase ) { case 0: // search for ESC/control sequence if( ch == 0x1B ) { // ESC command = command0; command.control = ch; phase++; } else if( ch < ' ' || ch == 0x7f ) { // other control character command.control = ch; switch( command.control ) { case 0x0C: // Form-Feed if( dirtybits ) { sprintf( PageNameBmp, "%s%d.bmp", NameBmp, PageNo ); bmp_save( PageNameBmp, &bmpinfo ); memset( bits, 0, sizeof(bits) ); dirtybits = 0; } PageNo++; if( debugtrace ) cout << endl << "Ff "; break; case 0x0E: // SO: select secondary font fontshift = 1; if( debugtrace ) cout << endl << "So "; break; case 0x0F: // SI: select primary font fontshift = 0; if( debugtrace ) cout << endl << "Si "; break; default: if( debugerror ) cerr << endl << hex << "unk: 0x" << ch << " " << dec; break; } } else { px += (font_drawchar( bits, px, py, curfont[fontshift], ch ) + 2) / 4; dirtybits = 1; if( debugtrace ) cout << char(ch); } break; case 1: if( ch >= '!' && ch <= '/' ) { command.group1 = ch; phase++; } else if( ch >= '0' && ch <= '~' ) { // two character escape sequence command.term = ch; Execute( command, ifPcl ); phase = 0; } else { if( debugtrace ) cout << endl << "unk: Ec " << hex << "0x" << ch << dec << " " << endl; phase = 0; } break; case 2: phase++; command.sign = 0; command.value = 0.0; if( ch >= '`' && ch <= '~' ) { command.group2 = ch; } else { command.group2 = 0; continue; } break; case 3: if( ch=='+' || ch=='-' ) { command.sign = ch; ch = ifPcl.get(); } while( ch != EOF && isdigit(ch) ) { command.value = command.value * 10 + (ch - '0'); ch = ifPcl.get(); } if( ch=='.' ) { double frac = 0.1; while( (ch = ifPcl.get()) != EOF && isdigit(ch) ) { command.value += (ch - '0') * frac; frac /= 10; } } if( command.sign == '-' ) command.value = -command.value; phase++; continue; case 4: command.term = ch; Execute( command, ifPcl ); if( ch >= '`' && ch <= '~' ) { phase = 3; command.sign = 0; command.value = 0; } else phase = 0; break; } ch = ifPcl.get(); } // while if( dirtybits ) { sprintf( PageNameBmp, "%s%d.bmp", NameBmp, PageNo ); bmp_save( PageNameBmp, &bmpinfo ); } return 0; } int Execute( COMMAND& command, ifstream& ifPcl ) { command.error = 1; // unrecognized command if( command.control == 0x1B ) { switch( command.group1 ) { case 0: switch( command.term ) { case 'E': // reset command.error = 2; break; } break; case ')': case '(': switch( command.group2 ) { case 's': switch( command.term ) { case 'W': if( command.group1 == ')' ) { // font descriptor and data int cdata = int(command.value); char *pdata = new char[cdata]; if( pdata ) { ifPcl.read( pdata, cdata ); font_new( fontid, pdata, cdata ); delete pdata; } } else { // char descriptor and data int cdata = int(command.value); char *pdata = new char[cdata]; if( pdata ) { ifPcl.read( pdata, cdata ); font_newchar( fontid, charcode, pdata, cdata ); delete pdata; } } command.error = 0; break; } break; case 0: if( toupper(command.term) == 'X' ) { curfont[command.group1==')'] = font_find( int(command.value) ); command.error = 0; } break; } break; case '*': switch( command.group2 ) { case 'b': // Raster Graphics switch( toupper(command.term) ) { case 'M': // set compression method // 0=unencoded // 1=run-length encoding // 2=TIFF revision 4.0 // 3=delta row // 5=adaptive compression command.error = 2; // ignored command break; case 'W': // transfer raster data { int i = rasterx/8, j = rasterx % 8; int n = int(command.value); int ch; while( n-- && (ch = ifPcl.get()) != EOF ) { if( ch ) { dirtybits = 1; bits[rastery][i++] |= ch >> j; bits[rastery][i] |= ch << (8-j); } else i++; } rastery++; py++; } command.error = 0; // processed command break; case 'Y': // y offset command.error = 2; // ignored command break; } break; case 'c': // Rectangular Area Fill Graphics switch( toupper(command.term) ) { case 'A': // rectangle width (dots) patternw = int(command.value); command.error = 0; break; case 'B': // rectangle height (dots) patternh = int(command.value); command.error = 0; break; case 'H': // rectangle width (decipoints) patternw = int( (long(command.value * 300) + 719) / 720 ); command.error = 0; break; case 'V': // rectangle height (decipoints) patternh = int( (long(command.value * 300) + 719) / 720 ); command.error = 0; break; case 'G': // area fill ID (pattern ID) // shading: 1-2, 2-10, 11-20, 21-35, 36-55, 56-80, 81-99, 100 // cross-hatch: 1 -, 2 |, 3 /, 4 \, 5 #, 6 X // user-defined: # of pattern (0-32767) command.error = 2; // ignored break; case 'P': // fill rectangular area switch( int(command.value) ) { case 0: // solid if( patternw > 0 && patternh > 0 ) { bit_set( bits, px, py, px + patternw - 1, py + patternh - 1 ); dirtybits = 1; } command.error = 0; break; case 1: // solid white command.error = 2; // ignored break; case 2: // shading command.error = 2; // ignored break; case 3: // cross-hatch pattern command.error = 2; // ignored break; case 4: // user-defined pattern command.error = 2; // ignored break; case 5: // current pattern command.error = 2; // ignored break; } break; case 'Q': // pattern control // 0=delete all paterns // 1=delete all temporary patterns // 2=delete pattern (last pattern ID specified) // 3=reserved // 4=make pattern temporary (last pattern ID specified) // 5=make pattern permanent (last pattern ID specified) command.error = 2; // ignored break; case 'W': // user-defined pattern // followed by # of pattern bytes ifPcl.ignore( int(command.value) ); command.error = 2; // ignored break; case 'D': // font ID fontid = int(command.value); command.error = 0; break; case 'E': // char code charcode = int(command.value); command.error = 0; break; case 'F': // soft font control command.error = 2; // ignored break; } break; case 'p': // Cursor Positioning/Rectangular Area Fill Graphics switch( toupper(command.term) ) { case 'R': // set pattern reference point // 0=rotate patterns with print direction // 1=keep patterns fixed patternf = int(command.value); patternx = px; patterny = py; command.error = 2; // ignored break; case 'X': // horizontal (dots) if( command.sign ) px += int(command.value); else px = int(command.value); command.error = 0; break; case 'Y': // vertical (dots) if( command.sign ) py += int(command.value); else py = int(command.value); command.error = 0; break; } break; case 'r': // Raster Graphics switch( toupper(command.term) ) { case 'A': // start // 0=at x-position 0 // 1=at current x-position if( int(command.value) ) rasterx = px; else rastery = 0; rastery = py; command.error = 0; break; case 'B': // end: any LaserJet case 'C': // end: LJ IIISi and IIIP command.error = 0; break; case 'F': // presentation mode // 0=current print direction // 3=along width of physical page command.error = 2; // ignored break; case 'S': // raster width command.error = 2; // ignored break; case 'T': // raster height command.error = 2; // ignored break; } break; case 't': // Raster Graphics if( toupper(command.term) == 'R' ) { // Resolution: values 75, 100, 150, 300 if( int(command.value) == 300 ) command.error = 0; else command.error = 2; // ignored } break; } break; } } if( command.control == 0x1B ) { ostream *pcout; switch( command.error ) { case 0: pcout = &cout; if( debugtrace ) *pcout << endl; break; case 1: pcout = &cerr; if( debugerror ) *pcout << endl << "unk: "; break; case 2: pcout = &cerr; if( debugerror ) *pcout << endl << "nop: "; break; default: pcout = &cerr; if( debugerror ) *pcout << endl << "int: "; break; } if( pcout == &cout && debugtrace || pcout == &cerr && debugerror ) { if( command.group1 ) { *pcout << "Ec " << command.group1; if( command.group2 ) *pcout << command.group2; *pcout << command.term << " "; if( command.sign ) *pcout << command.sign; *pcout << fabs(command.value) << " "; } else { *pcout << "Ec " << command.term << " "; } } } return 0; }