123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /* GraphicsPostscript.cpp
- *
- * Copyright (C) 1992-2011,2014,2015,2016,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 <math.h> /* For 'floor' and 'ceil' in BoundingBox. */
- #include <time.h> /* For creation date. */
- #include "GraphicsP.h"
- #include "Printer.h"
- Thing_implement (GraphicsPostscript, Graphics, 0);
- static void downloadPrologAndSetUp (GraphicsPostscript me) {
- /*
- * Procedures section of the document prolog: procedure definitions valid for all pages.
- */
- my d_printf (my d_file, "%%%%BeginProlog\n");
- my d_printf (my d_file, "%%%%BeginResource: procset (ppgb GraphicsPostscript procs) 1.0 0\n");
- my d_printf (my d_file, "/N { newpath } bind def /M { newpath moveto } bind def /L { rlineto } bind def\n");
- my d_printf (my d_file, "/F { 10 { 1 exch rlineto } repeat } bind def\n");
- my d_printf (my d_file, "/C { 0 360 arc stroke } bind def /FC { 0 360 arc fill } bind def\n");
- my d_printf (my d_file,
- "/PraatEncoding [\n"
- " /dotlessi/Aogonek/aogonek/Cacute/cacute/Ccaron/ccaron/Dcaron/dcaron/Dbar\n"
- " /dbar/Ecaron/ecaron/Eogonek/eogonek/Gcaron/gcaron/Lslash/lslash/Nacute\n"
- " /nacute/Ncaron/ncaron/Ohungarumlaut/ohungarumlaut/Rcaron/rcaron/Sacute/sacute/Scaron\n"
- " /scaron/Tcaron/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesinglright\n"
- " /parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one\n"
- " /two/three/four/five/six/seven/eight/nine/colon/semicolon\n"
- " /less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z\n"
- " /bracketleft/backslash/bracketright/asciicircum/underscore/quotesinglleft\n"
- " /a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n"
- " /Zdot/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute/agrave/acircumflex\n"
- " /adieresis/atilde/aring/ccedilla/eacute/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex\n");
- my d_printf (my d_file,
- " /idieresis/ntilde/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis\n"
- " /dagger/degree/cent/sterling/section/bullet/paragraph/germandbls/registered/copyright/trademark\n"
- " /acute/dieresis/notequal/AE/Oslash/infinity/plusminus/lessequal/greaterequal/yen/mu\n"
- " /partialdiff/summation/product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash\n"
- " /questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft/guillemotright\n"
- " /ellipsis/zdot/Agrave/Atilde/Otilde/OE/oe/endash/emdash/quotedblleft/quotedblright\n"
- " /quoteleft/quoteright/divide/lozenge/ydieresis/Ydieresis/fraction/currency\n"
- " /guilsinglleft/guilsinglright/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase\n"
- " /perthousand/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex/Idieresis\n"
- " /Igrave/Oacute/Ocircumflex/apple/Ograve/Uacute/Ucircumflex/Ugrave/tcaron\n"
- " /Uhungarumlaut/uhungarumlaut/Uring/uring/Yacute/yacute/Zacute/zacute/Zcaron/zcaron ] def\n");
- my d_printf (my d_file,
- "/PraatEncode { /font exch def /base exch def\n"
- " /basedict base findfont def /new basedict maxlength dict def\n"
- " basedict { exch dup dup /FID ne exch /Encoding ne and\n"
- " { exch new 3 1 roll put } { pop pop } ifelse } forall\n"
- " new /FontName font put new /Encoding PraatEncoding put font new definefont pop } def\n");
- my d_printf (my d_file, "%%%%EndResource\n");
- my d_printf (my d_file, "%%%%EndProlog\n");
- /*
- * Document setup: graphics state changes persistent across showpage calls.
- */
- my d_printf (my d_file, "%%%%BeginSetup\n");
- //my d_printf (my d_file, "%d %d { dup mul exch dup mul add 1.0 exch sub } setscreen\n", my spotsDensity, my spotsAngle);
- my d_printf (my d_file, "true setstrokeadjust\n");
- my d_printf (my d_file, "%%%%EndSetup\n");
- }
- static void initPage (GraphicsPostscript me) {
- ++ my pageNumber;
- if (my printer && my pageNumber > 1) downloadPrologAndSetUp (me); // has to be repeated for every page
- if (my job) {
- my d_printf (my d_file, "%%%%Page: %d %d\n", my pageNumber, my pageNumber);
- /*my d_printf (my d_file, "save\n");*/
- my d_printf (my d_file, "%%%%BeginPageSetup\n");
- }
- my d_printf (my d_file, "%g setlinewidth 2 setlinejoin\n", my resolution / 192.0); /* 0.375 point */
- if (my job || my printer) {
- if (my landscape)
- my d_printf (my d_file, "%d 0 translate 90 rotate ", (int) (my paperHeight * 72 * my magnification));
- }
- my d_printf (my d_file, "%.6g dup scale\n", 72.0 * my magnification / my resolution);
- if (my job) my d_printf (my d_file, "%%%%EndPageSetup\n");
- my lastFid = nullptr;
- }
- static void exitPage (GraphicsPostscript me) {
- int font, style;
- /*
- * A showpage is only needed if we are printing to a file.
- * If we are printing directly to a printer, the page will be ejected
- * by EndPage (Windows NT/2000/XP/Vista) or PMSessionEndPage (MacOSX).
- */
- if (my d_file) {
- if (my job) {
- /*my d_printf (my d_file, "restore\n");*/
- my d_printf (my d_file, "showpage\n");
- } else if (my eps) {
- my d_printf (my d_file, "showpage %% redefined by encapsulating program\n");
- }
- }
- for (font = 0; font <= kGraphics_font_DINGBATS; font ++)
- for (style = 0; style <= Graphics_BOLD_ITALIC; style ++)
- Melder_free (my fontInfos [font] [style]);
- my loadedXipa = false; // FIXME: include this because of the unpredictable page order with DSC?
- }
- void structGraphicsPostscript :: v_destroy () noexcept {
- exitPage (this);
- if (our d_file) {
- if (our job) {
- our d_printf (our d_file, "%%%%Trailer\n");
- our d_printf (our d_file, "%%%%Pages: %d\n", our pageNumber);
- }
- our d_printf (our d_file, "%%%%EOF\n"); // BUG. Correct according to DSC. But not good in EPS files?
- fclose (our d_file);
- }
- GraphicsPostscript_Parent :: v_destroy ();
- }
- autoGraphics Graphics_create_postscriptjob (MelderFile file, int resolution, kGraphicsPostscript_spots spots,
- kGraphicsPostscript_paperSize paperSize, kGraphicsPostscript_orientation rotation, double magnification)
- {
- autoGraphicsPostscript me = Thing_new (GraphicsPostscript);
- time_t today;
- my postScript = true, my yIsZeroAtTheTop = false, my languageLevel = 2;
- my job = true, my eps = false, my printer = false;
- my d_printf = (int (*)(void *, const char*, ...)) fprintf;
- Graphics_init (me.get(), resolution); // virtual resolution; may differ from that of the printer; OK if always 600 dpi
- my photocopyable = spots == kGraphicsPostscript_spots::PHOTOCOPYABLE;
- if (my photocopyable) { my spotsDensity = 85; my spotsAngle = 35; }
- else { my spotsDensity = 106; my spotsAngle = 46; }
- if (paperSize == kGraphicsPostscript_paperSize::A3) my paperWidth = 842 / 72.0, my paperHeight = 1191 / 72.0;
- else if (paperSize == kGraphicsPostscript_paperSize::US_LETTER) my paperWidth = 612 / 72.0, my paperHeight = 792 / 72.0;
- else my paperWidth = 595 / 72.0, my paperHeight = 842 / 72.0;
- my landscape = rotation == kGraphicsPostscript_orientation::LANDSCAPE;
- my magnification = magnification;
- my includeFonts = true;
- my d_file = Melder_fopen (file, "w");
- /*
- * The Device Coordinates are the PostScript user coordinates.
- * They are chosen in such a way that a distance of 1 in device coordinates
- * equals one dot if the printer's resolution is 'resolution' dots per inch.
- * Take a sensible default margin: half an inch on all sides.
- */
- my d_x1DC = my d_x1DCmin = resolution / 2;
- my d_x2DC = my d_x2DCmax = (my paperWidth - 0.5) * resolution;
- my d_y1DC = my d_y1DCmin = resolution / 2;
- my d_y2DC = my d_y2DCmax = (my paperHeight - 0.5) * resolution;
- /*
- * Now don't just set x1wNDC etc, but force computation of the scaling as well.
- */
- Graphics_setWsWindow (me.get(), 0, my paperWidth - 1.0, 13.0 - my paperHeight, 12.0);
- /*
- * We will adhere to version 3.0 of the Document Structuring Conventions for print jobs.
- */
- my d_printf (my d_file, "%%!PS-Adobe-3.0\n");
- my d_printf (my d_file, "%%%%Creator: Praat Shell 4.2\n");
- my d_printf (my d_file, "%%%%Title: %s\n", Melder_peek32to8 (MelderFile_name (file)));
- today = time (nullptr);
- my d_printf (my d_file, "%%%%CreationDate: %s", ctime (& today)); // contains newline symbol
- my d_printf (my d_file, "%%%%PageOrder: Special\n");
- my d_printf (my d_file, "%%%%Pages: (atend)\n");
- my d_printf (my d_file, "%%%%EndComments\n");
- downloadPrologAndSetUp (me.get());
- initPage (me.get());
- return me.move();
- }
- #if defined (macintosh)
- static int Eps_postScript_printf (void *stream, const char *format, ... ) {
- static char theLine [3002];
- char *p;
- va_list args;
- va_start (args, format);
- vsprintf (theLine, format, args);
- va_end (args);
- for (p = theLine; *p != '\0'; p ++) if (*p == '\n') *p = '\r';
- return fwrite (theLine, sizeof (char), strlen (theLine), reinterpret_cast <FILE *> (stream));
- }
- #endif
- autoGraphics Graphics_create_epsfile (MelderFile file, int resolution, enum kGraphicsPostscript_spots spots,
- double x1inches, double x2inches, double y1inches, double y2inches, bool includeFonts, bool useSilipaPS)
- {
- autoGraphicsPostscript me = Thing_new (GraphicsPostscript);
- time_t today;
- integer left, right, top, bottom;
- my postScript = true, my languageLevel = 2;
- my job = false, my eps = true, my printer = false;
- #if defined (macintosh)
- /* Replace newlines with carriage returns to be compatible with MS Word 5.1. */
- my d_printf = Eps_postScript_printf;
- #else
- my d_printf = (int (*)(void *, const char*, ...)) fprintf;
- #endif
- Graphics_init (me.get(), resolution); // virtual resolution; may differ from that of the printer; OK if always 600 dpi
- my photocopyable = spots == kGraphicsPostscript_spots::PHOTOCOPYABLE;
- if (my photocopyable) { my spotsDensity = 85; my spotsAngle = 35; }
- else { my spotsDensity = 106; my spotsAngle = 46; }
- my paperWidth = 7.5, my paperHeight = 11.0;
- my landscape = false;
- my magnification = 1.0;
- my includeFonts = includeFonts;
- my useSilipaPS = useSilipaPS;
- my d_file = Melder_fopen (file, "w");
- my d_x1DC = my d_x1DCmin = 0;
- my d_x2DC = my d_x2DCmax = my paperWidth * resolution; // 600 dpi -> 4500 virtual dots
- my d_y1DC = my d_y1DCmin = 0;
- my d_y2DC = my d_y2DCmax = my paperHeight * resolution; // 600 dpi -> 6600 virtual dots
- Graphics_setWsWindow (me.get(), 0, my paperWidth, 12.0 - my paperHeight, 12.0); // force scaling
- /*
- * We will honour version 3.0 of the DSC for Encapsulated PostScript files,
- * which includes supplying the bounding box information.
- */
- left = Melder_ifloor (x1inches * 72);
- right = Melder_iceiling (x2inches * 72);
- top = Melder_iceiling ((y2inches - my d_y1wNDC) * 72);
- bottom = Melder_ifloor ((y1inches - my d_y1wNDC) * 72);
- my d_printf (my d_file, "%%!PS-Adobe-3.0 EPSF-3.0\n");
- my d_printf (my d_file, "%%%%BoundingBox: %d %d %d %d\n", left, bottom, right, top);
- my d_printf (my d_file, "%%%%Creator: Praat Shell 5.1\n");
- /*
- * In an EPS file without screen preview, the file name will be visible anyway.
- * This leaves us room to show a warning that should keep users from thinking anything is wrong.
- */
- my d_printf (my d_file, "%%%%Title: NO SCREEN PREVIEW, BUT WILL PRINT CORRECTLY\n");
- today = time (nullptr);
- my d_printf (my d_file, "%%%%CreationDate: %s", ctime (& today)); /* Contains newline symbol. */
- my d_printf (my d_file, "%%%%EndComments\n");
- downloadPrologAndSetUp (me.get());
- initPage (me.get());
- return me.move();
- }
- #if defined (_WIN32)
- autoGraphics Graphics_create_postscriptprinter () {
- autoGraphicsPostscript me = Thing_new (GraphicsPostscript);
- my postScript = true, my languageLevel = 2;
- my job = false, my eps = false, my printer = true;
- my d_printf = Printer_postScript_printf;
- Graphics_init (me.get(), thePrinter. resolution); // virtual resolution
- my photocopyable = thePrinter. spots == kGraphicsPostscript_spots::PHOTOCOPYABLE;
- if (my photocopyable) { my spotsDensity = 85; my spotsAngle = 35; }
- else { my spotsDensity = 106; my spotsAngle = 46; }
- my paperWidth = (double) thePrinter. paperWidth / my resolution;
- my paperHeight = (double) thePrinter. paperHeight / my resolution;
- my landscape = thePrinter. orientation == kGraphicsPostscript_orientation::LANDSCAPE;
- my magnification = thePrinter. magnification;
- my includeFonts = true;
- my d_x1DC = my d_x1DCmin = my resolution / 2;
- my d_x2DC = my d_x2DCmax = (my paperWidth - 0.5) * my resolution;
- my d_y1DC = my d_y1DCmin = my resolution / 2;
- my d_y2DC = my d_y2DCmax = (my paperHeight - 0.5) * my resolution;
- Graphics_setWsWindow (me.get(), 0, my paperWidth - 1.0, 13.0 - my paperHeight, 12.0);
- downloadPrologAndSetUp (me.get());
- initPage (me.get());
- return me.move();
- }
- #endif
- void Graphics_nextSheetOfPaper (Graphics graphics) {
- if (graphics -> postScript) {
- GraphicsPostscript me = static_cast <GraphicsPostscript> (graphics);
- exitPage (me);
- if (my printer) Printer_nextPage ();
- initPage (me);
- } else if (graphics -> printer) {
- Printer_nextPage ();
- }
- }
- /* End of file GraphicsPostscript.cpp */
|