123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /* Printer.cpp
- *
- * Copyright (C) 1998-2011,2012,2013,2014,2015,2017 Paul Boersma
- *
- * This code 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 code is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this work. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <unistd.h> // close
- #include "melder.h"
- #if defined (_WIN32)
- #include <windows.h>
- #endif
- #include "Printer.h"
- #include "praat.h" // topShell
- #include "Ui.h"
- #include "site.h"
- #include "GraphicsP.h"
- #if cocoa
- #include "Picture.h"
- #endif
- /*
- * Everything must look the same on every printer, including on PDF,
- * so the margins must be constant with respect to the paper, not to the writable page.
- */
- /* exported */ struct Printer thePrinter = {
- kGraphicsPostscript_spots::DEFAULT, kGraphicsPostscript_paperSize::DEFAULT, kGraphicsPostscript_orientation::DEFAULT, false,
- true, kGraphicsPostscript_fontChoiceStrategy::DEFAULT,
- 600, 5100, 6600,
- 1.0
- };
- void Printer_prefs () {
- Preferences_addEnum (U"Printer.spots", & thePrinter. spots, kGraphicsPostscript_spots, kGraphicsPostscript_spots::DEFAULT);
- Preferences_addEnum (U"Printer.paperSize", & thePrinter. paperSize, kGraphicsPostscript_paperSize, kGraphicsPostscript_paperSize::DEFAULT);
- Preferences_addBool (U"Printer.allowDirectPostScript", & thePrinter. allowDirectPostScript, true);
- Preferences_addEnum (U"Printer.fontChoiceStrategy", & thePrinter. fontChoiceStrategy, kGraphicsPostscript_fontChoiceStrategy, kGraphicsPostscript_fontChoiceStrategy::DEFAULT);
- }
- #if cocoa
- static NSView *theMacView;
- #endif
- #ifdef _WIN32
- static PRINTDLG theWinPrint;
- static HDC theWinDC;
- #endif
- #if defined (_WIN32)
- int Printer_postScript_printf (void *stream, const char *format, ... ) {
- static union { char chars [3002]; short shorts [1501]; } theLine;
- int length;
- va_list args;
- va_start (args, format);
- (void) stream;
- vsprintf (theLine.chars + 2, format, args);
- length = strlen (theLine.chars + 2);
- theLine.shorts [0] = length;
- if (length > 0 && theLine.chars [length + 1] == '\n') {
- theLine.chars [length + 1] = '\r';
- theLine.chars [length + 2] = '\n';
- theLine.chars [length + 3] = '\0';
- length ++;
- }
- Escape (theWinDC, POSTSCRIPT_PASSTHROUGH, length + 2, theLine.chars, nullptr);
- va_end (args);
- return 1;
- }
- #endif
- #if defined (_WIN32)
- static void initPostScriptPage () {
- /*
- * Save the driver's state.
- */
- Printer_postScript_printf (nullptr, "/PraatPictureSaveObject save def\n");
- /*
- * The LaserWriter driver puts the coordinates upside down.
- * According to the PostScript Reference Manual,
- * "There are few situations in which a PostScript language program
- * should execute initgraphics explicitly."
- * This is one of them.
- BUG: it probably is *not* one of them. Just do something like
- currentmatrix [1 0 -1 0 0 0] mul setmatrix
- or whatever it is.
- */
- #if 1
- Printer_postScript_printf (nullptr, "initmatrix initclip\n");
- #else
- Printer_postScript_printf (nullptr, "8 8 scale initclip\n");
- #endif
- }
- static void exitPostScriptPage () {
- Printer_postScript_printf (nullptr, "PraatPictureSaveObject restore\n");
- }
- #endif
- #if cocoa
- #elif defined (_WIN32)
- static void initPrinter () {
- }
- #endif
- void Printer_nextPage () {
- #if cocoa
- [theMacView endPage];
- [theMacView beginPageInRect: [theMacView bounds] atPlacement: NSMakePoint (0, 0)];
- #elif defined (_WIN32)
- if (thePrinter. postScript) {
- exitPostScriptPage ();
- EndPage (theWinDC);
- StartPage (theWinDC);
- initPostScriptPage ();
- } else {
- if (EndPage (theWinDC) < 0) ; /* BUG: should give the opportunity of cancellation. */
- StartPage (theWinDC);
- /*
- * Since StartPage has reset the DC, restore some of our non-default settings.
- */
- SetBkMode (theWinDC, TRANSPARENT);
- SetTextAlign (theWinDC, TA_LEFT | TA_BASELINE | TA_NOUPDATECP);
- }
- #endif
- }
- int Printer_pageSetup () {
- #if cocoa
- NSPageLayout *cocoaPageSetupDialog = [NSPageLayout pageLayout];
- [cocoaPageSetupDialog runModal];
- #elif defined (_WIN32)
- #endif
- return 1;
- }
- #ifdef _WIN32
- static BOOL CALLBACK AbortFunc (HDC hdc, int nCode) {
- MSG msg;
- (void) hdc;
- (void) nCode;
- while (PeekMessage (& msg, 0, 0, 0, PM_REMOVE)) {
- TranslateMessage (& msg);
- DispatchMessage (& msg);
- }
- return true;
- }
- HDC Printer_getDC () {
- if (! theWinPrint. hDevMode) {
- memset (& theWinPrint, 0, sizeof (PRINTDLG));
- theWinPrint. lStructSize = sizeof (PRINTDLG);
- theWinPrint. Flags = PD_RETURNDEFAULT | PD_RETURNDC;
- PrintDlg (& theWinPrint);
- }
- return theWinPrint. hDC;
- }
- #endif
- #if cocoa
- static void (*theDraw) (void *boss, Graphics g);
- static void *theBoss;
- @interface GuiCocoaPrintingArea : NSView @end
- @implementation GuiCocoaPrintingArea {
- //GuiButton d_userData;
- }
- - (void) drawRect: (NSRect) dirtyRect {
- trace (U"printing ", dirtyRect. origin. x, U" ", dirtyRect. origin. y, U" ", dirtyRect. size. width, U" ", dirtyRect. size. height);
- int currentPage = [[NSPrintOperation currentOperation] currentPage];
- {// scope
- autoGraphics graphics = Graphics_create_screenPrinter (nullptr, self);
- theDraw (theBoss, graphics.get());
- }
- }
- - (BOOL) isFlipped {
- return YES;
- }
- - (NSPoint) locationOfPrintRect: (NSRect) aRect {
- (void) aRect;
- return NSMakePoint (0.0, 0.0); // the origin of the rect's coordinate system is always the top left corner of the physical page
- }
- - (BOOL) knowsPageRange: (NSRangePointer) range {
- range -> length = 1;
- return YES;
- }
- - (NSRect) rectForPage: (NSInteger) pageNumber {
- (void) pageNumber; // every page has the same rectangle
- return [self bounds];
- }
- - (void) printOperationDidRun: (NSPrintOperation *) printOperation success: (BOOL) success contextInfo: (void *) contextInfo {
- }
- @end
- #endif
- int Printer_print (void (*draw) (void *boss, Graphics g), void *boss) {
- try {
- #if defined (UNIX)
- structMelderFile tempFile { };
- char tempPath_utf8 [] = "/tmp/picXXXXXX";
- close (mkstemp (tempPath_utf8));
- Melder_pathToFile (Melder_peek8to32 (tempPath_utf8), & tempFile);
- {// scope
- autoGraphics graphics = Graphics_create_postscriptjob (& tempFile, thePrinter. resolution,
- thePrinter. spots, thePrinter. paperSize, thePrinter. orientation, thePrinter. magnification);
- draw (boss, graphics.get());
- }
- char command [500];
- sprintf (command, Melder_peek32to8 (Site_getPrintCommand ()), tempPath_utf8);
- system (command);
- MelderFile_delete (& tempFile);
- #elif cocoa
- theDraw = draw;
- theBoss = boss;
- NSPrintInfo *info = [NSPrintInfo sharedPrintInfo];
- NSSize paperSize = [info paperSize];
- //NSLog (@"%f %f", paperSize. width, paperSize. height);
- thePrinter. paperWidth = paperSize. width / 0.12;
- thePrinter. paperHeight = paperSize. height / 0.12;
- [info setLeftMargin: 0.0];
- [info setRightMargin: 0.0];
- [info setTopMargin: 0.0];
- [info setBottomMargin: 0.0];
- /*
- * Although the paper size reported may be 595 x 842 points (A4),
- * 783 points (just under 11 inches) is the largest height that keeps the view on one page.
- */
- int viewWidth = paperSize. width;
- int viewHeight = paperSize. height;
- NSLog (@"%d %d", viewWidth, viewHeight);
- NSRect rect = NSMakeRect (0, 0, viewWidth, viewHeight);
- NSView *cocoaPrintingArea = [[GuiCocoaPrintingArea alloc] initWithFrame: rect];
- theMacView = cocoaPrintingArea;
- [cocoaPrintingArea setBoundsSize: NSMakeSize (viewWidth / 0.12, viewHeight / 0.12)]; // 72 points per inch / 600 dpi = 0.12 points per dot
- [cocoaPrintingArea setBoundsOrigin: NSMakePoint (0, 0)];
- NSPrintOperation *op = [NSPrintOperation
- printOperationWithView: cocoaPrintingArea];
- #if 1
- if (op) [op runOperation];
- #else
- /*
- * This may crash with multiple pages.
- */
- if (op) {
- [op setCanSpawnSeparateThread: NO];
- NSView *pictureView = ((GraphicsScreen) Picture_peekGraphics ((Picture) boss)) -> d_macView;
- [op
- runOperationModalForWindow: [pictureView window]
- delegate: cocoaPrintingArea
- didRunSelector: @selector(printOperationDidRun:success:contextInfo:)
- contextInfo: nil
- ];
- }
- #endif
- #elif defined (_WIN32)
- int postScriptCode = POSTSCRIPT_PASSTHROUGH;
- DOCINFO docInfo;
- DEVMODE *devMode;
- initPrinter ();
- if (! theWinPrint. hDevMode) {
- memset (& theWinPrint, 0, sizeof (PRINTDLG));
- theWinPrint. lStructSize = sizeof (PRINTDLG);
- theWinPrint. Flags = PD_RETURNDEFAULT;
- if (! PrintDlg (& theWinPrint)) Melder_throw (U"Cannot initialize printer.");
- }
- if (Melder_backgrounding) {
- theWinPrint. Flags = PD_RETURNDEFAULT | PD_RETURNDC;
- if (! PrintDlg (& theWinPrint) || ! theWinPrint. hDC) {
- Melder_throw (U"Cannot print from a script on this computer.");
- }
- } else {
- theWinPrint. Flags &= ~ PD_RETURNDEFAULT;
- theWinPrint. Flags |= PD_RETURNDC;
- if (! PrintDlg (& theWinPrint)) return 1;
- }
- theWinDC = theWinPrint. hDC;
- thePrinter. postScript = thePrinter. allowDirectPostScript &&
- Escape (theWinDC, QUERYESCSUPPORT, sizeof (int), (LPSTR) & postScriptCode, nullptr);
- /*
- * The HP colour inkjet printer returns in dmFields:
- * 0, 1, 8, 9, 10, 11, 12, 13, 14, 15, 23, 24, 25, 26 = DM_ORIENTATION |
- * DM_PAPERSIZE | DM_COPIES | DM_DEFAULTSOURCE | DM_PRINTQUALITY |
- * DM_COLOR | DM_DUPLEX | DM_YRESOLUTION | DM_TTOPTION | DM_COLLATE |
- * DM_ICMMETHOD | DM_ICMINTENT | DM_MEDIATYPE | DM_DITHERTYPE
- */
- devMode = * (DEVMODE **) theWinPrint. hDevMode;
- thePrinter. resolution = devMode -> dmFields & DM_YRESOLUTION ? devMode -> dmYResolution :
- devMode -> dmFields & DM_PRINTQUALITY ?
- ( devMode -> dmPrintQuality > 0 ? devMode -> dmPrintQuality : 300 ) : 300;
- if (devMode -> dmFields & DM_PAPERWIDTH) {
- thePrinter. paperWidth = devMode -> dmPaperWidth * thePrinter. resolution / 254;
- thePrinter. paperHeight = devMode -> dmPaperLength * thePrinter. resolution / 254;
- } else if (devMode -> dmFields & DM_PAPERSIZE) {
- static struct { float width, height; } sizes [] = { { 0, 0 }, { 8.5, 11 }, { 8.5, 11 }, { 11, 17 },
- { 17, 11 }, { 8.5, 14 }, { 5.5, 8.5 }, { 7.25, 10.5 }, { 297/25.4, 420/25.4 },
- { 210/25.4, 297/25.4 }, { 210/25.4, 297/25.4 }, { 148.5/25.4, 210/25.4 },
- { 250/25.4, 354/25.4 }, { 182/25.4, 257/25.4 }, { 8.5, 13 },
- { 215/25.4, 275/25.4 }, { 10, 14 }, { 11, 17 }, { 8.5, 11 }, { 3.875, 8.875 },
- { 4.125, 9.5 }, { 4.5, 10.375 } };
- int paperSize = devMode -> dmPaperSize;
- if (paperSize <= 0 || paperSize > 21) paperSize = 1;
- thePrinter. paperWidth = sizes [paperSize]. width * thePrinter. resolution;
- thePrinter. paperHeight = sizes [paperSize]. height * thePrinter. resolution;
- if (devMode -> dmOrientation == DMORIENT_LANDSCAPE) {
- long dummy = thePrinter. paperWidth;
- thePrinter. paperWidth = thePrinter. paperHeight;
- thePrinter. paperHeight = dummy;
- }
- } else {
- thePrinter. paperWidth = 1000;
- thePrinter. paperHeight = 1000;
- }
- EnableWindow ((HWND) XtWindow (theCurrentPraatApplication -> topShell -> d_xmShell), false);
- SetAbortProc (theWinDC, AbortFunc);
- memset (& docInfo, 0, sizeof (DOCINFO));
- docInfo. cbSize = sizeof (DOCINFO);
- docInfo. lpszDocName = L"Praatjes";
- docInfo. lpszOutput = nullptr;
- if (thePrinter. postScript) {
- StartDoc (theWinDC, & docInfo);
- StartPage (theWinDC);
- initPostScriptPage ();
- {// scope
- autoGraphics graphics = Graphics_create_postscriptprinter ();
- draw (boss, graphics.get());
- }
- exitPostScriptPage ();
- EndPage (theWinDC);
- EndDoc (theWinDC);
- } else {
- StartDoc (theWinDC, & docInfo);
- StartPage (theWinDC);
- {// scope
- autoGraphics graphics = Graphics_create_screenPrinter (nullptr, theWinDC);
- draw (boss, graphics.get());
- }
- if (EndPage (theWinDC) < 0) {
- Melder_throw (U"Cannot print page.");
- } else {
- EndDoc (theWinDC);
- }
- }
- EnableWindow ((HWND) XtWindow (theCurrentPraatApplication -> topShell -> d_xmShell), true);
- DeleteDC (theWinDC), theWinDC = nullptr;
- #endif
- return 1;
- } catch (MelderError) {
- Melder_throw (U"Not printed.");
- }
- }
- /* End of file Printer.cpp */
|