/* GSPLUS - Advanced Apple IIGS Emulator Environment Based on the KEGS emulator written by Kent Dickey See COPYRIGHT.txt for Copyright information See LICENSE.txt for license (GPL v2) */ /* * 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 #include "glog.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)) { glogf("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 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 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 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>=1) { // for each bit if (bitGraph.column[i] & j) { for (Bitu xx=0; xxw) && ((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("%s",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; Iformat->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; ih; 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((char *)"page", (char *)".ps", &fname[0]); else findNextName((char *)"doc", (char *)".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= 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; yh; y++) for (Bit16u x=0; xw; 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(); }