DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "printer.h" 00020 00021 #if C_PRINTER 00022 00023 #include <math.h> 00024 #include "setup.h" 00025 #include "mapper.h" 00026 #include "printer_if.h" 00027 #include "support.h" 00028 #include "cross.h" 00029 #include "printer_charmaps.h" 00030 #include "control.h" 00031 00032 #include "pic.h" // for timeout 00033 00034 extern void GFX_CaptureMouse(void); 00035 extern bool mouselocked; 00036 00037 static CPrinter* defaultPrinter = NULL; 00038 00039 #define PARAM16(I) (params[I+1]*256+params[I]) 00040 #define PIXX ((Bitu)floor(curX*dpi+0.5)) 00041 #define PIXY ((Bitu)floor(curY*dpi+0.5)) 00042 00043 static Bit16u confdpi, confwidth, confheight; 00044 static Bitu printer_timout; 00045 static bool timeout_dirty; 00046 static const char* document_path; 00047 //static const char* font_path; 00048 static char confoutputDevice[50]; 00049 static bool confmultipageOutput; 00050 00051 void CPrinter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) 00052 { 00053 float red = (float)redmax / (float)30.9; 00054 float green = (float)greenmax / (float)30.9; 00055 float blue = (float)bluemax / (float)30.9; 00056 00057 Bit8u colormask = colorID<<=5; 00058 00059 for(int i = 0; i < 32; i++) { 00060 pal->colors[i+colormask].r = 255 - (Bit8u)floor(red * (float)i); 00061 pal->colors[i+colormask].g = 255 - (Bit8u)floor(green * (float)i); 00062 pal->colors[i+colormask].b = 255 - (Bit8u)floor(blue * (float)i); 00063 } 00064 } 00065 00066 CPrinter::CPrinter(Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput) 00067 { 00068 if (FT_Init_FreeType(&FTlib)) 00069 { 00070 LOG(LOG_MISC,LOG_ERROR)("PRINTER: Unable to init Freetype2. Printing disabled"); 00071 page = NULL; 00072 } 00073 else 00074 { 00075 this->dpi = dpi; 00076 this->output = output; 00077 this->multipageOutput = multipageOutput; 00078 00079 defaultPageWidth = (Real64)width / (Real64)10; 00080 defaultPageHeight = (Real64)height / (Real64)10; 00081 00082 // Create page 00083 page = SDL_CreateRGBSurface(SDL_SWSURFACE, (int)(defaultPageWidth*dpi), (int)(defaultPageHeight*dpi), 8, 0, 0, 0, 0); 00084 00085 // Set a grey palette 00086 SDL_Palette* palette = page->format->palette; 00087 00088 for (Bitu i = 0; i < 32; i++) 00089 { 00090 palette->colors[i].r = 255; 00091 palette->colors[i].g = 255; 00092 palette->colors[i].b = 255; 00093 } 00094 // 0 = all white needed for logic 000 00095 FillPalette( 0, 0, 0, 1, palette); 00096 // 1 = magenta* 001 00097 FillPalette( 0, 255, 0, 1, palette); 00098 // 2 = cyan* 010 00099 FillPalette(255, 0, 0, 2, palette); 00100 // 3 = "violet" 011 00101 FillPalette(255, 255, 0, 3, palette); 00102 // 4 = yellow* 100 00103 FillPalette( 0, 0, 255, 4, palette); 00104 // 5 = red 101 00105 FillPalette( 0, 255, 255, 5, palette); 00106 // 6 = green 110 00107 FillPalette(255, 0, 255, 6, palette); 00108 // 7 = black 111 00109 FillPalette(255, 255, 255, 7, palette); 00110 00111 // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max 00112 // Printing colors on top of each other ORs them and gets the 00113 // correct resulting color. 00114 // i.e. magenta on blank page yyy=001 00115 // then yellow on magenta 001 | 100 = 101 = red 00116 00117 color = COLOR_BLACK; 00118 00119 curFont = NULL; 00120 charRead = false; 00121 autoFeed = false; 00122 outputHandle = NULL; 00123 00124 resetPrinter(); 00125 00126 if (strcasecmp(output, "printer") == 0) 00127 { 00128 #if defined (WIN32) 00129 // Show Print dialog to obtain a printer device context 00130 PRINTDLG pd; 00131 pd.lStructSize = sizeof(PRINTDLG); 00132 pd.hDevMode = (HANDLE) NULL; 00133 pd.hDevNames = (HANDLE) NULL; 00134 pd.Flags = PD_RETURNDC; 00135 pd.hwndOwner = NULL; 00136 pd.hDC = (HDC) NULL; 00137 pd.nFromPage = 1; 00138 pd.nToPage = 1; 00139 pd.nMinPage = 0; 00140 pd.nMaxPage = 0; 00141 pd.nCopies = 1; 00142 pd.hInstance = NULL; 00143 pd.lCustData = 0L; 00144 pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; 00145 pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; 00146 pd.lpPrintTemplateName = (LPSTR) NULL; 00147 pd.lpSetupTemplateName = (LPSTR) NULL; 00148 pd.hPrintTemplate = (HANDLE) NULL; 00149 pd.hSetupTemplate = (HANDLE) NULL; 00150 PrintDlg(&pd); 00151 // TODO: what if user presses cancel? 00152 printerDC = pd.hDC; 00153 #endif 00154 } 00155 LOG(LOG_MISC,LOG_NORMAL)("PRINTER: Enabled"); 00156 } 00157 } 00158 00159 void CPrinter::resetPrinterHard() 00160 { 00161 charRead = false; 00162 resetPrinter(); 00163 } 00164 00165 void CPrinter::resetPrinter() 00166 { 00167 color = COLOR_BLACK; 00168 curX = curY = 0.0; 00169 ESCSeen = false; 00170 FSSeen = false; 00171 ESCCmd = 0; 00172 numParam = neededParam = 0; 00173 topMargin = leftMargin = 0.0; 00174 rightMargin = pageWidth = defaultPageWidth; 00175 bottomMargin = pageHeight = defaultPageHeight; 00176 lineSpacing = (Real64)1 / 6; 00177 cpi = 10.0; 00178 curCharTable = 1; 00179 style = 0; 00180 extraIntraSpace = 0.0; 00181 printUpperContr = true; 00182 bitGraph.remBytes = 0; 00183 densk = 0; 00184 densl = 1; 00185 densy = 2; 00186 densz = 3; 00187 charTables[0] = 0; // Italics 00188 charTables[1] = charTables[2] = charTables[3] = 437; 00189 definedUnit = -1; 00190 multipoint = false; 00191 multiPointSize = 0.0; 00192 multicpi = 0.0; 00193 hmi = -1.0; 00194 msb = 255; 00195 numPrintAsChar = 0; 00196 LQtypeFace = courier; 00197 00198 selectCodepage(charTables[curCharTable]); 00199 00200 updateFont(); 00201 00202 newPage(false,true); 00203 00204 // Default tabs => Each eight characters 00205 for (Bitu i = 0; i < 32; i++) 00206 horiztabs[i] = i * 8 * (1 / (Real64)cpi); 00207 numHorizTabs = 32; 00208 numVertTabs = 255; 00209 } 00210 00211 00212 CPrinter::~CPrinter(void) 00213 { 00214 finishMultipage(); 00215 if (page != NULL) 00216 { 00217 SDL_FreeSurface(page); 00218 page = NULL; 00219 FT_Done_FreeType(FTlib); 00220 } 00221 #if defined (WIN32) 00222 DeleteDC(printerDC); 00223 #endif 00224 } 00225 00226 void CPrinter::selectCodepage(Bit16u cp) 00227 { 00228 const Bit16u* mapToUse = NULL; 00229 00230 Bitu i = 0; 00231 while(charmap[i].codepage!=0) 00232 { 00233 if(charmap[i].codepage==cp) 00234 { 00235 mapToUse = charmap[i].map; 00236 break; 00237 } 00238 i++; 00239 } 00240 if (mapToUse == NULL) 00241 { 00242 LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); 00243 selectCodepage(437); 00244 return; 00245 } 00246 for (int i = 0; i < 256; i++) 00247 curMap[i] = mapToUse[i]; 00248 } 00249 00250 void CPrinter::updateFont() 00251 { 00252 if (curFont != NULL) 00253 FT_Done_Face(curFont); 00254 00255 const char* fontName; 00256 00257 switch (LQtypeFace) 00258 { 00259 case roman: 00260 fontName = "./FONTS/roman.ttf"; 00261 break; 00262 case sansserif: 00263 fontName = "./FONTS/sansserif.ttf"; 00264 break; 00265 case courier: 00266 fontName = "./FONTS/courier.ttf"; 00267 break; 00268 case script: 00269 fontName = "./FONTS/script.ttf"; 00270 break; 00271 case ocra: 00272 case ocrb: 00273 fontName = "./FONTS/ocra.ttf"; 00274 break; 00275 default: 00276 fontName = "./FONTS/roman.ttf"; 00277 } 00278 00279 #ifndef WIN32 00280 std::string configfont; 00281 Cross::GetPlatformConfigDir(configfont); 00282 configfont += fontName; 00283 fontName = configfont.c_str(); 00284 #endif 00285 00286 if (FT_New_Face(FTlib, fontName, 0, &curFont)) 00287 { 00288 //LOG(LOG_MISC,LOG_ERROR)("Unable to load font %s", fontName); 00289 LOG_MSG("Unable to load font %s", fontName); 00290 curFont = NULL; 00291 } 00292 00293 Real64 horizPoints = 10.5; 00294 Real64 vertPoints = 10.5; 00295 00296 if (!multipoint) 00297 { 00298 actcpi = cpi; 00299 /* 00300 switch(style & (STYLE_CONDENSED|STYLE_PROP)) { 00301 case STYLE_CONDENSED: // only condensed 00302 if (cpi == 10.0) { 00303 actcpi = 17.14; 00304 horizPoints *= 10.0/17.14; 00305 } else if(cpi == 12.0) { 00306 actcpi = 20.0; 00307 horizPoints *= 10.0/20.0; 00308 vertPoints *= 10.0/12.0; 00309 } else { 00310 // ignored 00311 } 00312 break; 00313 case STYLE_PROP|STYLE_CONDENSED: 00314 horizPoints /= 2.0; 00315 break; 00316 case 0: // neither 00317 case STYLE_PROP: // only proportional 00318 horizPoints *= 10.0/cpi; 00319 vertPoints *= 10.0/cpi; 00320 break; 00321 } 00322 */ 00323 if (!(style & STYLE_CONDENSED)) 00324 { 00325 horizPoints *= 10.0 / cpi; 00326 vertPoints *= 10.0 / cpi; 00327 } 00328 00329 if (!(style & STYLE_PROP)) 00330 { 00331 if ((cpi == 10.0) && (style & STYLE_CONDENSED)) 00332 { 00333 actcpi = 17.14; 00334 horizPoints *= 10.0 / 17.14; 00335 } 00336 if ((cpi == 12.0) && (style & STYLE_CONDENSED)) 00337 { 00338 actcpi = 20.0; 00339 horizPoints *= 10.0 / 20.0; 00340 vertPoints *= 10.0 / 12.0; 00341 } 00342 } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; 00343 00344 00345 if ((style & STYLE_DOUBLEWIDTH) || (style & STYLE_DOUBLEWIDTHONELINE)) 00346 { 00347 actcpi /= 2.0; 00348 horizPoints *= 2.0; 00349 } 00350 00351 if (style & STYLE_DOUBLEHEIGHT) vertPoints *= 2.0; 00352 } 00353 else 00354 { 00355 // multipoint true 00356 actcpi = multicpi; 00357 horizPoints = vertPoints = multiPointSize; 00358 } 00359 00360 if ((style & STYLE_SUPERSCRIPT) || (style & STYLE_SUBSCRIPT)) { 00361 horizPoints *= 2.0/3.0; 00362 vertPoints *= 2.0/3.0; 00363 actcpi /= 2.0/3.0; 00364 } 00365 00366 FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); 00367 00368 if (style & STYLE_ITALICS || charTables[curCharTable] == 0) 00369 { 00370 FT_Matrix matrix; 00371 matrix.xx = 0x10000L; 00372 matrix.xy = (FT_Fixed)(0.20 * 0x10000L); 00373 matrix.yx = 0; 00374 matrix.yy = 0x10000L; 00375 FT_Set_Transform(curFont, &matrix, 0); 00376 } 00377 } 00378 00379 bool CPrinter::processCommandChar(Bit8u ch) 00380 { 00381 if (ESCSeen || FSSeen) 00382 { 00383 ESCCmd = ch; 00384 if(FSSeen) ESCCmd |= 0x800; 00385 ESCSeen = FSSeen = false; 00386 numParam = 0; 00387 00388 switch (ESCCmd) { 00389 case 0x02: // Undocumented 00390 case 0x0a: // Reverse line feed (ESC LF) 00391 case 0x0c: // Return to top of current page (ESC FF) 00392 case 0x0e: // Select double-width printing (one line) (ESC SO) 00393 case 0x0f: // Select condensed printing (ESC SI) 00394 case 0x23: // Cancel MSB control (ESC #) 00395 case 0x30: // Select 1/8-inch line spacing (ESC 0) 00396 case 0x31: // Select 7/60-inch line spacing (ESC 1) 00397 case 0x32: // Select 1/6-inch line spacing (ESC 2) 00398 case 0x34: // Select italic font (ESC 4) 00399 case 0x35: // Cancel italic font (ESC 5) 00400 case 0x36: // Enable printing of upper control codes (ESC 6) 00401 case 0x37: // Enable upper control codes (ESC 7) 00402 case 0x38: // Disable paper-out detector (ESC 8) 00403 case 0x39: // Enable paper-out detector (ESC 9) 00404 case 0x3c: // Unidirectional mode (one line) (ESC <) 00405 case 0x3d: // Set MSB to 0 (ESC =) 00406 case 0x3e: // Set MSB to 1 (ESC >) 00407 case 0x40: // Initialize printer (ESC @) 00408 case 0x45: // Select bold font (ESC E) 00409 case 0x46: // Cancel bold font (ESC F) 00410 case 0x47: // Select double-strike printing (ESC G) 00411 case 0x48: // Cancel double-strike printing (ESC H) 00412 case 0x4d: // Select 10.5-point, 12-cpi (ESC M) 00413 case 0x4f: // Cancel bottom margin [conflict] (ESC O) 00414 case 0x50: // Select 10.5-point, 10-cpi (ESC P) 00415 case 0x54: // Cancel superscript/subscript printing (ESC T) 00416 case 0x5e: // Enable printing of all character codes on next character (ESC ^) 00417 case 0x67: // Select 10.5-point, 15-cpi (ESC g) 00418 00419 case 0x834: // Select italic font (FS 4) (= ESC 4) 00420 case 0x835: // Cancel italic font (FS 5) (= ESC 5) 00421 case 0x846: // Select forward feed mode (FS F) 00422 case 0x852: // Select reverse feed mode (FS R) 00423 neededParam = 0; 00424 break; 00425 case 0x19: // Control paper loading/ejecting (ESC EM) 00426 case 0x20: // Set intercharacter space (ESC SP) 00427 case 0x21: // Master select (ESC !) 00428 case 0x2b: // Set n/360-inch line spacing (ESC +) 00429 case 0x2d: // Turn underline on/off (ESC -) 00430 case 0x2f: // Select vertical tab channel (ESC /) 00431 case 0x33: // Set n/180-inch line spacing (ESC 3) 00432 case 0x41: // Set n/60-inch line spacing (ESC A) 00433 case 0x43: // Set page length in lines (ESC C) 00434 case 0x49: // Select character type and print pitch (ESC I) 00435 case 0x4a: // Advance print position vertically (ESC J) 00436 case 0x4e: // Set bottom margin (ESC N) 00437 case 0x51: // Set right margin (ESC Q) 00438 case 0x52: // Select an international character set (ESC R) 00439 case 0x53: // Select superscript/subscript printing (ESC S) 00440 case 0x55: // Turn unidirectional mode on/off (ESC U) 00441 //case 0x56: // Repeat data (ESC V) 00442 case 0x57: // Turn double-width printing on/off (ESC W) 00443 case 0x61: // Select justification (ESC a) 00444 case 0x66: // Absolute horizontal tab in columns [conflict] (ESC f) 00445 case 0x68: // Select double or quadruple size (ESC h) 00446 case 0x69: // Immediate print (ESC i) 00447 case 0x6a: // Reverse paper feed (ESC j) 00448 case 0x6b: // Select typeface (ESC k) 00449 case 0x6c: // Set left margin (ESC 1) 00450 case 0x70: // Turn proportional mode on/off (ESC p) 00451 case 0x72: // Select printing color (ESC r) 00452 case 0x73: // Low-speed mode on/off (ESC s) 00453 case 0x74: // Select character table (ESC t) 00454 case 0x77: // Turn double-height printing on/off (ESC w) 00455 case 0x78: // Select LQ or draft (ESC x) 00456 case 0x7e: // Select/Deselect slash zero (ESC ~) 00457 00458 case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) 00459 case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) 00460 case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) 00461 case 0x843: // Select LQ type style (FS C) (= ESC k) 00462 case 0x845: // Select character width (FS E) 00463 case 0x849: // Select character table (FS I) (= ESC t) 00464 case 0x853: // Select High Speed/High Density elite pitch (FS S) 00465 case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) 00466 neededParam = 1; 00467 break; 00468 case 0x24: // Set absolute horizontal print position (ESC $) 00469 case 0x3f: // Reassign bit-image mode (ESC ?) 00470 case 0x4b: // Select 60-dpi graphics (ESC K) 00471 case 0x4c: // Select 120-dpi graphics (ESC L) 00472 case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) 00473 case 0x5a: // Select 240-dpi graphics (ESC Z) 00474 case 0x5c: // Set relative horizontal print position (ESC \) 00475 case 0x63: // Set horizontal motion index (HMI) [conflict] (ESC c) 00476 case 0x65: // Set vertical tab stops every n lines (ESC e) 00477 case 0x85a: // Print 24-bit hex-density graphics (FS Z) 00478 neededParam = 2; 00479 break; 00480 case 0x2a: // Select bit image (ESC *) 00481 case 0x58: // Select font by pitch and point [conflict] (ESC X) 00482 neededParam = 3; 00483 break; 00484 case 0x5b: // Select character height, width, line spacing 00485 neededParam = 7; 00486 break; 00487 case 0x62: // Set vertical tabs in VFU channels (ESC b) 00488 case 0x42: // Set vertical tabs (ESC B) 00489 numVertTabs = 0; 00490 return true; 00491 case 0x44: // Set horizontal tabs (ESC D) 00492 numHorizTabs = 0; 00493 return true; 00494 case 0x25: // Select user-defined set (ESC %) 00495 case 0x26: // Define user-defined characters (ESC &) 00496 case 0x3a: // Copy ROM to RAM (ESC :) 00497 LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); 00498 return true; 00499 case 0x28: // Two bytes sequence 00500 return true; 00501 default: 00502 LOG_MSG("PRINTER: Unknown command %s (%02Xh) %c , unable to skip parameters.", 00503 (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd); 00504 00505 neededParam = 0; 00506 ESCCmd = 0; 00507 return true; 00508 } 00509 00510 if (neededParam > 0) 00511 return true; 00512 } 00513 00514 // Two bytes sequence 00515 if (ESCCmd == '(') 00516 { 00517 ESCCmd = 0x200 + ch; 00518 00519 switch (ESCCmd) 00520 { 00521 case 0x242: // Bar code setup and print (ESC (B) 00522 case 0x25e: // Print data as characters (ESC (^) 00523 neededParam = 2; 00524 break; 00525 case 0x255: // Set unit (ESC (U) 00526 neededParam = 3; 00527 break; 00528 case 0x243: // Set page length in defined unit (ESC (C) 00529 case 0x256: // Set absolute vertical print position (ESC (V) 00530 case 0x276: // Set relative vertical print position (ESC (v) 00531 neededParam = 4; 00532 break; 00533 case 0x274: // Assign character table (ESC (t) 00534 case 0x22d: // Select line/score (ESC (-) 00535 neededParam = 5; 00536 break; 00537 case 0x263: // Set page format (ESC (c) 00538 neededParam = 6; 00539 break; 00540 00541 default: 00542 // ESC ( commands are always followed by a "number of parameters" word parameter 00543 //LOG(LOG_MISC,LOG_ERROR) 00544 LOG_MSG("PRINTER: Skipping unsupported command ESC ( %c (%02X).", ESCCmd, ESCCmd); 00545 neededParam = 2; 00546 ESCCmd = 0x101; 00547 return true; 00548 } 00549 00550 if (neededParam > 0) 00551 return true; 00552 } 00553 00554 // Ignore VFU channel setting 00555 if (ESCCmd == 0x62) 00556 { 00557 ESCCmd = 0x42; 00558 return true; 00559 } 00560 00561 // Collect vertical tabs 00562 if (ESCCmd == 0x42) 00563 { 00564 if (ch == 0 || (numVertTabs > 0 && verttabs[numVertTabs-1] > (Real64)ch * lineSpacing)) // Done 00565 ESCCmd = 0; 00566 else 00567 if (numVertTabs < 16) 00568 verttabs[numVertTabs++] = (Real64)ch * lineSpacing; 00569 } 00570 00571 // Collect horizontal tabs 00572 if (ESCCmd == 0x44) 00573 { 00574 if (ch == 0 || (numHorizTabs > 0 && horiztabs[numHorizTabs-1] > (Real64)ch * (1 / (Real64)cpi))) // Done 00575 ESCCmd = 0; 00576 else 00577 if (numHorizTabs < 32) 00578 horiztabs[numHorizTabs++] = (Real64)ch*(1 / (Real64)cpi); 00579 } 00580 00581 if (numParam < neededParam) 00582 { 00583 params[numParam++] = ch; 00584 00585 if (numParam < neededParam) 00586 return true; 00587 } 00588 00589 if (ESCCmd != 0) 00590 { 00591 switch (ESCCmd) 00592 { 00593 case 0x02: // Undocumented 00594 // Ignore 00595 break; 00596 case 0x0e: // Select double-width printing (one line) (ESC SO) 00597 if (!multipoint) 00598 { 00599 hmi = -1; 00600 style |= STYLE_DOUBLEWIDTHONELINE; 00601 updateFont(); 00602 } 00603 break; 00604 case 0x0f: // Select condensed printing (ESC SI) 00605 if (!multipoint && (cpi != 15.0)) 00606 { 00607 hmi = -1; 00608 style |= STYLE_CONDENSED; 00609 updateFont(); 00610 } 00611 break; 00612 case 0x19: // Control paper loading/ejecting (ESC EM) 00613 // We are not really loading paper, so most commands can be ignored 00614 if (params[0] == 'R') 00615 newPage(true, false); // TODO resetx? 00616 break; 00617 case 0x20: // Set intercharacter space (ESC SP) 00618 if (!multipoint) 00619 { 00620 extraIntraSpace = (Real64)params[0] / (printQuality == QUALITY_DRAFT ? 120 : 180); 00621 hmi = -1; 00622 updateFont(); 00623 } 00624 break; 00625 case 0x21: // Master select (ESC !) 00626 cpi = params[0] & 0x01 ? 12:10; 00627 00628 // Reset first seven bits 00629 style &= 0xFF80; 00630 if (params[0] & 0x02) 00631 style |= STYLE_PROP; 00632 if (params[0] & 0x04) 00633 style |= STYLE_CONDENSED; 00634 if (params[0] & 0x08) 00635 style |= STYLE_BOLD; 00636 if (params[0] & 0x10) 00637 style |= STYLE_DOUBLESTRIKE; 00638 if (params[0] & 0x20) 00639 style |= STYLE_DOUBLEWIDTH; 00640 if (params[0] & 0x40) 00641 style |= STYLE_ITALICS; 00642 if (params[0] & 0x80) 00643 { 00644 score = SCORE_SINGLE; 00645 style |= STYLE_UNDERLINE; 00646 } 00647 00648 hmi = -1; 00649 multipoint = false; 00650 updateFont(); 00651 break; 00652 case 0x23: // Cancel MSB control (ESC #) 00653 msb = 255; 00654 break; 00655 case 0x24: // Set absolute horizontal print position (ESC $) 00656 { 00657 Real64 unitSize = definedUnit; 00658 if (unitSize < 0) 00659 unitSize = (Real64)60.0; 00660 00661 Real64 newX = leftMargin + ((Real64)PARAM16(0) / unitSize); 00662 if (newX <= rightMargin) 00663 curX = newX; 00664 } 00665 break; 00666 case 0x85a: // Print 24-bit hex-density graphics (FS Z) 00667 setupBitImage(40, PARAM16(0)); 00668 break; 00669 case 0x2a: // Select bit image (ESC *) 00670 setupBitImage(params[0], PARAM16(1)); 00671 break; 00672 case 0x2b: // Set n/360-inch line spacing (ESC +) 00673 case 0x833: // Set n/360-inch line spacing (FS 3) 00674 lineSpacing = (Real64)params[0] / 360; 00675 break; 00676 case 0x2d: // Turn underline on/off (ESC -) 00677 if (params[0] == 0 || params[0] == 48) 00678 style &= ~STYLE_UNDERLINE; 00679 if (params[0] == 1 || params[0] == 49) 00680 { 00681 style |= STYLE_UNDERLINE; 00682 score = SCORE_SINGLE; 00683 } 00684 updateFont(); 00685 break; 00686 case 0x2f: // Select vertical tab channel (ESC /) 00687 // Ignore 00688 break; 00689 case 0x30: // Select 1/8-inch line spacing (ESC 0) 00690 lineSpacing = (Real64)1 / 8; 00691 break; 00692 case 0x32: // Select 1/6-inch line spacing (ESC 2) 00693 lineSpacing = (Real64)1 / 6; 00694 break; 00695 case 0x33: // Set n/180-inch line spacing (ESC 3) 00696 lineSpacing = (Real64)params[0] / 180; 00697 break; 00698 case 0x34: // Select italic font (ESC 4) 00699 style |= STYLE_ITALICS; 00700 updateFont(); 00701 break; 00702 case 0x35: // Cancel italic font (ESC 5) 00703 style &= ~STYLE_ITALICS; 00704 updateFont(); 00705 break; 00706 case 0x36: // Enable printing of upper control codes (ESC 6) 00707 printUpperContr = true; 00708 break; 00709 case 0x37: // Enable upper control codes (ESC 7) 00710 printUpperContr = false; 00711 break; 00712 case 0x3c: // Unidirectional mode (one line) (ESC <) 00713 // We don't have a print head, so just ignore this 00714 break; 00715 case 0x3d: // Set MSB to 0 (ESC =) 00716 msb = 0; 00717 break; 00718 case 0x3e: // Set MSB to 1 (ESC >) 00719 msb = 1; 00720 break; 00721 case 0x3f: // Reassign bit-image mode (ESC ?) 00722 if (params[0] == 75) 00723 densk = params[1]; 00724 if (params[0] == 76) 00725 densl = params[1]; 00726 if (params[0] == 89) 00727 densy = params[1]; 00728 if (params[0] == 90) 00729 densz = params[1]; 00730 break; 00731 case 0x40: // Initialize printer (ESC @) 00732 resetPrinter(); 00733 break; 00734 case 0x41: // Set n/60-inch line spacing 00735 case 0x841: 00736 lineSpacing = (Real64)params[0] / 60; 00737 break; 00738 case 0x43: // Set page length in lines (ESC C) 00739 if (params[0] != 0) 00740 pageHeight = bottomMargin = (Real64)params[0] * lineSpacing; 00741 else // == 0 => Set page length in inches 00742 { 00743 neededParam = 1; 00744 numParam = 0; 00745 ESCCmd = 0x100; 00746 return true; 00747 } 00748 break; 00749 case 0x45: // Select bold font (ESC E) 00750 style |= STYLE_BOLD; 00751 updateFont(); 00752 break; 00753 case 0x46: // Cancel bold font (ESC F) 00754 style &= ~STYLE_BOLD; 00755 updateFont(); 00756 break; 00757 case 0x47: // Select dobule-strike printing (ESC G) 00758 style |= STYLE_DOUBLESTRIKE; 00759 break; 00760 case 0x48: // Cancel double-strike printing (ESC H) 00761 style &= ~STYLE_DOUBLESTRIKE; 00762 break; 00763 case 0x4a: // Advance print position vertically (ESC J n) 00764 curY += (Real64)((Real64)params[0] / 180); 00765 if (curY > bottomMargin) 00766 newPage(true, false); 00767 break; 00768 case 0x4b: // Select 60-dpi graphics (ESC K) 00769 setupBitImage(densk, PARAM16(0)); 00770 break; 00771 case 0x4c: // Select 120-dpi graphics (ESC L) 00772 setupBitImage(densl, PARAM16(0)); 00773 break; 00774 case 0x4d: // Select 10.5-point, 12-cpi (ESC M) 00775 cpi = 12; 00776 hmi = -1; 00777 multipoint = false; 00778 updateFont(); 00779 break; 00780 case 0x4e: // Set bottom margin (ESC N) 00781 topMargin = 0.0; 00782 bottomMargin = (Real64)params[0] * lineSpacing; 00783 break; 00784 case 0x4f: // Cancel bottom (and top) margin 00785 topMargin = 0.0; 00786 bottomMargin = pageHeight; 00787 break; 00788 case 0x50: // Select 10.5-point, 10-cpi (ESC P) 00789 cpi = 10; 00790 hmi = -1; 00791 multipoint = false; 00792 updateFont(); 00793 break; 00794 case 0x51: // Set right margin 00795 rightMargin = (Real64)(params[0] - 1.0) / (Real64)cpi; 00796 break; 00797 case 0x52: // Select an international character set (ESC R) 00798 if (params[0] <= 13 || params[0] == 64) 00799 { 00800 if (params[0] == 64) 00801 params[0] = 14; 00802 00803 curMap[0x23] = intCharSets[params[0]][0]; 00804 curMap[0x24] = intCharSets[params[0]][1]; 00805 curMap[0x40] = intCharSets[params[0]][2]; 00806 curMap[0x5b] = intCharSets[params[0]][3]; 00807 curMap[0x5c] = intCharSets[params[0]][4]; 00808 curMap[0x5d] = intCharSets[params[0]][5]; 00809 curMap[0x5e] = intCharSets[params[0]][6]; 00810 curMap[0x60] = intCharSets[params[0]][7]; 00811 curMap[0x7b] = intCharSets[params[0]][8]; 00812 curMap[0x7c] = intCharSets[params[0]][9]; 00813 curMap[0x7d] = intCharSets[params[0]][10]; 00814 curMap[0x7e] = intCharSets[params[0]][11]; 00815 } 00816 break; 00817 case 0x53: // Select superscript/subscript printing (ESC S) 00818 if (params[0] == 0 || params[0] == 48) 00819 style |= STYLE_SUBSCRIPT; 00820 if (params[0] == 1 || params[1] == 49) 00821 style |= STYLE_SUPERSCRIPT; 00822 updateFont(); 00823 break; 00824 case 0x54: // Cancel superscript/subscript printing (ESC T) 00825 style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; 00826 updateFont(); 00827 break; 00828 case 0x55: // Turn unidirectional mode on/off (ESC U) 00829 // We don't have a print head, so just ignore this 00830 break; 00831 case 0x57: // Turn double-width printing on/off (ESC W) 00832 if (!multipoint) 00833 { 00834 hmi = -1; 00835 if (params[0] == 0 || params[0] == 48) 00836 style &= ~STYLE_DOUBLEWIDTH; 00837 if (params[0] == 1 || params[0] == 49) 00838 style |= STYLE_DOUBLEWIDTH; 00839 updateFont(); 00840 } 00841 break; 00842 case 0x58: // Select font by pitch and point (ESC X) 00843 multipoint = true; 00844 // Copy currently non-multipoint CPI if no value was set so far 00845 if (multicpi == 0) 00846 multicpi = cpi; 00847 if (params[0] > 0) // Set CPI 00848 { 00849 if (params[0] == 1) // Proportional spacing 00850 style |= STYLE_PROP; 00851 else if (params[0] >= 5) 00852 multicpi = (Real64)360 / (Real64)params[0]; 00853 } 00854 if (multiPointSize == 0) 00855 multiPointSize = (Real64)10.5; 00856 if (PARAM16(1) > 0) // Set points 00857 multiPointSize = ((Real64)PARAM16(1)) / 2; 00858 updateFont(); 00859 break; 00860 case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) 00861 setupBitImage(densy, PARAM16(0)); 00862 break; 00863 case 0x5a: // Select 240-dpi graphics (ESC Z) 00864 setupBitImage(densz, PARAM16(0)); 00865 break; 00866 case 0x5c: // Set relative horizontal print position (ESC \) 00867 { 00868 Bit16s toMove = PARAM16(0); 00869 Real64 unitSize = definedUnit; 00870 if (unitSize < 0) 00871 unitSize = (Real64)(printQuality == QUALITY_DRAFT ? 120.0 : 180.0); 00872 curX += (Real64)((Real64)toMove / unitSize); 00873 } 00874 break; 00875 case 0x61: // Select justification (ESC a) 00876 // Ignore 00877 break; 00878 case 0x63: // Set horizontal motion index (HMI) (ESC c) 00879 hmi = (Real64)PARAM16(0) / (Real64)360.0; 00880 extraIntraSpace = 0.0; 00881 break; 00882 case 0x67: // Select 10.5-point, 15-cpi (ESC g) 00883 cpi = 15; 00884 hmi = -1; 00885 multipoint = false; 00886 updateFont(); 00887 break; 00888 case 0x846: // Select forward feed mode (FS F) - set reverse not implemented yet 00889 if (lineSpacing < 0) lineSpacing *= -1; 00890 break; 00891 case 0x6a: // Reverse paper feed (ESC j) 00892 { 00893 Real64 reverse = (Real64)PARAM16(0) / (Real64)216.0; 00894 reverse = curY - reverse; 00895 if (reverse < leftMargin) 00896 curY = leftMargin; 00897 else 00898 curY = reverse; 00899 break; 00900 } 00901 case 0x6b: // Select typeface (ESC k) 00902 if (params[0] <= 11 || params[0] == 30 || params[0] == 31) 00903 LQtypeFace = (Typeface)params[0]; 00904 updateFont(); 00905 break; 00906 case 0x6c: // Set left margin (ESC l) 00907 leftMargin = (Real64)(params[0] - 1.0) / (Real64)cpi; 00908 if (curX < leftMargin) 00909 curX = leftMargin; 00910 break; 00911 case 0x70: // Turn proportional mode on/off (ESC p) 00912 if (params[0] == 0 || params[0] == 48) 00913 style &= (0xffff - STYLE_PROP); 00914 if (params[0] == 1 || params[0] == 49) 00915 { 00916 style |= STYLE_PROP; 00917 printQuality = QUALITY_LQ; 00918 } 00919 multipoint = false; 00920 hmi = -1; 00921 updateFont(); 00922 break; 00923 case 0x72: // Select printing color (ESC r) 00924 if (params[0] == 0 || params[0] > 6) 00925 color = COLOR_BLACK; 00926 else 00927 color = params[0] << 5; 00928 break; 00929 case 0x73: // Select low-speed mode (ESC s) 00930 // Ignore 00931 break; 00932 case 0x74: // Select character table (ESC t) 00933 case 0x849: // Select character table (FS I) 00934 if (params[0] < 4) 00935 curCharTable = params[0]; 00936 if (params[0] >= 48 && params[0] <= 51) 00937 curCharTable = params[0] - 48; 00938 selectCodepage(charTables[curCharTable]); 00939 updateFont(); 00940 break; 00941 case 0x77: // Turn double-height printing on/off (ESC w) 00942 if (!multipoint) 00943 { 00944 if (params[0] == 0 || params[0] == 48) 00945 style &= ~STYLE_DOUBLEHEIGHT; 00946 if (params[0] == 1 || params[0] == 49) 00947 style |= STYLE_DOUBLEHEIGHT; 00948 updateFont(); 00949 } 00950 break; 00951 case 0x78: // Select LQ or draft (ESC x) 00952 if (params[0] == 0 || params[0] == 48) { 00953 printQuality = QUALITY_DRAFT; 00954 style |= STYLE_CONDENSED; 00955 } 00956 if (params[0] == 1 || params[0] == 49) { 00957 printQuality = QUALITY_LQ; 00958 style &= ~STYLE_CONDENSED; 00959 } 00960 hmi = -1; 00961 updateFont(); 00962 break; 00963 case 0x100: // Set page length in inches (ESC C NUL) 00964 pageHeight = (Real64)params[0]; 00965 bottomMargin = pageHeight; 00966 topMargin = 0.0; 00967 break; 00968 case 0x101: // Skip unsupported ESC ( command 00969 neededParam = PARAM16(0); 00970 numParam = 0; 00971 break; 00972 case 0x274: // Assign character table (ESC (t) 00973 if (params[2] < 4 && params[3] < 16) 00974 { 00975 charTables[params[2]] = codepages[params[3]]; 00976 //LOG_MSG("curr table: %d, p2: %d, p3: %d",curCharTable,params[2],params[3]); 00977 if (params[2] == curCharTable) 00978 selectCodepage(charTables[curCharTable]); 00979 } 00980 break; 00981 case 0x22d: // Select line/score (ESC (-) 00982 style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); 00983 score = params[4]; 00984 if (score) 00985 { 00986 if (params[3] == 1) 00987 style |= STYLE_UNDERLINE; 00988 if (params[3] == 2) 00989 style |= STYLE_STRIKETHROUGH; 00990 if (params[3] == 3) 00991 style |= STYLE_OVERSCORE; 00992 } 00993 updateFont(); 00994 break; 00995 case 0x242: // Bar code setup and print (ESC (B) 00996 LOG(LOG_MISC,LOG_ERROR)("PRINTER: Bardcode printing not supported"); 00997 // Find out how many bytes to skip 00998 neededParam = PARAM16(0); 00999 numParam = 0; 01000 break; 01001 case 0x243: // Set page length in defined unit (ESC (C) 01002 if (params[0] != 0 && definedUnit > 0) 01003 { 01004 pageHeight = bottomMargin = ((Real64)PARAM16(2)) * definedUnit; 01005 topMargin = 0.0; 01006 } 01007 break; 01008 case 0x255: // Set unit (ESC (U) 01009 definedUnit = (Real64)params[2] / (Real64)3600; 01010 break; 01011 case 0x256: // Set absolute vertical print position (ESC (V) 01012 { 01013 Real64 unitSize = definedUnit; 01014 if (unitSize < 0) 01015 unitSize = (Real64)360.0; 01016 Real64 newPos = topMargin + (((Real64)PARAM16(2)) * unitSize); 01017 if (newPos > bottomMargin) 01018 newPage(true, false); 01019 else 01020 curY = newPos; 01021 } 01022 break; 01023 case 0x25e: // Print data as characters (ESC (^) 01024 numPrintAsChar = PARAM16(0); 01025 break; 01026 case 0x263: // Set page format (ESC (c) 01027 if (definedUnit > 0) 01028 { 01029 Real64 newTop, newBottom; 01030 newTop = ((Real64)PARAM16(2)) * definedUnit; 01031 newBottom = ((Real64)PARAM16(4)) * definedUnit; 01032 if(newTop >= newBottom) break; 01033 if(newTop < pageHeight) topMargin = newTop; 01034 if(newBottom < pageHeight) bottomMargin = newBottom; 01035 if(topMargin > curY) curY = topMargin; 01036 //LOG_MSG("du %d, p1 %d, p2 %d, newtop %f, newbott %f, nt %f, nb %f, ph %f", 01037 // (Bitu)definedUnit,PARAM16(2),PARAM16(4),topMargin,bottomMargin, 01038 // newTop,newBottom,pageHeight); 01039 } 01040 break; 01041 case 0x276: // Set relative vertical print position (ESC (v) 01042 { 01043 Real64 unitSize = definedUnit; 01044 if (unitSize < 0) 01045 unitSize = (Real64)360.0; 01046 Real64 newPos = curY + ((Real64)((Bit16s)PARAM16(2)) * unitSize); 01047 if (newPos > topMargin) 01048 { 01049 if (newPos > bottomMargin) 01050 newPage(true, false); 01051 else 01052 curY = newPos; 01053 } 01054 } 01055 break; 01056 default: 01057 if (ESCCmd < 0x100) 01058 //LOG(LOG_MISC,LOG_WARN) 01059 LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); 01060 else 01061 //LOG(LOG_MISC,LOG_WARN) 01062 LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); 01063 } 01064 01065 ESCCmd = 0; 01066 return true; 01067 } 01068 01069 switch (ch) 01070 { 01071 case 0x00: // NUL is ignored by the printer 01072 return true; 01073 case 0x07: // Beeper (BEL) 01074 // BEEEP! 01075 return true; 01076 case 0x08: // Backspace (BS) 01077 { 01078 Real64 newX = curX - (1/(Real64)actcpi); 01079 if (hmi > 0) 01080 newX = curX - hmi; 01081 if (newX >= leftMargin) 01082 curX = newX; 01083 } 01084 return true; 01085 case 0x09: // Tab horizontally (HT) 01086 { 01087 // Find tab right to current pos 01088 Real64 moveTo = -1; 01089 for (Bit8u i = 0; i < numHorizTabs; i++) 01090 if (horiztabs[i] > curX) 01091 moveTo = horiztabs[i]; 01092 // Nothing found => Ignore 01093 if (moveTo > 0 && moveTo < rightMargin) 01094 curX = moveTo; 01095 } 01096 return true; 01097 case 0x0b: // Tab vertically (VT) 01098 if (numVertTabs == 0) // All tabs cancelled => Act like CR 01099 curX = leftMargin; 01100 else if (numVertTabs == 255) // No tabs set since reset => Act like LF 01101 { 01102 curX = leftMargin; 01103 curY += lineSpacing; 01104 if (curY > bottomMargin) 01105 newPage(true, false); 01106 } 01107 else 01108 { 01109 // Find tab below current pos 01110 Real64 moveTo = -1; 01111 for (Bit8u i = 0; i < numVertTabs; i++) 01112 if (verttabs[i] > curY) 01113 moveTo = verttabs[i]; 01114 01115 // Nothing found => Act like FF 01116 if (moveTo > bottomMargin || moveTo < 0) 01117 newPage(true, false); 01118 else 01119 curY = moveTo; 01120 } 01121 if (style & STYLE_DOUBLEWIDTHONELINE) 01122 { 01123 style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; 01124 updateFont(); 01125 } 01126 return true; 01127 case 0x0c: // Form feed (FF) 01128 if (style & STYLE_DOUBLEWIDTHONELINE) 01129 { 01130 style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; 01131 updateFont(); 01132 } 01133 newPage(true, true); 01134 return true; 01135 case 0x0d: // Carriage Return (CR) 01136 curX = leftMargin; 01137 if (!autoFeed) 01138 return true; 01139 case 0x0a: // Line feed 01140 if (style & STYLE_DOUBLEWIDTHONELINE) 01141 { 01142 style &= 0xFFFF - STYLE_DOUBLEWIDTHONELINE; 01143 updateFont(); 01144 } 01145 curX = leftMargin; 01146 curY += lineSpacing; 01147 if (curY > bottomMargin) 01148 newPage(true, false); 01149 return true; 01150 case 0x0e: //Select Real64-width printing (one line) (SO) 01151 if (!multipoint) 01152 { 01153 hmi = -1; 01154 style |= STYLE_DOUBLEWIDTHONELINE; 01155 updateFont(); 01156 } 01157 return true; 01158 case 0x0f: // Select condensed printing (SI) 01159 if (!multipoint && (cpi != 15.0)) 01160 { 01161 hmi = -1; 01162 style |= STYLE_CONDENSED; 01163 updateFont(); 01164 } 01165 return true; 01166 case 0x11: // Select printer (DC1) 01167 // Ignore 01168 return true; 01169 case 0x12: // Cancel condensed printing (DC2) 01170 hmi = -1; 01171 style &= ~STYLE_CONDENSED; 01172 updateFont(); 01173 return true; 01174 case 0x13: // Deselect printer (DC3) 01175 // Ignore 01176 return true; 01177 case 0x14: // Cancel double-width printing (one line) (DC4) 01178 hmi = -1; 01179 style &= ~STYLE_DOUBLEWIDTHONELINE; 01180 updateFont(); 01181 return true; 01182 case 0x18: // Cancel line (CAN) 01183 return true; 01184 case 0x1b: // ESC 01185 ESCSeen = true; 01186 return true; 01187 case 0x1c: // FS (IBM commands) 01188 FSSeen = true; 01189 return true; 01190 default: 01191 return false; 01192 } 01193 01194 return false; 01195 } 01196 01197 static void PRINTER_EventHandler(Bitu param); 01198 01199 void CPrinter::newPage(bool save, bool resetx) 01200 { 01201 PIC_RemoveEvents(PRINTER_EventHandler); 01202 if (printer_timout) 01203 timeout_dirty=false; 01204 if (save) 01205 outputPage(); 01206 if (resetx) 01207 curX = leftMargin; 01208 curY = topMargin; 01209 01210 SDL_Rect rect; 01211 rect.x = 0; 01212 rect.y = 0; 01213 rect.w = page->w; 01214 rect.h = page->h; 01215 SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); 01216 01217 /*for(int i = 0; i < 256; i++) 01218 { 01219 *((Bit8u*)page->pixels+i)=i; 01220 }*/ 01221 } 01222 01223 void CPrinter::printChar(Bit8u ch) 01224 { 01225 charRead = true; 01226 if (page == NULL) return; 01227 01228 // Don't think that DOS programs uses this but well: Apply MSB if desired 01229 if (msb != 255) { 01230 if (msb == 0) ch &= 0x7F; 01231 if (msb == 1) ch |= 0x80; 01232 } 01233 01234 // Are we currently printing a bit graphic? 01235 if (bitGraph.remBytes > 0) { 01236 printBitGraph(ch); 01237 return; 01238 } 01239 01240 // Print everything? 01241 if (numPrintAsChar > 0) numPrintAsChar--; 01242 else if (processCommandChar(ch)) return; 01243 01244 // Do not print if no font is available 01245 if (!curFont) return; 01246 01247 if(ch == 0x1) ch = 0x20; 01248 01249 // Find the glyph for the char to render 01250 FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); 01251 01252 // Load the glyph 01253 FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); 01254 01255 // Render a high-quality bitmap 01256 FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); 01257 01258 Bit16u penX = (Bit16u)(PIXX + curFont->glyph->bitmap_left); 01259 Bit16u penY = (Bit16u)(PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender / 64); 01260 01261 if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; 01262 01263 // Copy bitmap into page 01264 SDL_LockSurface(page); 01265 01266 blitGlyph(curFont->glyph->bitmap, penX, penY, false); 01267 blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); 01268 01269 // Doublestrike => Print the glyph a second time one pixel below 01270 if (style & STYLE_DOUBLESTRIKE) 01271 { 01272 blitGlyph(curFont->glyph->bitmap, penX, penY+1, true); 01273 blitGlyph(curFont->glyph->bitmap, penX+1, penY+1, true); 01274 } 01275 01276 // Bold => Print the glyph a second time one pixel to the right 01277 // or be a bit more bold... 01278 if (style & STYLE_BOLD) 01279 { 01280 blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); 01281 blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); 01282 blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); 01283 } 01284 SDL_UnlockSurface(page); 01285 01286 // For line printing 01287 Bit16u lineStart = (Bit16u)PIXX; 01288 01289 // advance the cursor to the right 01290 Real64 x_advance; 01291 if (style & STYLE_PROP) 01292 x_advance = (Real64)((Real64)(curFont->glyph->advance.x) / (Real64)(dpi * 64)); 01293 else 01294 { 01295 if (hmi < 0) 01296 x_advance = 1 / (Real64)actcpi; 01297 else 01298 x_advance = hmi; 01299 } 01300 x_advance += extraIntraSpace; 01301 curX += x_advance; 01302 01303 // Draw lines if desired 01304 if ((score != SCORE_NONE) && (style & (STYLE_UNDERLINE|STYLE_STRIKETHROUGH|STYLE_OVERSCORE))) 01305 { 01306 // Find out where to put the line 01307 Bit16u lineY = (Bit16u)PIXY; 01308 double height = (curFont->size->metrics.height >> 6); // TODO height is fixed point madness... 01309 01310 if (style & STYLE_UNDERLINE) 01311 lineY = (Bit16u)PIXY + (Bit16u)(height * 0.9); 01312 else if (style & STYLE_STRIKETHROUGH) 01313 lineY = (Bit16u)PIXY + (Bit16u)(height * 0.45); 01314 else if (style & STYLE_OVERSCORE) 01315 lineY = (Bit16u)PIXY - (Bit16u)(((score == SCORE_DOUBLE) || (score == SCORE_DOUBLEBROKEN)) ? 5 : 0); 01316 01317 drawLine(lineStart, PIXX, lineY, score == SCORE_SINGLEBROKEN || score == SCORE_DOUBLEBROKEN); 01318 01319 // draw second line if needed 01320 if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) 01321 drawLine(lineStart, PIXX, lineY + 5, score == SCORE_SINGLEBROKEN || score == SCORE_DOUBLEBROKEN); 01322 } 01323 // If the next character would go beyond the right margin, line-wrap. 01324 if((curX + x_advance) > rightMargin) 01325 { 01326 curX = leftMargin; 01327 curY += lineSpacing; 01328 if (curY > bottomMargin) newPage(true, false); 01329 } 01330 } 01331 01332 void CPrinter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { 01333 for (Bitu y = 0; y < bitmap.rows; y++) 01334 { 01335 for (Bitu x = 0; x < bitmap.width; x++) 01336 { 01337 // Read pixel from glyph bitmap 01338 Bit8u source = *(bitmap.buffer + x + y * bitmap.pitch); 01339 01340 // Ignore background and don't go over the border 01341 if (source > 0 && (destx + x < (Bitu)page->w) && (desty + y < (Bitu)page->h)) 01342 { 01343 Bit8u* target = (Bit8u*)page->pixels + (x + destx) + (y + desty) * page->pitch; 01344 source>>=3; 01345 01346 if (add) 01347 { 01348 if (((*target) & 0x1f) + source > 31) 01349 *target |= (color | 0x1f); 01350 else 01351 { 01352 *target += source; 01353 *target |= color; 01354 } 01355 } 01356 else 01357 *target = source|color; 01358 } 01359 } 01360 } 01361 } 01362 01363 void CPrinter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) 01364 { 01365 SDL_LockSurface(page); 01366 01367 Bitu breakmod = dpi / 15; 01368 Bitu gapstart = (breakmod * 4) / 5; 01369 01370 // Draw anti-aliased line 01371 for (Bitu x = fromx; x <= tox; x++) 01372 { 01373 // Skip parts if broken line or going over the border 01374 if ((!broken || (x % breakmod <= gapstart)) && (x < (Bitu)page->w)) 01375 { 01376 if (y > 0 && (y - 1) < (Bitu)page->h) 01377 *((Bit8u*)page->pixels + x + (y - 1) * (Bitu)page->pitch) = 240; 01378 if (y < (Bitu)page->h) 01379 *((Bit8u*)page->pixels + x + y * (Bitu)page->pitch) = !broken ? 255 : 240; 01380 if (y + 1 < (Bitu)page->h) 01381 *((Bit8u*)page->pixels + x + (y + 1) * (Bitu)page->pitch) = 240; 01382 } 01383 } 01384 SDL_UnlockSurface(page); 01385 } 01386 01387 void CPrinter::setAutofeed(bool feed) 01388 { 01389 autoFeed = feed; 01390 } 01391 01392 bool CPrinter::getAutofeed() 01393 { 01394 return autoFeed; 01395 } 01396 01397 bool CPrinter::isBusy() 01398 { 01399 // We're never busy 01400 return false; 01401 } 01402 01403 bool CPrinter::ack() 01404 { 01405 // Acknowledge last char read 01406 if(charRead) 01407 { 01408 charRead=false; 01409 return true; 01410 } 01411 return false; 01412 } 01413 01414 void CPrinter::setupBitImage(Bit8u dens, Bit16u numCols) 01415 { 01416 switch (dens) 01417 { 01418 case 0: 01419 bitGraph.horizDens = 60; 01420 bitGraph.vertDens = 60; 01421 bitGraph.adjacent = true; 01422 bitGraph.bytesColumn = 1; 01423 break; 01424 case 1: 01425 bitGraph.horizDens = 120; 01426 bitGraph.vertDens = 60; 01427 bitGraph.adjacent = true; 01428 bitGraph.bytesColumn = 1; 01429 break; 01430 case 2: 01431 bitGraph.horizDens = 120; 01432 bitGraph.vertDens = 60; 01433 bitGraph.adjacent = false; 01434 bitGraph.bytesColumn = 1; 01435 break; 01436 case 3: 01437 bitGraph.horizDens = 60; 01438 bitGraph.vertDens = 240; 01439 bitGraph.adjacent = false; 01440 bitGraph.bytesColumn = 1; 01441 break; 01442 case 4: 01443 bitGraph.horizDens = 80; 01444 bitGraph.vertDens = 60; 01445 bitGraph.adjacent = true; 01446 bitGraph.bytesColumn = 1; 01447 break; 01448 case 6: 01449 bitGraph.horizDens = 90; 01450 bitGraph.vertDens = 60; 01451 bitGraph.adjacent = true; 01452 bitGraph.bytesColumn = 1; 01453 break; 01454 case 32: 01455 bitGraph.horizDens = 60; 01456 bitGraph.vertDens = 180; 01457 bitGraph.adjacent = true; 01458 bitGraph.bytesColumn = 3; 01459 break; 01460 case 33: 01461 bitGraph.horizDens = 120; 01462 bitGraph.vertDens = 180; 01463 bitGraph.adjacent = true; 01464 bitGraph.bytesColumn = 3; 01465 break; 01466 case 38: 01467 bitGraph.horizDens = 90; 01468 bitGraph.vertDens = 180; 01469 bitGraph.adjacent = true; 01470 bitGraph.bytesColumn = 3; 01471 break; 01472 case 39: 01473 bitGraph.horizDens = 180; 01474 bitGraph.vertDens = 180; 01475 bitGraph.adjacent = true; 01476 bitGraph.bytesColumn = 3; 01477 break; 01478 case 40: 01479 bitGraph.horizDens = 360; 01480 bitGraph.vertDens = 180; 01481 bitGraph.adjacent = false; 01482 bitGraph.bytesColumn = 3; 01483 break; 01484 case 71: 01485 bitGraph.horizDens = 180; 01486 bitGraph.vertDens = 360; 01487 bitGraph.adjacent = true; 01488 bitGraph.bytesColumn = 6; 01489 break; 01490 case 72: 01491 bitGraph.horizDens = 360; 01492 bitGraph.vertDens = 360; 01493 bitGraph.adjacent = false; 01494 bitGraph.bytesColumn = 6; 01495 break; 01496 case 73: 01497 bitGraph.horizDens = 360; 01498 bitGraph.vertDens = 360; 01499 bitGraph.adjacent = true; 01500 bitGraph.bytesColumn = 6; 01501 break; 01502 default: 01503 LOG(LOG_MISC,LOG_ERROR)("PRINTER: Unsupported bit image density %i", dens); 01504 } 01505 01506 bitGraph.remBytes = numCols * bitGraph.bytesColumn; 01507 bitGraph.readBytesColumn = 0; 01508 } 01509 01510 void CPrinter::printBitGraph(Bit8u ch) 01511 { 01512 bitGraph.column[bitGraph.readBytesColumn++] = ch; 01513 bitGraph.remBytes--; 01514 01515 // Only print after reading a full column 01516 if (bitGraph.readBytesColumn < bitGraph.bytesColumn) 01517 return; 01518 01519 Real64 oldY = curY; 01520 01521 SDL_LockSurface(page); 01522 01523 // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" 01524 Bitu pixsizeX = 1; 01525 Bitu pixsizeY = 1; 01526 if(bitGraph.adjacent) 01527 { 01528 pixsizeX = dpi / bitGraph.horizDens > 0 ? dpi / bitGraph.horizDens : 1; 01529 pixsizeY = dpi / bitGraph.vertDens > 0 ? dpi / bitGraph.vertDens : 1; 01530 } 01531 // TODO figure this out for 360dpi mode in windows 01532 01533 // Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; 01534 // Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; 01535 01536 for (Bitu i = 0; i < bitGraph.bytesColumn; i++) 01537 { 01538 // for each byte 01539 for (Bitu j = 128; j != 0; j >>= 1) 01540 { 01541 // for each bit 01542 if (bitGraph.column[i] & j) 01543 { 01544 for (Bitu xx=0; xx<pixsizeX; xx++) 01545 for (Bitu yy=0; yy<pixsizeY; yy++) 01546 { 01547 if (((PIXX + xx) < (Bitu)page->w) && ((PIXY + yy) < (Bitu)page->h)) 01548 *((Bit8u*)page->pixels + (PIXX + xx) + (PIXY + yy)*page->pitch) |= (color | 0x1F); 01549 } 01550 } // else white pixel 01551 curY += (Real64)1 / (Real64)bitGraph.vertDens; // TODO line wrap? 01552 } 01553 } 01554 01555 SDL_UnlockSurface(page); 01556 01557 curY = oldY; 01558 01559 bitGraph.readBytesColumn = 0; 01560 01561 // Advance to the left 01562 curX += (Real64)1 / (Real64)bitGraph.horizDens; 01563 } 01564 01565 void CPrinter::formFeed() 01566 { 01567 // Don't output blank pages 01568 newPage(!isBlank(), true); 01569 finishMultipage(); 01570 } 01571 01572 static void findNextName(const char* front, const char* ext, char* fname) 01573 { 01574 int i = 1; 01575 Bitu slen = (Bitu)strlen(document_path); 01576 if(slen > (200 - 15)) 01577 { 01578 fname[0] = 0; 01579 return; 01580 } 01581 01582 FILE *test = NULL; 01583 do 01584 { 01585 strcpy(fname, document_path); 01586 #ifdef WIN32 01587 const char* const pathstring = "\\%s%d%s"; 01588 #else 01589 const char* const pathstring = "/%s%d%s"; 01590 #endif 01591 sprintf(fname + strlen(fname), pathstring, front, i++, ext); 01592 test = fopen(fname, "rb"); 01593 if (test != NULL) fclose(test); 01594 } 01595 while (test != NULL); 01596 } 01597 01598 void CPrinter::outputPage() 01599 { 01600 char fname[200]; 01601 01602 if (strcasecmp(output, "printer") == 0) 01603 { 01604 #if defined (WIN32) 01605 // You'll need the mouse for the print dialog 01606 if(mouselocked) 01607 GFX_CaptureMouse(); 01608 01609 Bit16u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); 01610 Bit16u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); 01611 01612 Real64 scaleW, scaleH; 01613 01614 if (page->w > physW) 01615 scaleW = (Real64)page->w / (Real64)physW; 01616 else 01617 scaleW = (Real64)physW / (Real64)page->w; 01618 01619 if (page->h > physH) 01620 scaleH = (Real64)page->h / (Real64)physH; 01621 else 01622 scaleH = (Real64)physH / (Real64)page->h; 01623 01624 HDC memHDC = CreateCompatibleDC(printerDC); 01625 HBITMAP bitmap = CreateCompatibleBitmap(memHDC, page->w, page->h); 01626 SelectObject(memHDC, bitmap); 01627 01628 // Start new printer job? 01629 if (outputHandle == NULL) 01630 { 01631 DOCINFO docinfo; 01632 memset(&docinfo, 0, sizeof(docinfo)); 01633 docinfo.cbSize = sizeof(docinfo); 01634 docinfo.lpszDocName = "DOSBOX Printer"; 01635 docinfo.lpszOutput = NULL; 01636 docinfo.lpszDatatype = NULL; 01637 docinfo.fwType = 0; 01638 01639 StartDoc(printerDC, &docinfo); 01640 multiPageCounter = 1; 01641 } 01642 01643 if (StartPage(printerDC) < 0) 01644 { 01645 LOG_MSG("PRINTER: Cannot start page."); 01646 DeleteObject(bitmap); 01647 DeleteDC(memHDC); 01648 return; 01649 } 01650 SDL_LockSurface(page); 01651 01652 SDL_Palette* sdlpal = page->format->palette; 01653 01654 for (Bit16u y = 0; y < page->h; y++) 01655 { 01656 for (Bit16u x = 0; x < page->w; x++) 01657 { 01658 Bit8u pixel = *((Bit8u*)page->pixels + x + (y*page->pitch)); 01659 Bit32u color = 0; 01660 color |= sdlpal->colors[pixel].r; 01661 color |= ((Bit32u)sdlpal->colors[pixel].g) << 8; 01662 color |= ((Bit32u)sdlpal->colors[pixel].b) << 16; 01663 SetPixel(memHDC, x, y, color); 01664 } 01665 } 01666 01667 SDL_UnlockSurface(page); 01668 01669 StretchBlt(printerDC, 0, 0, physW, physH, memHDC, 0, 0, page->w, page->h, SRCCOPY); 01670 01671 EndPage(printerDC); 01672 01673 if (multipageOutput) 01674 { 01675 multiPageCounter++; 01676 outputHandle = printerDC; 01677 } 01678 else 01679 { 01680 EndDoc(printerDC); 01681 outputHandle = NULL; 01682 } 01683 DeleteObject(bitmap); 01684 DeleteDC(memHDC); 01685 #else 01686 LOG_MSG("PRINTER: Direct printing not supported under this OS"); 01687 #endif 01688 } 01689 #ifdef C_LIBPNG 01690 else if (strcasecmp(output, "png") == 0) 01691 { 01692 // Find a page that does not exists 01693 findNextName("page", ".png", &fname[0]); 01694 01695 png_structp png_ptr; 01696 png_infop info_ptr; 01697 png_bytep* row_pointers; 01698 png_color palette[256]; 01699 Bitu i; 01700 01701 /* Open the actual file */ 01702 FILE* fp = fopen(fname,"wb"); 01703 if (!fp) 01704 { 01705 LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); 01706 return; 01707 } 01708 01709 /* First try to alloacte the png structures */ 01710 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 01711 if (!png_ptr) return; 01712 info_ptr = png_create_info_struct(png_ptr); 01713 if (!info_ptr) 01714 { 01715 png_destroy_write_struct(&png_ptr, (png_infopp)NULL); 01716 return; 01717 } 01718 01719 /* Finalize the initing of png library */ 01720 png_init_io(png_ptr, fp); 01721 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); 01722 01723 /* set other zlib parameters */ 01724 png_set_compression_mem_level(png_ptr, 8); 01725 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); 01726 png_set_compression_window_bits(png_ptr, 15); 01727 png_set_compression_method(png_ptr, 8); 01728 png_set_compression_buffer_size(png_ptr, 8192); 01729 01730 png_set_IHDR(png_ptr, info_ptr, page->w, page->h, 01731 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, 01732 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 01733 for (i = 0; i < 256; i++) 01734 { 01735 palette[i].red = page->format->palette->colors[i].r; 01736 palette[i].green = page->format->palette->colors[i].g; 01737 palette[i].blue = page->format->palette->colors[i].b; 01738 } 01739 png_set_PLTE(png_ptr, info_ptr, palette,256); 01740 01741 SDL_LockSurface(page); 01742 01743 // Allocate an array of scanline pointers 01744 row_pointers = (png_bytep*)malloc(page->h * sizeof(png_bytep)); 01745 for (i = 0; i < (Bitu)page->h; i++) 01746 row_pointers[i] = ((Bit8u*)page->pixels + (i * page->pitch)); 01747 01748 // tell the png library what to encode. 01749 png_set_rows(png_ptr, info_ptr, row_pointers); 01750 01751 // Write image to file 01752 png_write_png(png_ptr, info_ptr, 0, NULL); 01753 01754 SDL_UnlockSurface(page); 01755 01756 /*close file*/ 01757 fclose(fp); 01758 01759 /*Destroy PNG structs*/ 01760 png_destroy_write_struct(&png_ptr, &info_ptr); 01761 01762 /*clean up dynamically allocated RAM.*/ 01763 free(row_pointers); 01764 } 01765 #endif 01766 else if (strcasecmp(output, "ps") == 0) 01767 { 01768 FILE* psfile = NULL; 01769 01770 // Continue postscript file? 01771 if (outputHandle != NULL) 01772 psfile = (FILE*)outputHandle; 01773 01774 // Create new file? 01775 if (psfile == NULL) 01776 { 01777 if (!multipageOutput) 01778 findNextName("page", ".ps", &fname[0]); 01779 else 01780 findNextName("doc", ".ps", &fname[0]); 01781 01782 psfile = fopen(fname, "wb"); 01783 if (!psfile) 01784 { 01785 LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); 01786 return; 01787 } 01788 01789 // Print header 01790 fprintf(psfile, "%%!PS-Adobe-3.0\n"); 01791 fprintf(psfile, "%%%%Pages: (atend)\n"); 01792 fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth * 72), (Bit16u)(defaultPageHeight * 72)); 01793 fprintf(psfile, "%%%%Creator: DOSBOX Virtual Printer\n"); 01794 fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); 01795 fprintf(psfile, "%%%%LanguageLevel: 2\n"); 01796 fprintf(psfile, "%%%%EndComments\n"); 01797 multiPageCounter = 1; 01798 } 01799 01800 fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); 01801 fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth * 72), (Bit16u)(defaultPageHeight * 72)); 01802 fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); 01803 fprintf(psfile, "currentfile\n"); 01804 fprintf(psfile, "/ASCII85Decode filter\n"); 01805 fprintf(psfile, "/RunLengthDecode filter\n"); 01806 fprintf(psfile, "image\n"); 01807 01808 SDL_LockSurface(page); 01809 01810 Bit32u pix = 0; 01811 Bit32u numpix = page->h * page->w; 01812 ASCII85BufferPos = ASCII85CurCol = 0; 01813 01814 while (pix < numpix) 01815 { 01816 // Compress data using RLE 01817 if ((pix < numpix - 2) && (getPixel(pix) == getPixel(pix + 1)) && (getPixel(pix) == getPixel(pix + 2))) 01818 { 01819 // Found three or more pixels with the same color 01820 Bit8u sameCount = 3; 01821 Bit8u col = getPixel(pix); 01822 while (sameCount < 128 && sameCount + pix < numpix && col == getPixel(pix + sameCount)) 01823 sameCount++; 01824 01825 fprintASCII85(psfile, 257 - sameCount); 01826 fprintASCII85(psfile, 255 - col); 01827 01828 // Skip ahead 01829 pix += sameCount; 01830 } 01831 else 01832 { 01833 // Find end of heterogenous area 01834 Bit8u diffCount = 1; 01835 while ( 01836 diffCount < 128 && diffCount + pix < numpix && 01837 ( 01838 (diffCount + pix < numpix - 2) || (getPixel(pix + diffCount) != getPixel(pix + diffCount+1)) || (getPixel(pix + diffCount) != getPixel(pix + diffCount+2)) 01839 ) 01840 ) diffCount++; 01841 01842 fprintASCII85(psfile, diffCount-1); 01843 for (Bit8u i = 0; i < diffCount; i++) 01844 fprintASCII85(psfile, 255 - getPixel(pix++)); 01845 } 01846 } 01847 01848 // Write EOD for RLE and ASCII85 01849 fprintASCII85(psfile, 128); 01850 fprintASCII85(psfile, 256); 01851 01852 SDL_UnlockSurface(page); 01853 01854 fprintf(psfile, "showpage\n"); 01855 01856 if (multipageOutput) 01857 { 01858 multiPageCounter++; 01859 outputHandle = psfile; 01860 } 01861 else 01862 { 01863 fprintf(psfile, "%%%%Pages: 1\n"); 01864 fprintf(psfile, "%%%%EOF\n"); 01865 fclose(psfile); 01866 outputHandle = NULL; 01867 } 01868 } 01869 else 01870 { 01871 // Find a page that does not exists 01872 findNextName("page", ".bmp", &fname[0]); 01873 SDL_SaveBMP(page, fname); 01874 } 01875 } 01876 01877 void CPrinter::fprintASCII85(FILE* f, Bit16u b) 01878 { 01879 if (b != 256) 01880 { 01881 if (b < 256) 01882 ASCII85Buffer[ASCII85BufferPos++] = (Bit8u)b; 01883 01884 if (ASCII85BufferPos == 4 || b == 257) 01885 { 01886 Bit32u num = (Bit32u)ASCII85Buffer[0] << 24 | (Bit32u)ASCII85Buffer[1] << 16 | (Bit32u)ASCII85Buffer[2] << 8 | (Bit32u)ASCII85Buffer[3]; 01887 01888 // Deal with special case 01889 if (num == 0 && b != 257) 01890 { 01891 fprintf(f, "z"); 01892 if (++ASCII85CurCol >= 79) 01893 { 01894 ASCII85CurCol = 0; 01895 fprintf(f, "\n"); 01896 } 01897 } 01898 else 01899 { 01900 char buffer[5]; 01901 for (Bit8s i = 4; i >= 0; i--) 01902 { 01903 buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); 01904 buffer[i] += 33; 01905 num /= (Bit32u)85; 01906 } 01907 01908 // Make sure a line never starts with a % (which may be mistaken as start of a comment) 01909 if (ASCII85CurCol == 0 && buffer[0] == '%') 01910 fprintf(f, " "); 01911 01912 for (int i = 0; i < ((b != 257) ? 5 : ASCII85BufferPos + 1); i++) 01913 { 01914 fprintf(f, "%c", buffer[i]); 01915 if (++ASCII85CurCol >= 79) 01916 { 01917 ASCII85CurCol = 0; 01918 fprintf(f, "\n"); 01919 } 01920 } 01921 } 01922 01923 ASCII85BufferPos = 0; 01924 } 01925 01926 } 01927 else // Close string 01928 { 01929 // Partial tupel if there are still bytes in the buffer 01930 if (ASCII85BufferPos > 0) 01931 { 01932 for (Bit8u i = ASCII85BufferPos; i < 4; i++) 01933 ASCII85Buffer[i] = 0; 01934 01935 fprintASCII85(f, 257); 01936 } 01937 01938 fprintf(f, "~"); 01939 fprintf(f, ">\n"); 01940 } 01941 } 01942 01943 void CPrinter::finishMultipage() 01944 { 01945 if (outputHandle != NULL) 01946 { 01947 if (strcasecmp(output, "ps") == 0) 01948 { 01949 FILE* psfile = (FILE*)outputHandle; 01950 fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); 01951 fprintf(psfile, "%%%%EOF\n"); 01952 fclose(psfile); 01953 } 01954 else if (strcasecmp(output, "printer") == 0) 01955 { 01956 #if defined (WIN32) 01957 EndDoc(printerDC); 01958 #endif 01959 } 01960 outputHandle = NULL; 01961 } 01962 } 01963 01964 bool CPrinter::isBlank() 01965 { 01966 bool blank = true; 01967 01968 SDL_LockSurface(page); 01969 01970 for (Bit16u y = 0; y < page->h; y++) 01971 for (Bit16u x = 0; x < page->w; x++) 01972 if (*((Bit8u*)page->pixels + x + (y * page->pitch)) != 0) 01973 blank = false; 01974 01975 SDL_UnlockSurface(page); 01976 return blank; 01977 } 01978 01979 Bit8u CPrinter::getPixel(Bit32u num) 01980 { 01981 // Respect the pitch 01982 return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); 01983 } 01984 01985 static Bit8u dataregister; // contents of the parallel port data register 01986 01987 Bitu PRINTER_readdata(Bitu port,Bitu iolen) 01988 { 01989 (void)port; 01990 (void)iolen; 01991 return dataregister; 01992 } 01993 01994 void PRINTER_writedata(Bitu port,Bitu val,Bitu iolen) 01995 { 01996 (void)port; 01997 (void)iolen; 01998 dataregister = (Bit8u)val; 01999 } 02000 Bit8u controlreg = 0x04; 02001 02002 Bitu PRINTER_readstatus(Bitu port,Bitu iolen) 02003 { 02004 (void)port; 02005 (void)iolen; 02006 //LOG_MSG("PRINTER_readstatus CS:IP %8x:%8x",SegValue(cs),reg_eip); 02007 // Don't create a CPrinter unless the program really wants to print 02008 // Return standard: No error, printer online, no ack and not busy 02009 if (!defaultPrinter) 02010 return 0xdf; 02011 02012 // Printer is always online and never reports an error 02013 Bit8u status = 0x1f;// 0x18; 02014 02015 // if (controlreg&0x08==0) 02016 // status |= 0x10; 02017 02018 if (!defaultPrinter->isBusy()) 02019 status |= 0x80; 02020 02021 if (!defaultPrinter->ack()) 02022 status |= 0x40; 02023 02024 return status; 02025 } 02026 02027 static void FormFeed(bool pressed) 02028 { 02029 if (pressed) 02030 if (defaultPrinter) 02031 { 02032 PIC_RemoveEvents(PRINTER_EventHandler); 02033 if (printer_timout) timeout_dirty = false; 02034 02035 defaultPrinter->formFeed(); 02036 } 02037 } 02038 02039 02040 static void PRINTER_EventHandler(Bitu param) 02041 { 02042 (void)param; 02043 //LOG_MSG("printerevent"); 02044 if (timeout_dirty) 02045 { 02046 // add another 02047 PIC_AddEvent(PRINTER_EventHandler, (float)printer_timout, 0); 02048 //LOG_MSG("timeout renew"); 02049 timeout_dirty = false; 02050 } 02051 else 02052 { 02053 timeout_dirty = false; 02054 FormFeed(true); 02055 } 02056 } 02057 02058 void PRINTER_writecontrol(Bitu port,Bitu val,Bitu iolen) 02059 { 02060 (void)port; 02061 (void)iolen; 02062 //LOG_MSG("PRINTER_writecontrol CS:IP %8x:%8x",SegValue(cs),reg_eip); 02063 // init printer if bit 4 is switched on 02064 if ((val & 0x04) && defaultPrinter && (!(controlreg & 0x04))) 02065 defaultPrinter->resetPrinterHard(); 02066 02067 // data is strobed to the parallel printer on the falling edge of strobe bit 02068 if(!(val & 0x1) && (controlreg & 0x1)) { 02069 if (!defaultPrinter) 02070 defaultPrinter = new CPrinter(confdpi, confwidth, confheight, confoutputDevice, confmultipageOutput); 02071 defaultPrinter->printChar(dataregister); 02072 if (!timeout_dirty) 02073 { 02074 PIC_AddEvent(PRINTER_EventHandler, (float)printer_timout, 0); 02075 timeout_dirty = true; 02076 } 02077 } 02078 02079 controlreg = (Bit8u)val; 02080 if (defaultPrinter) 02081 defaultPrinter->setAutofeed((val & 0x02) > 0); 02082 } 02083 02084 Bitu PRINTER_readcontrol(Bitu port,Bitu iolen) 02085 { 02086 (void)port; 02087 (void)iolen; 02088 //LOG_MSG("PRINTER_readcontrol CS:IP %8x:%8x",SegValue(cs),reg_eip); 02089 // Don't create a CPrinter unless the program really wants to print 02090 if (!defaultPrinter) 02091 return 0xe0 | controlreg; //0xe8; 02092 02093 return 0xe0 | (defaultPrinter->getAutofeed() ? 0x02 : 0x00) | (controlreg & 0xfd); 02094 } 02095 02096 void PRINTER_Shutdown(Section* sec) 02097 { 02098 (void)sec;//UNUSED 02099 02100 if (defaultPrinter) 02101 { 02102 delete defaultPrinter; 02103 defaultPrinter = NULL; 02104 } 02105 } 02106 02107 bool inited = false; 02108 bool PRINTER_isInited() 02109 { 02110 return inited; 02111 } 02112 02113 void PRINTER_Init() 02114 { 02115 Section_prop * section = static_cast<Section_prop *>(control->GetSection("printer")); 02116 AddExitFunction(AddExitFunctionFuncPair(PRINTER_Shutdown), true); 02117 02118 // Set base address of LPT1 in the BIOS variable segment 02119 //real_writew(0x0040, 0x0008, LPTPORT); 02120 02121 if (!section->Get_bool("printer")) return; 02122 inited = true; 02123 document_path = section->Get_string("docpath"); 02124 //font_path = section->Get_string("fontpath"); 02125 confdpi = section->Get_int("dpi"); 02126 confwidth = section->Get_int("width"); 02127 confheight = section->Get_int("height"); 02128 printer_timout = section->Get_int("timeout"); 02129 if(!printer_timout) timeout_dirty = true; // this will lock up the timeout 02130 else timeout_dirty = false; 02131 strcpy(&confoutputDevice[0], section->Get_string("printoutput")); 02132 confmultipageOutput = section->Get_bool("multipage"); 02133 02134 //IO_RegisterWriteHandler(LPTPORT,PRINTER_writedata,IO_MB); 02135 //IO_RegisterReadHandler(LPTPORT,PRINTER_readdata,IO_MB); 02136 02137 //IO_RegisterReadHandler(LPTPORT+1,PRINTER_readstatus,IO_MB); 02138 //IO_RegisterWriteHandler(LPTPORT+2,PRINTER_writecontrol,IO_MB); 02139 //IO_RegisterReadHandler(LPTPORT+2,PRINTER_readcontrol,IO_MB); 02140 02141 MAPPER_AddHandler(FormFeed, MK_f2 , MMOD1, "ejectpage", "formfeed"); 02142 } 02143 02144 #endif