summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/epspdf
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-03-08 01:37:33 +0000
committerKarl Berry <karl@freefriends.org>2009-03-08 01:37:33 +0000
commit527a74fac35059aa094d70a74a74949e35655060 (patch)
treef72b507060bd21b802a6b47aa453ce236031a239 /Master/texmf-dist/scripts/epspdf
parentff0e5deb9aa09b585004a4e4c66a0543979e8425 (diff)
epspdf update
git-svn-id: svn://tug.org/texlive/trunk@12334 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/epspdf')
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdf2
-rw-r--r--Master/texmf-dist/scripts/epspdf/epspdf.help485
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdf.rb540
-rw-r--r--Master/texmf-dist/scripts/epspdf/epspdfboot.rb40
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdfrc.rb415
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdftk2
-rwxr-xr-xMaster/texmf-dist/scripts/epspdf/epspdftk.rb274
-rw-r--r--Master/texmf-dist/scripts/epspdf/makegray.pro4
8 files changed, 1148 insertions, 614 deletions
diff --git a/Master/texmf-dist/scripts/epspdf/epspdf b/Master/texmf-dist/scripts/epspdf/epspdf
index 4492608f398..f973474b312 100755
--- a/Master/texmf-dist/scripts/epspdf/epspdf
+++ b/Master/texmf-dist/scripts/epspdf/epspdf
@@ -1,3 +1,3 @@
#!/bin/sh
script=`kpsewhich -format=texmfscripts epspdf.rb`
-"$script" $*
+"$script" "$@"
diff --git a/Master/texmf-dist/scripts/epspdf/epspdf.help b/Master/texmf-dist/scripts/epspdf/epspdf.help
index 5bdc475ff8d..f7d37ff3c2c 100644
--- a/Master/texmf-dist/scripts/epspdf/epspdf.help
+++ b/Master/texmf-dist/scripts/epspdf/epspdf.help
@@ -1,173 +1,366 @@
- Epspdf and epspdftk User Guide
+Epspdf and epsdftk
+******************
- A multiplatform GUI- and command-line converter for [e]ps and pdf.
+This manual is for epspdf, version 0.4.0.
- Siep Kroonenberg,
- siepo at cybercomm dot nl
+Copyright (C) 2006, 2007, 2008, 2009 Siep Kroonenberg.
-Overview
+ Permission is granted to make and distribute verbatim copies of
+ this entire document without royalty provided the copyright notice
+ and this notice are preserved.
- Epspdftk converts files between eps, pdf and general PostScript. The main
- screen lets you open a file, select some options and convert the file.
+1 Usage
+*******
- When opening a file, epspdf tries to find out file type and, in the case
- of a pdf file, the number of pages. This information is displayed in the
- box in the upper half of the screen.
+1.1 Overview
+============
-Viewing
+Epspdftk converts files between eps, pdf and general PostScript. The
+main screen lets you open a file, select some options and convert the
+file.
- The View button at the bottom of the screen calls an appropriate external
- viewer. For Windows this is determined by the default Open command, for OS
- X it is always Preview, and under Linux it is configurable; see below
- under [1]The Configuration screen.
+When opening a file, epspdf tries to find out file type and, in the
+case of a pdf file, the number of pages. This information is displayed
+in the box in the upper part of the screen.
- The View button is grayed if epspdf thinks that there is no previewer for
- the current file; see [2]the epspdf main page for details.
-Conversion options
- Grayscaling: Simple color figures can be converted to grayscale.
- Grayscaling will fail for bitmapped data and for advanced color models.
- 'Try harder to grayscale' will handle a few more cases, but may take
- longer and still won't handle bitmaps.
+1.2 Viewing
+===========
- Call for assistance: If a PostScript color expert is reading this: please
- have a look at makegray.pro and see whether you can come up with something
- that handles more color models.
+The View button at the bottom of the screen calls an appropriate
+external viewer.
- Compute tight boundingbox: This option is only available if a single page
- is converted.
+Windows: Epspdftk simply tries to use the default Open command. A
+second button, labeled View with..., lets the user select a different
+program to view the file.
- Page selection: The only possibilities are selecting a single page or
- selecting all pages. When converting to eps you are restricted to a single
- page.
+For OS X the viewer is also the default program, but there is no View
+with... button.
- For general PostScript files, there is no quick way to determine the
- number of pages, so the program won't check beforehand whether you picked
- an existing page. If you picked a non-existent page, the program will
- abort. If you don't like that, convert the entire document to pdf first -
- which will be done behind the scenes anyhow.
+Under Linux the PostScript- and pdf viewers are configurable; see *note
+The configuration screen::.
- Specifying options such as grayscaling or page selection may require
- several roundtrips between PostScript or eps and pdf. If epspdf cannot use
- pdftops then some combinations of options will not be available.
+The View button is grayed if epspdf thinks that there is no previewer
+for the current file.
-Converting
+1.3 Conversion options
+======================
- The Convert and save... button calls up a file save dialog, with
- appropriate default extension. After a successful conversion, the result
- becomes the new current file, so you can judge the result by pressing the
- View button again.
+Grayscaling: Simple color figures can be converted to grayscale.
+Bitmapped data won't be converted. If grayscaling doesn't work on
+non-bitmapped data, select the "Try harder to grayscale" option. This
+may cause an extra pdf-PostScript roundtrip.
-The configuration screen
+Compute tight boundingbox: This option is only available if a single
+page is converted.
- Epspdftk also has a configuration screen. The settings here are preserved
- between sessions. Pay particular attention to 'Intended use' under PDF
- CONVERSION. Choose 'prepress' for pdfs which are intended for commercial
- printing. This option will try to embed all fonts, among other things.
- More and more often, printshops insist on this. With luck, Ghostscript
- fonts and system fonts will be used for fonts which were not originally
- embedded.
+Page selection: The only possibilities are selecting a single page or
+selecting all pages. When converting to eps you are restricted to a
+single page.
- Under Windows, this screen also lets you tell the program where to find
- pdftops.exe. Under Linux, it lets you pick PostScript- and pdf previewers.
+For general PostScript files, there is no quick way to determine the
+number of pages, so the program won't check beforehand whether you
+picked an existing page. If you picked a non-existent page, the program
+will abort. If you don't like that, convert the entire document to pdf
+first - which will be done behind the scenes anyhow.
-Adding standard fonts to an existing pdf
+Specifying options such as grayscaling or page selection may require
+several roundtrips between PostScript or eps and pdf.
- You can add standard fonts such as Times and Helvetica to an existing pdf:
- first, convert to ps, with 'Convert all pages' selected. Then, make sure
- that in the configuration screen 'Intended use' is set to prepress, then
- convert back to pdf.
+1.4 Converting
+==============
- If this option is set to screen, then standard fonts will be removed
- instead of added. This option may also affect the resolution of bitmaps.
+The Convert and save... button calls up a file save dialog. After a
+successful conversion, the result becomes the new current file, so you
+can judge the result by pressing the View button again.
-Eps preview headers
+1.5 The configuration screen
+============================
- Preview headers are quietly stripped from eps files. These preview headers
- are used by e.g. desktop-publishing software to represent eps files on
- screen without having to interpret the PostScript code itself. Epspdf
- currently has no option to preserve or add them.
+ Epspdftk also has a configuration screen. The settings here are
+preserved between sessions.
-On-the-fly conversion
+1.5.1 Configuring viewers
+-------------------------
+
+Under Linux, the preferred PostScript- and pdf viewers can be configured
+in this screen. Epspdf looks for a number of PostScript- and pdf
+viewers, from which you can select one, but you can also enter one
+manually.
+
+For Windows and Mac OS X, there is no such configuration option. Epspdf
+will use the program associated with the file type, which can be
+configured outside epspdf. Under Windows, you can use the "View
+with..." button instead.
+
+1.5.2 Options for converting to pdf
+-----------------------------------
+
+Double-check the setting "Target use" under "Conversion to pdf". Choose
+"prepress" for pdfs which are target for commercial printing. This
+option will try to embed all fonts, among other things. Often,
+printshops insist on this. With luck, Ghostscript fonts and system
+fonts will be used for fonts which were not originally embedded.
+
+On the other hand, you may prefer "screen" if file size is a concern.
+See also the Ghostscript documentation, in particular Use.htm and
+Ps2pdf.htm.
+
+1.5.3 Options for converting to PostScript
+------------------------------------------
+
+For conversion the other way you may opt not to use pdftops even if it
+is available. In this case, the conversion will be done by Ghostscript.
+Characters may be converted to drawn shapes or little bitmaps so this
+is not recommended.
+
+Under Windows, this is also the place to point the program to the
+location of pdftops.exe.
+
+1.5.4 Hires BoundingBox
+-----------------------
+
+Uncheck the option "Use hires boundingbox if possible" if otherwise the
+computed boundingbox is slightly too tight, resulting in some clipping.
+It has two effects:
+ * When converting to pdf, it uses the standard rather than the hires
+ boundingbox for page dimensions
+
+ * When computing a boundingbox, it adds a small safety margin of 1pt
+ to the standard boundingbox, except where it would make any
+ boundingbox coordinate negative.
+
+2 Command-line usage
+********************
+
+epspdf.rb, the library for epspdftk.rb, does double duty as command-line
+version of epspdftk.rb. It shares configuration settings with
+epspdftk.rb.
+
+It is strongly recommended to invoke epspdf.rb via a wrapper script
+epspdf or epspdf.bat on the search path, e.g.
+ #!/bin/sh
+ PATH_TO_EPSPDF/epspdf.rb "@"
+for Unix/Linux/OS X, or
+ "PATH_TO_RUBY.EXE" "PATH_TO_EPSPDF.RB" %*
+for Windows. It is the responsibility of the caller to provide double
+quotes.
+
+The TeX Live package for epspdf already includes such wrapper scripts.
+
+Basic usage:
+
+ epspdf [OPTIONS] INFILE OUTFILE
+
+2.1 Option summary
+==================
+
+The summary below is the output of a command `epspdf --help' for help.
+ $ epspdf --help
+ Epspdf version 0.4.0
+ Copyright (C) 2006, 2008, 2009 Siep Kroonenberg
+ Epspdf 0.4.0
+ Convert between [e]ps and pdf formats
+ Usage: epspdf.rb [options] infile [outfile]
+ Default for outfile is file.pdf if infile is file.eps or file.ps
+ Default for outfile is file.eps if infile is file.pdf
+ -g, --gray, --grey Convert to grayscale;
+ success not guaranteed
+ -G, --GRAY, --GREY Try harder to convert to grayscale
+ -p, --pagenumber=PAGENUMBER Page to be converted or selected
+ -b, --bbox, --BoundingBox Compute tight boundingbox
+ -n, --no-hires Don't use hires boundingbox
+ -r, --hires Use hires boundingbox
+ -T, --target=TARGET Target use of pdf; one of
+ default, printer, prepress, screen, ebook
+ -N, --pdfversion=PDFVERSION Pdf version to be generated
+ -V, --version=PDFVERSION Deprecated; use `-N' or `--pdfversion'.
+ -I Ignore pdftops even if available
+ (default: use if available)
+ -U Use pdftops if available
+ (overrides previous -I setting)
+ -C, --custom=CUSTOMOPTIONS Custom options for conversion to pdf,
+ view Use.htm and ps2pdf.htm from
+ the Ghostscript documentation set
+ -P, --psoptions=PSOPTIONS Options for pdftops; default -level3,
+ don't include -eps or page number options;
+ these will be generated by the program
+ -i, --info Info: display detected filetype
+ -s Save (some) settings
+ -d Debug: don't remove temp files
+ -v Prints version info
+ -h, --help Show this message
+
+3 Notes on PostScript and pdf
+*****************************
+
+3.1 Bitmapped and vector
+========================
+
+Pictures can be described either in terms of pixels, or more abstractly,
+in terms of geometric shapes, fonts and text.
+
+Bitmapped or pixel-based graphics are appropriate for photographs and
+screenshots, but less so for diagrams and spreadsheet-generated
+graphics.
+
+A file in PostScript- or pdf format can contain both types of graphic
+data, e.g. a text in vector format agains a photographic background in
+bitmapped format.
+
+Vector graphics can be freely scaled without losing sharpness or
+becoming pixellated. If bitmapped graphics are enlarged too much,
+individual pixels become apparent. With low-resolution bitmaps this
+happens sooner than with high-resolution bitmaps, but high-resolution
+bitmaps have (much) larger file sizes, and take longer to process.
+
+So avoid converting vector to bitmap. However, converting from bitmap to
+vector is also best avoided, since it is very hard to do well.
+
+Epspdf normally avoids conversion from vector to bitmap and never
+converts the other way. With the screen- and ebook "Target use" option,
+included bitmaps tend to be downsampled, i.e. reduced to a lower
+resolution.
+
+3.2 Font embedding
+==================
+
+When converting to pdf, Ghostscript handles font embedding differently
+depending on the "Target use" option. For prepress, it embeds even the
+standard fonts, including Times etc. Ghostscript has copies of these
+fonts in case the PostScript file doesn't have them. For screen, it
+doesn't embed standard fonts.
+
+You can embed fonts after the fact by converting pdf to eps or ps, and
+back to pdf, with target use set to "prepress". However, don't try this
+unless you have pdftops.
+
+If target use is set to "screen", then standard fonts will be removed
+instead of added. This option may also cause downsampling of bitmaps.
+
+3.3 Eps preview headers
+=======================
+
+Preview headers are quietly stripped from eps files. These preview
+headers are used by e.g. desktop-publishing software to represent eps
+files on screen without having to interpret the PostScript code itself.
+Epspdf currently has no option to preserve or add them.
+
+3.4 Bounding- and other boxes
+=============================
+
+A PostScript file may have a page size and a boundingbox defined. A pdf
+file may have a mediabox, a trimbox and various other boxes. Ghostscript
+by itself normally converts the PostScript page - which is anchored at
+(0,0) - to the pdf mediabox.
+
+When epspdf or a similar program converts eps to pdf, it adds code to
+move the bottom left corner of the graphic to (0,0) and to set the page
+to the size of the graphic. Anything outside the boundingbox should be
+cut off.
+
+Both Ghostscript and pdftops have some parameters for setting or using
+these boxes; consult Ps2pdf.htm from the Ghostscript documentation and
+"pdftops -help" or "man pdftops".
+
+3.5 Orientation
+===============
+
+There appears to be no reliable way to set orientation for PostScript-
+and pdf files. This may result part of a graphic being cut off after
+conversion or even everything falling outside the page / mediabox /
+boundingbox. It may help to change the extension from ".eps" to ".ps"
+before converting to pdf. In this case, let epspdf generate a new
+boundingbox.
+
+3.6 Exporting PostScript from Windows programs
+==============================================
+
+Often, the only way to get EPS or PostScript from a Windows program is
+by "printing" to a PostScript file. From some programs, you can print a
+selection. A suitable driver which comes with Windows is Generic / MS
+Publisher Imagesetter. Pay attention to the printer properties: choose
+"Outline" for font downloading and avoid the "Optimize for speed"
+setting for PostScript Output Option. Try e.g. "Archive" instead. These
+options can be found under the Advanced button.
+
+ Other possibilities are the TpX and wmf2eps programs, which both have
+options to write clipboard contents to an emf file. Wmf2eps uses a
+printer driver in the background. For faithful conversion, pick
+wmf2eps; for subsequent editing, choose TpX. Both programs are
+available from `http://www.tug.org/ctan.html'.
+
+4 Troubleshooting
+*****************
+
+4.1 Grayscaling fails
+=====================
+
+See above, under *note Grayscaling: gray. Epspdf is limited by what can
+be done by the backend tools, i.e. Ghostscript and pdftops. In
+particular, epspdf cannot grayscale bitmapped data.
+
+4.2 Part of the graphic gets cut off
+====================================
+
+Things to try:
+ * If the PostScript file was generated with the Windows PostScript
+ driver, experiment with the PostScript Output option. Don't choose
+ Optimize for Speed.
+
+ * Replace the extension with ".ps" and let epspdf generate a
+ boundingbox.
+
+ * Boundingbox calculations may be slightly inaccurate where text is
+ involved. If just a sliver is cut off, let epspdf ignore the
+ high-resolutuion boundingbox. Command-line option: "-n" or
+ "-no-hires".
+
+4.3 Fonts look ugly
+===================
+
+If Ghostscript has to do the conversion from pdf to ps then text will
+not remain text, but will be replaced by drawn shapes or bitmaps. Try
+to get hold of the xpdf suite, which includes pdftops, especially if
+your files contain serious amount of text.
+
+4.4 Resources for troubleshooting
+=================================
+
+Logfile. Epspdf and epspdftk maintain a log file epspdf.log in your
+home directory or, in case of Windows, your profile directory. This
+profile directory may be `c:\Documents and Settings\YOUR USER NAME'.
+Otherwise, open a DOS box and type `echo %USERPROFILE%', which will
+produce this information.
+
+This logfile lists all Ghostscript- and pdftops program calls plus
+error information. "EPCallError" is probably a program error.
+'EPSystemError" is more likely caused by a faulty file, but may be a
+program error as well.
+
+Temporary files. The temporary files may give clues as well. They will
+be deleted at the end of the session (for the command-line version,
+give a -d parameter to keep the temporary files). Check the logfile as
+to which temporary files have been created.
+
+Ghostscript- and pdftops documentation. For Ghostscript, the most
+important files are Ps2pdf.htm and Use.htm. For pdftops, type `pdftops
+-h'. For Unix, there is also a man page, and for Windows there is a
+file pdftops.txt in the distribution zip.
+
+5 Changes in version 0.4
+************************
+
+Hi-res boundingboxes are now supported. By default, conversion from eps
+to pdf now uses the hires boundingbox as "page" to determine the page
+dmensions of the pdf file. Other conversions preserve or generate a
+hires boundingbox.
+
+Under Windows, the new version looks for an installed TeX and will use
+its private Ghostscript if it cannot find separately installed
+Ghostscript. TeX Live's pdftops, being on the searchpath, will be used
+unless epspdf finds another copy first.
+
+There is now a "-v" (lowercase) option to print the version string.
- Daniel Becker wrote a LaTeX package epspdfconversion which converts eps
- files on the fly to pdf, like Heiko Oberdiek's epstopdf package, but with
- epspdf as backend. It can make use of the epspdf conversion options. Both
- packages are available from [3]CTAN and included in TeX Live.
-
-Exporting PostScript from Windows programs
-
- Often, the only way to get EPS or PostScript from a Windows program is by
- 'printing' to a PostScript file. From some programs, you can print a
- selection. A suitable driver which comes with Windows is Generic / MS
- Publisher Imagesetter. Pay attention to the printer properties: avoid the
- 'Optimize for speed' setting and choose Outline for font downloading.
- These options can be found under the Advanced button.
-
- Other possibilities are the TpX and wmf2eps programs, which both have
- options to write clipboard contents to an emf file. Wmf2eps uses a printer
- driver in the background. For faithful conversion, pick wmf2eps; for
- subsequent editing, choose TpX. Both programs are availbable from [4]CTAN.
-
-Command-line use
-
- Epspdf.rb, the library for epspdftk.rb, does double duty as command-line
- version of epspdftk.rb. Type epspdf.rb -h for help. It shares
- configuration settings with epspdftk.
-
-Troubleshooting
-
- Grayscaling fails
-
- See above, under [5]Grayscaling. Epspdf is limited by what can be done by
- the backend tools, i.e. Ghostscript and pdftops.
-
- Part of the graphic gets cut off
-
- I have seen this happen with eps files generated by printing landscape
- PowerPoint slides to PostScript with the Encapsulated PostScript output
- option. Using the Archive output option instead solved the problem. In
- general, experiment a bit in generating your PostScript.
-
- Mac OS X problems with epspdftk
-
- Even though epspdftk is not an X11 program, you may still need some pieces
- of X11 and the X11 SDK, which are optional installs of OS X.
-
- Under Leopard, the window that is displayed during the conversion stays
- blank. I have no idea why.
-
- Resources for troubleshooting
-
- Logfile. Epspdf and epspdftk maintain a log file. For Unix and Mac OS X it
- is epspdf.log in your home directory. For Windows, it is epspdf.log or
- epspdftl.log in your profile directory. The latter filename is used if
- epspdf is embedded in TeX Live. This profile directory may be c:\Documents
- and Settings\<your user name>. Otherwise, open a DOS box and type 'echo
- %USERPROFILE%', which will produce this information.
-
- This logfile lists all Ghostscript- and pdftops program calls plus error
- information. 'EPCallError' is probably a program error. 'EPSystemError' is
- more likely caused by a faulty file, but may be a program error as well.
-
- Temporary files. The temporary files may give clues as well. They will be
- deleted at the end of the session (for the command-line version, give a -d
- parameter to keep the temporary files). The logfile can tell you which
- temporary files have been created.
-
- [6]Main page...
-
- --------------------------------------------------------------------------
-
- Last revised: July 27, 2008
-
-References
-
- Visible links
- 1. http://tex.aanhet.net/epspdf/epspdf_UG.html#configure
- 2. http://tex.aanhet.net/epspdf/index.html#preview
- 3. http://www.tug.org/ctan.html
- 4. http://www.tug.org/ctan.html
- 5. http://tex.aanhet.net/epspdf/epspdf_UG.html#gray
- 6. http://tex.aanhet.net/epspdf/index.html
diff --git a/Master/texmf-dist/scripts/epspdf/epspdf.rb b/Master/texmf-dist/scripts/epspdf/epspdf.rb
index 3b11c62278f..09462af8330 100755
--- a/Master/texmf-dist/scripts/epspdf/epspdf.rb
+++ b/Master/texmf-dist/scripts/epspdf/epspdf.rb
@@ -3,7 +3,7 @@
# epspdf conversion utility, main source
#####
-# Copyright (C) 2006, 2008 Siep Kroonenberg
+# Copyright (C) 2006, 2008, 2009 Siep Kroonenberg
# n dot s dot kroonenberg at rug dot nl
#
# This program is free software, licensed under the GNU GPL, >=2.0.
@@ -14,41 +14,32 @@
# The focus is on converting between eps and pdf.
# Code is organized as a set of single-step conversion methods plus an
-# any-to-any conversion.
+# any-to-any conversion chaining them together.
# `Target' is not a parameter; all conversions write to a new temp
# file. Conversions can be chained: object.conversion1( params
# ).conversion2( params ) ... The final temp file is moved or copied to
-# the desired destination by the main program (which can be epspdf
+# the desired destination by the main program (which can be epspdf.rb
# itself).
# The use of exception handling makes it unnecessary to inspect return
# values.
-# Limitation
-# HiRes boundingboxes are ignored.
-# Two reasons:
-# - they get lost anyhow on conversion to pdf
-# - They are not required so when you find one you have to make sure
-# that it doesn't refer to an included eps. This would
-# require additional logic.
-
###########################################
# some initialization in case this file is used as main program
if __FILE__ == $0
- # epspdfboot.rb: modify loadpath in a way which works both
- # with a full Ruby and with a custom subset ruby
-
- require __FILE__.sub( /epspdf\.rb/, 'epspdfboot.rb' )
+ # add directory of this source to loadpath
+ $:.unshift( File.dirname( __FILE__ ) )
# turn on warnings
#$VERBOSE = 1
end # if main program
+
###########################################
# Error handling
@@ -241,24 +232,30 @@ end # def
###########################################
-# Boundingboxes
+# Boundingboxes; first standard, then hires
-BB_PAT = /^\s*%%BoundingBox:\s*(-?\d+)((\s+-?\d+){3})\s*$/
+#changes:
+#hires boundingboxes
+#numbers may start with a plus-sign. DSC manual is ambiguous,
+# PostScript manual allows it, but of course PS != DSC
+#left-right and lower-upper need not be in natural order
+
+BB_PAT = /^\s*%%BoundingBox:\s*([-+]?\d+)((\s+[-+]?\d+){3})\s*$/
BB_END = /^\s*%%BoundingBox:\s*\(\s*atend\s*\)\s*$/
-# for multiline matching:
-BB_PAT1 = /%%BoundingBox:\s*(-?\d+)((\s+-?\d+){3})/m
-BB_END1 = /%%BoundingBox:\s*\(\s*atend\s*\)/m
class Bb
- attr_accessor :llx, :lly, :urx, :ury
+ attr_accessor :llx, :lly, :urx, :ury # strings
def initialize( llx, lly, urx, ury )
@llx, @lly, @urx, @ury = llx, lly, urx, ury
+ # guarantee valid syntax:
[@llx, @lly, @urx, @ury].each { |l| l = l.to_i.to_s }
+ @llx, @urx = @urx, @llx if @llx.to_i > @urx.to_i
+ @lly, @ury = @ury, @lly if @lly.to_i > @ury.to_i
end
- def Bb.from_bbcomment( s )
+ def Bb.from_comment( s )
return nil unless s =~ BB_PAT
llx, lly, urx, ury =
s.sub( /^\s*%%BoundingBox:\s*/, '' ).split( /\s+/ )
@@ -325,13 +322,103 @@ class Bb
# convert boundingbox to boundingbox comment
- def bbcomment
+ def comment
fail EPBBError, prn unless valid
"%%BoundingBox: #{@llx} #{@lly} #{@urx} #{@ury}"
end
end # class Bb
+# [-+](\d+(\.\d*)?|\.\d+)([eE]\d+)? PostScript number
+HRBB_PAT = /^\s*%%HiResBoundingBox:\s*[-+]?(\d+(\.\d*)?|\.\d+)([eE]\d+)?((\s[-+]?(\d+(\.\d*)?|\.\d+)([eE]\d+)?){3})\s*$/
+HRBB_END = /^\s*%%HiResBoundingBox:\s*\(\s*atend\s*\)\s*$/
+
+class HRBb
+
+ attr_accessor :llx, :lly, :urx, :ury
+
+ def initialize( llx, lly, urx, ury )
+ @llx, @lly, @urx, @ury = llx, lly, urx, ury
+ [@llx, @lly, @urx, @ury].each do |l|
+ if l =~ /\./
+ # make floats conform to Ruby syntax:
+ # decimal dots must be padded with digits on either side
+ l.sub!( /^\./, '0.' )
+ l.sub!( /\.(?!\d)/, '.0' ) # (?!\d): zero-width neg. lookahead
+ end
+ l = l.to_f.to_s
+ end
+ @llx, @urx = @urx, @llx if @llx.to_f > @urx.to_f
+ @lly, @ury = @ury, @lly if @lly.to_f > @ury.to_f
+ end
+
+ def HRBb.from_hrcomment( s )
+ return nil unless s =~ HRBB_PAT
+ llx, lly, urx, ury =
+ s.sub( /^\s*%%HiResBoundingBox:\s*/, '' ).split( /\s+/ )
+ HRBb.new( llx, lly, urx, ury )
+ end
+
+ def height
+ ( @ury.to_f - @lly.to_f ).to_s
+ end
+
+ def width
+ ( @urx.to_f - @llx.to_f ).to_s
+ end
+
+ def valid
+ @llx.to_f < @urx.to_f and @lly.to_f < @ury.to_f
+ end
+
+ def non_negative
+ valid and @llx.to_f >= 0 and @lly.to_f >= 0
+ end
+
+ def copy
+ HRBb.new( @llx, @lly, @urx, @ury )
+ end
+
+ def prn
+ "#{@llx} #{@lly} #{@urx} #{@ury}"
+ end
+
+ ##################
+
+ # wrapper code for a hires boundingbox;
+ # moves lower left corner of eps to (0,0)
+ # and defines a page size identical to the eps width and height.
+ # The gsave in the wrapper code should be matched by
+ # a grestore at the end of the PostScript code.
+ # This grestore can be specified on the Ghostscript command-line.
+
+ def wrapper
+ fail EPBBError, prn unless valid
+ fname = mktemp( 'ps' )
+ File.open( fname, $W ) do |f|
+ f.binmode if ARCH == 'w32'
+ f.write(
+ "%%BoundingBox: 0 0 #{width.to_f.ceil} #{height.to_f.ceil}\n" +
+ "%%HiResBoundingBox: 0 0 #{width.to_f} #{height.to_f}\n" +
+ "<< /PageSize [#{width} #{height}] >>" +
+ " setpagedevice\n" +
+ "gsave #{(-(@llx.to_f)).to_s} #{(-(@lly.to_f)).to_s}" +
+ " translate\n" ) > 0
+ end # open
+ return fname
+ end # wrapper
+
+ ##################
+
+ # convert hiresboundingbox to hires boundingbox comment
+
+ def hrcomment
+ fail EPBBError, prn unless valid
+ "%%HiResBoundingBox: #{@llx} #{@lly} #{@urx} #{@ury}"
+ end
+
+end # class HRBb
+
###########################################
# PsPdf class definition
@@ -367,7 +454,7 @@ class PsPdf
when /-level\d\b/
$settings.ps_options.sub( /(-level\d)/, '\1sep' )
else
- $settings.ps_options + " -level2sep"
+ $settings.ps_options + " -level3sep"
end # case
else
$settings.ps_options
@@ -376,7 +463,7 @@ class PsPdf
# instance methods ###
- attr_accessor :path, :bb, :type, :npages, :atfront
+ attr_accessor :path, :bb, :hrbb, :type, :npages, :atfront, :hr_atfront
##################
@@ -421,22 +508,33 @@ class PsPdf
# Find boundingbox, simple case.
# We shall call this method only for eps PsPdf objects which were
# converted by pdftops or Ghostscript, so we can be sure that
- # the boundingbox is not (atend). The file is not rewritten.
+ # the boundingbox is not (atend).
+ # We also assume that the hrbb lies within the bb.
+ # The file is not rewritten.
def find_bb_simple
fail EPCallError, buginfo unless @type == 'eps'
@bb = nil
+ @hrbb = nil
slurp = ''
File.open( @path, $R ) do |fl|
slurp = fl.read( [File.size(@path), SAFESIZE].min )
end
lines = slurp.split( /\r\n?|\n/ )
+ # look for a bb or a hrbb
+ # if a valid bb is found, check the next line for hrbb
+ # but look no further; we don't want to mistake a hrbb of
+ # an included eps for the hrbb of the outer eps.
lines.each do |l|
if l =~ BB_PAT
- @bb = Bb.from_bbcomment( l )
- break
+ @bb = Bb.from_comment( l )
+ elsif l =~ HRBB_PAT
+ @hrbb = HRBb.from_hrcomment( l )
+ elsif @bb
+ break # stop looking; we expect hrbb next to bb
end
+ break if @bb and @hrbb
end # do |l|
fail EPBBError, @path unless @bb and @bb.valid
@@ -484,12 +582,14 @@ class PsPdf
# eps_clean: write source eps to an eps without preview, and
# with a boundingbox in the header.
+ # clean up any potential problems
# the eps is always written to a new file.
def eps_clean
fail EPCallError, buginfo if @type != 'eps' and @type != 'epsPreview'
atend = nil
+ hr_atend = nil
slurp = ''
offset, ps_len = nil, nil
if @type == 'eps'
@@ -507,8 +607,8 @@ class PsPdf
end # File
end # ifthenelse @type
- # boundingbox unknown and possibly atend
- @bb, @atfront = nil, nil
+ # [hires] boundingbox unknown and possibly atend
+ @bb, @atfront, @hrbb, @hr_atfront = nil, nil, nil, nil
# limit search for boundingbox comments.
# For very large eps files, we don't want to scan the entire file.
@@ -522,68 +622,147 @@ class PsPdf
# We capture both lines and separators, as an easy way to
# keep track of how many bytes have been read.
- # It is not necessary to treat lines and separators differently.
-
- lines = slurp.split( /(\r\n?|\n)/ )
- pre_block = ''
- post_block = ''
+ # we assume that if there is a hires bb then
+ # bb and hires bb are on consecutive lines.
+ # Otherwise the logic would get too messy.
+
+ # The epsfile will be reconstituted from:
+ # a series of lines and line separators; then either
+ # - a bbox or
+ # - (bbox or hrbbox), separator, (hrbbox or bbox)
+ # the big blob
+ # possibly a trailer with removed bb comments
+
+ pre_lines = slurp.split( /(\r\n?|\n)/ )
bb_comment = ''
- lines.each do |l|
- pre_block = pre_block + l
+ # initialize indices of bb comments to less than smallest index
+ i_bb = -1
+ i_hrbb = -1
+ i = -1
+ i_end = -1
+ pre_length = 0
+ pre_lines.each do |l|
+ pre_length += l.length
+ i += 1
+ next if l =~ /(\r\n?|\n)/
if l =~ BB_PAT
- @bb = Bb.from_bbcomment( l )
+ @bb = Bb.from_comment( l )
@atfront = true
- break
+ i_bb = i
elsif l =~ BB_END
atend = true
- break
+ i_bb = i
+ elsif l =~ HRBB_PAT
+ @hrbb = HRBb.from_hrcomment( l )
+ @hr_atfront = true
+ i_hrbb = i
+ elsif l =~ HRBB_END
+ hr_atend = true
+ i_hrbb = i
+ elsif @bb or atend
+ i_end = i
+ break # stop looking; we expect hrbb next to bb
end # =~ BB_PAT
end # do |l|
- if atend
+ if atend or hr_atend
if ps_len > SAFESIZE
File.open( @path, $R ) do |fl|
fl.seek( offset + ps_len - SAFESIZE, IO::SEEK_SET )
slurp = fl.read( SAFESIZE )
end
- lines = slurp.split( /(\r\n?|\n)/ )
- end
- lines.reverse_each do |l|
- post_block = l + post_block
+ end # else use old slurp
+ post_lines = slurp.split( /(\r\n?|\n)/ )
+ # initialize indices of atend bb comments to more than largest index
+ j = post_lines.length
+ j_bb = j
+ j_hrbb = j
+ j_end = j
+ post_length = 0
+ post_lines.reverse_each do |l|
+ post_length += l.length
+ j -= 1
+ next if l =~ /(\r\n?|\n)/
if l =~ BB_PAT
bb_comment = l
- @bb = Bb.from_bbcomment( bb_comment )
+ @bb = Bb.from_comment( bb_comment )
+ j_bb = j
+ elsif l =~ HRBB_PAT
+ bb_comment = l
+ @hrbb = HRBb.from_hrcomment( bb_comment )
+ j_hrbb = j
+ end
+ if (@bb or !atend) and (@hrbb or !hr_atend)
+ j_end = j
break
- end # if
+ end
end # do
+ #post_lines.slice([j_bb,j_hrbb].min .. -1).each do |l|
+ # post_block = post_block + l
end # if atend
+
fail EPBBError, @path unless @bb.valid
+ # in case of discrepancy, drop @hrbb.
+ # we accept a `safety margin': a difference >1pt is not a discrepancy.
+ @hrbb = nil if @hrbb and
+ (( @bb.llx.to_i > @hrbb.llx.to_f.floor ) or
+ ( @bb.lly.to_i > @hrbb.lly.to_f.floor ) or
+ ( @bb.urx.to_i < @hrbb.urx.to_f.ceil ) or
+ ( @bb.ury.to_i < @hrbb.ury.to_f.ceil ))
+
retVal = PsPdf.new( 'ext' => 'eps' )
- if @type == 'eps' and @atfront # simple copy
- ccp( @path, retVal.path )
- elsif @atfront # copy a slice
- sliceFile( @path, retVal.path, ps_len, offset )
- elsif atend # relocate boundingbox
- File.open( retVal.path, $W ) do |fl|
- fl.write( pre_block.sub( BB_END1, bb_comment ))
+
+ # always rewrite the eps, to get normalized, ruby-compatible bb syntax.
+ # we modify part of the header, and possibly of the trailer.
+
+ # offset, length of middle part, which can be copied byte for byte
+ cp_start = offset + pre_length
+ cp_len = ps_len - pre_length
+ cp_len -= post_length if ( atend or hr_atend )
+ # replace boundingbox comments
+ if atend
+ pre_lines[i_bb].sub!( BB_END, @bb.comment )
+ post_lines[j_bb].sub!( BB_PAT, '%%' )
+ else
+ pre_lines[i_bb].sub!( BB_PAT, @bb.comment )
+ end
+ if @hrbb
+ # replace valid hires boundingbox comments
+ if hr_atend
+ pre_lines[i_hrbb].sub!( HRBB_END, @hrbb.hrcomment )
+ post_lines[j_hrbb].sub!( HRBB_PAT, '%%' )
+ else
+ pre_lines[i_hrbb].sub!( HRBB_PAT, @hrbb.hrcomment )
end
- sliceFile( @path, retVal.path,
- ps_len - pre_block.length - post_block.length,
- offset + pre_block.length, $A )
+ elsif i_hrbb # invalid hires bb
+ # erase invalid hr boundingbox comments
+ if atend
+ pre_lines[i_hrbb].sub!( HRBB_END, '%%' )
+ post_lines[j_hrbb].sub!( HRBB_PAT, '%%' )
+ else
+ pre_lines[i_hrbb].sub!( HRBB_PAT, '%%' )
+ end
+ end # test for @hrbb
+
+ File.open( retVal.path, $W ) do |fl|
+ fl.write( pre_lines[ 0 .. i_end ].join )
+ end
+ sliceFile( @path, retVal.path, cp_len, cp_start, $A )
+ if ( atend or hr_atend )
File.open( retVal.path, $A ) do |fl|
- fl.write( post_block.sub( BB_PAT1, '%' ))
+ fl.write( post_lines[ j_end .. -1 ].join )
end
- end # if atend
+ end
retVal.bb = @bb.copy
+ retVal.hrbb = @hrbb.copy if @hrbb
retVal.atfront = true
+ retVal.hr_atfront = true
return retVal
-
end # eps_clean
##################
# Use the Ghostscript bbox device to give an eps a tight boundingbox.
- # Newer versions of Ghostscript can do that by themselves, but
- # for the time being we just assume a bbox device.
+ # Here, we don't test for use_hires_bb.
# The eps should already have been cleaned up by eps_clean
# and the current boundingbox should not contain negative coordinates,
# otherwise the bbox output device may give incorrect results.
@@ -597,44 +776,74 @@ class PsPdf
fail EPCallError, buginfo \
unless @type == 'eps' and @bb.non_negative
- cmd = "#{short_name($settings.gs_prog)} #{PsPdf.gs_options}" +
- " -sDEVICE=bbox #{short_name(@path)} 2>&1"
+ # let ghostscript calculate new boundingbox
+ cmd = $settings.gs_prog + ' ' + PsPdf.gs_options +
+ " -sDEVICE=bbox \"" + @path + "\" 2>&1"
write_log cmd # if $DEBUG
bb_output = `#{cmd}`
+ # inspect the result
fail EPSystemError, cmd unless $? == 0 and bb_output
bb_output.split(/\r\n?|\n/).each do |b|
if b =~ BB_PAT
- bb_temp = Bb.from_bbcomment( b )
+ bb_temp = Bb.from_comment( b )
fail EPBBError, bb_output unless bb_temp.valid
- bb_temp.expand
+ bb_temp.expand unless $settings.use_hires_bb
@bb = bb_temp.copy
- # write a new eps file with a new boundingbox comment
- ps_len = File.size( @path )
- slurp = ''
- File.open( @path, $R ) do |fl|
- slurp = fl.read( [ps_len,SAFESIZE].min )
- end
- lines = slurp.split( /(\r\n?|\n)/ )
- pre_block = ''
- pre_length = 0
- lines.each do |l|
- pre_length = pre_length + l.length
- if l =~ BB_PAT
- pre_block = pre_block + bb_temp.bbcomment
- oldpath = @path
- @path = mktemp( 'eps' )
- File.open( @path, $W ) { |fl| fl.write( pre_block ) }
- sliceFile( oldpath, @path, \
- ps_len - pre_length, pre_length, $A )
- return self
- else
- pre_block = pre_block + l
- end
- end # do |l|
- fail EPBBError, bb_output
- end # if =~ BB_PAT
+ elsif b =~ HRBB_PAT
+ bb_temp = HRBb.from_hrcomment( b )
+ @hrbb = bb_temp.valid ? bb_temp.copy : nil
+ end
end # do |b|
- fail EPBBError, bb_output
+ fail EPBBError, bb_output unless @bb
+ # this won't happen, but we deal with it anyway:
+ @hrbb = HRBb.new( @bb.llx, @bb.lly, @bb.urx, @bb.ury ) unless @hrbb
+
+ # locate current [hr]boundingbox, which ha[s|ve] to be replaced
+ # assumptions: both in header, and hrbb no later than
+ # first line after bb.
+ slurp = ''
+ File.open( @path, $R ) do |fl|
+ slurp = fl.read( [File.size(@path),SAFESIZE].min )
+ end
+ pre_lines = slurp.split( /(\r\n?|\n)/ )
+ i_bb = -1
+ i_hrbb = -1
+ i = -1
+ i_end = -1
+ pre_length = 0
+ pre_lines.each do |l|
+ pre_length += l.length
+ i += 1
+ next if l =~ /(\r\n?|\n)/
+ if l =~ BB_PAT
+ i_bb = i
+ elsif l =~ HRBB_PAT
+ i_hrbb = i
+ elsif i_bb >= 0
+ i_end = i
+ break # stop looking; we expect hrbb next to bb
+ end # =~ BB_PAT
+ end # do |l,i|
+ fail EPBBError, "No boundingbox found in #{@path}" if i_bb < 0
+
+ # replace boundingbox[es] by editing initial part pre_block
+ # and copying the rest byte for byte
+ if i_hrbb < 0
+ # no old hrbb; replace bb with new bb and new hrbb
+ # pre_lines[i_bb+1] should match /\r\n?|\n/
+ pre_lines[i_bb].sub!( BB_PAT, @bb.comment +
+ pre_lines[i_bb+1] + @hrbb.hrcomment )
+ else
+ pre_lines[i_bb].sub!( BB_PAT, @bb.comment )
+ pre_lines[i_hrbb].sub!( HRBB_PAT, @hrbb.hrcomment )
+ end
+ oldpath = @path
+ @path = mktemp( 'eps' )
+ File.open( @path, $W ) { |fl|
+ fl.write( pre_lines[ 0 .. i_end ].join ) }
+ sliceFile( oldpath, @path, \
+ File.size( oldpath ) - pre_length, pre_length, $A )
+ return self
end # fix_bb
@@ -642,8 +851,6 @@ class PsPdf
# Convert eps to pdf.
# The eps should already have a boundingbox in the header.
- # When fix_bbox, let Ghostscript calculate a tight boundingbox.
- # For this, we require non-negative boundingbox coordinates.
def eps_to_pdf( params={} )
@@ -651,7 +858,7 @@ class PsPdf
fail EPCallError, buginfo( params ) unless @type == 'eps' and @atfront
- wrp = @bb.wrapper
+ wrp = ( $settings.use_hires_bb and @hrbb ) ? @hrbb.wrapper : @bb.wrapper
retVal = PsPdf.new( 'ext' => 'pdf' )
cmd = "\"#{$settings.gs_prog}\" #{PsPdf.gs_options}" +
@@ -687,7 +894,7 @@ class PsPdf
" -paper match -eps -f #{page} -l #{page}" +
" \"#{@path}\" \"#{retVal.path}\""
else
- cmd = "\"#{$settings.gs_prog}\" -sDEVICE=epswrite" +
+ cmd = "\"#{$settings.gs_prog}\" -sDEVICE=epswrite -r600" +
" #{PsPdf.gs_options}" +
" -dFirstPage=#{page}" +
" -dLastPage=#{page}" +
@@ -696,24 +903,28 @@ class PsPdf
write_log cmd # if $DEBUG
fail EPSystemError, cmd unless \
system( cmd ) and test( ?s, retVal.path )
+
# fix for incorrect DSC header produced by some versions of pdftops:
# if necessary, change line `% Produced by ...' into `%%Produced by ...'
+# this is usually the second line.
# otherwise the DSC header would be terminated before the bbox comment
-# this bug has been reported, but not yet acted upon.
-# match first 500 chars against `% Produced by'
- fhead = ''
+# match first chk_ze chars against `% Produced by'
+ chk_size = [ 1500, File.size( retVal.path ) ].min
+ slurp = ''
File.open( retVal.path, $R ) do |fl|
- fhead = fl.read( 500 )
+ slurp = fl.read( chk_size )
end # File
- if fhead.match( /[\r\n]% Produced by/ )
+ pdfpat = /([\r\n])% Produced by/m
+ if slurp =~ pdfpat
newpath = mktemp( 'eps' )
write_log "pdftops header fix #{retVal.path} => #{newpath}"
File.open( newpath, $W ) do |fl2|
- fl2.write( fhead.sub( /([\r\n])(% Produced by)/, '\1%%Produced by' ) )
+ fl2.write( slurp.sub( pdfpat, '\1%% Produced by)' ) )
end
- sliceFile( retVal.path, newpath, File.size( retVal.path ) - 500, 500, $A )
+ sliceFile( retVal.path, newpath, File.size( retVal.path ) - chk_size,
+ chk_size, $A )
retVal.path = newpath
- end
+ end # if =~
# end fix for incorrect DSC header produced by some versions of pdftops
retVal.atfront = 1
retVal.find_bb_simple
@@ -751,12 +962,18 @@ class PsPdf
sep = params[ 'sep' ]
page = params[ 'page' ] ? params[ 'page' ].to_s : nil
- fail EPCallError, buginfo( params ) unless \
- $settings.pdftops_prog and $settings.use_pdftops and @type == 'pdf'
+ fail EPCallError, buginfo( params ) unless @type == 'pdf'
retVal = PsPdf.new( 'ext' => 'ps' )
- cmd = "\"#{$settings.pdftops_prog}\" #{PsPdf.ps_options( sep )}" +
- ( page ? " -f #{page} -l #{page}" : '' ) +
- " -paper match \"#{@path}\" \"#{retVal.path}\""
+ if $settings.pdftops_prog and $settings.use_pdftops
+ cmd = "\"#{$settings.pdftops_prog}\" #{PsPdf.ps_options( sep )}" +
+ ( page ? " -f #{page} -l #{page}" : '' ) +
+ " -paper match \"#{@path}\" \"#{retVal.path}\""
+ else
+ cmd = "\"#{$settings.gs_prog}\" #{PsPdf.gs_options}" +
+ " -sDEVICE=pswrite -r600" +
+ ( page ? " -dFirstPage=#{page} -dLastPage#{page}" : '' ) +
+ " -sOutputFile=\"#{retVal.path}\"" + " \"#{@path}\""
+ end
write_log cmd # if $DEBUG
fail EPSystemError, cmd unless \
system( cmd ) and test( ?s, retVal.path )
@@ -793,14 +1010,11 @@ class PsPdf
# an extra roundtrip.
# The separable color conversion is an option of pdftops.
- gRAY = nil unless \
- ( $settings.pdftops_prog and $settings.use_pdftops )
-
pp = self
pp = pp.eps_clean if pp.type == 'epsPreview'
pp = pp.eps_clean if pp.type == 'eps' and \
- not ( pp.bb and pp.atfront )
+ not ( pp.bb and pp.atfront ) # => not yet `cleaned'
pp.pdf_pages if pp.type == 'pdf' and not pp.npages
case pp.type
@@ -931,7 +1145,7 @@ save_settings = false
opts = OptionParser.new do |opts|
# for help output
- opts.banner = "Epspdf 0.3.0"
+ opts.banner = "Epspdf 0.4.0"
opts.separator "Convert between [e]ps and pdf formats"
opts.separator "Usage: epspdf.rb [options] infile [outfile]"
opts.separator ""
@@ -941,30 +1155,68 @@ opts = OptionParser.new do |opts|
" if infile is file.pdf"
opts.separator ""
- opts.on( "-I",
- "Ignore pdftops even if available",
- "(default: use if available)" ) do |opt|
- $settings.ignore_pdftops = '1'
+ opts.on( "-g", "--gray", "--grey",
+ "Convert to grayscale;",
+ "success not guaranteed" ) do |opt|
+ $options.gray = true
end
- opts.on( "-U",
- "Use pdftops if available",
- "(overrides previous -I setting)" ) do |opt|
- $settings.ignore_pdftops = '0'
+ opts.on( "-G", "--GRAY", "--GREY",
+ "Try harder to convert to grayscale" ) do |opt|
+ $options.gRAY = true
+ end
+
+ opts.on( "-p PAGENUMBER", "--pagenumber=PAGENUMBER",
+ "Page to be converted or selected", Integer ) do |opt|
+ $options.page = opt
+ end
+
+ opts.on( "-b", "--bbox", "--BoundingBox",
+ "Compute tight boundingbox" ) do |opt|
+ $options.bbox = true
end
- opts.on( "-T TARGET", "--target=TARGET", PDF_TARGETS,
+ opts.on( "-n", "--no-hires",
+ "Don't use hires boundingbox" ) do |opt|
+ $settings.ignore_hires_bb = '1'
+ end
+
+ opts.on( "-r", "--hires",
+ "Use hires boundingbox" ) do |opt|
+ $settings.ignore_hires_bb = '0'
+ end
+
+ opts.on( "-T TARGET", "--target=TARGET",
+ PDF_TARGETS,
"Target use of pdf; one of",
"#{PDF_TARGETS.join( ', ' )}" ) do |opt|
$settings.pdf_target = opt
end
- opts.on( "-V VERSION", "--version=VERSION", PDF_VERSIONS,
- "Pdf version to be generated;",
- "one of #{PDF_VERSIONS.join( ', ' )}" ) do |opt|
+ opts.on( "-N PDFVERSION", "--pdfversion=PDFVERSION",
+ PDF_VERSIONS,
+ "Pdf version to be generated" ) do |opt|
$settings.pdf_version = opt
end
+ opts.on( "-V PDFVERSION", "--version=PDFVERSION",
+ PDF_VERSIONS,
+ "Deprecated; use `-N' or `--pdfversion'." ) do |opt|
+ $settings.pdf_version = opt
+ end
+
+ opts.on( "-I",
+ "Ignore pdftops even if available",
+ "(default: use if available)" ) do |opt|
+ $settings.ignore_pdftops = '1'
+ end
+
+ opts.on( "-U",
+ "Use pdftops if available",
+ "(overrides previous -I setting)" ) do |opt|
+ $settings.ignore_pdftops = '0'
+ end
+
opts.on( "-C CUSTOMOPTIONS", "--custom=CUSTOMOPTIONS",
"Custom options for conversion to pdf,",
"view Use.htm and ps2pdf.htm from",
@@ -973,34 +1225,12 @@ opts = OptionParser.new do |opts|
end
opts.on( "-P PSOPTIONS", "--psoptions=PSOPTIONS",
- "Options for pdftops; default -level2,",
+ "Options for pdftops; default -level3,",
"don't include -eps or page number options;",
"these will be generated by the program" ) do |opt|
$settings.ps_options = opt
end
- opts.on( "-p PAGENUMBER", "--pagenumber=PAGENUMBER",
- "Page to be converted or selected", Integer ) do |opt|
- $options.page = opt
- end
-
- opts.on( "-b", "--bbox", "--BoundingBox",
- "Compute tight boundingbox" ) do |opt|
- $options.bbox = true
- end
-
- opts.on( "-g", "--gray", "--grey",
- "Convert to grayscale;",
- "success not guaranteed" ) do |opt|
- $options.gray = true
- end
-
- opts.on( "-G", "--GRAY", "--GREY",
- "Try harder to convert to grayscale;",
- "success still not guaranteed" ) do |opt|
- $options.gRAY = true
- end
-
opts.on( "-i", "--info",
"Info: display detected filetype" ) do |opt|
$options.info = true
@@ -1017,15 +1247,17 @@ opts = OptionParser.new do |opts|
opts.separator ""
+ opts.on( "-v", "Prints version info" ) do |opt|
+ puts EPVERSION
+ exit
+ end
+
opts.on_tail("-h", "--help", "Show this message") do
+ puts "Epspdf version " + EPVERSION
+ puts "Copyright (C) " + COPYRIGHT + " Siep Kroonenberg"
puts opts
exit
end
-
- # opts.on_tail("--version", "Show version") do
- # puts OptionParser::Version.join('.')
- # exit
- # end
end # opts
# parse options destructively
diff --git a/Master/texmf-dist/scripts/epspdf/epspdfboot.rb b/Master/texmf-dist/scripts/epspdf/epspdfboot.rb
deleted file mode 100644
index bdcebb77b26..00000000000
--- a/Master/texmf-dist/scripts/epspdf/epspdfboot.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# Manipulate library path and maybe search path.
-
-# Problem to be solved:
-
-# We don't want to require Windows users to install Ruby and Tcl/Tk so
-# we offer a package with a built-in Ruby subset. This subset is
-# slightly modified from the subset created by rubyscript2exe
-# (http://www.erikveen.dds.nl/rubyscript2exe/).
-
-# The rubyscript2exe directory structure is simplified compared to the
-# original Ruby directory structure, so we need to modify the library
-# search path and also the general search path.
-
-# Assumptions:
-
-# - The script itself is at the root or in a toplevel subdirectory.
-# - If an rbconfig.rb is found at the root or in
-# a toplevel directory then there is a Ruby subset.
-# If that is the Ruby which is used
-# then it needs help to find its files.
-
-dir = File.expand_path( File.dirname( __FILE__ ) )
-parent = File.dirname( dir )
-parent_sl = parent.dup + ( parent =~ /[\\\/]$/ ? '' : '/' )
-dir_sl = dir.dup + ( parent =~ /[\\\/]$/ ? '' : '/' )
-spath = ENV['PATH'].dup
-
-if test( ?e, parent_sl + 'lib/rbconfig.rb' )
- root_sl = parent_sl
-elsif test( ?e, dir_sl + 'lib/rbconfig.rb' )
- root_sl = dir_sl
-else
- root_sl = nil
-end
-
-if root_sl
- $: << "#{root_sl}lib"
-end
-
-$:.unshift( dir )
diff --git a/Master/texmf-dist/scripts/epspdf/epspdfrc.rb b/Master/texmf-dist/scripts/epspdf/epspdfrc.rb
index aa64309a822..acdbd9ac5e4 100755
--- a/Master/texmf-dist/scripts/epspdf/epspdfrc.rb
+++ b/Master/texmf-dist/scripts/epspdf/epspdfrc.rb
@@ -1,20 +1,16 @@
+EPVERSION = '0.4.0'
+COPYRIGHT = '2006, 2008, 2009'
+
# epspdf conversion utility, configuration module
#####
-# Copyright (C) 2006, 2008 Siep Kroonenberg
+# Copyright (C) 2006, 2008, 2009 Siep Kroonenberg
# n dot s dot kroonenberg at rug dot nl
#
# This program is free software, licensed under the GNU GPL, >=2.0.
# This software comes with absolutely NO WARRANTY. Use at your own risk!
#####
-# This version has been adapted for TeX Live. The adaptations only
-# concern Windows. If TL is set then pdftops and
-# ghostscript are set to the version included in TeXLive, settings are
-# stored in HKCU\software\epspdftl (rather than epspdf) and the logfile
-# is %USERPROFILE%\epspdftl.log, rather than epspdf.log.
-# A future version should offer a dynamic way of settingt his option.
-
# Settings are stored in a settings hash, with some methods added
# for less unwieldy notation.
#
@@ -43,112 +39,145 @@ else
'unix'
end
-TL = ENV.has_key?('TLROOT')
if ARCH == 'w32'
+ # registry and API calls
require 'dl/win32'
require 'win32/registry'
include Win32 # this lets us abbreviate Win32::Registry to Registry
+ # lay groundwork for short_name function
ShortPName = Win32API.new(
'kernel32', 'GetShortPathName', ['P','P','N'], 'N' )
- TLROOT = ENV['TLROOT']
+ # shellopen function
+ ShellEx = Win32API.new(
+ 'shell32','ShellExecute', ['L','P','P','P','P','L'], 'L' )
+ #FindEx = Win32API.new(
+ # 'shell32','FindExecutable', ['P','P','P'], 'L' )
+ # from winuser.h:
+ SW_SHOWNORMAL = 1
end
-# for Windows, use short names within backquotes
-# to avoid quotes within backquotes
-
+# need short_name function to get around limitations of w2k quoting
def short_name( fn )
+ #puts "Calculate short name for #{fn}\n"
return fn if ARCH != 'w32'
- fn.gsub!( /\\/, '/' )
+ fn.gsub!( /\//, "\\" )
buffer = ' ' * 260
length = ShortPName.call( fn, buffer, buffer.size )
- return ( length > 0 ) ? buffer.slice(0..length-1) : fn
+ fn = buffer.slice(0..length-1) if length > 0
+ fn.gsub!( /\\/, '/' )
+ return fn
+end
+
+def shell_open( fn )
+ return nil if ARCH != 'w32'
+ result = ShellEx.call( 0, 0, fn, 0, 0, SW_SHOWNORMAL )
end
+def shell_open_with( fn )
+ return nil if ARCH != 'w32'
+ result = ShellEx.call( 0, 0, "RUNDLL32.EXE", "shell32.dll,OpenAs_RunDLL #{fn}",
+ 0, SW_SHOWNORMAL )
+end
+
+# interpret error value for shell_open
+# values <=32 indicate error
+# constants defined in winerror.h, shellapi.h
+
+def shell_error_string ( e )
+ if e > 32
+ returl nil
+ else
+ return case e
+ when 0: "Out of memory or resources"
+ #define ERROR_FILE_NOT_FOUND 2L
+ #define SE_ERR_FNF 2
+ when 2: "File not found"
+ #define ERROR_PATH_NOT_FOUND 3L
+ #define SE_ERR_PNF 3
+ when 3: "Path not found"
+ #define SE_ERR_ACCESSDENIED 5
+ when 5: "Access denied"
+ #define SE_ERR_OOM 8
+ when 8: "Not enough memory"
+ #define ERROR_BAD_FORMAT 11L
+ when 11: "Invalid exe"
+ #define SE_ERR_SHARE 26
+ when 26: "Sharing violation"
+ #define SE_ERR_ASSOCINCOMPLETE 27
+ when 27: "Invalid file association"
+ #define SE_ERR_DDETIMEOUT 28
+ when 28: "DDE timeout"
+ #define SE_ERR_DDEFAIL 29
+ when 29: "DDE fail"
+ #define SE_ERR_DDEBUSY 30
+ when 30: "DDE busy"
+ #define SE_ERR_NOASSOC 31
+ when 31: "No file association"
+ #define SE_ERR_DLLNOTFOUND 32
+ when 32: "DLL not found"
+ else "Unspecified error"
+ end # case
+ end # else
+end # def
+
# system-dependent location of logfile
LOGFILE = case ARCH
when 'w32'
- TL ? "#{ENV['USERPROFILE']}\\epspdftl.log" :
"#{ENV['USERPROFILE']}\\epspdf.log"
else
- "#{ENV['HOME']}//epspdf.log"
+ "#{ENV['HOME']}/epspdf.log"
end
LOGFILE_OLD = LOGFILE + '.old'
# system-dependent locations of saved settings
-RC_FILE = "#{ENV['HOME']}/.epspdfrc"
-REG_K = TL ? 'epspdftl' : 'epspdf'
-REG_KEY = TL ? 'SOFTWARE\\epspdftl' : 'SOFTWARE\\epspdf'
+RC_FILE = "#{ENV['HOME']}/.epspdfrc" # not used under Windows
+REG_K = 'epspdf'
+REG_KEY = 'SOFTWARE\\epspdf'
# hash of saved settings from rc file or registry
$rc_settings = {}
-# find open command for extension (w32 only)
-
-def open_with( ext )
- ext = '' unless ext
- answer = nil
- if ARCH == 'w32'
- begin # open cl = HKCR\ext safely
- Registry::HKEY_CLASSES_ROOT.open(
- (ext =~ /^\./ ? ext : '.'+ext) ) do |cl|
- begin # read ftype safely
- ftype = cl.read_s( nil )
- begin # open cmd = HKCR\ftype\shell... safely
- Registry::HKEY_CLASSES_ROOT.open(
- ftype + '\\shell\\open\\command' ) do |cmd|
- begin # read answer safely
- answer = cmd.read_s( nil )
- if answer =~ /^"([^"]+)".*/
- answer = $1
- elsif answer =~ /^([^ ]+) .*/
- answer = $1
- end
- answer = nil unless answer and test( ?s, answer )
- rescue # answer not read
- end # read answer safely
- end # HKCR\ftype\shell... do |cmd|
- rescue # cmd not opened
- end # open cmd = HKCR\ftype\shell... safely
- rescue # ftype not read
- end # read ftype safely
- end # HKCR\ext do |cl|
- rescue # cl not opened
- end # open cl = HKCR\ext safely
- end # w32
- answer
-end
-
# test whether a string is a valid program call
# 'which' also works with explicit paths.
# 'which' returns an error for non-executable files.
+# Linux/Unix OS X: for testing existence of gs, pdftops and ps/pdf viewers
+# Mac OS X: for testing existence of gs and pdftops
+# Windows: function not usable and not used
def is_a_program( s )
case ARCH
when 'w32'
nil
else
- ( system "which #{s} >/dev/null" ) ? 1 : nil
+ ( system "which #{s} >/dev/null 2>&1" ) ? 1 : nil
end
end # is_a_program
-# Parse version info from a prog from the xpdf suite.
-# This is used as validity test.
-
-def xpdf_version( arg )
- retval = nil
- arg = short_name( arg ) if ARCH == 'w32'
- version_output = `#{arg} -v 2>&1`
- if version_output and not version_output.empty?
- vo = version_output.split(/\r\n?|\n/)
- vo.grep(/version/i) { |a|
- a =~ /^\D*(\d+\.\w*)\b/
- retval = $& # matched part; nil if no match
- }
+# for Windows, use the registry or the following function instead:
+
+def find_on_path( s )
+ # for now, Windows-only; parameter s with or without path
+ if ARCH != 'w32'
+ return nil
end
- retval
+ ENV['PATH'].gsub( "\\", "/" ).split( /;/ ).each do |d|
+ d = File.expand_path( d ) # this seems a syntactic operation
+ s_full = d.sub( /\/$/, '' ) + '/' + s
+ if test( ?d, d ) and test( ?f, s_full )
+ return s_full
+ end
+ ENV['PATHEXT'].split( /;/ ).each do |e|
+ # components of PATHEXT should include leading dot
+ s_full = d.sub( /\/$/, '' ) + '/' + s + e
+ if test( ?f, s_full )
+ return s_full
+ end
+ end # do |e|
+ end # do |d|
+ return nil
end
class Setting
@@ -167,30 +196,56 @@ PDF_VERSIONS = [ '1.2', '1.3', '1.4', 'default' ]
$settings = {
# converters
+ # ghostscript: under windows it must be told about its directories,
+ # so we don't want users to mess with it.
+ # If they really want to, they can manually edit PATH and set GS_LIB
'gs_prog' => Setting.new( nil, 'auto', nil ),
- 'gs_version' => Setting.new( nil, 'auto', nil ),
+ #'gs_version' => Setting.new( nil, 'auto', nil ),
'pdftops_prog' => Setting.new( nil, ARCH=='w32' ? 'config' : 'auto', nil ),
- # viewers
+ # epspdftk: viewers
'pdf_viewers' => Setting.new( nil, ARCH=='unix' ? 'auto' : nil, nil ),
'ps_viewers' => Setting.new( nil, ARCH=='unix' ? 'auto' : nil, nil ),
'pdf_viewer' => Setting.new( nil, ARCH=='unix' ? 'config' : 'auto', nil ),
'ps_viewer' => Setting.new( nil, ARCH=='unix' ? 'config' : 'auto', nil ),
+ # epspdftk: initial dir
+ 'defaultDir' => Setting.new( nil, 'config', nil ),
# conversion options
'ignore_pdftops' => Setting.new( '0', 'config',
'Ignore pdftops even if available; 1=yes, empty or 0=no(default)' ),
'pdf_target' => Setting.new( 'prepress', 'config',
'Target: screen, ebook, print, prepress (default) or default' ),
- 'pdf_version' => Setting.new( '1.4', 'config',
- 'Pdf version: e.g 1.4 or 1.2 (fewer features, more compatibility)' +
- ' or unspecified' ),
+ 'pdf_version' => Setting.new( 'default', 'config',
+ 'Pdf version: e.g 1.4 or 1.2 or default' ),
'pdf_custom' => Setting.new( '', 'config',
'additional options for [e]ps to pdf conversion' ),
- 'ps_options' => Setting.new( '-level2', 'config',
- 'options for pdftops; default -level2' ),
+ 'ps_options' => Setting.new( '-level3', 'config',
+ 'options for pdftops; default -level3' ),
+ 'ignore_hires_bb' => Setting.new( '0', 'config',
+ 'Ignore hi-res boundingbox for pdf generation;' +
+ ' 1=yes, empty or 0=no(default)' ),
'bb_spread' => Setting.new( '1', 'config',
- 'margin to be added to computed boundingbox; default 1' )
+ 'margin to be added to computed lores boundingbox; default 1' )
}
+# Using pdftops or a hires boundingbox should be the norm, not the exception.
+# We emphasize this by naming the corresponding options ignore_pdftops and
+# ignore_hires_bb, and letting them default to false.
+
+def reverse_of( x )
+ case x
+ when /t(rue)?|y(es)?|1/i
+ false
+ when /f(alse)?|n(o)?|0/i
+ true
+ when 1
+ false
+ when 0
+ true
+ else
+ true
+ end
+end
+
class << $settings
# create shortcut methods $settings.x and $settings.x=
@@ -201,47 +256,15 @@ class << $settings
eval "def #{k}=(v) ; self[\'#{k}\'].val=v ; end"
}
- # use_pdftops is a boolean counterpart and inverse
- # of the stored string attribute ignore_pdftops
+ # use_pdftops and use_hires_bb are a boolean counterparts and inverses
+ # of the stored string attributes ignore_pdftops and ignore_hires_bb
- def use_pdftops
- case self['ignore_pdftops'].val
- when /t(rue)?|y(es)?|1/i
- false
- when /f(alse)?|n(o)?|0/i
- true
- when 1
- false
- when 0
- true
- else
- true
- end
+ def use_hires_bb
+ reverse_of( self['ignore_hires_bb'].val )
end
- # we want use_pdftops = nil = default = true but
- # we also want use_pdftops = nil <=> use_pdftops = false
- # we give the second one priority.
-
- def use_pdftops=( x )
- self['ignore_pdftops'].val = case x
- when /t(rue)?|y(es)?|1/i
- '0'
- when /f(alse)?|n(o)?|0/i
- '1'
- when 1
- '0'
- when 0
- '1'
- when false
- '1'
- when nil # try to avoid this assignment
- '1'
- when true
- '0'
- else
- '1'
- end
+ def use_pdftops
+ reverse_of( self['ignore_pdftops'].val )
end
def accept_pdf_viewer( s )
@@ -337,7 +360,7 @@ class << $settings
end
else
File.open( RC_FILE, 'w' ) do |f|
- f.write( "# This file will be overwritten by epspdf_tk[.rb]" \
+ f.write( "# This file will be overwritten by epspdf[tk][.rb]" \
+ $/ )
$settings.each do |key, st|
if st.type == 'config'
@@ -355,26 +378,40 @@ class << $settings
def get_settings
# phase 1: autodetect
- # w32: gs_prog, gs_version, pdf_viewer, ps_viewer
- # gs: search registry settings; the highest version wins.
- # viewers: check file type registry entry for valid open commands
- # w32/TL: gs_prog, gs_version, pdf_viewer, ps_viewer
- # gs: from TL
- # viewers: check file type registry entry for valid open commands
- # unix: gs_prog, gs_version, pdftops_prog, pdf_viewers, ps_viewers
- # osx: gs_prog, gs_version, pdftops_prog
+ # w32: gs_prog, pdf_viewer, ps_viewer
+ # gs: search path; search registry settings (user and system);
+ # search tex installation. The first one wins.
+ # viewers: check file type registry entry for valid open commands
+ # unix: gs_prog, pdftops_prog, pdf_viewers, ps_viewers
+ # osx: gs_prog, pdftops_prog
# viewers: use Preview; don't check anything
# unix/osx are done together, except that for osx
# the viewers code is skipped.
+ # Windows: test for TeX, because it may come with a hidden
+ # ghostscript. TeX may also come with pdftops.exe, but pdftops
+ # would then be on the searchpath and not require special treatment.
+
+ texbindir = ( ARCH == 'w32' ) ? find_on_path( 'tex' ) : nil
+ texbindir = short_name( File.dirname( texbindir ) ) if texbindir
+
case ARCH
when 'w32'
- if !TL then # else use built-in texlive versions
- # check registry for latest valid version of Ghostscript
- # tentative values; HKLM and HKCU may provide different values
- try_gs_version = nil
+ # ghostscript:
+ # 1. check searchpath
+ # 2. check registry for latest valid version of Ghostscript
+ # 3. check tex installation
+ # TeX Live- and MikTeX versions need environment variables
+ # no need to remember: it will be the last thing we try
+ # searchpath
+ self.gs_prog = find_on_path( 'gswin32c' )
+
+ if not self.gs_prog
+ try_gs_version = 0
try_gs_prog = nil
+ this_gs_prog = nil
+ # tentative values; HKLM and HKCU may provide different values
[Registry::HKEY_LOCAL_MACHINE,
Registry::HKEY_CURRENT_USER].each { |hk|
puts hk.to_s if $DEBUG
@@ -384,55 +421,75 @@ class << $settings
puts key.to_s if $DEBUG
if key =~ /ghostscript/i
gh = hk.open('SOFTWARE\\' + key)
- gh.each_key { |skey, wtime|
- if skey =~ /^\d+\.\d+$/ # version number
- if skey.to_f > try_gs_version.to_f
- this_gs = hk.open('SOFTWARE\\' + key + '\\' + skey)
+ gh.each_key { |this_gs_version, wtime|
+ if this_gs_version =~ /^\d+\.\d+/ # version number
+ if this_gs_version.to_f > try_gs_version.to_f
+ this_gs = hk.open('SOFTWARE\\' + key +
+ '\\' + this_gs_version)
this_gs_prog = this_gs['GS_DLL'].sub(
/([\\\/])([^\\\/]+)$/, '\1gswin32c.exe')
if test(?e,this_gs_prog)
- try_gs_version = skey
+ try_gs_version = this_gs_version
try_gs_prog = this_gs_prog
end # if ?e (exist)
- end # skey.to_f > try_gs_version.to_f
- end # if skey =~ /^\d+\.\d+$/
+ end # this_gs_version.to_f > try_gs_version.to_f
+ end # if this_gs_version =~ /^\d+\.\d+$/
} # gh.each_key
end # if key =~ /ghostscript/i
} # sof.each_key
} # hk.open |sof|
} # [HKCU, HKLM].each
- self.gs_version = try_gs_version
- self.gs_prog = try_gs_prog
- end
-
- # viewers
- self.pdf_viewer = open_with( 'pdf' )
- self.ps_viewer = open_with( 'ps' )
+ self.gs_prog = this_gs_prog if this_gs_prog
+ end # if not self.gs_prog
+ if texbindir and ! self.gs_prog
+ # TeX Live >= 2008:
+ # hidden gs in texbindir/../../tlpkg/tlgs
+ texroot = File.dirname( File.dirname( File.expand_path( texbindir )))
+ gsroot = texroot + '/tlpkg/tlgs'
+ this_gs_prog = gsroot + '/bin/gswin32c.exe'
+ if test( ?f, this_gs_prog )
+ self.gs_prog = this_gs_prog
+ ENV['GS_LIB'] = "#{gsroot}/lib;#{gsroot}/fonts;#{gsroot}/Resource"
+ else # test for MikTeX hidden ghostscript
+ # http://blog.miktex.org/post/2005/04/
+ # Starting-mgsexe-at-the-DOS-Prompt.aspx
+ # That's because mgs.exe doesn't use the original registry keys
+ # and environment variables. For example, mgs.exe queries
+ # MIKTEX_GS_LIB instead of GS_LIB. You can start mgs.exe
+ # at the DOS-prompt if you set MIKTEX_GS_LIB as follows:
+ # MIKTEX_GS_LIB=C:\texmf\ghostscript\base;C:\texmf\fonts
+ this_gs_prog = texbindir + '/mgs.exe'
+ if test( ?f, this_gs_prog ) and
+ test( ?d, "#{texroot}/ghostscript/base" )
+ self.gs_prog = this_gs_prog
+ ENV['MIKTEX_GS_LIB'] =
+ "#{texroot}/ghostscript/base;#{texroot}/fonts"
+ end # ?f, this_gs_prog
+ end # try MikTeX hidden Ghostscript
+ end # texbindir and ! self.gs_prog
+ fail( "No ghostscript" ) unless self.gs_prog
+ self.gs_prog = short_name( self.gs_prog )
+
+ # pdftops: just check the searchpath
+ self.pdftops_prog = find_on_path( 'pdftops' )
when /unix|osx/
# gs
- answer = `gs --version`
- if answer and not answer.empty?
- self.gs_prog = 'gs'
- self.gs_version = answer.chomp
- else
- self.gs_prog = nil
- self.gs_version = nil
- end
+ self.gs_prog = is_a_program( 'gs' ) ? 'gs' : nil
# pdftops
- self.pdftops_prog = xpdf_version( 'pdftops' ) ? 'pdftops' : nil
+ self.pdftops_prog = is_a_program( 'pdftops' ) ? 'pdftops' : nil
# viewers
if ARCH == 'unix'
- vw = %w{ gpdf xpdf acroread evince ggv gv kghostview }
+ vw = %w{ evince gpdf xpdf acroread epdfview gv gsview okular }
vw.delete_if { |x| not is_a_program( x ) }
vw = nil if vw.empty?
self.pdf_viewers = vw
self.pdf_viewer = vw ? vw[0] : nil
if vw
vw2 = vw.dup # copy the elements rather than the array ref
- [ 'gpdf', 'xpdf', 'acroread' ].each { |pg|
+ [ 'gpdf', 'xpdf', 'acroread', 'epdfview' ].each { |pg|
vw2.delete( pg ) if vw2.index( pg )
}
vw2 = nil if vw2.empty?
@@ -440,7 +497,8 @@ class << $settings
self.ps_viewer = vw2 ? vw2[ 0 ] : nil
end # if vw
end # if unix
- end # case
+
+ end # case ARCH
# built-in defaults already set during initialization of $settings
@@ -452,21 +510,10 @@ class << $settings
case ARCH
when 'w32'
- $rc_settings[ 'pdftops_prog' ] = (
- TL ? (TLROOT.gsub( /\//, '\\' ) + '\\bin\\win32\\pdftops.exe') :
- "z:\\aps\\staff\\ber\\miktex\\xpdf\\pdftops.exe" ) unless
- ( $rc_settings[ 'pdftops_prog' ] and
- ! $rc_settings[ 'pdftops_prog' ].empty? )
- ptop = $rc_settings[ 'pdftops_prog' ]
- if xpdf_version( ptop ) then
- self.pdftops_prog = ptop
- end
- if TL
- self.gs_prog = TLROOT.gsub( /\//, '\\' ) +
- '\\tlpkg\\tlgs\\bin\\gswin32c.exe'
- self.gs_version =
- ( `#{short_name( self.gs_prog )} --version` ).chomp
- end
+ self.pdftops_prog = $rc_settings[ 'pdftops_prog' ] if
+ $rc_settings[ 'pdftops_prog' ] and
+ ! $rc_settings[ 'pdftops_prog' ].empty? and
+ test( ?f, $rc_settings[ 'pdftops_prog' ] )
when 'unix'
if v = $rc_settings[ 'pdf_viewer' ] and is_a_program( v )
self.pdf_viewer = v
@@ -482,22 +529,44 @@ class << $settings
end # if
end # case ARCH
+ if ( $rc_settings[ 'defaultDir' ] and
+ ( not $rc_settings[ 'defaultDir' ].strip.empty? ) and
+ test( ?d, $rc_settings[ 'defaultDir' ] ) )
+ self.defaultDir = File.expand_path( $rc_settings[ 'defaultDir' ] )
+ else
+ self.defaultDir = Dir.getwd
+ end
+ #print "defaultDir set to #{self.defaultDir} by epspdfrc.getsettings"
+
+
# no validity checks for pdf- and ps output options.
# reminder: self.s shortcut for self['s'].val
[ 'pdf_target', 'pdf_version', 'pdf_custom', 'ps_options' ].each { |p|
self[ p ].val = $rc_settings[ p ] if $rc_settings[ p ]
}
if $rc_settings.has_key?( 'ignore_pdftops' )
- $settings.ignore_pdftops = case $rc_settings[ 'ignore_pdftops' ]
+ self.ignore_pdftops = case $rc_settings[ 'ignore_pdftops' ]
+ when /1|yes|true|y|t/i
+ '1'
+ when /0|no|false|n|f/i
+ '0'
+ end
+ else
+ self.ignore_pdftops = '0'
+ end
+
+ if $rc_settings.has_key?( 'ignore_hires_bb' )
+ self.ignore_hires_bb = case $rc_settings[ 'ignore_hires_bb' ]
when /1|yes|true|y|t/i
'1'
when /0|no|false|n|f/i
'0'
end
else
- $settings.ignore_pdftops = '0'
+ self.ignore_hires_bb = '0'
end
+ # bb_spread has an effect only if ignore_hires_bb
self.bb_spread = $rc_settings[ 'bb_spread' ] if
$rc_settings.has_key?( 'bb_spread' ) and
$rc_settings[ 'bb_spread' ] =~ /^[+-]?[\d]+$/
diff --git a/Master/texmf-dist/scripts/epspdf/epspdftk b/Master/texmf-dist/scripts/epspdf/epspdftk
index 6d3465a8c4b..95c551cf8c1 100755
--- a/Master/texmf-dist/scripts/epspdf/epspdftk
+++ b/Master/texmf-dist/scripts/epspdf/epspdftk
@@ -3,5 +3,5 @@ script=`kpsewhich -format=texmfscripts epspdftk.rb`
if test "x$1" = "x"; then
"$script" $HOME
else
- "$script" $*
+ "$script" "$@"
fi \ No newline at end of file
diff --git a/Master/texmf-dist/scripts/epspdf/epspdftk.rb b/Master/texmf-dist/scripts/epspdf/epspdftk.rb
index 356ec78d620..79dbdd5d325 100755
--- a/Master/texmf-dist/scripts/epspdf/epspdftk.rb
+++ b/Master/texmf-dist/scripts/epspdf/epspdftk.rb
@@ -3,7 +3,7 @@
# epspdf conversion utility, GUI frontend
#####
-# Copyright (C) 2006, 2008 Siep Kroonenberg
+# Copyright (C) 2006, 2008, 2009 Siep Kroonenberg
# n dot s dot kroonenberg at rug dot nl
#
# This program is free software, licensed under the GNU GPL, >=2.0.
@@ -12,10 +12,8 @@
#$DEBUG=1
-# epspdfboot.rb: modify loadpath in a way which works both
-# with a full Ruby and with a custom subset ruby
-
-require __FILE__.sub( /epspdftk\.rbw?/, 'epspdfboot.rb' )
+# find other pieces of epspdf
+$:.unshift( File.dirname( __FILE__ ) )
##########################################
@@ -31,25 +29,21 @@ $VERBOSE = nil
if $DEBUG
puts ARCH
puts Config::CONFIG['arch']
- puts "Ghostscript command #{$settings.gs_prog}" \
- " and version #{$settings.gs_version}"
- puts "Pdftops command #{$settings.pdftops_prog}" \
- " and version #{$settings.pdftops_version}"
+ puts "Ghostscript command #{$settings.gs_prog}"
+ puts "Pdftops command #{$settings.pdftops_prog}"
end
+# is there a viewer for the PsPdf object p?
+
def viewable( p )
return nil unless p && p.path
return nil if p.type == 'other'
case ARCH
- when 'osx'
- return true
- when 'w32'
- return nil if p.type == 'epsPreview'
- return open_with( File.extname( p.path ) )
- else
- return nil if p.type == 'epsPreview'
+ when 'unix'
return true if p.type =~ /e?ps/ and ( not $settings.ps_viewer.empty? )
return true if p.type == 'pdf' and ( not $settings.pdf_viewer.empty? )
+ else
+ return true
end # case ARCH
return nil
end # viewable
@@ -79,6 +73,8 @@ static unsigned char dwnarrow.icn_bits[] = {
0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 };
STR
+BG = 'gray85'
+
class TkACombobox < TkFrame
include TkComposite
@@ -320,7 +316,7 @@ if not $settings.gs_prog
abort
end
-if ARCH != 'osx'
+if ARCH == 'unix'
if not $settings.pdf_viewer
Tk.messageBox( :icon=>'warning', :type=>'ok', :message =>
"No PostScript- or pdf viewer found" )
@@ -332,14 +328,17 @@ end
########################################
-$defaultDir = ENV['PWD']
+# defaultDir already initialized by epspdfrc
-$defaultDir = ARGV[0] if ((ARGV.length > 0) and File.directory?(ARGV[0]))
+if ((ARGV.length > 0) and (ARGV[0].length > 0) and File.directory?(ARGV[0]))
+ $settings.defaultDir = ARGV[0]
+ #print "Default dir set to #{ARGV[0]} by epspdftk"
+end
$source = PsPdf.new # currently loaded PsPdf object
$tl_config = nil # configuration screen
-$tl_wait = nil # instead of a wait cursor or progress bar
+# $tl_wait = nil # instead of a wait cursor or progress bar
# widgets which are configured on the fly,
# e.g. by ep_config, get a global name.
@@ -347,6 +346,7 @@ $tl_wait = nil # instead of a wait cursor or progress bar
# buttons and option widgets
$view_button = nil
+$view_with_button = nil
$page_radio = nil
$page_entry = nil
$type_radio = nil
@@ -366,6 +366,8 @@ def set_widget_states
$view_button.configure( :state =>
( viewable( $source ) ? 'normal' : 'disabled' ) )
+ $view_with_button.configure( :state =>
+ ( viewable( $source ) ? 'normal' : 'disabled' ) ) if ARCH == 'w32'
$save_button.configure( :state =>
( ( $source.type and $source.type != 'other' ) ? \
'normal' : 'disabled' ) )
@@ -431,16 +433,20 @@ def ep_config
if not $tl_config
- $tl_config = TkToplevel.new( $root, :title => 'Configure epspdf' )
+ $tl_config = TkToplevel.new( $root,
+ :title => 'Configure epspdf' )
### viewers frame
if ARCH == 'unix'
TkFrame.new( $tl_config ) { |frm|
frm.borderwidth 2
- frm.relief 'groove'
- TkLabel.new( frm, :text => 'VIEWERS'
- ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ frm.relief 'sunken'
+ TkLabel.new( frm ) do
+ text 'Viewers'
+ font.weight 'bold'
+ pack( :side => 'top', :padx => 8, :anchor => 'w' )
+ end
TkFrame.new( frm ) { |fm|
TkLabel.new( fm, :text => 'Pdf viewer' ).grid(
:in => fm, :row => 0, :column => 0,
@@ -461,13 +467,57 @@ def ep_config
}.pack( FRM_PACK )
end # if unix
+ ### pdf frame
+
+ TkFrame.new( $tl_config ){ |frm|
+ frm.borderwidth 2
+ frm.relief 'sunken'
+ TkLabel.new( frm ) do
+ text 'Conversion to pdf'
+ font.weight 'bold'
+ pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ end
+
+ # internal packing
+ pack_pdf = {
+ :side => 'left', :padx => 2, :pady => 4, :anchor => 'w' }
+
+ TkLabel.new( frm, :text => 'Target use'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+ $pdf_target_radio = TkRadios.new( frm,
+ 'values' => PDF_TARGETS, 'packing' => pack_pdf
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ # dummy widget for extra vertical space
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ TkLabel.new( frm, :text => 'Pdf version'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+
+ $pdf_version_radio = TkRadios.new( frm,
+ 'values' => PDF_VERSIONS, 'packing' => pack_pdf
+ ).pack( :side => 'top', :anchor => 'w' )
+
+ TkLabel.new( frm, :text => ' ' ).pack
+
+ TkLabel.new( frm, :text => 'Custom Ghostscript/ps2pdf parameters'
+ ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+
+ $pdf_custom_entry = TkEntry.new( frm, :width => 50
+ ).pack( :side => 'top', :padx => 2, :pady => 2, :anchor => 'w' )
+
+ }.pack( FRM_PACK )
+
### postscript frame
TkFrame.new( $tl_config ){ |frm|
frm.borderwidth 2
- frm.relief 'groove'
- TkLabel.new( frm, :text => 'POSTSCRIPT CONVERSION'
- ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ frm.relief 'sunken'
+ TkLabel.new( frm ) do
+ text 'Conversion to EPS and PostScript'
+ font.weight 'bold'
+ pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ end
if ARCH == 'w32' # others: assume pdftops on search path
TkLabel.new( frm, :text => "Find pdftops"
@@ -484,17 +534,11 @@ def ep_config
:parent => fm
)
if tryprog and ( not tryprog.empty? )
- if not xpdf_version( tryprog )
- Tk.messageBox(
- :icon => 'warning',
- :type => 'ok',
- :parent => fm,
- :message => "pdftops missing or dysfunctional"
- )
- else
+ tryprog.sub!( /([\/\\])[^\/\\]+$/, '\1pdftops.exe' )
+ if test( ?f, tryprog )
$pdftops_entry.delete( 0, 'end' )
$pdftops_entry.insert( 'end', tryprog )
- end # ifthenelse xpdf_version
+ end
end # ifthenelse tryprog
} # command lambda
).pack( :side => 'left' ) # TkButton
@@ -502,52 +546,37 @@ def ep_config
end # ARCH == 'w32'
$pdftops_check = TkACheck.new( frm,
- 'text' => "Use pdftops if available"
+ 'text' => "Use pdftops if available (recommended)"
).pack( :side => 'top', :pady => 4, :anchor => 'w' )
}.pack( FRM_PACK ) # TkFrame |frm|
- ### pdf frame
+ ### boundingbox frame
TkFrame.new( $tl_config ){ |frm|
frm.borderwidth 2
- frm.relief 'groove'
- TkLabel.new( frm, :text => 'PDF CONVERSION'
- ).pack( :side => 'top', :padx => 4, :anchor => 'w' )
-
- # internal packing
- pack_pdf = {
- :side => 'left', :padx => 2, :pady => 4, :anchor => 'w' }
-
- TkLabel.new( frm, :text => 'Intended use'
- ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
- $pdf_target_radio = TkRadios.new( frm,
- 'values' => PDF_TARGETS, 'packing' => pack_pdf
- ).pack( :side => 'top', :anchor => 'w' )
-
- # dummy widget for extra vertical space
- TkLabel.new( frm, :text => ' ' ).pack
-
- TkLabel.new( frm, :text => 'Pdf version'
- ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
-
- $pdf_version_radio = TkRadios.new( frm,
- 'values' => PDF_VERSIONS, 'packing' => pack_pdf
- ).pack( :side => 'top', :anchor => 'w' )
-
- TkLabel.new( frm, :text => ' ' ).pack
+ frm.relief 'sunken'
+ TkLabel.new( frm ) do
+ text 'Hires BoundingBox'
+ font.weight 'bold'
+ pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ end
- TkLabel.new( frm, :text => 'Custom Ghostscript/ps2pdf parameters'
- ).pack( :side => 'top', :padx => 2, :pady => 0, :anchor => 'w' )
+ TkLabel.new( frm ) do
+ text "Uncheck to prevent clipping"
+ pack( :side => 'top', :padx => 4, :anchor => 'w' )
+ end
- $pdf_custom_entry = TkEntry.new( frm, :width => 50
- ).pack( :side => 'top', :padx => 2, :pady => 2, :anchor => 'w' )
+ $hires_check = TkACheck.new( frm,
+ 'text' => "Use hires boundingbox if possible"
+ ).pack( :side => 'top', :pady => 4, :anchor => 'w' )
- }.pack( FRM_PACK )
+ }.pack( FRM_PACK ) # TkFrame |frm|
### button frame
TkFrame.new( $tl_config ) { |frm|
+ #frm.bg = BG
TkButton.new( frm,
:text => 'Cancel',
@@ -568,7 +597,8 @@ def ep_config
when 'w32'
$settings.pdftops_prog = $pdftops_entry.get
end
- $settings.use_pdftops = ( not $pdftops_check.value == '0' )
+ $settings.ignore_hires_bb = ( $hires_check.value == '0' ) ? '1' : '0'
+ $settings.ignore_pdftops = ( $pdftops_check.value == '0' ) ? '1' : '0'
$settings.pdf_target = $pdf_target_radio.value
$settings.pdf_version = $pdf_version_radio.value
$settings.pdf_custom = $pdf_custom_entry.get
@@ -595,6 +625,7 @@ def ep_config
$pdftops_entry.insert( 'end', $settings.pdftops_prog ) \
if $settings.pdftops_prog and not $settings.pdftops_prog.empty?
end # ifthenelse ARCH
+ $hires_check.value = $settings.use_hires_bb ? '1' : '0'
$pdftops_check.value = $settings.use_pdftops ? '1' : '0'
$pdf_target_radio.value = $settings.pdf_target
$pdf_version_radio.value = $settings.pdf_version
@@ -658,6 +689,39 @@ TkFrame.new( $root ) { |frm|
:command => lambda { ep_config }
).pack( :side => 'left', :padx => 4, :pady => 4 )
+ # There is pdf- and html help, and it would be simple enough to invoke
+ # either file from here, but for TL this would be in an entirely
+ # different directory, so instead we display an ascified helpfile
+ # packaged in the same directory as the code.
+
+# TkButton.new( frm,
+# :text => 'Help',
+# :command => lambda {
+# docdir = File.dirname( __FILE__ )
+# docdir.sub!( /[\\\/]$/, '' )
+# docdir = docdir + '/doc'
+# if ARCH == 'w32'
+# result = shell_open( docdir + "/epspdf_UG.html" )
+# Tk.messageBox(
+# 'icon' => 'error',
+# 'title' => 'ShellExecute error',
+# 'message' => shell_error_string( result )
+# ) if result <= 32
+# elsif ARCH == 'osx'
+# fork { exec "open \"#{docdir}/epspdf_UG.html\"" }
+# elsif $settings.pdf_viewer
+# fork { exec "\"#{$settings.pdf_viewer}\" \"#{docdir}/epspdf.pdf\"" }
+# else
+# Tk.messageBox(
+# 'icon' => 'warning',
+# 'title' => 'No help viewer',
+# 'message' => "Please select a pdf viewer in the configuration screen" +
+# "\nand restart this program."
+# )
+# end
+# }
+# ).pack( :side => 'right', :padx => 4, :pady => 4)
+
TkButton.new( frm,
:text => 'Help',
:command => lambda { ep_help }
@@ -671,7 +735,7 @@ TkFrame.new( $root ) { |frm|
TkFrame.new( $root ){ |frm|
frm.borderwidth 2
- frm.relief 'groove'
+ frm.relief 'sunken'
### status info
@@ -803,6 +867,13 @@ TkFrame.new( $root ) { |frm|
########################################
+### wait message packed at bottom
+
+$cnv_label = TkLabel.new( $root, 'text' => ''
+).pack( 'side' => 'bottom', 'fill' => 'x', :anchor => 'nw' )
+
+########################################
+
### view | open | save | done buttons
TkFrame.new( $root ) { |frm|
@@ -813,12 +884,14 @@ TkFrame.new( $root ) { |frm|
:command => lambda {
# start a viewer
if ARCH == 'w32'
- shell = Win32API.new("shell32", "ShellExecute",
- ['l','p','p','p','p','l'], 'l')
- shell.Call(0, 'open', $source.path, 0, 0, 1)
- # shell.Call(0, 'open', $source.path, 0, 0, SW_SHOWNORMAL)
+ result = shell_open( $source.path )
+ Tk.messageBox(
+ 'icon' => 'error',
+ 'title' => 'ShellExecute error',
+ 'message' => shell_error_string( result )
+ ) if result <= 32
elsif ARCH == 'osx'
- fork { exec "open -a Preview \"#{$source.path}\"" }
+ fork { exec "open \"#{$source.path}\"" }
elsif viewable( $source )
viewer =
$source.type == 'pdf' ? $settings.pdf_viewer : $settings.ps_viewer
@@ -827,12 +900,27 @@ TkFrame.new( $root ) { |frm|
}
).pack( :side=>'left', :anchor => 'w', :padx=>4, :pady=>4 )
+ if ARCH == 'w32'
+ $view_with_button = TkButton.new( frm,
+ :text => 'View with...',
+ :state => 'disabled',
+ :command => lambda {
+ result = shell_open_with( $source.path )
+ Tk.messageBox(
+ 'icon' => 'error',
+ 'title' => 'ShellExecute error',
+ 'message' => shell_error_string( result )
+ ) if result <= 32
+ }
+ ).pack( :side=>'left', :anchor => 'w', :padx=>4, :pady=>4 )
+ end # 'w32'
+
TkFrame.new( frm ) { |fm|
TkButton.new( fm,
:text => 'Open..',
:command => lambda {
path = Tk.getOpenFile(
- :initialdir => $defaultDir,
+ :initialdir => $settings.defaultDir,
:filetypes => [
['All files', '*'],
['EPS', ['.eps']],
@@ -843,7 +931,7 @@ TkFrame.new( $root ) { |frm|
)
if path and ( not path.empty? )
load_file( path )
- $defaultDir = File.expand_path( File.dirname( path ) )
+ $settings.defaultDir = File.expand_path( File.dirname( path ) )
end
}
).pack( :side=>'left', :padx=>4, :pady=>4 )
@@ -873,29 +961,14 @@ TkFrame.new( $root ) { |frm|
:defaultextension => '.' + $options.type
)
return unless path && ! path.empty?
- $defaultDir = File.expand_path( File.dirname( path ) )
-
- # waitbox
- if not $tl_wait
- $tl_wait = TkToplevel.new( $root,
- 'title' => 'Converting...',
- 'geometry' =>
- '+' + ( TkWinfo.rootx( $root ).to_i + 100 ).to_s +
- '+' + ( TkWinfo.rooty( $root ).to_i + 100 ).to_s,
- 'borderwidth' => 2,
- 'relief' => 'solid'
- )
- $cnv_label = TkLabel.new( $tl_wait,
- 'text' => 'converting...'
- ).pack( 'side' => 'top' )
- $tl_wait.overrideredirect( 1 )
- end
+ $settings.defaultDir = File.expand_path( File.dirname( path ) )
+
$cnv_label.configure(
- 'text' => "Converting #{$source.path} to \n #{path}..."
+ 'text' => "Converting #{File.basename($source.path)}" +
+ " to #{ File.basename(path)}..."
)
- $tl_wait.update
- $tl_wait.deiconify
- $tl_wait.raise
+ $cnv_label.update
+
begin
result = $source.any_to_any( $options )
rescue EPCallError => exc
@@ -930,7 +1003,9 @@ TkFrame.new( $root ) { |frm|
'message' => "#{mess}\nSee #{LOGFILE} for details."
)
ensure
- $tl_wait.withdraw
+ # $tl_wait.withdraw
+ $cnv_label.configure( 'text' => '' )
+ $cnv_label.update
end
if result
ccp( result.path, path )
@@ -957,4 +1032,5 @@ set_widget_states
$root.raise
Tk.mainloop
+$settings.write_settings
cleantemp
diff --git a/Master/texmf-dist/scripts/epspdf/makegray.pro b/Master/texmf-dist/scripts/epspdf/makegray.pro
index 67dc5705839..6206e559560 100644
--- a/Master/texmf-dist/scripts/epspdf/makegray.pro
+++ b/Master/texmf-dist/scripts/epspdf/makegray.pro
@@ -26,4 +26,8 @@ userdict begin
1 exch sub
systemdict begin setgray end
} def
+% hsb: toss hue and saturation; keep brightness for gray setting
+/sethsbcolor {
+ pop pop systemdict begin setgray end
+} def
end