mirror of
https://github.com/digarok/gsplus.git
synced 2025-02-20 02:28:57 +00:00
2121 lines
57 KiB
Plaintext
2121 lines
57 KiB
Plaintext
/*
|
|
GSport - an Apple //gs Emulator
|
|
Copyright (C) 2010 - 2011 by GSport contributors
|
|
|
|
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2002-2004 The DOSBox Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
//Modified for the KEGS emulator by Christopher G. Mason 02/2010
|
|
//Added support for configuring the built in printer fonts
|
|
|
|
#include "printer.h"
|
|
#include <math.h>
|
|
#include "support.h"
|
|
//#include "png.h"
|
|
//#pragma comment( lib, "libpng.lib" )
|
|
//#pragma comment (lib, "zdll.lib" )
|
|
|
|
static CPrinter* defaultPrinter = NULL;
|
|
|
|
static FILE *textPrinterFile = NULL;
|
|
#ifdef WIN32
|
|
const char* const textPrinterFileName = ".\\printer.txt";
|
|
#else
|
|
const char* const textPrinterFileName = "./printer.txt";
|
|
#endif
|
|
|
|
#define PARAM16(I) (params[I+1]*256+params[I])
|
|
#define PIXX ((Bitu)floor(curX*dpi+0.5))
|
|
#define PIXY ((Bitu)floor(curY*dpi+0.5))
|
|
|
|
static Bitu printer_timout;
|
|
static bool timeout_dirty;
|
|
static const char* document_path;
|
|
extern "C" char* g_printer_font_roman;
|
|
extern "C" char* g_printer_font_sans;
|
|
extern "C" char* g_printer_font_courier;
|
|
extern "C" char* g_printer_font_prestige;
|
|
extern "C" char* g_printer_font_script;
|
|
extern "C" char* g_printer_font_ocra;
|
|
Bit8u paramc = '0';
|
|
|
|
#include "printer_charmaps.h"
|
|
|
|
#ifdef HAVE_SDL
|
|
void CPrinter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal)
|
|
{
|
|
float red=redmax/30.9;
|
|
float green=greenmax/30.9;
|
|
float blue=bluemax/30.9;
|
|
|
|
Bit8u colormask=colorID<<=5;
|
|
|
|
for(int i = 0; i < 32;i++) {
|
|
pal->colors[i+colormask].r=255-(red*(float)i);
|
|
pal->colors[i+colormask].g=255-(green*(float)i);
|
|
pal->colors[i+colormask].b=255-(blue*(float)i);
|
|
}
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
CPrinter::CPrinter(Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput)
|
|
{
|
|
#ifdef HAVE_SDL
|
|
if (FT_Init_FreeType(&FTlib))
|
|
{
|
|
page = NULL;
|
|
}
|
|
else
|
|
{
|
|
this->dpi = dpi;
|
|
this->output = output;
|
|
this->multipageOutput = multipageOutput;
|
|
|
|
defaultPageWidth = (Real64)width/(Real64)10;
|
|
defaultPageHeight = (Real64)height/(Real64)10;
|
|
|
|
// Create page
|
|
page = SDL_CreateRGBSurface(
|
|
SDL_SWSURFACE,
|
|
(Bitu)(defaultPageWidth*dpi),
|
|
(Bitu)(defaultPageHeight*dpi),
|
|
8,
|
|
0,
|
|
0,
|
|
0,
|
|
0);
|
|
|
|
// Set a grey palette
|
|
SDL_Palette* palette = page->format->palette;
|
|
|
|
for (Bitu i=0; i<32; i++)
|
|
{
|
|
palette->colors[i].r =255;
|
|
palette->colors[i].g =255;
|
|
palette->colors[i].b =255;
|
|
}
|
|
// 0 = all white needed for logic 000
|
|
FillPalette( 0, 0, 0, 1, palette);
|
|
// 1 = magenta* 001
|
|
FillPalette( 0, 255, 0, 1, palette);
|
|
// 2 = cyan* 010
|
|
FillPalette(255, 0, 0, 2, palette);
|
|
// 3 = "violet" 011
|
|
FillPalette(255, 255, 0, 3, palette);
|
|
// 4 = yellow* 100
|
|
FillPalette( 0, 0, 255, 4, palette);
|
|
// 5 = red 101
|
|
FillPalette( 0, 255, 255, 5, palette);
|
|
// 6 = green 110
|
|
FillPalette(255, 0, 255, 6, palette);
|
|
// 7 = black 111
|
|
FillPalette(255, 255, 255, 7, palette);
|
|
|
|
// yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max
|
|
// Printing colors on top of each other ORs them and gets the
|
|
// correct resulting color.
|
|
// i.e. magenta on blank page yyy=001
|
|
// then yellow on magenta 001 | 100 = 101 = red
|
|
|
|
color=COLOR_BLACK;
|
|
|
|
curFont = NULL;
|
|
charRead = false;
|
|
autoFeed = false;
|
|
outputHandle = NULL;
|
|
|
|
resetPrinter();
|
|
|
|
if (strcasecmp(output, "printer") == 0)
|
|
{
|
|
#if defined (WIN32)
|
|
// Show Print dialog to obtain a printer device context
|
|
|
|
PRINTDLG pd;
|
|
pd.lStructSize = sizeof(PRINTDLG);
|
|
pd.hDevMode = (HANDLE) NULL;
|
|
pd.hDevNames = (HANDLE) NULL;
|
|
pd.Flags = PD_RETURNDC;
|
|
pd.hwndOwner = NULL;
|
|
pd.hDC = (HDC) NULL;
|
|
pd.nFromPage = 1;
|
|
pd.nToPage = 1;
|
|
pd.nMinPage = 0;
|
|
pd.nMaxPage = 0;
|
|
pd.nCopies = 1;
|
|
pd.hInstance = NULL;
|
|
pd.lCustData = 0L;
|
|
pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL;
|
|
pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;
|
|
pd.lpPrintTemplateName = (LPCSTR) NULL;
|
|
pd.lpSetupTemplateName = (LPCSTR) NULL;
|
|
pd.hPrintTemplate = (HANDLE) NULL;
|
|
pd.hSetupTemplate = (HANDLE) NULL;
|
|
PrintDlg(&pd);
|
|
// TODO: what if user presses cancel?
|
|
printerDC = pd.hDC;
|
|
#endif // WIN32
|
|
}
|
|
}
|
|
#endif // HAVE_SDL
|
|
#ifndef HAVE_SDL
|
|
this->output = output;
|
|
this->multipageOutput = multipageOutput;
|
|
#endif // !HAVE_SDL
|
|
};
|
|
|
|
void CPrinter::resetPrinterHard()
|
|
{
|
|
#ifdef HAVE_SDL
|
|
charRead = false;
|
|
resetPrinter();
|
|
#endif // HAVE_SDL
|
|
}
|
|
|
|
void CPrinter::resetPrinter()
|
|
{
|
|
#ifdef HAVE_SDL
|
|
color=COLOR_BLACK;
|
|
curX = curY = 0.0;
|
|
ESCSeen = false;
|
|
FSSeen = false;
|
|
ESCCmd = 0;
|
|
numParam = neededParam = 0;
|
|
topMargin = 0.0;
|
|
leftMargin = 0.0;
|
|
rightMargin = pageWidth = defaultPageWidth;
|
|
bottomMargin = pageHeight = defaultPageHeight;
|
|
lineSpacing = (Real64)1/6;
|
|
cpi = 10.0;
|
|
curCharTable = 1;
|
|
style = 0;
|
|
extraIntraSpace = 0.0;
|
|
printUpperContr = true;
|
|
bitGraph.remBytes = 0;
|
|
densk = 0;
|
|
densl = 1;
|
|
densy = 2;
|
|
densz = 3;
|
|
charTables[0] = 0; // Italics
|
|
charTables[1] = charTables[2] = charTables[3] = 437;
|
|
definedUnit = -1;
|
|
multipoint = false;
|
|
multiPointSize = 0.0;
|
|
multicpi = 0.0;
|
|
hmi = -1.0;
|
|
msb = 255;
|
|
numPrintAsChar = 0;
|
|
LQtypeFace = roman;
|
|
|
|
selectCodepage(charTables[curCharTable]);
|
|
|
|
updateFont();
|
|
|
|
#endif // HAVE_SDL
|
|
newPage(false,true);
|
|
#ifdef HAVE_SDL
|
|
|
|
// Default tabs => Each eight characters
|
|
for (Bitu i=0;i<32;i++)
|
|
horiztabs[i] = i*8*(1/(Real64)cpi);
|
|
numHorizTabs = 32;
|
|
|
|
numVertTabs = 255;
|
|
#endif // HAVE_SDL
|
|
}
|
|
|
|
|
|
CPrinter::~CPrinter(void)
|
|
{
|
|
#ifdef HAVE_SDL
|
|
finishMultipage();
|
|
if (page != NULL)
|
|
{
|
|
SDL_FreeSurface(page);
|
|
page = NULL;
|
|
FT_Done_FreeType(FTlib);
|
|
}
|
|
#if defined (WIN32)
|
|
DeleteDC(printerDC);
|
|
#endif
|
|
#endif // HAVE_SDL
|
|
};
|
|
|
|
#ifdef HAVE_SDL
|
|
void CPrinter::selectCodepage(Bit16u cp)
|
|
{
|
|
Bit16u *mapToUse = NULL;
|
|
|
|
switch(cp)
|
|
{
|
|
case 0: // Italics, use cp437
|
|
case 437:
|
|
mapToUse = (Bit16u*)&cp437Map;
|
|
break;
|
|
case 737:
|
|
mapToUse = (Bit16u*)&cp737Map;
|
|
break;
|
|
case 775:
|
|
mapToUse = (Bit16u*)&cp775Map;
|
|
break;
|
|
case 850:
|
|
mapToUse = (Bit16u*)&cp850Map;
|
|
break;
|
|
case 852:
|
|
mapToUse = (Bit16u*)&cp852Map;
|
|
break;
|
|
case 855:
|
|
mapToUse = (Bit16u*)&cp855Map;
|
|
break;
|
|
case 857:
|
|
mapToUse = (Bit16u*)&cp857Map;
|
|
break;
|
|
case 860:
|
|
mapToUse = (Bit16u*)&cp860Map;
|
|
break;
|
|
case 861:
|
|
mapToUse = (Bit16u*)&cp861Map;
|
|
break;
|
|
case 863:
|
|
mapToUse = (Bit16u*)&cp863Map;
|
|
break;
|
|
case 864:
|
|
mapToUse = (Bit16u*)&cp864Map;
|
|
break;
|
|
case 865:
|
|
mapToUse = (Bit16u*)&cp865Map;
|
|
break;
|
|
case 866:
|
|
mapToUse = (Bit16u*)&cp866Map;
|
|
break;
|
|
default:
|
|
//LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp);
|
|
mapToUse = (Bit16u*)&cp437Map;
|
|
}
|
|
|
|
for (int i=0; i<256; i++)
|
|
curMap[i] = mapToUse[i];
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
#ifdef HAVE_SDL
|
|
void CPrinter::updateFont()
|
|
{
|
|
// char buffer[1000];
|
|
if (curFont != NULL)
|
|
FT_Done_Face(curFont);
|
|
|
|
char* fontName;
|
|
|
|
switch (LQtypeFace)
|
|
{
|
|
case roman:
|
|
fontName = g_printer_font_roman;
|
|
break;
|
|
case sansserif:
|
|
fontName = g_printer_font_sans;
|
|
break;
|
|
case courier:
|
|
fontName = g_printer_font_courier;
|
|
break;
|
|
case prestige:
|
|
fontName = g_printer_font_prestige;
|
|
break;
|
|
case script:
|
|
fontName = g_printer_font_script;
|
|
break;
|
|
case ocra:
|
|
case ocrb:
|
|
fontName = g_printer_font_ocra;
|
|
break;
|
|
default:
|
|
fontName = g_printer_font_roman;
|
|
}
|
|
|
|
if (FT_New_Face(FTlib, fontName, 0, &curFont))
|
|
{
|
|
|
|
printf("Unable to load font %s\n");
|
|
//LOG_MSG("Unable to load font %s", fontName);
|
|
curFont = NULL;
|
|
}
|
|
|
|
Real64 horizPoints = 10.5;
|
|
Real64 vertPoints = 10.5;
|
|
|
|
if (!multipoint) {
|
|
actcpi = cpi;
|
|
/*
|
|
switch(style & (STYLE_CONDENSED|STYLE_PROP)) {
|
|
case STYLE_CONDENSED: // only condensed
|
|
if (cpi == 10.0) {
|
|
actcpi = 17.14;
|
|
horizPoints *= 10.0/17.14;
|
|
} else if(cpi == 12.0) {
|
|
actcpi = 20.0;
|
|
horizPoints *= 10.0/20.0;
|
|
vertPoints *= 10.0/12.0;
|
|
} else {
|
|
// ignored
|
|
}
|
|
break;
|
|
case STYLE_PROP|STYLE_CONDENSED:
|
|
horizPoints /= 2.0;
|
|
break;
|
|
case 0: // neither
|
|
case STYLE_PROP: // only proportional
|
|
horizPoints *= 10.0/cpi;
|
|
vertPoints *= 10.0/cpi;
|
|
break;
|
|
}
|
|
*/
|
|
if (!(style & STYLE_CONDENSED)) {
|
|
horizPoints *= 10.0/cpi;
|
|
vertPoints *= 10.0/cpi;
|
|
}
|
|
|
|
if (!(style & STYLE_PROP)) {
|
|
if ((cpi == 10.0) && (style & STYLE_CONDENSED)) {
|
|
actcpi = 17.14;
|
|
horizPoints *= 10.0/17.14;
|
|
}
|
|
if ((cpi == 12.0) && (style & STYLE_CONDENSED)) {
|
|
actcpi = 20.0;
|
|
horizPoints *= 10.0/20.0;
|
|
vertPoints *= 10.0/12.0;
|
|
}
|
|
} else if (style & STYLE_CONDENSED) horizPoints /= 2.0;
|
|
|
|
|
|
if ((style & STYLE_DOUBLEWIDTH) || (style & STYLE_DOUBLEWIDTHONELINE)) {
|
|
actcpi /= 2.0;
|
|
horizPoints *= 2.0;
|
|
}
|
|
|
|
if (style & STYLE_DOUBLEHEIGHT) vertPoints *= 2.0;
|
|
} else { // multipoint true
|
|
actcpi = multicpi;
|
|
horizPoints = vertPoints = multiPointSize;
|
|
}
|
|
|
|
if ((style & STYLE_SUPERSCRIPT) || (style & STYLE_SUBSCRIPT)) {
|
|
horizPoints *= 2.0/3.0;
|
|
vertPoints *= 2.0/3.0;
|
|
actcpi /= 2.0/3.0;
|
|
}
|
|
|
|
FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi);
|
|
|
|
if (style & STYLE_ITALICS || charTables[curCharTable] == 0)
|
|
{
|
|
FT_Matrix matrix;
|
|
matrix.xx = 0x10000L;
|
|
matrix.xy = (FT_Fixed)(0.20 * 0x10000L);
|
|
matrix.yx = 0;
|
|
matrix.yy = 0x10000L;
|
|
FT_Set_Transform(curFont, &matrix, 0);
|
|
}
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
#ifdef HAVE_SDL
|
|
bool CPrinter::processCommandChar(Bit8u ch)
|
|
{
|
|
if (ESCSeen || FSSeen)
|
|
{
|
|
ESCCmd = ch;
|
|
if(FSSeen) ESCCmd |= 0x800;
|
|
ESCSeen = FSSeen = false;
|
|
numParam = 0;
|
|
|
|
switch (ESCCmd) {
|
|
case 0x02: // Undocumented
|
|
case 0x0a: // Reverse line feed (ESC LF)
|
|
case 0x0c: // Return to top of current page (ESC FF)
|
|
case 0x0e: // Select double-width printing (one line) (ESC SO)
|
|
case 0x0f: // Select condensed printing (ESC SI)
|
|
case 0x23: // Cancel MSB control (ESC #)
|
|
case 0x30: // Select 1/8-inch line spacing (ESC 0)
|
|
case 0x31: // Select 7/60-inch line spacing (ESC 1)
|
|
case 0x32: // Select 1/6-inch line spacing (ESC 2)
|
|
case 0x34: // Select italic font (ESC 4)
|
|
case 0x35: // Cancel italic font (ESC 5)
|
|
case 0x36: // Enable printing of upper control codes (ESC 6)
|
|
case 0x37: // Enable upper control codes (ESC 7)
|
|
case 0x38: // Disable paper-out detector (ESC 8)
|
|
case 0x39: // Enable paper-out detector (ESC 9)
|
|
case 0x3c: // Unidirectional mode (one line) (ESC <)
|
|
case 0x3d: // Set MSB to 0 (ESC =)
|
|
case 0x3e: // Set MSB to 1 (ESC >)
|
|
case 0x40: // Initialize printer (ESC @)
|
|
case 0x45: // Select bold font (ESC E)
|
|
case 0x46: // Cancel bold font (ESC F)
|
|
case 0x47: // Select double-strike printing (ESC G)
|
|
case 0x48: // Cancel double-strike printing (ESC H)
|
|
case 0x4d: // Select 10.5-point, 12-cpi (ESC M)
|
|
case 0x4f: // Cancel bottom margin [conflict] (ESC O)
|
|
case 0x50: // Select 10.5-point, 10-cpi (ESC P)
|
|
case 0x54: // Cancel superscript/subscript printing (ESC T)
|
|
case 0x5e: // Enable printing of all character codes on next character (ESC ^)
|
|
case 0x67: // Select 10.5-point, 15-cpi (ESC g)
|
|
|
|
case 0x834: // Select italic font (FS 4) (= ESC 4)
|
|
case 0x835: // Cancel italic font (FS 5) (= ESC 5)
|
|
case 0x846: // Select forward feed mode (FS F)
|
|
case 0x852: // Select reverse feed mode (FS R)
|
|
neededParam = 0;
|
|
break;
|
|
case 0x19: // Control paper loading/ejecting (ESC EM)
|
|
case 0x20: // Set intercharacter space (ESC SP)
|
|
case 0x21: // Master select (ESC !)
|
|
case 0x2b: // Set n/360-inch line spacing (ESC +)
|
|
case 0x2d: // Turn underline on/off (ESC -)
|
|
case 0x2f: // Select vertical tab channel (ESC /)
|
|
case 0x33: // Set n/180-inch line spacing (ESC 3)
|
|
case 0x41: // Set n/60-inch line spacing (ESC A)
|
|
case 0x43: // Set page length in lines (ESC C)
|
|
case 0x49: // Select character type and print pitch (ESC I)
|
|
case 0x4a: // Advance print position vertically (ESC J)
|
|
case 0x4e: // Set bottom margin (ESC N)
|
|
case 0x51: // Set right margin (ESC Q)
|
|
case 0x52: // Select an international character set (ESC R)
|
|
case 0x53: // Select superscript/subscript printing (ESC S)
|
|
case 0x55: // Turn unidirectional mode on/off (ESC U)
|
|
//case 0x56: // Repeat data (ESC V)
|
|
case 0x57: // Turn double-width printing on/off (ESC W)
|
|
case 0x61: // Select justification (ESC a)
|
|
case 0x66: // Absolute horizontal tab in columns [conflict] (ESC f)
|
|
case 0x68: // Select double or quadruple size (ESC h)
|
|
case 0x69: // Immediate print (ESC i)
|
|
case 0x6a: // Reverse paper feed (ESC j)
|
|
case 0x6b: // Select typeface (ESC k)
|
|
case 0x6c: // Set left margin (ESC 1)
|
|
case 0x70: // Turn proportional mode on/off (ESC p)
|
|
case 0x72: // Select printing color (ESC r)
|
|
case 0x73: // Low-speed mode on/off (ESC s)
|
|
case 0x74: // Select character table (ESC t)
|
|
case 0x77: // Turn double-height printing on/off (ESC w)
|
|
case 0x78: // Select LQ or draft (ESC x)
|
|
case 0x7e: // Select/Deselect slash zero (ESC ~)
|
|
|
|
case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2)
|
|
case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +)
|
|
case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A)
|
|
case 0x843: // Select LQ type style (FS C) (= ESC k)
|
|
case 0x845: // Select character width (FS E)
|
|
case 0x849: // Select character table (FS I) (= ESC t)
|
|
case 0x853: // Select High Speed/High Density elite pitch (FS S)
|
|
case 0x856: // Turn double-height printing on/off (FS V) (= ESC w)
|
|
neededParam = 1;
|
|
break;
|
|
case 0x24: // Set absolute horizontal print position (ESC $)
|
|
case 0x3f: // Reassign bit-image mode (ESC ?)
|
|
case 0x4b: // Select 60-dpi graphics (ESC K)
|
|
case 0x4c: // Select 120-dpi graphics (ESC L)
|
|
case 0x59: // Select 120-dpi, double-speed graphics (ESC Y)
|
|
case 0x5a: // Select 240-dpi graphics (ESC Z)
|
|
case 0x5c: // Set relative horizontal print position (ESC \)
|
|
case 0x63: // Set horizontal motion index (HMI) [conflict] (ESC c)
|
|
case 0x65: // Set vertical tab stops every n lines (ESC e)
|
|
case 0x85a: // Print 24-bit hex-density graphics (FS Z)
|
|
neededParam = 2;
|
|
break;
|
|
case 0x2a: // Select bit image (ESC *)
|
|
case 0x58: // Select font by pitch and point [conflict] (ESC X)
|
|
neededParam = 3;
|
|
break;
|
|
case 0x5b: // Select character height, width, line spacing
|
|
neededParam = 7;
|
|
break;
|
|
case 0x62: // Set vertical tabs in VFU channels (ESC b)
|
|
case 0x42: // Set vertical tabs (ESC B)
|
|
numVertTabs = 0;
|
|
return true;
|
|
case 0x44: // Set horizontal tabs (ESC D)
|
|
numHorizTabs = 0;
|
|
return true;
|
|
case 0x25: // Select user-defined set (ESC %)
|
|
case 0x26: // Define user-defined characters (ESC &)
|
|
case 0x3a: // Copy ROM to RAM (ESC :)
|
|
//LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!");
|
|
return true;
|
|
case 0x28: // Two bytes sequence
|
|
return true;
|
|
default:
|
|
/*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.",
|
|
(ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/
|
|
|
|
neededParam = 0;
|
|
ESCCmd = 0;
|
|
return true;
|
|
}
|
|
|
|
if (neededParam > 0)
|
|
return true;
|
|
}
|
|
|
|
// Two bytes sequence
|
|
if (ESCCmd == '(')
|
|
{
|
|
ESCCmd = 0x200 + ch;
|
|
|
|
switch (ESCCmd)
|
|
{
|
|
case 0x242: // Bar code setup and print (ESC (B)
|
|
case 0x25e: // Print data as characters (ESC (^)
|
|
neededParam = 2;
|
|
break;
|
|
case 0x255: // Set unit (ESC (U)
|
|
neededParam = 3;
|
|
break;
|
|
case 0x243: // Set page length in defined unit (ESC (C)
|
|
case 0x256: // Set absolute vertical print position (ESC (V)
|
|
case 0x276: // Set relative vertical print position (ESC (v)
|
|
neededParam = 4;
|
|
break;
|
|
case 0x274: // Assign character table (ESC (t)
|
|
case 0x22d: // Select line/score (ESC (-)
|
|
neededParam = 5;
|
|
break;
|
|
case 0x263: // Set page format (ESC (c)
|
|
neededParam = 6;
|
|
break;
|
|
default:
|
|
// ESC ( commands are always followed by a "number of parameters" word parameter
|
|
//LOG(LOG_MISC,LOG_ERROR)
|
|
printf("PRINTER: Skipping unsupported command ESC ( %c (%02X).", ESCCmd, ESCCmd);
|
|
neededParam = 2;
|
|
ESCCmd = 0x101;
|
|
return true;
|
|
}
|
|
|
|
if (neededParam > 0)
|
|
return true;
|
|
}
|
|
|
|
// Ignore VFU channel setting
|
|
if (ESCCmd == 0x62) {
|
|
ESCCmd = 0x42;
|
|
return true;
|
|
}
|
|
|
|
// Collect vertical tabs
|
|
if (ESCCmd == 0x42) {
|
|
if (ch == 0 || (numVertTabs>0 && verttabs[numVertTabs-1] > (Real64)ch*lineSpacing)) // Done
|
|
ESCCmd = 0;
|
|
else
|
|
if (numVertTabs < 16)
|
|
verttabs[numVertTabs++] = (Real64)ch*lineSpacing;
|
|
}
|
|
|
|
// Collect horizontal tabs
|
|
if (ESCCmd == 0x44)
|
|
{
|
|
if (ch == 0 || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)ch*(1/(Real64)cpi))) // Done
|
|
ESCCmd = 0;
|
|
else
|
|
if (numHorizTabs < 32)
|
|
horiztabs[numHorizTabs++] = (Real64)ch*(1/(Real64)cpi);
|
|
}
|
|
|
|
if (numParam < neededParam)
|
|
{
|
|
params[numParam++] = ch;
|
|
|
|
if (numParam < neededParam)
|
|
return true;
|
|
}
|
|
|
|
if (ESCCmd != 0)
|
|
{
|
|
switch (ESCCmd)
|
|
{
|
|
case 0x02: // Undocumented
|
|
// Ignore
|
|
break;
|
|
case 0x0e: // Select double-width printing (one line) (ESC SO)
|
|
if (!multipoint)
|
|
{
|
|
hmi = -1;
|
|
style |= STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
}
|
|
break;
|
|
case 0x0f: // Select condensed printing (ESC SI)
|
|
if (!multipoint && (cpi!=15.0)) {
|
|
hmi = -1;
|
|
style |= STYLE_CONDENSED;
|
|
updateFont();
|
|
}
|
|
break;
|
|
case 0x19: // Control paper loading/ejecting (ESC EM)
|
|
// We are not really loading paper, so most commands can be ignored
|
|
if (params[0] == 'R')
|
|
newPage(true,false); // TODO resetx?
|
|
break;
|
|
case 0x20: // Set intercharacter space (ESC SP)
|
|
if (!multipoint)
|
|
{
|
|
extraIntraSpace = (Real64)params[0] / (printQuality==QUALITY_DRAFT?120:180);
|
|
hmi = -1;
|
|
updateFont();
|
|
}
|
|
break;
|
|
case 0x21: // Master select (ESC !)
|
|
cpi = params[0] & 0x01 ? 12:10;
|
|
|
|
// Reset first seven bits
|
|
style &= 0xFF80;
|
|
if (params[0] & 0x02)
|
|
style |= STYLE_PROP;
|
|
if (params[0] & 0x04)
|
|
style |= STYLE_CONDENSED;
|
|
if (params[0] & 0x08)
|
|
style |= STYLE_BOLD;
|
|
if (params[0] & 0x10)
|
|
style |= STYLE_DOUBLESTRIKE;
|
|
if (params[0] & 0x20)
|
|
style |= STYLE_DOUBLEWIDTH;
|
|
if (params[0] & 0x40)
|
|
style |= STYLE_ITALICS;
|
|
if (params[0] & 0x80)
|
|
{
|
|
score = SCORE_SINGLE;
|
|
style |= STYLE_UNDERLINE;
|
|
}
|
|
|
|
hmi = -1;
|
|
multipoint = false;
|
|
updateFont();
|
|
break;
|
|
case 0x23: // Cancel MSB control (ESC #)
|
|
msb = 255;
|
|
break;
|
|
case 0x24: // Set absolute horizontal print position (ESC $)
|
|
{
|
|
Real64 unitSize = definedUnit;
|
|
if (unitSize < 0)
|
|
unitSize = (Real64)60.0;
|
|
|
|
Real64 newX = leftMargin + ((Real64)PARAM16(0)/unitSize);
|
|
if (newX <= rightMargin)
|
|
curX = newX;
|
|
}
|
|
break;
|
|
case 0x85a: // Print 24-bit hex-density graphics (FS Z)
|
|
setupBitImage(40, PARAM16(0));
|
|
break;
|
|
case 0x2a: // Select bit image (ESC *)
|
|
setupBitImage(params[0], PARAM16(1));
|
|
break;
|
|
case 0x2b: // Set n/360-inch line spacing (ESC +)
|
|
case 0x833: // Set n/360-inch line spacing (FS 3)
|
|
lineSpacing = (Real64)params[0]/360;
|
|
break;
|
|
case 0x2d: // Turn underline on/off (ESC -)
|
|
if (params[0] == 0 || params[0] == 48)
|
|
style &= ~STYLE_UNDERLINE;
|
|
if (params[0] == 1 || params[0] == 49)
|
|
{
|
|
style |= STYLE_UNDERLINE;
|
|
score = SCORE_SINGLE;
|
|
}
|
|
updateFont();
|
|
break;
|
|
case 0x2f: // Select vertical tab channel (ESC /)
|
|
// Ignore
|
|
break;
|
|
case 0x30: // Select 1/8-inch line spacing (ESC 0)
|
|
lineSpacing = (Real64)1/8;
|
|
break;
|
|
case 0x32: // Select 1/6-inch line spacing (ESC 2)
|
|
lineSpacing = (Real64)1/6;
|
|
break;
|
|
case 0x33: // Set n/180-inch line spacing (ESC 3)
|
|
lineSpacing = (Real64)params[0]/180;
|
|
break;
|
|
case 0x34: // Select italic font (ESC 4)
|
|
style |= STYLE_ITALICS;
|
|
updateFont();
|
|
break;
|
|
case 0x35: // Cancel italic font (ESC 5)
|
|
style &= ~STYLE_ITALICS;
|
|
updateFont();
|
|
break;
|
|
case 0x36: // Enable printing of upper control codes (ESC 6)
|
|
printUpperContr = true;
|
|
break;
|
|
case 0x37: // Enable upper control codes (ESC 7)
|
|
printUpperContr = false;
|
|
break;
|
|
case 0x3c: // Unidirectional mode (one line) (ESC <)
|
|
// We don't have a print head, so just ignore this
|
|
break;
|
|
case 0x3d: // Set MSB to 0 (ESC =)
|
|
msb = 0;
|
|
break;
|
|
case 0x3e: // Set MSB to 1 (ESC >)
|
|
msb = 1;
|
|
break;
|
|
case 0x3f: // Reassign bit-image mode (ESC ?)
|
|
if (params[0] == 75)
|
|
densk = params[1];
|
|
if (params[0] == 76)
|
|
densl = params[1];
|
|
if (params[0] == 89)
|
|
densy = params[1];
|
|
if (params[0] == 90)
|
|
densz = params[1];
|
|
break;
|
|
case 0x40: // Initialize printer (ESC @)
|
|
resetPrinter();
|
|
break;
|
|
case 0x41: // Set n/60-inch line spacing
|
|
case 0x841:
|
|
lineSpacing = (Real64)params[0]/60;
|
|
break;
|
|
case 0x43: // Set page length in lines (ESC C)
|
|
if (params[0] != 0)
|
|
pageHeight = bottomMargin = (Real64)params[0] * lineSpacing;
|
|
else // == 0 => Set page length in inches
|
|
{
|
|
neededParam = 1;
|
|
numParam = 0;
|
|
ESCCmd = 0x100;
|
|
return true;
|
|
}
|
|
break;
|
|
case 0x45: // Select bold font (ESC E)
|
|
style |= STYLE_BOLD;
|
|
updateFont();
|
|
break;
|
|
case 0x46: // Cancel bold font (ESC F)
|
|
style &= ~STYLE_BOLD;
|
|
updateFont();
|
|
break;
|
|
case 0x47: // Select dobule-strike printing (ESC G)
|
|
style |= STYLE_DOUBLESTRIKE;
|
|
break;
|
|
case 0x48: // Cancel double-strike printing (ESC H)
|
|
style &= ~STYLE_DOUBLESTRIKE;
|
|
break;
|
|
case 0x4a: // Advance print position vertically (ESC J n)
|
|
curY += (Real64)((Real64)params[0] / 180);
|
|
if (curY > bottomMargin)
|
|
newPage(true,false);
|
|
break;
|
|
case 0x4b: // Select 60-dpi graphics (ESC K)
|
|
setupBitImage(densk, PARAM16(0));
|
|
break;
|
|
case 0x4c: // Select 120-dpi graphics (ESC L)
|
|
setupBitImage(densl, PARAM16(0));
|
|
break;
|
|
case 0x4d: // Select 10.5-point, 12-cpi (ESC M)
|
|
cpi = 12;
|
|
hmi = -1;
|
|
multipoint = false;
|
|
updateFont();
|
|
break;
|
|
case 0x4e: // Set bottom margin (ESC N)
|
|
topMargin = 0.0;
|
|
bottomMargin = (Real64)params[0] * lineSpacing;
|
|
break;
|
|
case 0x4f: // Cancel bottom (and top) margin
|
|
topMargin = 0.0;
|
|
bottomMargin = pageHeight;
|
|
break;
|
|
case 0x50: // Select 10.5-point, 10-cpi (ESC P)
|
|
cpi = 10;
|
|
hmi = -1;
|
|
multipoint = false;
|
|
updateFont();
|
|
break;
|
|
case 0x51: // Set right margin
|
|
rightMargin = (Real64)(params[0]-1.0) / (Real64)cpi;
|
|
break;
|
|
case 0x52: // Select an international character set (ESC R)
|
|
if (params[0] <= 13 || params[0] == 64)
|
|
{
|
|
if (params[0] == 64)
|
|
params[0] = 14;
|
|
|
|
curMap[0x23] = intCharSets[params[0]][0];
|
|
curMap[0x24] = intCharSets[params[0]][1];
|
|
curMap[0x40] = intCharSets[params[0]][2];
|
|
curMap[0x5b] = intCharSets[params[0]][3];
|
|
curMap[0x5c] = intCharSets[params[0]][4];
|
|
curMap[0x5d] = intCharSets[params[0]][5];
|
|
curMap[0x5e] = intCharSets[params[0]][6];
|
|
curMap[0x60] = intCharSets[params[0]][7];
|
|
curMap[0x7b] = intCharSets[params[0]][8];
|
|
curMap[0x7c] = intCharSets[params[0]][9];
|
|
curMap[0x7d] = intCharSets[params[0]][10];
|
|
curMap[0x7e] = intCharSets[params[0]][11];
|
|
}
|
|
break;
|
|
case 0x53: // Select superscript/subscript printing (ESC S)
|
|
if (params[0] == 0 || params[0] == 48)
|
|
style |= STYLE_SUBSCRIPT;
|
|
if (params[0] == 1 || params[1] == 49)
|
|
style |= STYLE_SUPERSCRIPT;
|
|
updateFont();
|
|
break;
|
|
case 0x54: // Cancel superscript/subscript printing (ESC T)
|
|
style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT;
|
|
updateFont();
|
|
break;
|
|
case 0x55: // Turn unidirectional mode on/off (ESC U)
|
|
// We don't have a print head, so just ignore this
|
|
break;
|
|
case 0x57: // Turn double-width printing on/off (ESC W)
|
|
if (!multipoint)
|
|
{
|
|
hmi = -1;
|
|
if (params[0] == 0 || params[0] == 48)
|
|
style &= ~STYLE_DOUBLEWIDTH;
|
|
if (params[0] == 1 || params[0] == 49)
|
|
style |= STYLE_DOUBLEWIDTH;
|
|
updateFont();
|
|
}
|
|
break;
|
|
case 0x58: // Select font by pitch and point (ESC X)
|
|
multipoint = true;
|
|
// Copy currently non-multipoint CPI if no value was set so far
|
|
if (multicpi == 0)
|
|
multicpi = cpi;
|
|
if (params[0] > 0) // Set CPI
|
|
{
|
|
if (params[0] == 1) // Proportional spacing
|
|
style |= STYLE_PROP;
|
|
else if (params[0] >= 5)
|
|
multicpi = (Real64)360 / (Real64)params[0];
|
|
}
|
|
if (multiPointSize == 0)
|
|
multiPointSize = (Real64)10.5;
|
|
if (PARAM16(1) > 0) // Set points
|
|
multiPointSize = ((Real64)PARAM16(1)) / 2;
|
|
updateFont();
|
|
break;
|
|
case 0x59: // Select 120-dpi, double-speed graphics (ESC Y)
|
|
setupBitImage(densy, PARAM16(0));
|
|
break;
|
|
case 0x5a: // Select 240-dpi graphics (ESC Z)
|
|
setupBitImage(densz, PARAM16(0));
|
|
break;
|
|
case 0x5c: // Set relative horizontal print position (ESC \)
|
|
{
|
|
Bit16s toMove = PARAM16(0);
|
|
Real64 unitSize = definedUnit;
|
|
if (unitSize < 0)
|
|
unitSize = (Real64)(printQuality==QUALITY_DRAFT?120.0:180.0);
|
|
curX += (Real64)((Real64)toMove / unitSize);
|
|
}
|
|
break;
|
|
case 0x61: // Select justification (ESC a)
|
|
// Ignore
|
|
break;
|
|
case 0x63: // Set horizontal motion index (HMI) (ESC c)
|
|
hmi = (Real64)PARAM16(0) / (Real64)360.0;
|
|
extraIntraSpace = 0.0;
|
|
break;
|
|
case 0x67: // Select 10.5-point, 15-cpi (ESC g)
|
|
cpi = 15;
|
|
hmi = -1;
|
|
multipoint = false;
|
|
updateFont();
|
|
break;
|
|
case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet
|
|
if(lineSpacing < 0) lineSpacing *= -1;
|
|
break;
|
|
case 0x6a: // Reverse paper feed (ESC j)
|
|
{
|
|
Real64 reverse = (Real64)PARAM16(0) / (Real64)216.0;
|
|
reverse = curY - reverse;
|
|
if(reverse < leftMargin) curY = leftMargin;
|
|
else curY = reverse;
|
|
break;
|
|
}
|
|
case 0x6b: // Select typeface (ESC k)
|
|
paramc = params[0]-'0';
|
|
//if (params[0] <= 11 || params[0] == 30 || params[0] == 31)
|
|
if (paramc <= 11 || paramc == 30 || paramc == 31)
|
|
LQtypeFace = (Typeface)paramc;
|
|
updateFont();
|
|
break;
|
|
case 0x6c: // Set left margin (ESC l)
|
|
leftMargin = (Real64)(params[0]-1.0) / (Real64)cpi;
|
|
if (curX < leftMargin)
|
|
curX = leftMargin;
|
|
break;
|
|
case 0x70: // Turn proportional mode on/off (ESC p)
|
|
if (params[0] == 0 || params[0] == 48)
|
|
style &= (0xffff - STYLE_PROP);
|
|
if (params[0] == 1 || params[0] == 49)
|
|
{
|
|
style |= STYLE_PROP;
|
|
printQuality = QUALITY_LQ;
|
|
}
|
|
multipoint = false;
|
|
hmi = -1;
|
|
updateFont();
|
|
break;
|
|
case 0x72: // Select printing color (ESC r)
|
|
|
|
if(params[0]==0 || params[0] > 6) color = COLOR_BLACK;
|
|
else color = params[0]<<5;
|
|
break;
|
|
case 0x73: // Select low-speed mode (ESC s)
|
|
// Ignore
|
|
break;
|
|
case 0x74: // Select character table (ESC t)
|
|
case 0x849: // Select character table (FS I)
|
|
if (params[0] < 4)
|
|
curCharTable = params[0];
|
|
if (params[0] >= 48 && params[0] <= 51)
|
|
curCharTable = params[0] - 48;
|
|
selectCodepage(charTables[curCharTable]);
|
|
updateFont();
|
|
break;
|
|
case 0x77: // Turn double-height printing on/off (ESC w)
|
|
if (!multipoint)
|
|
{
|
|
if (params[0] == 0 || params[0] == 48)
|
|
style &= ~STYLE_DOUBLEHEIGHT;
|
|
if (params[0] == 1 || params[0] == 49)
|
|
style |= STYLE_DOUBLEHEIGHT;
|
|
updateFont();
|
|
}
|
|
break;
|
|
case 0x78: // Select LQ or draft (ESC x)
|
|
if (params[0] == 0 || params[0] == 48) {
|
|
printQuality = QUALITY_DRAFT;
|
|
style |= STYLE_CONDENSED;
|
|
}
|
|
if (params[0] == 1 || params[0] == 49) {
|
|
printQuality = QUALITY_LQ;
|
|
style &= ~STYLE_CONDENSED;
|
|
}
|
|
hmi = -1;
|
|
updateFont();
|
|
break;
|
|
case 0x100: // Set page length in inches (ESC C NUL)
|
|
pageHeight = (Real64)params[0];
|
|
bottomMargin = pageHeight;
|
|
topMargin = 0.0;
|
|
break;
|
|
case 0x101: // Skip unsupported ESC ( command
|
|
neededParam = PARAM16(0);
|
|
numParam = 0;
|
|
break;
|
|
case 0x274: // Assign character table (ESC (t)
|
|
if (params[2] < 4 && params[3] < 16)
|
|
{
|
|
charTables[params[2]] = codepages[params[3]];
|
|
//LOG_MSG("curr table: %d, p2: %d, p3: %d",curCharTable,params[2],params[3]);
|
|
if (params[2] == curCharTable)
|
|
selectCodepage(charTables[curCharTable]);
|
|
}
|
|
break;
|
|
case 0x22d: // Select line/score (ESC (-)
|
|
style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE);
|
|
score = params[4];
|
|
if (score)
|
|
{
|
|
if (params[3] == 1)
|
|
style |= STYLE_UNDERLINE;
|
|
if (params[3] == 2)
|
|
style |= STYLE_STRIKETHROUGH;
|
|
if (params[3] == 3)
|
|
style |= STYLE_OVERSCORE;
|
|
}
|
|
updateFont();
|
|
break;
|
|
case 0x242: // Bar code setup and print (ESC (B)
|
|
//LOG(LOG_MISC,LOG_ERROR)("PRINTER: Bardcode printing not supported");
|
|
// Find out how many bytes to skip
|
|
neededParam = PARAM16(0);
|
|
numParam = 0;
|
|
break;
|
|
case 0x243: // Set page length in defined unit (ESC (C)
|
|
if (params[0] != 0 && definedUnit > 0)
|
|
{
|
|
pageHeight = bottomMargin = ((Real64)PARAM16(2)) * definedUnit;
|
|
topMargin = 0.0;
|
|
}
|
|
break;
|
|
case 0x255: // Set unit (ESC (U)
|
|
definedUnit = (Real64)params[2] / (Real64)3600;
|
|
break;
|
|
case 0x256: // Set absolute vertical print position (ESC (V)
|
|
{
|
|
Real64 unitSize = definedUnit;
|
|
if (unitSize < 0)
|
|
unitSize = (Real64)360.0;
|
|
Real64 newPos = topMargin + (((Real64)PARAM16(2)) * unitSize);
|
|
if (newPos > bottomMargin)
|
|
newPage(true,false);
|
|
else
|
|
curY = newPos;
|
|
}
|
|
break;
|
|
case 0x25e: // Print data as characters (ESC (^)
|
|
numPrintAsChar = PARAM16(0);
|
|
break;
|
|
case 0x263: // Set page format (ESC (c)
|
|
if (definedUnit > 0)
|
|
{
|
|
Real64 newTop, newBottom;
|
|
newTop = ((Real64)PARAM16(2)) * definedUnit;
|
|
newBottom = ((Real64)PARAM16(4)) * definedUnit;
|
|
if(newTop >= newBottom) break;
|
|
if(newTop < pageHeight) topMargin = newTop;
|
|
if(newBottom < pageHeight) bottomMargin = newBottom;
|
|
if(topMargin > curY) curY = topMargin;
|
|
//LOG_MSG("du %d, p1 %d, p2 %d, newtop %f, newbott %f, nt %f, nb %f, ph %f",
|
|
// (Bitu)definedUnit,PARAM16(2),PARAM16(4),topMargin,bottomMargin,
|
|
// newTop,newBottom,pageHeight);
|
|
}
|
|
break;
|
|
case 0x276: // Set relative vertical print position (ESC (v)
|
|
{
|
|
Real64 unitSize = definedUnit;
|
|
if (unitSize < 0)
|
|
unitSize = (Real64)360.0;
|
|
Real64 newPos = curY + ((Real64)((Bit16s)PARAM16(2)) * unitSize);
|
|
if (newPos > topMargin)
|
|
{
|
|
if (newPos > bottomMargin)
|
|
newPage(true,false);
|
|
else
|
|
curY = newPos;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
if (ESCCmd < 0x100);
|
|
//LOG(LOG_MISC,LOG_WARN)
|
|
//LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd);
|
|
else;
|
|
//LOG(LOG_MISC,LOG_WARN)
|
|
//LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200);
|
|
}
|
|
|
|
ESCCmd = 0;
|
|
return true;
|
|
}
|
|
|
|
switch (ch)
|
|
{
|
|
case 0x00: // NUL is ignored by the printer
|
|
return true;
|
|
case 0x07: // Beeper (BEL)
|
|
// BEEEP!
|
|
return true;
|
|
case 0x08: // Backspace (BS)
|
|
{
|
|
Real64 newX = curX - (1/(Real64)actcpi);
|
|
if (hmi > 0)
|
|
newX = curX - hmi;
|
|
if (newX >= leftMargin)
|
|
curX = newX;
|
|
}
|
|
return true;
|
|
case 0x09: // Tab horizontally (HT)
|
|
{
|
|
// Find tab right to current pos
|
|
Real64 moveTo = -1;
|
|
for (Bit8u i=0; i<numHorizTabs; i++)
|
|
if (horiztabs[i] > curX)
|
|
moveTo = horiztabs[i];
|
|
// Nothing found => Ignore
|
|
if (moveTo > 0 && moveTo < rightMargin)
|
|
curX = moveTo;
|
|
}
|
|
return true;
|
|
case 0x0b: // Tab vertically (VT)
|
|
if (numVertTabs == 0) // All tabs cancelled => Act like CR
|
|
curX = leftMargin;
|
|
else if (numVertTabs == 255) // No tabs set since reset => Act like LF
|
|
{
|
|
curX = leftMargin;
|
|
curY += lineSpacing;
|
|
if (curY > bottomMargin)
|
|
newPage(true,false);
|
|
}
|
|
else
|
|
{
|
|
// Find tab below current pos
|
|
Real64 moveTo = -1;
|
|
for (Bit8u i=0; i<numVertTabs; i++)
|
|
if (verttabs[i] > curY)
|
|
moveTo = verttabs[i];
|
|
|
|
// Nothing found => Act like FF
|
|
if (moveTo > bottomMargin || moveTo < 0)
|
|
newPage(true,false);
|
|
else
|
|
curY = moveTo;
|
|
}
|
|
if (style & STYLE_DOUBLEWIDTHONELINE)
|
|
{
|
|
style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
}
|
|
return true;
|
|
case 0x0c: // Form feed (FF)
|
|
if (style & STYLE_DOUBLEWIDTHONELINE)
|
|
{
|
|
style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
}
|
|
newPage(true,true);
|
|
return true;
|
|
case 0x0d: // Carriage Return (CR)
|
|
curX = leftMargin;
|
|
if (!autoFeed)
|
|
return true;
|
|
case 0x0a: // Line feed
|
|
if (style & STYLE_DOUBLEWIDTHONELINE)
|
|
{
|
|
style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
}
|
|
curX = leftMargin;
|
|
curY += lineSpacing;
|
|
if (curY > bottomMargin)
|
|
newPage(true,false);
|
|
return true;
|
|
case 0x0e: //Select Real64-width printing (one line) (SO)
|
|
if (!multipoint)
|
|
{
|
|
hmi = -1;
|
|
style |= STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
}
|
|
return true;
|
|
case 0x0f: // Select condensed printing (SI)
|
|
if (!multipoint && (cpi!=15.0)) {
|
|
hmi = -1;
|
|
style |= STYLE_CONDENSED;
|
|
updateFont();
|
|
}
|
|
return true;
|
|
case 0x11: // Select printer (DC1)
|
|
// Ignore
|
|
return true;
|
|
case 0x12: // Cancel condensed printing (DC2)
|
|
hmi = -1;
|
|
style &= ~STYLE_CONDENSED;
|
|
updateFont();
|
|
return true;
|
|
case 0x13: // Deselect printer (DC3)
|
|
// Ignore
|
|
return true;
|
|
case 0x14: // Cancel double-width printing (one line) (DC4)
|
|
hmi = -1;
|
|
style &= ~STYLE_DOUBLEWIDTHONELINE;
|
|
updateFont();
|
|
return true;
|
|
case 0x18: // Cancel line (CAN)
|
|
return true;
|
|
case 0x1b: // ESC
|
|
ESCSeen = true;
|
|
return true;
|
|
case 0x1c: // FS (IBM commands)
|
|
FSSeen = true;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
//static void PRINTER_EventHandler(Bitu param);
|
|
|
|
void CPrinter::newPage(bool save, bool resetx)
|
|
{
|
|
//PIC_RemoveEvents(PRINTER_EventHandler);
|
|
if(printer_timout) timeout_dirty=false;
|
|
|
|
#ifdef HAVE_SDL
|
|
if (save)
|
|
outputPage();
|
|
|
|
if(resetx) curX=leftMargin;
|
|
curY = topMargin;
|
|
|
|
SDL_Rect rect;
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.w = page->w;
|
|
rect.h = page->h;
|
|
SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255));
|
|
|
|
/*for(int i = 0; i < 256; i++)
|
|
{
|
|
*((Bit8u*)page->pixels+i)=i;
|
|
}*/
|
|
#endif // HAVE_SDL
|
|
if (strcasecmp(output, "text") == 0) { /* Text file */
|
|
if (textPrinterFile) {
|
|
fclose(textPrinterFile);
|
|
textPrinterFile = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPrinter::printChar(Bit8u ch)
|
|
{
|
|
#ifdef HAVE_SDL
|
|
|
|
charRead = true;
|
|
if (page == NULL) return;
|
|
#endif // HAVE_SDL
|
|
// Don't think that DOS programs uses this but well: Apply MSB if desired
|
|
if (msb != 255) {
|
|
if (msb == 0) ch &= 0x7F;
|
|
if (msb == 1) ch |= 0x80;
|
|
}
|
|
if (strcasecmp(output, "text") == 0) {
|
|
if (!textPrinterFile) {
|
|
textPrinterFile = fopen(textPrinterFileName,"ab");
|
|
}
|
|
fprintf(textPrinterFile,"%c",ch);
|
|
fflush(textPrinterFile);
|
|
return;
|
|
}
|
|
#ifdef HAVE_SDL
|
|
|
|
// Are we currently printing a bit graphic?
|
|
if (bitGraph.remBytes > 0) {
|
|
printBitGraph(ch);
|
|
return;
|
|
}
|
|
|
|
// Print everything?
|
|
if (numPrintAsChar > 0) numPrintAsChar--;
|
|
else if (processCommandChar(ch)) return;
|
|
|
|
// Do not print if no font is available
|
|
if (!curFont) return;
|
|
if(ch==0x1) ch=0x20;
|
|
|
|
// Find the glyph for the char to render
|
|
FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]);
|
|
|
|
// Load the glyph
|
|
FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT);
|
|
|
|
// Render a high-quality bitmap
|
|
FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL);
|
|
|
|
Bit16u penX = PIXX + curFont->glyph->bitmap_left;
|
|
Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64;
|
|
|
|
if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2;
|
|
|
|
// Copy bitmap into page
|
|
SDL_LockSurface(page);
|
|
|
|
blitGlyph(curFont->glyph->bitmap, penX, penY, false);
|
|
blitGlyph(curFont->glyph->bitmap, penX+1, penY, true);
|
|
|
|
// Doublestrike => Print the glyph a second time one pixel below
|
|
if (style & STYLE_DOUBLESTRIKE) {
|
|
blitGlyph(curFont->glyph->bitmap, penX, penY+1, true);
|
|
blitGlyph(curFont->glyph->bitmap, penX+1, penY+1, true);
|
|
}
|
|
|
|
// Bold => Print the glyph a second time one pixel to the right
|
|
// or be a bit more bold...
|
|
if (style & STYLE_BOLD) {
|
|
blitGlyph(curFont->glyph->bitmap, penX+1, penY, true);
|
|
blitGlyph(curFont->glyph->bitmap, penX+2, penY, true);
|
|
blitGlyph(curFont->glyph->bitmap, penX+3, penY, true);
|
|
}
|
|
SDL_UnlockSurface(page);
|
|
|
|
// For line printing
|
|
Bit16u lineStart = PIXX;
|
|
|
|
// advance the cursor to the right
|
|
Real64 x_advance;
|
|
if (style & STYLE_PROP)
|
|
x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64));
|
|
else {
|
|
if (hmi < 0) x_advance = 1/(Real64)actcpi;
|
|
else x_advance = hmi;
|
|
}
|
|
x_advance += extraIntraSpace;
|
|
curX += x_advance;
|
|
|
|
// Draw lines if desired
|
|
if ((score != SCORE_NONE) && (style &
|
|
(STYLE_UNDERLINE|STYLE_STRIKETHROUGH|STYLE_OVERSCORE)))
|
|
{
|
|
// Find out where to put the line
|
|
Bit16u lineY = PIXY;
|
|
double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness...
|
|
|
|
if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9);
|
|
else if (style & STYLE_STRIKETHROUGH) lineY = PIXY + (Bit16u)(height*0.45);
|
|
else if (style & STYLE_OVERSCORE)
|
|
lineY = PIXY - (((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN))?5:0);
|
|
|
|
drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN);
|
|
|
|
// draw second line if needed
|
|
if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN))
|
|
drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN);
|
|
}
|
|
// If the next character would go beyond the right margin, line-wrap.
|
|
if((curX + x_advance) > rightMargin) {
|
|
curX = leftMargin;
|
|
curY += lineSpacing;
|
|
if (curY > bottomMargin) newPage(true,false);
|
|
}
|
|
#endif // HAVE_SDL
|
|
}
|
|
|
|
#ifdef HAVE_SDL
|
|
void CPrinter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) {
|
|
for (Bitu y=0; y<bitmap.rows; y++) {
|
|
for (Bitu x=0; x<bitmap.width; x++) {
|
|
// Read pixel from glyph bitmap
|
|
Bit8u source = *(bitmap.buffer + x + y*bitmap.pitch);
|
|
|
|
// Ignore background and don't go over the border
|
|
if (source > 0 && (destx+x < page->w) && (desty+y < page->h) ) {
|
|
Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch;
|
|
source>>=3;
|
|
|
|
if (add) {
|
|
if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f);
|
|
else {
|
|
*target += source;
|
|
*target |= color;
|
|
}
|
|
}
|
|
else *target = source|color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPrinter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken)
|
|
{
|
|
SDL_LockSurface(page);
|
|
|
|
Bitu breakmod = dpi / 15;
|
|
Bitu gapstart = (breakmod * 4)/5;
|
|
|
|
// Draw anti-aliased line
|
|
for (Bitu x=fromx; x<=tox; x++)
|
|
{
|
|
// Skip parts if broken line or going over the border
|
|
if ((!broken || (x%breakmod <= gapstart)) && (x < page->w))
|
|
{
|
|
if (y > 0 && (y-1) < page->h)
|
|
*((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240;
|
|
if (y < page->h)
|
|
*((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240;
|
|
if (y+1 < page->h)
|
|
*((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240;
|
|
}
|
|
}
|
|
SDL_UnlockSurface(page);
|
|
}
|
|
|
|
void CPrinter::setAutofeed(bool feed) {
|
|
autoFeed = feed;
|
|
}
|
|
|
|
bool CPrinter::getAutofeed() {
|
|
return autoFeed;
|
|
}
|
|
|
|
bool CPrinter::isBusy() {
|
|
// We're never busy
|
|
return false;
|
|
}
|
|
|
|
bool CPrinter::ack() {
|
|
// Acknowledge last char read
|
|
if(charRead) {
|
|
charRead=false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CPrinter::setupBitImage(Bit8u dens, Bit16u numCols) {
|
|
switch (dens)
|
|
{
|
|
case 0:
|
|
bitGraph.horizDens = 60;
|
|
bitGraph.vertDens = 60;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 1:
|
|
bitGraph.horizDens = 120;
|
|
bitGraph.vertDens = 60;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 2:
|
|
bitGraph.horizDens = 120;
|
|
bitGraph.vertDens = 60;
|
|
bitGraph.adjacent = false;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 3:
|
|
bitGraph.horizDens = 60;
|
|
bitGraph.vertDens = 240;
|
|
bitGraph.adjacent = false;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 4:
|
|
bitGraph.horizDens = 80;
|
|
bitGraph.vertDens = 60;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 6:
|
|
bitGraph.horizDens = 90;
|
|
bitGraph.vertDens = 60;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 1;
|
|
break;
|
|
case 32:
|
|
bitGraph.horizDens = 60;
|
|
bitGraph.vertDens = 180;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 3;
|
|
break;
|
|
case 33:
|
|
bitGraph.horizDens = 120;
|
|
bitGraph.vertDens = 180;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 3;
|
|
break;
|
|
case 38:
|
|
bitGraph.horizDens = 90;
|
|
bitGraph.vertDens = 180;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 3;
|
|
break;
|
|
case 39:
|
|
bitGraph.horizDens = 180;
|
|
bitGraph.vertDens = 180;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 3;
|
|
break;
|
|
case 40:
|
|
bitGraph.horizDens = 360;
|
|
bitGraph.vertDens = 180;
|
|
bitGraph.adjacent = false;
|
|
bitGraph.bytesColumn = 3;
|
|
break;
|
|
case 71:
|
|
bitGraph.horizDens = 180;
|
|
bitGraph.vertDens = 360;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 6;
|
|
break;
|
|
case 72:
|
|
bitGraph.horizDens = 360;
|
|
bitGraph.vertDens = 360;
|
|
bitGraph.adjacent = false;
|
|
bitGraph.bytesColumn = 6;
|
|
break;
|
|
case 73:
|
|
bitGraph.horizDens = 360;
|
|
bitGraph.vertDens = 360;
|
|
bitGraph.adjacent = true;
|
|
bitGraph.bytesColumn = 6;
|
|
break;
|
|
default:
|
|
//break;
|
|
printf("PRINTER: Unsupported bit image density");
|
|
}
|
|
|
|
bitGraph.remBytes = numCols * bitGraph.bytesColumn;
|
|
bitGraph.readBytesColumn = 0;
|
|
}
|
|
|
|
void CPrinter::printBitGraph(Bit8u ch)
|
|
{
|
|
bitGraph.column[bitGraph.readBytesColumn++] = ch;
|
|
bitGraph.remBytes--;
|
|
|
|
// Only print after reading a full column
|
|
if (bitGraph.readBytesColumn < bitGraph.bytesColumn)
|
|
return;
|
|
|
|
Real64 oldY = curY;
|
|
|
|
SDL_LockSurface(page);
|
|
|
|
// When page dpi is greater than graphics dpi, the drawn pixels get "bigger"
|
|
Bitu pixsizeX=1;
|
|
Bitu pixsizeY=1;
|
|
if(bitGraph.adjacent) {
|
|
pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1;
|
|
pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1;
|
|
}
|
|
// TODO figure this out for 360dpi mode in windows
|
|
|
|
// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1;
|
|
// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1;
|
|
|
|
for (Bitu i=0; i<bitGraph.bytesColumn; i++) // for each byte
|
|
{
|
|
for (Bitu j=128; j!=0; j>>=1) { // for each bit
|
|
if (bitGraph.column[i] & j) {
|
|
for (Bitu xx=0; xx<pixsizeX; xx++)
|
|
for (Bitu yy=0; yy<pixsizeY; yy++) {
|
|
if (((PIXX + xx) < page->w) && ((PIXY + yy) < page->h))
|
|
*((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F);
|
|
}
|
|
} // else white pixel
|
|
|
|
curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap?
|
|
}
|
|
}
|
|
SDL_UnlockSurface(page);
|
|
|
|
curY = oldY;
|
|
|
|
bitGraph.readBytesColumn = 0;
|
|
|
|
// Advance to the left
|
|
curX += (Real64)1/(Real64)bitGraph.horizDens;
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
void CPrinter::formFeed()
|
|
{
|
|
#ifdef HAVE_SDL
|
|
// Don't output blank pages
|
|
newPage(!isBlank(),true);
|
|
finishMultipage();
|
|
#endif // HAVE_SDL
|
|
}
|
|
|
|
#ifdef HAVE_SDL
|
|
static void findNextName(char* front, char* ext, char* fname)
|
|
{
|
|
document_path = "";
|
|
Bitu i = 1;
|
|
Bitu slen = strlen(document_path);
|
|
if(slen>(200-15)) {
|
|
fname[0]=0;
|
|
return;
|
|
}
|
|
FILE *test = NULL;
|
|
do
|
|
{
|
|
strcpy(fname, document_path);
|
|
printf(fname);
|
|
#ifdef WIN32
|
|
const char* const pathstring = ".\\%s%d%s";
|
|
#else
|
|
const char* const pathstring = "./%s%d%s";
|
|
#endif
|
|
sprintf(fname+strlen(fname), pathstring, front,i++,ext);
|
|
test = fopen(fname, "rb");
|
|
if (test != NULL)
|
|
fclose(test);
|
|
}
|
|
while (test != NULL );
|
|
}
|
|
|
|
void CPrinter::outputPage()
|
|
{
|
|
/* SDL_Surface *screen;
|
|
|
|
screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE);
|
|
if (screen == NULL) {
|
|
printf("Unable to set video mode: %s\n", SDL_GetError());
|
|
}
|
|
SDL_Surface *image;
|
|
SDL_LockSurface(page);
|
|
image = SDL_DisplayFormat(page);
|
|
SDL_UnlockSurface(page);
|
|
SDL_Rect src, dest;
|
|
|
|
src.x = 0;
|
|
src.y = 0;
|
|
src.w = image->w;
|
|
src.h = image->h;
|
|
|
|
dest.x = 100;
|
|
dest.y = 100;
|
|
dest.w = image->w;
|
|
dest.h = image->h;
|
|
|
|
SDL_BlitSurface(image, &src, screen, &dest);
|
|
SDL_Flip(screen);
|
|
|
|
SDL_Delay(2000);
|
|
SDL_FreeSurface(image);*/
|
|
|
|
char fname[200];
|
|
|
|
if (strcasecmp(output, "printer") == 0)
|
|
{
|
|
#if defined (WIN32)
|
|
|
|
Bit16u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH);
|
|
Bit16u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT);
|
|
|
|
Real64 scaleW, scaleH;
|
|
|
|
if (page->w > physW)
|
|
scaleW = (Real64)page->w / (Real64)physW;
|
|
else
|
|
scaleW = (Real64)physW / (Real64)page->w;
|
|
|
|
if (page->h > physH)
|
|
scaleH = (Real64)page->h / (Real64)physH;
|
|
else
|
|
scaleH = (Real64)physH / (Real64)page->h;
|
|
|
|
HDC memHDC = CreateCompatibleDC(printerDC);
|
|
BITMAPINFO *BitmapInfo;
|
|
HBITMAP bitmap;
|
|
|
|
// Start new printer job?
|
|
if (outputHandle == NULL)
|
|
{
|
|
DOCINFO docinfo;
|
|
docinfo.cbSize = sizeof(docinfo);
|
|
docinfo.lpszDocName = "GSport Virtual Printer";
|
|
docinfo.lpszOutput = NULL;
|
|
docinfo.lpszDatatype = NULL;
|
|
docinfo.fwType = 0;
|
|
|
|
StartDoc(printerDC, &docinfo);
|
|
multiPageCounter = 1;
|
|
}
|
|
SDL_LockSurface(page);
|
|
StartPage(printerDC);
|
|
DWORD TotalSize;
|
|
HGDIOBJ Prev;
|
|
void* Pixels;
|
|
BitmapInfo = (BITMAPINFO*)
|
|
malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD));
|
|
memset (BitmapInfo,0,sizeof (bitmap));
|
|
BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
BitmapInfo->bmiHeader.biWidth = page->w;
|
|
BitmapInfo->bmiHeader.biHeight = -page->h;
|
|
BitmapInfo->bmiHeader.biPlanes = 1;
|
|
BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel;
|
|
BitmapInfo->bmiHeader.biCompression = BI_RGB;
|
|
BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch;
|
|
BitmapInfo->bmiHeader.biXPelsPerMeter = 0;
|
|
BitmapInfo->bmiHeader.biYPelsPerMeter = 0;
|
|
BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors;
|
|
BitmapInfo->bmiHeader.biClrImportant = 0;
|
|
if (page->format->palette) {
|
|
for (int I=0; I<page->format->palette->ncolors; I++) {
|
|
BitmapInfo->bmiColors[I].rgbRed =
|
|
(page->format->palette->colors+I)->r;
|
|
BitmapInfo->bmiColors[I].rgbGreen =
|
|
(page->format->palette->colors+I)->g;
|
|
BitmapInfo->bmiColors[I].rgbBlue =
|
|
(page->format->palette->colors+I)->b;
|
|
}
|
|
}
|
|
memHDC = CreateCompatibleDC(printerDC);
|
|
if (memHDC) {
|
|
bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS,
|
|
(&Pixels), NULL, 0);
|
|
if (bitmap) {
|
|
memcpy (Pixels, page->pixels,
|
|
BitmapInfo->bmiHeader.biSizeImage);
|
|
Prev = SelectObject (memHDC, bitmap);
|
|
StretchBlt(printerDC, 0, 0, physW, physH, memHDC, 0, 0, page->w, page->h, SRCCOPY);
|
|
SelectObject (memHDC,Prev);
|
|
DeleteObject (bitmap);
|
|
}
|
|
}
|
|
free (BitmapInfo);
|
|
SDL_UnlockSurface(page);
|
|
EndPage(printerDC);
|
|
|
|
if (multipageOutput)
|
|
{
|
|
multiPageCounter++;
|
|
outputHandle = printerDC;
|
|
}
|
|
else
|
|
{
|
|
EndDoc(printerDC);
|
|
outputHandle = NULL;
|
|
}
|
|
DeleteObject(bitmap);
|
|
DeleteDC(memHDC);
|
|
#else
|
|
//LOG_MSG("PRINTER: Direct printing not supported under this OS");
|
|
#endif
|
|
}
|
|
#ifdef C_LIBPNG
|
|
else if (strcasecmp(output, "png") == 0)
|
|
{
|
|
// Find a page that does not exists
|
|
findNextName("page", ".png", &fname[0]);
|
|
|
|
png_structp png_ptr;
|
|
png_infop info_ptr;
|
|
png_bytep * row_pointers;
|
|
png_color palette[256];
|
|
Bitu i;
|
|
|
|
/* Open the actual file */
|
|
FILE * fp=fopen(fname,"wb");
|
|
if (!fp)
|
|
{
|
|
//LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname);
|
|
return;
|
|
}
|
|
|
|
/* First try to alloacte the png structures */
|
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
|
|
if (!png_ptr) return;
|
|
info_ptr = png_create_info_struct(png_ptr);
|
|
if (!info_ptr) {
|
|
png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
|
|
return;
|
|
}
|
|
|
|
/* Finalize the initing of png library */
|
|
png_init_io(png_ptr, fp);
|
|
png_set_compression_level(png_ptr,Z_BEST_COMPRESSION);
|
|
|
|
/* set other zlib parameters */
|
|
png_set_compression_mem_level(png_ptr, 8);
|
|
png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
|
|
png_set_compression_window_bits(png_ptr, 15);
|
|
png_set_compression_method(png_ptr, 8);
|
|
png_set_compression_buffer_size(png_ptr, 8192);
|
|
|
|
|
|
png_set_IHDR(png_ptr, info_ptr, page->w, page->h,
|
|
8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
for (i=0;i<256;i++)
|
|
{
|
|
palette[i].red = page->format->palette->colors[i].r;
|
|
palette[i].green = page->format->palette->colors[i].g;
|
|
palette[i].blue = page->format->palette->colors[i].b;
|
|
}
|
|
png_set_PLTE(png_ptr, info_ptr, palette,256);
|
|
png_set_packing(png_ptr);
|
|
SDL_LockSurface(page);
|
|
|
|
// Allocate an array of scanline pointers
|
|
row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep));
|
|
for (i=0; i<page->h; i++)
|
|
row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch));
|
|
|
|
// tell the png library what to encode.
|
|
png_set_rows(png_ptr, info_ptr, row_pointers);
|
|
|
|
// Write image to file
|
|
png_write_png(png_ptr, info_ptr, 0, NULL);
|
|
|
|
|
|
|
|
|
|
SDL_UnlockSurface(page);
|
|
|
|
/*close file*/
|
|
fclose(fp);
|
|
|
|
/*Destroy PNG structs*/
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
|
|
/*clean up dynamically allocated RAM.*/
|
|
free(row_pointers);
|
|
}
|
|
#endif
|
|
else if (strcasecmp(output, "ps") == 0)
|
|
{
|
|
FILE* psfile = NULL;
|
|
|
|
// Continue postscript file?
|
|
if (outputHandle != NULL)
|
|
psfile = (FILE*)outputHandle;
|
|
|
|
// Create new file?
|
|
if (psfile == NULL)
|
|
{
|
|
if (!multipageOutput)
|
|
findNextName("page", ".ps", &fname[0]);
|
|
else
|
|
findNextName("doc", ".ps", &fname[0]);
|
|
|
|
psfile = fopen(fname, "wb");
|
|
if (!psfile)
|
|
{
|
|
printf("PRINTER: Can't open file %s for printer output", fname);
|
|
return;
|
|
}
|
|
|
|
// Print header
|
|
fprintf(psfile, "%%!PS-Adobe-3.0\n");
|
|
fprintf(psfile, "%%%%Pages: (atend)\n");
|
|
fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72));
|
|
fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n");
|
|
fprintf(psfile, "%%%%DocumentData: Clean7Bit\n");
|
|
fprintf(psfile, "%%%%LanguageLevel: 2\n");
|
|
fprintf(psfile, "%%%%EndComments\n");
|
|
multiPageCounter = 1;
|
|
}
|
|
|
|
fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter);
|
|
fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*72), (Bit16u)(defaultPageHeight*72));
|
|
fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h);
|
|
fprintf(psfile, "currentfile\n");
|
|
fprintf(psfile, "/ASCII85Decode filter\n");
|
|
fprintf(psfile, "/RunLengthDecode filter\n");
|
|
fprintf(psfile, "image\n");
|
|
|
|
SDL_LockSurface(page);
|
|
|
|
Bit32u pix = 0;
|
|
Bit32u numpix = page->h*page->w;
|
|
ASCII85BufferPos = ASCII85CurCol = 0;
|
|
|
|
while (pix < numpix)
|
|
{
|
|
// Compress data using RLE
|
|
|
|
if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2)))
|
|
{
|
|
// Found three or more pixels with the same color
|
|
Bit8u sameCount = 3;
|
|
Bit8u col = getPixel(pix);
|
|
while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount))
|
|
sameCount++;
|
|
|
|
fprintASCII85(psfile, 257-sameCount);
|
|
fprintASCII85(psfile, 255-col);
|
|
|
|
// Skip ahead
|
|
pix += sameCount;
|
|
}
|
|
else
|
|
{
|
|
// Find end of heterogenous area
|
|
Bit8u diffCount = 1;
|
|
while (diffCount < 128 && diffCount+pix < numpix &&
|
|
(
|
|
(diffCount+pix < numpix-2)
|
|
|| (getPixel(pix+diffCount) != getPixel(pix+diffCount+1))
|
|
|| (getPixel(pix+diffCount) != getPixel(pix+diffCount+2))
|
|
))
|
|
diffCount++;
|
|
|
|
fprintASCII85(psfile, diffCount-1);
|
|
for (Bit8u i=0; i<diffCount; i++)
|
|
fprintASCII85(psfile, 255-getPixel(pix++));
|
|
}
|
|
}
|
|
|
|
// Write EOD for RLE and ASCII85
|
|
fprintASCII85(psfile, 128);
|
|
fprintASCII85(psfile, 256);
|
|
|
|
SDL_UnlockSurface(page);
|
|
|
|
fprintf(psfile, "showpage\n");
|
|
|
|
if (multipageOutput)
|
|
{
|
|
multiPageCounter++;
|
|
outputHandle = psfile;
|
|
}
|
|
else
|
|
{
|
|
fprintf(psfile, "%%%%Pages: 1\n");
|
|
fprintf(psfile, "%%%%EOF\n");
|
|
fclose(psfile);
|
|
outputHandle = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Find a page that does not exists
|
|
findNextName("page", ".bmp", &fname[0]);
|
|
SDL_SaveBMP(page, fname);
|
|
}
|
|
}
|
|
|
|
void CPrinter::fprintASCII85(FILE* f, Bit16u b)
|
|
{
|
|
if (b != 256)
|
|
{
|
|
if (b < 256)
|
|
ASCII85Buffer[ASCII85BufferPos++] = (Bit8u)b;
|
|
|
|
if (ASCII85BufferPos == 4 || b == 257)
|
|
{
|
|
Bit32u num = (Bit32u)ASCII85Buffer[0] << 24 | (Bit32u)ASCII85Buffer[1] << 16 | (Bit32u)ASCII85Buffer[2] << 8 | (Bit32u)ASCII85Buffer[3];
|
|
|
|
// Deal with special case
|
|
if (num == 0 && b != 257)
|
|
{
|
|
fprintf(f, "z");
|
|
if (++ASCII85CurCol >= 79)
|
|
{
|
|
ASCII85CurCol = 0;
|
|
fprintf(f, "\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char buffer[5];
|
|
for (Bit8s i=4; i>=0; i--)
|
|
{
|
|
buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85);
|
|
buffer[i] += 33;
|
|
num /= (Bit32u)85;
|
|
}
|
|
|
|
// Make sure a line never starts with a % (which may be mistaken as start of a comment)
|
|
if (ASCII85CurCol == 0 && buffer[0] == '%')
|
|
fprintf(f, " ");
|
|
|
|
for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++)
|
|
{
|
|
fprintf(f, "%c", buffer[i]);
|
|
if (++ASCII85CurCol >= 79)
|
|
{
|
|
ASCII85CurCol = 0;
|
|
fprintf(f, "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
ASCII85BufferPos = 0;
|
|
}
|
|
|
|
}
|
|
else // Close string
|
|
{
|
|
// Partial tupel if there are still bytes in the buffer
|
|
if (ASCII85BufferPos > 0)
|
|
{
|
|
for (Bit8u i = ASCII85BufferPos; i < 4; i++)
|
|
ASCII85Buffer[i] = 0;
|
|
|
|
fprintASCII85(f, 257);
|
|
}
|
|
|
|
fprintf(f, "~");
|
|
fprintf(f, ">\n");
|
|
}
|
|
}
|
|
|
|
void CPrinter::finishMultipage()
|
|
{
|
|
if (outputHandle != NULL)
|
|
{
|
|
if (strcasecmp(output, "ps") == 0)
|
|
{
|
|
FILE* psfile = (FILE*)outputHandle;
|
|
fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter);
|
|
fprintf(psfile, "%%%%EOF\n");
|
|
fclose(psfile);
|
|
}
|
|
else if (strcasecmp(output, "printer") == 0)
|
|
{
|
|
#if defined (WIN32)
|
|
EndDoc(printerDC);
|
|
#endif
|
|
}
|
|
outputHandle = NULL;
|
|
}
|
|
}
|
|
|
|
bool CPrinter::isBlank() {
|
|
bool blank = true;
|
|
SDL_LockSurface(page);
|
|
|
|
for (Bit16u y=0; y<page->h; y++)
|
|
for (Bit16u x=0; x<page->w; x++)
|
|
if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0)
|
|
blank = false;
|
|
|
|
SDL_UnlockSurface(page);
|
|
return blank;
|
|
}
|
|
|
|
Bit8u CPrinter::getPixel(Bit32u num) {
|
|
Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch));
|
|
return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch));
|
|
}
|
|
#endif // HAVE_SDL
|
|
|
|
//Interfaces to C code
|
|
|
|
|
|
extern "C" void printer_init(int pdpi, int pwidth, int pheight, char* poutput, bool mpage)
|
|
{
|
|
if (defaultPrinter != NULL) return;
|
|
defaultPrinter = new CPrinter(pdpi, pwidth,pheight, poutput, mpage);
|
|
}
|
|
extern "C" void printer_loop(Bit8u pchar)
|
|
{
|
|
if (defaultPrinter == NULL) return;
|
|
defaultPrinter->printChar(pchar);
|
|
}
|
|
|
|
extern "C" void printer_close()
|
|
{
|
|
delete defaultPrinter;
|
|
defaultPrinter = NULL;
|
|
}
|
|
extern "C" void printer_feed()
|
|
{
|
|
if(defaultPrinter == NULL) return;
|
|
defaultPrinter->formFeed();
|
|
}
|