From 4a697a53a3c9c2795d549c7d5eb7a6c88c7911a9 Mon Sep 17 00:00:00 2001 From: Siep Kroonenberg Date: Fri, 4 Jul 2008 10:17:06 +0000 Subject: Added: epspdf conversion utility git-svn-id: svn://tug.org/texlive/trunk@9222 c570f23f-e606-0410-a88d-b1316a301751 --- Master/bin/alpha-linux/epspdf | 1 + Master/bin/alpha-linux/epspdftk | 1 + Master/bin/amd64-freebsd/epspdf | 1 + Master/bin/amd64-freebsd/epspdftk | 1 + Master/bin/hppa-hpux/epspdf | 1 + Master/bin/hppa-hpux/epspdftk | 1 + Master/bin/i386-darwin/epspdf | 1 + Master/bin/i386-darwin/epspdftk | 1 + Master/bin/i386-freebsd/epspdf | 1 + Master/bin/i386-freebsd/epspdftk | 1 + Master/bin/i386-linux/epspdf | 1 + Master/bin/i386-linux/epspdftk | 1 + Master/bin/i386-openbsd/epspdf | 1 + Master/bin/i386-openbsd/epspdftk | 1 + Master/bin/i386-solaris/epspdf | 1 + Master/bin/i386-solaris/epspdftk | 1 + Master/bin/mips-irix/epspdf | 1 + Master/bin/mips-irix/epspdftk | 1 + Master/bin/powerpc-aix/epspdf | 1 + Master/bin/powerpc-aix/epspdftk | 1 + Master/bin/powerpc-darwin/epspdf | 1 + Master/bin/powerpc-darwin/epspdftk | 1 + Master/bin/powerpc-linux/epspdf | 1 + Master/bin/powerpc-linux/epspdftk | 1 + Master/bin/sparc-linux/epspdf | 1 + Master/bin/sparc-linux/epspdftk | 1 + Master/bin/sparc-solaris/epspdf | 1 + Master/bin/sparc-solaris/epspdftk | 1 + Master/bin/win32/epspdf.bat | 11 + Master/bin/win32/epspdf.texlua | 51 + Master/bin/win32/epspdftk.bat | 11 + Master/bin/x86_64-linux/epspdf | 1 + Master/bin/x86_64-linux/epspdftk | 1 + Master/texmf-dist/doc/epspdf/COPYING | 339 ++++++ Master/texmf-dist/doc/epspdf/default.css | 56 + Master/texmf-dist/doc/epspdf/epspdf.install | 285 +++++ Master/texmf-dist/doc/epspdf/epspdf_UG.html | 185 ++++ Master/texmf-dist/doc/epspdf/images/config_mac.png | Bin 0 -> 27971 bytes Master/texmf-dist/doc/epspdf/images/dia_save.png | Bin 0 -> 29314 bytes .../texmf-dist/doc/epspdf/images/greenbroccoli.png | Bin 0 -> 71686 bytes Master/texmf-dist/doc/epspdf/images/main_w32.png | Bin 0 -> 6111 bytes Master/texmf-dist/doc/epspdf/index.html | 312 ++++++ Master/texmf-dist/scripts/epspdf/epspdf | 3 + Master/texmf-dist/scripts/epspdf/epspdf.help | 155 +++ Master/texmf-dist/scripts/epspdf/epspdf.rb | 1123 ++++++++++++++++++++ Master/texmf-dist/scripts/epspdf/epspdfboot.rb | 40 + Master/texmf-dist/scripts/epspdf/epspdfrc.rb | 507 +++++++++ Master/texmf-dist/scripts/epspdf/epspdftk | 7 + Master/texmf-dist/scripts/epspdf/epspdftk.rb | 958 +++++++++++++++++ Master/texmf-dist/scripts/epspdf/makegray.pro | 29 + 50 files changed, 4102 insertions(+) create mode 120000 Master/bin/alpha-linux/epspdf create mode 120000 Master/bin/alpha-linux/epspdftk create mode 120000 Master/bin/amd64-freebsd/epspdf create mode 120000 Master/bin/amd64-freebsd/epspdftk create mode 120000 Master/bin/hppa-hpux/epspdf create mode 120000 Master/bin/hppa-hpux/epspdftk create mode 120000 Master/bin/i386-darwin/epspdf create mode 120000 Master/bin/i386-darwin/epspdftk create mode 120000 Master/bin/i386-freebsd/epspdf create mode 120000 Master/bin/i386-freebsd/epspdftk create mode 120000 Master/bin/i386-linux/epspdf create mode 120000 Master/bin/i386-linux/epspdftk create mode 120000 Master/bin/i386-openbsd/epspdf create mode 120000 Master/bin/i386-openbsd/epspdftk create mode 120000 Master/bin/i386-solaris/epspdf create mode 120000 Master/bin/i386-solaris/epspdftk create mode 120000 Master/bin/mips-irix/epspdf create mode 120000 Master/bin/mips-irix/epspdftk create mode 120000 Master/bin/powerpc-aix/epspdf create mode 120000 Master/bin/powerpc-aix/epspdftk create mode 120000 Master/bin/powerpc-darwin/epspdf create mode 120000 Master/bin/powerpc-darwin/epspdftk create mode 120000 Master/bin/powerpc-linux/epspdf create mode 120000 Master/bin/powerpc-linux/epspdftk create mode 120000 Master/bin/sparc-linux/epspdf create mode 120000 Master/bin/sparc-linux/epspdftk create mode 120000 Master/bin/sparc-solaris/epspdf create mode 120000 Master/bin/sparc-solaris/epspdftk create mode 100755 Master/bin/win32/epspdf.bat create mode 100755 Master/bin/win32/epspdf.texlua create mode 100755 Master/bin/win32/epspdftk.bat create mode 120000 Master/bin/x86_64-linux/epspdf create mode 120000 Master/bin/x86_64-linux/epspdftk create mode 100644 Master/texmf-dist/doc/epspdf/COPYING create mode 100644 Master/texmf-dist/doc/epspdf/default.css create mode 100644 Master/texmf-dist/doc/epspdf/epspdf.install create mode 100644 Master/texmf-dist/doc/epspdf/epspdf_UG.html create mode 100644 Master/texmf-dist/doc/epspdf/images/config_mac.png create mode 100644 Master/texmf-dist/doc/epspdf/images/dia_save.png create mode 100644 Master/texmf-dist/doc/epspdf/images/greenbroccoli.png create mode 100644 Master/texmf-dist/doc/epspdf/images/main_w32.png create mode 100644 Master/texmf-dist/doc/epspdf/index.html create mode 100755 Master/texmf-dist/scripts/epspdf/epspdf create mode 100644 Master/texmf-dist/scripts/epspdf/epspdf.help create mode 100755 Master/texmf-dist/scripts/epspdf/epspdf.rb create mode 100644 Master/texmf-dist/scripts/epspdf/epspdfboot.rb create mode 100755 Master/texmf-dist/scripts/epspdf/epspdfrc.rb create mode 100755 Master/texmf-dist/scripts/epspdf/epspdftk create mode 100755 Master/texmf-dist/scripts/epspdf/epspdftk.rb create mode 100644 Master/texmf-dist/scripts/epspdf/makegray.pro (limited to 'Master') diff --git a/Master/bin/alpha-linux/epspdf b/Master/bin/alpha-linux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/alpha-linux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/alpha-linux/epspdftk b/Master/bin/alpha-linux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/alpha-linux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/amd64-freebsd/epspdf b/Master/bin/amd64-freebsd/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/amd64-freebsd/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/amd64-freebsd/epspdftk b/Master/bin/amd64-freebsd/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/amd64-freebsd/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/hppa-hpux/epspdf b/Master/bin/hppa-hpux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/hppa-hpux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/hppa-hpux/epspdftk b/Master/bin/hppa-hpux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/hppa-hpux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/i386-darwin/epspdf b/Master/bin/i386-darwin/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/i386-darwin/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/i386-darwin/epspdftk b/Master/bin/i386-darwin/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/i386-darwin/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/i386-freebsd/epspdf b/Master/bin/i386-freebsd/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/i386-freebsd/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/i386-freebsd/epspdftk b/Master/bin/i386-freebsd/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/i386-freebsd/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/i386-linux/epspdf b/Master/bin/i386-linux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/i386-linux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/i386-linux/epspdftk b/Master/bin/i386-linux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/i386-linux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/i386-openbsd/epspdf b/Master/bin/i386-openbsd/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/i386-openbsd/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/i386-openbsd/epspdftk b/Master/bin/i386-openbsd/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/i386-openbsd/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/i386-solaris/epspdf b/Master/bin/i386-solaris/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/i386-solaris/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/i386-solaris/epspdftk b/Master/bin/i386-solaris/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/i386-solaris/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/mips-irix/epspdf b/Master/bin/mips-irix/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/mips-irix/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/mips-irix/epspdftk b/Master/bin/mips-irix/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/mips-irix/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/powerpc-aix/epspdf b/Master/bin/powerpc-aix/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/powerpc-aix/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/powerpc-aix/epspdftk b/Master/bin/powerpc-aix/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/powerpc-aix/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/powerpc-darwin/epspdf b/Master/bin/powerpc-darwin/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/powerpc-darwin/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/powerpc-darwin/epspdftk b/Master/bin/powerpc-darwin/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/powerpc-darwin/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/powerpc-linux/epspdf b/Master/bin/powerpc-linux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/powerpc-linux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/powerpc-linux/epspdftk b/Master/bin/powerpc-linux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/powerpc-linux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/sparc-linux/epspdf b/Master/bin/sparc-linux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/sparc-linux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/sparc-linux/epspdftk b/Master/bin/sparc-linux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/sparc-linux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/sparc-solaris/epspdf b/Master/bin/sparc-solaris/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/sparc-solaris/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/sparc-solaris/epspdftk b/Master/bin/sparc-solaris/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/sparc-solaris/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/bin/win32/epspdf.bat b/Master/bin/win32/epspdf.bat new file mode 100755 index 00000000000..b203b576c3e --- /dev/null +++ b/Master/bin/win32/epspdf.bat @@ -0,0 +1,11 @@ +@echo off +ruby -v >nul 2>&1 +if not errorlevel 1 goto doit +echo Ruby not found. Install Ruby, +echo get the Ruby-included version or use epstopdf. +goto :EOF +:doit +setlocal +set ownpath=%~dp0% +texlua "%ownpath%epspdf.texlua" "%~dpn0" %* +endlocal diff --git a/Master/bin/win32/epspdf.texlua b/Master/bin/win32/epspdf.texlua new file mode 100755 index 00000000000..b31efa964d7 --- /dev/null +++ b/Master/bin/win32/epspdf.texlua @@ -0,0 +1,51 @@ +#! /usr/bin/env texlua + +function fixwin(args_unix) + if os.type == 'windows' then + local args_win={} -- new table + args_win[0]=args_unix[1] + for i=1, #args_unix do + args_win[i]='"'..args_unix[i]..'"' + end + return args_win + else + return args_unix + end +end + +if string.find(arg[0], '/') then -- UNIX path + basename = select(1, string.gsub(arg[1], '.*/', '')) +elseif string.find(arg[0], '\\') then -- Windows path + basename = select(1, string.gsub(arg[1], '.*\\', '')) + -- we might have \ and / mixed together ... + basename = select(1, string.gsub(basename, '.*/', '')) +else -- no path + basename = arg[1] +end + +kpse.set_program_name(basename..".bat", basename) +TLROOT=kpse.var_value('SELFAUTOPARENT') +BINDIR=kpse.var_value('SELFAUTOLOC') + +os.setenv('PATH', TLROOT..'/tlpkg/tlgs/bin;'..os.getenv('PATH')) +os.setenv('GS_LIB', TLROOT..'/tlpkg/tlgs/lib;'..TLROOT..'/tlpkg/tlgs/fonts') +os.setenv('TLROOT', TLROOT) + +script=kpse.find_file(basename..'.rb', 'texmfscripts') +command={'ruby.exe', script} + +for i=2, #arg do + command[#command+1]=arg[i] +end + +command=fixwin(command) + +--[[ Prepend an additional hyphen to activate this code. +for i=0, #command do + print (command[i]) +end +os.exit(ret) +--]] + +ret=os.spawn(command) +os.exit(ret) diff --git a/Master/bin/win32/epspdftk.bat b/Master/bin/win32/epspdftk.bat new file mode 100755 index 00000000000..d688da08ffc --- /dev/null +++ b/Master/bin/win32/epspdftk.bat @@ -0,0 +1,11 @@ +@echo off +ruby -v >nul 2>&1 +if not errorlevel 1 goto doit +echo Ruby not found. Install Ruby and Tcl, +echo get the Ruby-included version or use epstopdf. +goto :EOF +:doit +setlocal +set ownpath=%~dp0% +texlua "%ownpath%epspdf.texlua" "%~dpn0" %* +endlocal diff --git a/Master/bin/x86_64-linux/epspdf b/Master/bin/x86_64-linux/epspdf new file mode 120000 index 00000000000..0195c700955 --- /dev/null +++ b/Master/bin/x86_64-linux/epspdf @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdf \ No newline at end of file diff --git a/Master/bin/x86_64-linux/epspdftk b/Master/bin/x86_64-linux/epspdftk new file mode 120000 index 00000000000..ef9d117fd47 --- /dev/null +++ b/Master/bin/x86_64-linux/epspdftk @@ -0,0 +1 @@ +../../texmf-dist/scripts/epspdf/epspdftk \ No newline at end of file diff --git a/Master/texmf-dist/doc/epspdf/COPYING b/Master/texmf-dist/doc/epspdf/COPYING new file mode 100644 index 00000000000..3c69bb94fa5 --- /dev/null +++ b/Master/texmf-dist/doc/epspdf/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Master/texmf-dist/doc/epspdf/default.css b/Master/texmf-dist/doc/epspdf/default.css new file mode 100644 index 00000000000..0b1cdd46c3a --- /dev/null +++ b/Master/texmf-dist/doc/epspdf/default.css @@ -0,0 +1,56 @@ +body { + color: black; + background-color: #ffffff; + margin-left: 15px; + margin-right: 9px; + font-family: serif; +} +h1 { + font-size: xx-large; + font-weight: bold; + margin-top: 12px; + margin-bottom: 6px; +} +h1.display { + text-align: center +} +h2 { + font-size: x-large; + font-weight: bold; + margin-top: 12px; + margin-bottom: 6px; +} +h3 { + font-weight: bold; + margin-top: 9px; + margin-bottom: 3px; +} +p { + margin-top: 6px; + margin-bottom: 3px; +} +p.display { + text-align: center +} +.fineprint { + font-size: x-small; +} +table { + border-width: 0px; + margin-left: 0px; + margin-right: 6px; +} +ul { + margin-top: 9px; + margin-bottom: 9px; +} +ul li { + margin-top: 3px; + margin-bottom: 3px; + margin-left: -6px +} +pre { + margin-top: 3px; + margin-bottom: 3px; + margin-left: 0px; +} \ No newline at end of file diff --git a/Master/texmf-dist/doc/epspdf/epspdf.install b/Master/texmf-dist/doc/epspdf/epspdf.install new file mode 100644 index 00000000000..759cebde26e --- /dev/null +++ b/Master/texmf-dist/doc/epspdf/epspdf.install @@ -0,0 +1,285 @@ + Epspdf and epspdftk + + A multiplatform GUI- and command-line converter for [e]ps and pdf. + + Siep Kroonenberg, + siepo at cybercomm dot nl + + [1]Current online version of this page + +Table of Contents + + * [2]Features + * [3]Prerequisites + * [4]Installation + * [5]Preview programs + * [6]Files + * [7]Supporting software + * [8]Releases + * [9]To do + * [10]User Guide + +Features + + * Distiller + * Works both for documents and for graphics + * Single-page selection + * Also converts from pdf back to PostScript and eps + * Removal of preview headers from eps files + * Cropping extra whitespace + * Grayscaling (sometimes) + * GUI- and command-line version + * GUI-configurable preferences + * Multiplatform: works unchanged on Windows, Unix/Linux and Mac OS X + + Epspdf has been created with TeX users in mind. For them, eps and pdf are + the preferred graphics formats. + + Ghostscript can convert PostScript to pdf. However, few people are + prepared to deal with the ghostscript command-line. Several command-line + utilities try to help out, e.g. epstopdf, a2ping, and the convert utility + from ImageMagick. But for most users this is still not good enough. + + Epspdftk adds a GUI, with buttons to select options and with dialogs for + opening and saving files. + + A lot more can be done if you can round-trip between PostScript and pdf. + Although Ghostscript can go from pdf to PostScript, pdftops does a much + better job. This opens several new possibilities: grayscaling and + computing a better boundingbox for either eps- or pdf graphics, and page + selection from multipage PostScript- and pdf documents. Epspdf will use + pdftops if it can find it, and silently does whatever back-and-forth + conversions are necessary. + + The command-line program epspdf is written in Ruby. Epspdftk, its GUI + companion, in Ruby/Tk. + +Prerequisites + + Windows with setup progrogam + + Download Ghostscript and GSview from the [11]Ghostscript site. Ghostscript + and GSview each come with a standard Windows setup program. + + You can get pdftops as part of the xpdf suite from the [12]xpdf site. + Download the zipfile with Windows binaries and unpack it in a location of + your choice. The Configure screen of epspdftk lets you browse for this + location. You only have to do this once. Xpdf itself is not in this zip + file. + + The necessary Ruby components are already included in the setup program. + + Windows zipfile with separately installed Ruby + + For Ghostscript, GSview and the xpdf suite, see above. + + You can get a [13]one-click Ruby installer from [14]Rubyforge. For Ruby + version 1.8.4 and later you have to download and install Tcl/Tk + separately, in the form of [15]ActiveTcl. If you are only interested in + the command-line version then you can leave out ActiveTcl. + + Unix/Linux + + You need Ghostscript, preferably xpdf/pdftops, Ruby (version at least 1.8) + and for GUI use also Ruby/Tk. These will almost certainly be available as + packages from your distribution. + + Mac OS X + + Ghostscript and xpdf are available via the [16]Fink Project, in the Text + section. + + If you don't (want to) use Fink, you can download and install Gerben + Wierda's i-Installer from the [17]i-Installer Home Page and then use the + i-Installer to download and install the Ghostscript i-package. + + There is a [18]package for the xpdf suite at + [19]http://users.phg-online.de/tk/MOSXS/. Or you can compile it yourself. + You can download the source from the [20]xpdf site. For compilation, you + need to have XCode installed, but nothing else, I think, at least not + under Tiger. You can safely omit the xpdf- and pdftoppm components if + configure says that they will not be compiled because of missing + libraries. + + Ruby 1.8.2 and Ruby/Tk are part of Mac OS X Tiger. X11 needs to be + installed, although Ruby/Tk is not an X11 application. For earlier + versions of Mac OS X, you are on your own. + +Installation + + Windows with setup program + + Download the [21]epspdftk setup program. You can run it in the usual way, + by double-clicking. The setup program will create entries in your start + menu for epspdftk and for the user manual. + + Windows zipfile + + Download the [22]epspdf zip file, unpack it somewhere and create a + shortcut for epspdftk.rbw. If you plan to use the command-line version, + put a batchfile in a directory on your path with the line + + "" "" %1 %2 %3 %4 %5 %6 %7 %8 %9 + + Epspdf[tk] has been tested with Windows 2000 and Windows XP. + + Unix/Linux + + Download the [23]tar.gz archive and unpack it in some directory. All files + should be in the same directory; that is how they find each other. If you + plan to use epspdf.rb from the command-line, then you may want to create a + shell script epspdf such as + + #!/bin/sh + /epspdf.rb $* + + and put it somewhere on your path. + + You can do the same for epspdftk. The first command-line parameter will be + interpreted as startup directory for the file browser. + + Mac OS X + + Install as for Unix/Linux. Here, too, all files should be in the same + directory. + + You can try to start epspdftk.rb from the dock or by doubleclicking. If + that doesn't work out, give the [24]epspdf.app applet a try. After + unpacking, move the file epspdf.app to the same directory as the .rb + files. The zipfile also includes this file in text format + (epspdf.applescript). + + Epspdf mostly duplicates functionality of Preview. But having an alternate + conversion engine means that you can have another shot at problem files. + +Preview programs + + Windows + + Epspdftk will use the default Windows viewers for PostScript and pdf. + Without GSview, you probably won't be able to view PostScript files. + + Unix/Linux + + Supported PostScript viewers include evince, gv, ggv and kghostview. These + are also listed as pdf viewers. Additional pdf viewers are xpdf, gpdf and + acroread/Adobe Reader. If you think that I omitted a PostScript- or pdf + viewer, let me know and I'll probably add it in the next release. + + Mac OS X + + Epspdftk will always use Preview as viewer under OS X. + +Files + + * [25]epspdf.0.2.12.tgz preferred for Unix and Mac OS X + * [26]epspdf.0.2.12.zip preferred for Windows + * [27]epspdf.0.2.12.exe Windows setup program, including Ruby/Tk subset + * [28]epspdf_app.0.2.01.zip Mac OS X applet for starting epspdftk.rb + + Older releases + + * [29]epspdf.0.2.11.tgz for Unix and Mac OS X + * [30]epspdf.0.2.11.zip for Windows + * [31]epspdf.0.2.11.exe Windows setup program + * [32]epspdf.0.2.01.tgz for Unix and Mac OS X + * [33]epspdf.0.2.01.zip for Windows + * [34]epspdf.0.2.exe, Windows setup program + +Supporting software + + * [35]Ghostscript and GSview + * [36]XPDF + * [37]OS X binary for xpdf/pdftops + * [38]Ruby one-click installer + * [39]Ruby Home Page + * [40]ActiveTcl + +Releases + + 0.2.12 + Current version. Bug fixes: log rotation now works. Under Windows, + sometimes boundingboxes couldn't be calculated. This was caused by + double quotes within backquotes. This is now avoided by using + short filenames within backquotes. Minor changes in user guide. + + 0.2.11 + Minor fixes. Changes in documentation. + + 0.2.10 + A computed boundingbox is now expanded by one point in all + directions. This should prevent too-tight cropping. There is no + interface for changing this amount; it can only be changed by + hand-editing the bb_spread option in the .epspdfrc file or in the + HKCU\software\epspdf registry key. + The File Open dialog remembers the last directory visited (between + calls, not between program sessions). + Changes in documentation. + + 0.2.01 + Fixes to the Applescript applet epspdf.app for starting up + epspdftk under Mac OS X. It picks up the terminal search path and + no longer requires correct settings in + $HOME/.MacOSX/environment.plist. + Epspdf.app is now [41]packaged separately, under Mac OS X, and now + has an intact resource fork. It has been removed from the other + archives. + + 0.2 + Original release + +To do + + * Artwork + * GUI for some pdftops options + * Proper help + * Support for bitmapped formats (maybe) + + -------------------------------------------------------------------------- + + Last revised: November 20, 2006 + +References + + Visible links + 1. http://tex.aanhet.net/epspdf/ + 2. http://tex.aanhet.net/epspdf/index.html#features + 3. http://tex.aanhet.net/epspdf/index.html#prerequisites + 4. http://tex.aanhet.net/epspdf/index.html#install + 5. http://tex.aanhet.net/epspdf/index.html#preview + 6. http://tex.aanhet.net/epspdf/index.html#files + 7. http://tex.aanhet.net/epspdf/index.html#supporting + 8. http://tex.aanhet.net/epspdf/index.html#releases + 9. http://tex.aanhet.net/epspdf/index.html#todo + 10. http://tex.aanhet.net/epspdf/epspdf_UG.html + 11. http://www.cs.wisc.edu/~ghost/ + 12. http://www.foolabs.com/xpdf/ + 13. http://rubyforge.org/projects/rubyinstaller/ + 14. http://rubyforge.org/ + 15. http://activestate.com/Products/ActiveTcl/ + 16. http://fink.sourceforge.net/ + 17. http://ii2.sourceforge.net/ + 18. http://users.phg-online.de/tk/MOSXS/xpdf-tools-3.dmg + 19. http://users.phg-online.de/tk/MOSXS/ + 20. http://www.foolabs.com/xpdf/ + 21. http://tex.aanhet.net/epspdf/epspdf.0.2.12.exe + 22. http://tex.aanhet.net/epspdf/epspdf.0.2.12.zip + 23. http://tex.aanhet.net/epspdf/epspdf.0.2.12.tgz + 24. http://tex.aanhet.net/epspdf/epspdf_app.0.2.01.zip + 25. http://tex.aanhet.net/epspdf/epspdf.0.2.12.tgz + 26. http://tex.aanhet.net/epspdf/epspdf.0.2.12.zip + 27. http://tex.aanhet.net/epspdf/epspdf.0.2.12.exe + 28. http://tex.aanhet.net/epspdf/epspdf_app.0.2.01.zip + 29. http://tex.aanhet.net/epspdf/epspdf.0.2.11.tgz + 30. http://tex.aanhet.net/epspdf/epspdf.0.2.11.zip + 31. http://tex.aanhet.net/epspdf/epspdf.0.2.11.exe + 32. http://tex.aanhet.net/epspdf/epspdf.0.2.01.tgz + 33. http://tex.aanhet.net/epspdf/epspdf.0.2.01.zip + 34. http://tex.aanhet.net/epspdf/epspdf.0.2.exe + 35. http://www.cs.wisc.edu/~ghost/ + 36. http://www.foolabs.com/xpdf/ + 37. http://users.phg-online.de/tk/MOSXS/ + 38. http://rubyforge.org/projects/rubyinstaller/ + 39. http://ruby-lang.org/ + 40. http://activestate.com/Products/ActiveTcl/ + 41. http://tex.aanhet.net/epspdf/epspdf_app.0.2.01.zip diff --git a/Master/texmf-dist/doc/epspdf/epspdf_UG.html b/Master/texmf-dist/doc/epspdf/epspdf_UG.html new file mode 100644 index 00000000000..27a7d96626a --- /dev/null +++ b/Master/texmf-dist/doc/epspdf/epspdf_UG.html @@ -0,0 +1,185 @@ + + + + + + + + +Epspdf and epspdftk User Guide + + + +

Epspdf and epspdftk User Guide

+ +

A multiplatform GUI- and command-line converter +for [e]ps and pdf.

+ +

Siep Kroonenberg,
siepo at cybercomm +dot nl

+ +

Overview

+ +

Epspdftk converts files between eps, pdf and general +PostScript. The main screen lets you open a file, select some options +and convert the file.

+ +

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.

+ +

+ +

Viewing

+ +

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 The Configuration +screen.

+ +

The View button is grayed if epspdf thinks that there is no +previewer for the current file.

+ +

+ +

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.

+ +

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.

+ +

Compute tight boundingbox: This option is only available +if a single page is converted.

+ +

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 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.

+ +

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.

+ +

Converting

+ +

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.

+ +

+ +

The configuration screen

+ +

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.

+ +

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.

+ +

+ +

Adding standard fonts to an existing 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.

+ +

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.

+ +

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.

+ +

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 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 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.

+ +

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 which temporary files have been +created.

+ +

Main page...

+ +
+

Last revised: Noverber 20, 2006

+ diff --git a/Master/texmf-dist/doc/epspdf/images/config_mac.png b/Master/texmf-dist/doc/epspdf/images/config_mac.png new file mode 100644 index 00000000000..0ad0c855509 Binary files /dev/null and b/Master/texmf-dist/doc/epspdf/images/config_mac.png differ diff --git a/Master/texmf-dist/doc/epspdf/images/dia_save.png b/Master/texmf-dist/doc/epspdf/images/dia_save.png new file mode 100644 index 00000000000..ea56dbcab0e Binary files /dev/null and b/Master/texmf-dist/doc/epspdf/images/dia_save.png differ diff --git a/Master/texmf-dist/doc/epspdf/images/greenbroccoli.png b/Master/texmf-dist/doc/epspdf/images/greenbroccoli.png new file mode 100644 index 00000000000..64883e00d47 Binary files /dev/null and b/Master/texmf-dist/doc/epspdf/images/greenbroccoli.png differ diff --git a/Master/texmf-dist/doc/epspdf/images/main_w32.png b/Master/texmf-dist/doc/epspdf/images/main_w32.png new file mode 100644 index 00000000000..579e64f0db9 Binary files /dev/null and b/Master/texmf-dist/doc/epspdf/images/main_w32.png differ diff --git a/Master/texmf-dist/doc/epspdf/index.html b/Master/texmf-dist/doc/epspdf/index.html new file mode 100644 index 00000000000..476deff50c9 --- /dev/null +++ b/Master/texmf-dist/doc/epspdf/index.html @@ -0,0 +1,312 @@ + + + + + + + + +Epspdf and epspdftk + + + +

Epspdf and epspdftk

+ +

A multiplatform GUI- and command-line converter +for [e]ps and pdf.

+ +

Siep Kroonenberg,
siepo at cybercomm +dot nl

+ +

Current online version of +this page

+ +

Table of Contents

+ + + +

Features

+ +
    +
  • Distiller
  • +
  • Works both for documents and for graphics
  • +
  • Single-page selection
  • +
  • Also converts from pdf back to PostScript and eps
  • +
  • Removal of preview headers from eps files
  • +
  • Cropping extra whitespace
  • +
  • Grayscaling (sometimes)
  • +
  • GUI- and command-line version
  • +
  • GUI-configurable preferences
  • +
  • Multiplatform: works unchanged on Windows, Unix/Linux and Mac OS X
  • +
+ +

Epspdf has been created with TeX users in mind. For them, eps and +pdf are the preferred graphics formats.

+ +

Ghostscript can convert PostScript to pdf. However, few people +are prepared to deal with the ghostscript command-line. Several +command-line utilities try to help out, e.g. epstopdf, a2ping, and +the convert utility from ImageMagick. But for most users this is +still not good enough.

+ +

Epspdftk adds a GUI, with buttons to select options and with +dialogs for opening and saving files.

+ +

A lot more can be done if you can round-trip between PostScript +and pdf. Although Ghostscript can go from pdf to PostScript, pdftops +does a much better job. This opens several new possibilities: +grayscaling and computing a better boundingbox for either eps- or pdf +graphics, and page selection from multipage PostScript- and pdf +documents. Epspdf will use pdftops if it can find it, and silently +does whatever back-and-forth conversions are necessary.

+ +

The command-line program epspdf is written in Ruby. Epspdftk, +its GUI companion, in Ruby/Tk.

+ +

Prerequisites

+ +

Windows with setup progrogam

+ +

Download Ghostscript and GSview from the Ghostscript site. +Ghostscript and GSview each come with a standard Windows setup +program.

+ +

You can get pdftops as part of the xpdf suite from the xpdf site. Download the +zipfile with Windows binaries and unpack it in a location of your +choice. The Configure screen of epspdftk lets you browse for this +location. You only have to do this once. Xpdf itself is not in this +zip file.

+ +

The necessary Ruby components are already included in the setup +program.

+ +

Windows zipfile with separately installed Ruby

+ +

For Ghostscript, GSview and the xpdf suite, see above.

+ +

You can get a one-click Ruby +installer from Rubyforge. +For Ruby version 1.8.4 and later you have to download and install +Tcl/Tk separately, in the form of ActiveTcl. If +you are only interested in the command-line version then you can +leave out ActiveTcl.

+ +

Unix/Linux

+ +

You need Ghostscript, preferably xpdf/pdftops, Ruby (version at +least 1.8) and for GUI use also Ruby/Tk. These will almost certainly +be available as packages from your distribution.

+ +

Mac OS X

+ +

Ghostscript and xpdf are available via the Fink Project, in the Text +section.

+ +

If you don't (want to) use Fink, you can download and +install Gerben Wierda's i-Installer from the i-Installer Home Page and +then use the i-Installer to download and install the Ghostscript +i-package.

+ +

There is +a package +for the xpdf suite +at http://users.phg-online.de/tk/MOSXS/. +Or you can compile it yourself. You can download the source from +the xpdf site. For +compilation, you need to have XCode installed, but nothing else, I +think, at least not under Tiger. You can safely omit the xpdf- and +pdftoppm components if configure says that they will not be compiled +because of missing libraries.

+ +

Ruby 1.8.2 and Ruby/Tk are part of Mac OS X Tiger. X11 needs to +be installed, although Ruby/Tk is not an X11 application. For +earlier versions of Mac OS X, you are on your own.

+ +

Installation

+ +

Windows with setup program

+ +

Download the epspdftk setup +program. You can run it in the usual way, by double-clicking. The +setup program will create entries in your start menu for epspdftk +and for the user manual.

+ +

Windows zipfile

+ +

Download the epspdf zip file, +unpack it somewhere and create a shortcut for epspdftk.rbw. If you +plan to use the command-line version, put a batchfile in a directory +on your path with the line

+ +
+"<path_to_ruby.exe>" "<path_to_epspdf.rb>" %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+ +

Epspdf[tk] has been tested with Windows 2000 and Windows XP.

+ +

Unix/Linux

+ +

Download the tar.gz archive and +unpack it in some directory. All files should be in the same +directory; that is how they find each other. If you plan to use +epspdf.rb from the command-line, then you may want to create a shell +script epspdf such as

+ +
+#!/bin/sh
+<path_to_epspdf>/epspdf.rb $*
+
+ +

and put it somewhere on your path.

+ +

You can do the same for epspdftk. The first command-line +parameter will be interpreted as startup directory for the file +browser.

+ +

Mac OS X

+ +

Install as for Unix/Linux. Here, too, all files should be in the +same directory.

+ +

You can try to start epspdftk.rb from the dock or by +doubleclicking. If that doesn't work out, give the epspdf.app applet a try. After +unpacking, move the file epspdf.app to the same directory +as the .rb files. The zipfile also includes this file in text format +(epspdf.applescript).

+ +

Epspdf mostly duplicates functionality of Preview. But having an +alternate conversion engine means that you can have another shot at +problem files.

+ +

Preview programs

+ +

Windows

+ +

Epspdftk will use the default Windows viewers for PostScript and +pdf. Without GSview, you probably won't be able to view PostScript +files.

+ +

Unix/Linux

+ +

Supported PostScript viewers include evince, gv, ggv and +kghostview. These are also listed as pdf viewers. Additional pdf +viewers are xpdf, gpdf and acroread/Adobe Reader. If you think that +I omitted a PostScript- or pdf viewer, let me know and I'll probably +add it in the next release.

+ +

Mac OS X

+ +

Epspdftk will always use Preview as viewer under OS X.

+ +

Files

+ + + +

Older releases

+ + +

Supporting software

+ + + +

Releases

+ +
+
0.2.12
Current version. Bug fixes: log rotation now +works. Under Windows, sometimes boundingboxes couldn't be +calculated. This was caused by double quotes within backquotes. This +is now avoided by using short filenames within backquotes. Minor +changes in user guide.
+ +
0.2.11
Minor fixes. Changes in documentation.
+ +
0.2.10
A computed boundingbox is now expanded by one +point in all directions. This should prevent too-tight +cropping. There is no interface for changing this amount; it can +only be changed by hand-editing the bb_spread +option in the .epspdfrc file or in the HKCU\software\epspdf registry +key.
The File Open dialog remembers the last directory +visited (between calls, not between program +sessions).
Changes in documentation.
+ +
0.2.01
Fixes to the Applescript applet epspdf.app for +starting up epspdftk under Mac OS X. It picks up the terminal search +path and no longer requires correct settings in +$HOME/.MacOSX/environment.plist.
Epspdf.app is now packaged separately, under Mac OS +X, and now has an intact resource fork. It has been removed from the +other archives.
+ +
0.2
Original release
+
+ +

To do

+ +
    +
  • Artwork
  • +
  • GUI for some pdftops options
  • +
  • Proper help
  • +
  • Support for bitmapped formats (maybe)
  • +
+ +
+ +

Last revised: November 20, 2006

+ diff --git a/Master/texmf-dist/scripts/epspdf/epspdf b/Master/texmf-dist/scripts/epspdf/epspdf new file mode 100755 index 00000000000..4492608f398 --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdf @@ -0,0 +1,3 @@ +#!/bin/sh +script=`kpsewhich -format=texmfscripts epspdf.rb` +"$script" $* diff --git a/Master/texmf-dist/scripts/epspdf/epspdf.help b/Master/texmf-dist/scripts/epspdf/epspdf.help new file mode 100644 index 00000000000..90d9c795a0d --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdf.help @@ -0,0 +1,155 @@ + Epspdf and epspdftk User Guide + + A multiplatform GUI- and command-line converter for [e]ps and pdf. + + Siep Kroonenberg, + siepo at cybercomm dot nl + +Overview + + Epspdftk converts files between eps, pdf and general PostScript. The main + screen lets you open a file, select some options and convert the file. + + 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. + +Viewing + + 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. + + The View button is grayed if epspdf thinks that there is no previewer for + the current file. + +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. + + 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. + + Compute tight boundingbox: This option is only available if a single page + is converted. + + 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 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. + + 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. + +Converting + + 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. + +The configuration screen + + 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. + + 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. + +Adding standard fonts to an existing 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. + + 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. + +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. + +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 [2]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 [3]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. + + 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\. 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 which temporary + files have been created. + + [4]Main page... + + -------------------------------------------------------------------------- + + Last revised: Noverber 20, 2006 + +References + + Visible links + 1. http://tex.aanhet.net/epspdf/epspdf_UG.html#configure + 2. http://www.tug.org/ctan.html + 3. http://tex.aanhet.net/epspdf/epspdf_UG.html#gray + 4. 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 new file mode 100755 index 00000000000..fb391b6dde6 --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdf.rb @@ -0,0 +1,1123 @@ +#!/usr/bin/env ruby + +# epspdf conversion utility, main source + +##### +# Copyright (C) 2006 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! +##### + +# Operations on a PostScript- or pdf file. +# 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. + +# `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 +# 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' ) + + # turn on warnings + #$VERBOSE = 1 + +end # if main program + +########################################### + +# Error handling + +# internal error: method should not have been called +# under the current conditions +class EPCallError < StandardError; end + +# Can't get a valid boundingbox for an eps file +class EPBBError < StandardError; end + +# system call failed +class EPSystemError < StandardError; end + +########################################### + +# PostScript header file for grayscaling + +$GRAYHEAD = File.join( File.dirname( __FILE__ ), "makegray.pro" ) + +########################################### + +# handle auto-detected and saved settings + +require 'epspdfrc' + +########################################### + +# Transient options. These will never be saved. +# We set default values here. + +$options = { + 'type' => nil, + 'page' => nil, + 'bbox' => false, + 'gray' => false, + 'gRAY' => false, + 'info' => false +} + +class << $options + + # create shortcut methods $options.x and $options.x= + # for reading and writing hash elements. + + $options.each_key { |k| + eval "def #{k} ; self[\'#{k}\'] ; end" + eval "def #{k}=(v) ; self[\'#{k}\']=v ; end" + } + +end # class + +########################################### + +def hash_prn( h ) + if h.empty? + s = "No parameters" + $/ + else + s = "Parameters were:" + $/ + h.each_key { |k| s = s + ' ' + k.to_s + ' => ' + h[ k ].to_s + $/ } + end + s +end + +########################################### + +require 'fileutils' +#include FileUtils::Verbose +include FileUtils + +########################################### + +# Mode strings for file i/o + +if ARCH == 'w32' + $W = 'wb' + $A = 'ab' + $R = 'rb' +else + $W = 'w' + $A = 'a' + $R = 'r' +end + +########################################### + +# copy a slice of a file; is there no such standard function? +# some eps files are very large; don't slurp the file at one go. +# Mode: can be set to append 'a' rather than write 'w'. + +def sliceFile( source, dest, len, offs, mode=$W ) + buffer = '' + File.open( source ) do |s| + s.binmode if ARCH == 'w32' + s.seek( offs, IO::SEEK_SET ) + if s.pos == offs + File.open( dest, mode ) do |d| + d.binmode if ARCH == 'w32' + tocopy = len + while tocopy>0 and s.read( [ tocopy, 16384 ].min, buffer ) + tocopy = tocopy - d.write( buffer ) + end # while + end # |d| (automatic closing) + end # if s.seek + end # |s| (automatic closing) + # return value true if anything has been copied + File.size?( dest ) # nil if zero-length +end # def + +# write our own file copy, to bypass bug in FileUtils.cp + +def ccp( source, dest ) + sliceFile( source, dest, File.size( source ), 0, $W ) +end + +########################################### + +# logging + +def write_log( s ) + if test( ?e, LOGFILE ) and File.size( LOGFILE ) > 100000 + rm( LOGFILE_OLD ) if test( ?e, LOGFILE_OLD ) + ccp( LOGFILE, LOGFILE_OLD ) + File.truncate( LOGFILE, 0 ) + end + File.open( LOGFILE, 'a' ) { |f| + f.print( "#{$$} #{Time.now.strftime('%Y/%m/%d %H:%M:%S')} #{s}\n" ) + } +end + +########################################### + +require 'tmpdir' + +#$DEBUG=1 + +# save filenames for cleanup at end +$tempfiles = [] + +def mktemp( ext ) + isdone = nil + (0..99).each do |i| + fname = Dir.tmpdir + File::SEPARATOR + \ + sprintf( '%d_%02d.%s', $$, i, ext ) # $$ is process id + next if test( ?e, fname ) + File.open( fname, 'w' ) do |f|; end # creates empty file + isdone = 1 + $tempfiles.unshift( fname ) + return fname + end # each do |i| + fail StandardError, "Cannot create temp file" unless isdone +end # def + +def cleantemp + write_log( "Cleaning tempfiles" + $/ + $tempfiles.join( $/ ) ) + $tempfiles.each{ |tf|; rm( tf ) } +end + +########################################### + +# identifying file type + +# EPS with preview starts with 0xC5D0D3C6 +# Encapsulated PostScript starts with %!PS-Adobe-n.n EPSF-n.n +# but %!PS-Adobe-n.n will also be identified as Encapsulated PostScript +# if the filename extension suggests it. +# PostScript starts with %! +# PDF starts with %PDF-version + +def identify( path ) + filestart = nil + File.open( path, $R ) do |f| + filestart = f.read( 23 ) + end # this syntax automatically closes the file at end of block + case filestart + when /^\xc5\xd0\xd3\xc6/ + 'epsPreview' + when /^%!PS-Adobe-\d\.\d EPSF-\d\.\d/ + 'eps' + when /^%!PS-Adobe-\d\.\d/ + ( path =~ /\.ep(i|s|si|sf)$/i ) ? 'eps' : 'ps' + when /^%!/ + 'ps' + when /^%PDF/ + 'pdf' + else + 'other' + end # case +end # def + +########################################### + +# Boundingboxes + +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 + + def initialize( llx, lly, urx, ury ) + @llx, @lly, @urx, @ury = llx, lly, urx, ury + [@llx, @lly, @urx, @ury].each { |l| l = l.to_i.to_s } + end + + def Bb.from_bbcomment( s ) + return nil unless s =~ BB_PAT + llx, lly, urx, ury = + s.sub( /^\s*%%BoundingBox:\s*/, '' ).split( /\s+/ ) + Bb.new( llx, lly, urx, ury ) + end + + def height + ( @ury.to_i - @lly.to_i ).to_s + end + + def width + ( @urx.to_i - @llx.to_i ).to_s + end + + def valid + @llx.to_i < @urx.to_i and @lly.to_i < @ury.to_i + end + + def non_negative + valid and @llx.to_i >= 0 and @lly.to_i >= 0 + end + + def copy + Bb.new( @llx, @lly, @urx, @ury ) + end + + def prn + "#{@llx} #{@lly} #{@urx} #{@ury}" + end + + def expand + i = ( $settings.bb_spread ).to_i + return if i <= 0 + @llx = ( [ 0, @llx.to_i - i ].max ).to_s + @lly = ( [ 0, @lly.to_i - i ].max ).to_s + @urx = ( @urx.to_i + i ).to_s + @ury = ( @ury.to_i + i ).to_s + end + + ################## + + # wrapper code for a 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} #{height}\n" + + "<< /PageSize [#{width} #{height}] >>" + + " setpagedevice\n" + + "gsave #{(-(@llx.to_i)).to_s} #{(-(@lly.to_i)).to_s}" + + " translate\n" ) > 0 + end # open + return fname + end # wrapper + + ################## + + # convert boundingbox to boundingbox comment + + def bbcomment + fail EPBBError, prn unless valid + "%%BoundingBox: #{@llx} #{@lly} #{@urx} #{@ury}" + end + +end # class Bb + +########################################### + +# PsPdf class definition + +class PsPdf + + protected + + SAFESIZE = 16000 + + public + + # class methods ### + + def PsPdf.pdf_options + "-dPDFSETTINGS=/#{$settings.pdf_target}" + \ + ( $settings.pdf_version == 'default' ? '' : \ + " -dCompatibilityLevel=#{$settings.pdf_version}" ) + \ + ($settings.pdf_custom ? ' ' + $settings.pdf_custom : '') + end + + def PsPdf.gs_options + "-dNOPAUSE -dBATCH -q -dSAFER" + end + + def PsPdf.ps_options( sep ) + # the sep(arable_color) option forces a cmyk color model, + # which should improve chances of grayscaling later on. + if sep + case $settings.ps_options + when /-level\dsep\b/ + $settings.ps_options + when /-level\d\b/ + $settings.ps_options.sub( /(-level\d)/, '\1sep' ) + else + $settings.ps_options + " -level2sep" + end # case + else + $settings.ps_options + end # ifthenelse sep + end + + # instance methods ### + + attr_accessor :path, :bb, :type, :npages, :atfront + + ################## + + def initialize( params={} ) + + ext = params[ 'ext' ] + file = params[ 'file' ] + + if not ext and not file + @path = nil + @type = nil + elsif not file + @path = mktemp( ext ) + @type = case ext.downcase + when 'pdf' + 'pdf' + when 'eps' + 'eps' + when 'ps' + 'ps' + else + 'other' + end + else + @path = file + @type = identify( file ) + end + end # initialize + + ################## + + # debug string for EPCallError + + def buginfo( params = nil ) + b = "Source was: " + @path + $/ + b = b + hash_prn( params ) if params + b + end + + ################## + + # 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. + + def find_bb_simple + + fail EPCallError, buginfo unless @type == 'eps' + @bb = nil + slurp = '' + File.open( @path, $R ) do |fl| + slurp = fl.read( [File.size(@path), SAFESIZE].min ) + end + lines = slurp.split( /\r\n?|\n/ ) + lines.each do |l| + if l =~ BB_PAT + @bb = Bb.from_bbcomment( l ) + break + end + end # do |l| + fail EPBBError, @path unless @bb and @bb.valid + + end # def find_bb_simple + + ################## + + def pdf_pages + + fail EPCallError, buginfo unless @type == 'pdf' + + @npages = nil + + # get n. of pages; the Ghostscript pdf2dsc.ps script will + # create a list of pages. It seems to ignore logical p. numbers. + + dsc = mktemp( "dsc" ) + cmd = "\"#{$settings.gs_prog}\" -dNODISPLAY -q" + + " -sPDFname=\"#{@path}\" -sDSCname=\"#{dsc}\" pdf2dsc.ps" + write_log cmd # if $DEBUG + fail EPSystemError, cmd unless system( cmd ) and test( ?s, dsc ) + lines = [] + File.open( dsc, $R ) do |f| + lines = f.read( SAFESIZE ).split( /\r\n?|\n/ ) + end + lines.each do |l| + if l =~ /^%%Pages:\s+(\d+)\s*$/ + @npages = $1.to_i + break + end # if =~ + end # do |l| + + return @npages + + end # pdf_pages + + ############################################################# + + # direct conversions. These methods return a PsPdf object, + # and raise an exception in case of failure. + # Direct conversions convert at most once between PostScript and pdf. + # They always write to a temporary file. + + ################## + + # eps_clean: write source eps to an eps without preview, and + # with a boundingbox in the header. + # the eps is always written to a new file. + + def eps_clean + + fail EPCallError, buginfo if @type != 'eps' and @type != 'epsPreview' + atend = nil + slurp = '' + offset, ps_len = nil, nil + if @type == 'eps' + offset = 0 + ps_len = File.size( @path ) + else + # read ToC; see Adobe EPS spec + File.open( @path, $R ) do |fl| + # bug workaround for unpack + if "\001\000\000\000".unpack( 'V' )[0] == 1 + dummy, offset, ps_len = fl.read( 12 ).unpack( 'VVV' ) + else + dummy, offset, ps_len = fl.read( 12 ).unpack( 'NNN' ) + end + end # File + end # ifthenelse @type + + # boundingbox unknown and possibly atend + @bb, @atfront = nil, nil + + # limit search for boundingbox comments. + # For very large eps files, we don't want to scan the entire file. + # A boundingbox comment should be in the header or trailer, + # so scanning the first and last few KB should be plenty. + + File.open( @path, $R ) do |fl| + fl.seek( offset, IO::SEEK_SET ) + slurp = fl.read( [ps_len,SAFESIZE].min ) + end + + # 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 = '' + bb_comment = '' + lines.each do |l| + pre_block = pre_block + l + if l =~ BB_PAT + @bb = Bb.from_bbcomment( l ) + @atfront = true + break + elsif l =~ BB_END + atend = true + break + end # =~ BB_PAT + end # do |l| + if 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 + if l =~ BB_PAT + bb_comment = l + @bb = Bb.from_bbcomment( bb_comment ) + break + end # if + end # do + end # if atend + fail EPBBError, @path unless @bb.valid + 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 )) + end + sliceFile( @path, retVal.path, + ps_len - pre_block.length - post_block.length, + offset + pre_block.length, $A ) + File.open( retVal.path, $A ) do |fl| + fl.write( post_block.sub( BB_PAT1, '%' )) + end + end # if atend + retVal.bb = @bb.copy + retVal.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. + # 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. + # Maybe we should test whether gs' bbox device can handle + # nonnegative coordinates. + # The boundingbox in the eps is rewritten, but the eps is + # not otherwise converted. + # We don't create a new PsPdf object. + + def fix_bb + + 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" + write_log cmd # if $DEBUG + bb_output = `#{cmd}` + 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 ) + fail EPBBError, bb_output unless bb_temp.valid + bb_temp.expand + @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 + end # do |b| + fail EPBBError, bb_output + + end # fix_bb + + ################## + + # 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={} ) + + gray = params[ 'gray' ] + + fail EPCallError, buginfo( params ) unless @type == 'eps' and @atfront + + wrp = @bb.wrapper + + retVal = PsPdf.new( 'ext' => 'pdf' ) + cmd = "\"#{$settings.gs_prog}\" #{PsPdf.gs_options}" + + " -sDEVICE=pdfwrite #{PsPdf.pdf_options}" + + " -sOutputFile=\"#{retVal.path}\"" + + ( gray ? (' "' + $GRAYHEAD + '"') : "" ) + + " \"#{wrp}\" \"#{@path}\" -c grestore" + write_log cmd # if $DEBUG + fail EPSystemError, cmd \ + unless system( cmd ) and test( ?s, retVal.path ) + retVal.npages = 1 + return retVal + + end # eps_to_pdf + + ################## + + # Convert source pdf to eps. + # The option sep_color is ignored if pdftops is not available. + + def pdf_to_eps( params={} ) + + page = params[ 'page' ] ? params[ 'page' ].to_i : 1 + sep = params[ 'sep' ] + + fail EPCallError, buginfo( params ) unless @type == 'pdf' + fail EPCallError, buginfo( params ) \ + unless page > 0 and page <= @npages + retVal = PsPdf.new( 'ext' => 'eps' ) + if $settings.pdftops_prog and $settings.use_pdftops + cmd = "\"#{$settings.pdftops_prog}\"" + + " #{PsPdf.ps_options( sep )}" + + " -eps -f #{page} -l #{page}" + + " \"#{@path}\" \"#{retVal.path}\"" + else + cmd = "\"#{$settings.gs_prog}\" -sDEVICE=epswrite" + + " #{PsPdf.gs_options}" + + " -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 ) + retVal.atfront = 1 + retVal.find_bb_simple + return retVal + + end # pdf_to_eps + + ################## + + def ps_to_pdf( params={} ) + + gray = params[ 'gray' ] + + fail EPCallError, buginfo( params ) \ + unless @type == 'ps' + + retVal = PsPdf.new( 'ext' => 'pdf' ) + cmd = "\"#{$settings.gs_prog}\" #{PsPdf.gs_options}" + + " -sDEVICE=pdfwrite #{PsPdf.pdf_options}" + + " -sOutputFile=\"#{retVal.path}\"" + + ( gray ? (' "' + $GRAYHEAD + '"') : "" ) + " \"#{@path}\"" + write_log cmd # if $DEBUG + fail EPSystemError, cmd \ + unless system( cmd ) and test( ?s, retVal.path ) + + retVal.pdf_pages + return retVal + + end # def ps_to_pdf + + ################## + + def pdf_to_ps( params={} ) + + 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' + retVal = PsPdf.new( 'ext' => 'ps' ) + cmd = "\"#{$settings.pdftops_prog}\" #{PsPdf.ps_options( sep )}" + + ( page ? " -f #{page} -l #{page}" : '' ) + + " -paper match \"#{@path}\" \"#{retVal.path}\"" + write_log cmd # if $DEBUG + fail EPSystemError, cmd unless \ + system( cmd ) and test( ?s, retVal.path ) + return retVal + + end # pdf_to_ps + + ################## + + # all possible conversions, as concatenations of direct conversions. + + def any_to_any( params={} ) + + type = params[ 'type' ] + page = params[ 'page' ] + bbox = params[ 'bbox' ] + gray = params[ 'gray' ] + gRAY = params[ 'gRAY' ] # try harder to grayscale + gray = 1 if gRAY + bbox = nil if type == 'ps' + + fail EPCallError, buginfo( params ) \ + unless ( type=='eps' or type=='pdf' or type=='ps' ) + fail EPCallError, buginfo( params ) \ + if @type=='other' + fail EPCallError, buginfo( params ) \ + if type=='ps' and bbox + fail EPCallError, buginfo( params ) \ + if @type=='eps' and type=='ps' + + # gRAY tries harder to grayscale, by converting color first to cmyk + # even if it requires an additional eps - pdf - eps roundtrip. + # Normally, conversion to cmyk is done only if it doesn't take + # 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 ) + pp.pdf_pages if pp.type == 'pdf' and not pp.npages + + case pp.type + when 'eps' + + # in some cases extra eps => pdf => eps roundtrip: + # roundtrip guarantees bb.non_negative, necessary for fix_bb. + # pdf_to_ps( sep ) improves chances of grayscaling. + + pp = pp.eps_to_pdf.pdf_to_eps( 'sep' => gray ) \ + if gRAY or ( bbox and not pp.bb.non_negative ) + + case type + when 'eps' + pp = pp.eps_to_pdf( 'gray' => gray ).pdf_to_eps if gray + pp = pp.fix_bb if bbox + return pp + + when 'pdf' + pp = pp.fix_bb if bbox + return pp.eps_to_pdf( 'gray' => gray ) + + end # case type + + when 'pdf' + + case type + when 'eps' + if not gray + pp = pp.pdf_to_eps( 'page' => page ) + pp = pp.fix_bb if bbox + return pp + else + pp = pp.pdf_to_eps( 'page' => page, 'sep' => 1 ) + pp = pp.fix_bb if bbox + pp = pp.eps_to_pdf( 'gray' => 1 ) + return pp.pdf_to_eps + end + + when 'pdf' + return pp unless ( gray or bbox or page ) + if bbox or not $settings.pdftops_prog + pp = pp.pdf_to_eps( 'page' => page, 'sep' => gray ) + pp = pp.fix_bb if bbox + return pp.eps_to_pdf( 'gray' => gray ) + else + pp = pp.pdf_to_ps( 'page' => page, 'sep' => gray ) + return pp.ps_to_pdf( 'gray' => gray ) + end + + when 'ps' + if gray + pp = pp.pdf_to_ps( 'sep' => 1 ) + pp = pp.ps_to_pdf( 'gray' => 1 ) + end + return pp.pdf_to_ps + + end # case type + + when 'ps' + + case type + when 'eps' + if gRAY + pp = pp.ps_to_pdf.pdf_to_eps( 'page' => page, 'sep' => 1 ) + pp = pp.eps_to_pdf( 'gray' => 1 ) + pp = pp.pdf_to_eps + else + pp = pp.ps_to_pdf( 'gray' => gray ) + pp = pp.pdf_to_eps( 'page' => page ) + end + return pp.fix_bb + + when 'pdf' + if bbox + pp = pp.ps_to_pdf( 'sep' => gray ) + pp = pp.pdf_to_eps( 'page' => page ) + pp = pp.fix_bb + return pp = pp.eps_to_pdf( 'gray' => gray ) + elsif page + pp = pp.ps_to_pdf( 'sep' => gray ) + pp = pp.pdf_to_ps( 'page' => page ) + return pp = pp.ps_to_pdf( 'gray' => gray ) + else + pp = pp.ps_to_pdf.pdf_to_ps( 'sep' => 1 ) if gRAY + return pp.ps_to_pdf( 'gray' => gray ) + end + + when 'ps' + return pp unless page or gray + if gRAY + pp = pp.ps_to_pdf.pdf_to_ps( 'page' => page, 'sep' => 1 ) + return pp.ps_to_pdf( 'gray' => 1 ).pdf_to_ps + else + pp = pp.ps_to_pdf( 'gray' => gray ) + return pp = pp.pdf_to_ps( 'page' => page ) + end + + end # case type + + end # case pp.type + + fail "Unsupported conversion" + + end # any_to_any + +end # class PsPdf + +################################# +# main program when not called from GUI + +if __FILE__ == $0 + +require 'optparse' + +# create a pause to examine temp files +def abortt( msg ) + if $DEBUG + $stderr.puts msg + "\nPress to finish" + $stdin.gets + end + fail +end + +begin # outer rescue block + +save_settings = false + +opts = OptionParser.new do |opts| + # for help output + opts.banner = "Convert between [e]ps and pdf formats" + opts.separator "Usage: epspdf.rb [options] infile [outfile]" + opts.separator "" + opts.separator "Default for outfile is file.pdf" + + " if infile is file.eps or file.ps" + opts.separator "Default for outfile is file.eps" + + " 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' + end + + opts.on( "-U", + "Use pdftops if available", + "(overrides previous -I setting)" ) do |opt| + $settings.ignore_pdftops = '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| + $settings.pdf_version = opt + end + + opts.on( "-C CUSTOMOPTIONS", "--custom=CUSTOMOPTIONS", + "Custom options for conversion to pdf,", + "view Use.htm and ps2pdf.htm from", + "the Ghostscript documentation set" ) do |opt| + $settings.pdf_custom = opt + end + + opts.on( "-P PSOPTIONS", "--psoptions=PSOPTIONS", + "Options for pdftops; default -level2,", + "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 + end + + opts.on( "-s", + "Save (some) settings" ) do |opt| + save_settings = true + end + + opts.on( "-d", "Debug: don't remove temp files" ) do |opt| + $DEBUG = 1 + end + + opts.separator "" + + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + + # opts.on_tail("--version", "Show version") do + # puts OptionParser::Version.join('.') + # exit + # end +end # opts + +# parse options destructively + +opts.parse!( ARGV ) + +$options.page = 1 if $options.bbox and not $options.page + +$settings.write_settings if save_settings + +if ARGV.length < 1 + puts opts if not save_settings # help output + # puts "Settings:" + # $settings.each_key do |k| + # puts "key #{k} value #{$settings[k].val}" + # end + abort +elsif $options.info + puts "File type of #{ARGV[0]} is #{PsPdf.new( 'file' => ARGV[0] ).type}" + exit +elsif ARGV.length > 1 and + File.expand_path( ARGV[0] ) == File.expand_path( ARGV[1] ) + abort " Input and output files should be different." +else + infile = ARGV[0] + abort( infile + " not found or empty" ) unless test( ?s, infile ) +end + +# done with options + +######################################## + +source = PsPdf.new( 'file' => infile ) + +# We aren't finicky about the extension of the input file, +# but still want to check whether pdf is pdf. + +case source.type +when 'eps', 'epsPreview', 'ps' + abort "Wrong extension; input is not in pdf format" \ + if infile =~ /\.pdf$/i +when 'pdf' + abort "Wrong extension; input is in pdf format" \ + if infile !~ /\.pdf$/i +else + abort "Invalid input file type; not [e]ps or pdf" \ + if source.type == 'other' +end # case source.type + +# find or construct output file name +if ARGV.length > 1 + outfile = ARGV[1] +else + case source.type + when 'eps', 'epsPreview', 'ps' + outfile = infile.sub( /\.[^.]+$/, '.pdf' ) + when 'pdf' + outfile = infile.sub( /\.[^.]+$/, '.eps' ) + end # case +end # ifthenelse ARGV.length +outfile = File.expand_path( outfile ) + +$options.type = case outfile +when /\.pdf$/i + "pdf" +when /\.ps$/i + "ps" +when /\.eps$/i + "eps" +else + nil +end # case outfile + +abort "Unknown or unsupported output file extension" \ + unless $options.type +abort "Output format not supported without xpdf utilities" \ + if outfile == 'ps' and not $settings.pstopdf_prog + +pp = PsPdf.new( 'file' => infile ) + +begin # inner rescue block + pp = pp.any_to_any( $options ) +rescue EPCallError => exc + mess = + "Wrong method call or conversion not supported or wrong page number" + + $/ + exc.message + $/ + exc.backtrace.join( $/ ) + write_log( mess ) + puts mess + fail StandardError +rescue EPBBError => exc + mess = "Boundingbox problem" + $/ + + exc.message + $/ + exc.backtrace.join( $/ ) + write_log( mess ) + puts mess + fail StandardError +rescue EPSystemError => exc + mess = "Problem with system call" + $/ + + exc.message + $/ + exc.backtrace.join( $/ ) + write_log( mess ) + puts mess + fail StandardError +end # rescue block + +ccp( pp.path, outfile ) + +cleantemp unless $DEBUG == 1 + +rescue => detail +write_log detail.backtrace.join( $/ ) +puts detail.backtrace.join( $/ ) +exit +end # outer rescue block + +end # if called as main program +__END__ diff --git a/Master/texmf-dist/scripts/epspdf/epspdfboot.rb b/Master/texmf-dist/scripts/epspdf/epspdfboot.rb new file mode 100644 index 00000000000..bdcebb77b26 --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdfboot.rb @@ -0,0 +1,40 @@ +# 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 new file mode 100755 index 00000000000..f75d65b5339 --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdfrc.rb @@ -0,0 +1,507 @@ +# epspdf conversion utility, configuration module + +##### +# Copyright (C) 2006, 2008 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. +# +# In phase 1, some programs (converters, viewers) are autodetected. +# In phase 2, user preferences are read from the epspdf configuration. +# +# For unix/osx, configuration info is stored in $HOME/.epspdfrc. +# For w32, configuration info is stored in HKCU\software\epspdf. +# +# The UIs for settings are not here; they are: +# 1. the epspdf.rb command-line if epspdf.rb is run as +# a stand-alone program, and +# 2. a configuration screen in epspdftk.rb. + +require 'rbconfig' +include Config + +# for notational convenience, we keep ARCH separate + +ARCH = case CONFIG['arch'] +when /win32|mingw/ + 'w32' +when /darwin/ + 'osx' +else + 'unix' +end + +TL = ENV.has_key?('TLROOT') +if ARCH == 'w32' + require 'dl/win32' + require 'win32/registry' + include Win32 # this lets us abbreviate Win32::Registry to Registry + ShortPName = Win32API.new( + 'kernel32', 'GetShortPathName', ['P','P','N'], 'N' ) + TLROOT = ENV['TLROOT'] +end + +# for Windows, use short names within backquotes +# to avoid quotes within backquotes + +def short_name( fn ) + return fn if ARCH != 'w32' + fn.gsub!( /\\/, '/' ) + buffer = ' ' * 260 + length = ShortPName.call( fn, buffer, buffer.size ) + return ( length > 0 ) ? buffer.slice(0..length-1) : fn +end + +# system-dependent location of logfile + +LOGFILE = case ARCH +when 'w32' + TL ? "#{ENV['USERPROFILE']}\\epspdftl.log" : + "#{ENV['USERPROFILE']}\\epspdf.log" +else + "#{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' + +# 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. + +def is_a_program( s ) + case ARCH + when 'w32' + nil + else + ( system "which #{s} >/dev/null" ) ? 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 + } + end + retval +end + +class Setting + attr_reader :val, :type, :comment + attr_writer :val + + def initialize( v, t, c ) + @val = v + @type = t + @comment = c + end +end + +PDF_TARGETS = [ 'default', 'printer', 'prepress', 'screen', 'ebook' ] +PDF_VERSIONS = [ '1.2', '1.3', '1.4', 'default' ] + +$settings = { + # converters + 'gs_prog' => Setting.new( nil, 'auto', nil ), + 'gs_version' => Setting.new( nil, 'auto', nil ), + 'pdftops_prog' => Setting.new( nil, ARCH=='w32' ? 'config' : 'auto', nil ), + # 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 ), + # 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_custom' => Setting.new( '', 'config', + 'additional options for [e]ps to pdf conversion' ), + 'ps_options' => Setting.new( '-level2', 'config', + 'options for pdftops; default -level2' ), + 'bb_spread' => Setting.new( '1', 'config', + 'margin to be added to computed boundingbox; default 1' ) +} + +class << $settings + + # create shortcut methods $settings.x and $settings.x= + # for reading and writing hash elements. + + $settings.each_key { |k| + eval "def #{k} ; self[\'#{k}\'].val ; end" + eval "def #{k}=(v) ; self[\'#{k}\'].val=v ; end" + } + + # use_pdftops is a boolean counterpart and inverse + # of the stored string attribute ignore_pdftops + + 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 + 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 + end + + def accept_pdf_viewer( s ) + if ARCH == 'unix' + if is_a_program( s ) + self.pdf_viewer = s + self.pdf_viewers.unshift( s ) unless self.pdf_viewers.index( s ) + return 1 + else + return nil + end + else + return nil + end + end # accept_pdf_viewer + + def accept_ps_viewer( s ) + if ARCH == 'unix' + if is_a_program( s ) + self.ps_viewer = s + self.pdf_viewer = s unless \ + self.pdf_viewer and not self.pdf_viewer.empty? + self.ps_viewers.unshift( s ) unless self.ps_viewers.index( s ) + self.pdf_viewers.push( s ) unless self.pdf_viewers.index( s ) + return 1 + else + return nil + end + else + return nil + end + end # accept_ps_viewer + + # previously-configured settings into hash $rc_settings + # here no validity testing. + # we accept empty settings. + + def read_settings + if ARCH == 'w32' + [Registry::HKEY_LOCAL_MACHINE, + Registry::HKEY_CURRENT_USER].each { |hk| + begin # open REG_KEY safely + hk.open( REG_KEY ) do |ep| + ep.each_value do |key, type, val| + $rc_settings[ key ] = val \ + if $settings[ key ] and $settings[ key ].type == 'config' + end # do |key, type, val| + end # do |ep| + rescue + end # open REG_KEY safely + } # each |hk| + else + if test( ?s, RC_FILE ) + lines = File.read( RC_FILE ).split( /\r\n?|\n/ ) + lines.each do |l| + l = l.sub( /#.*$/, '' ) # remove trailing comments + if l =~ /^\s*(\S+)\s*=\s*(\S(.*\S)?)\s*$/ + key, val = $1, $2 + $rc_settings[ key ] = val \ + if $settings[ key ] and $settings[ key ].type == 'config' + elsif l =~ /^\s*(\S+)\s*=\s*$/ + key, val = $1, '' + $rc_settings[ key ] = '' \ + if $settings[ key ] and $settings[ key ].type == 'config' + end # if l =~ + end # do |l| + end # if ?s + end # if ARCH + end # def + + def write_settings + if ARCH == 'w32' + begin + Registry::HKEY_CURRENT_USER.create( + 'SOFTWARE', desired = Registry::KEY_ALL_ACCESS) do |reg| + reg.create( REG_K, desired = Registry::KEY_ALL_ACCESS ) do |rk| + $settings.each do |k, s| + key = String.new( k ) + st = Setting.new( s.val, s.type, s.comment ) + # this copying looks kind of silly, + # but prevents a 'modifying frozen object' error. + if st.type == 'config' + vl = st.val ? st.val : '' + rk.write_s( key, vl ) + end + end # do each + end # do |rk| + end # do |reg| + rescue => er # no real error handling for now + puts $! + puts er.backtrace.join( $/ ) + puts 'Settings will be lost at next run' + end + else + File.open( RC_FILE, 'w' ) do |f| + f.write( "# This file will be overwritten by epspdf_tk[.rb]" \ + + $/ ) + $settings.each do |key, st| + if st.type == 'config' + f.write( $/ ) + f.write( '# ' + st.comment + $/ ) if st.comment + # STDERR.puts "write setting for " + key + # STDERR.flush + f.write( key + " = " + ( st.val ? st.val : '' ) + $/ ) + end + end # do |key, st| + end # do |f| + end # if + end # def + + 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 + # viewers: use Preview; don't check anything + # unix/osx are done together, except that for osx + # the viewers code is skipped. + + 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 + try_gs_prog = nil + [Registry::HKEY_LOCAL_MACHINE, + Registry::HKEY_CURRENT_USER].each { |hk| + puts hk.to_s if $DEBUG + hk.open('SOFTWARE') { |sof| + puts sof.to_s if $DEBUG + sof.each_key { |key, wtime| + 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) + this_gs_prog = this_gs['GS_DLL'].sub( + /([\\\/])([^\\\/]+)$/, '\1gswin32c.exe') + if test(?e,this_gs_prog) + try_gs_version = skey + try_gs_prog = this_gs_prog + end # if ?e (exist) + end # skey.to_f > try_gs_version.to_f + end # if skey =~ /^\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' ) + + 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 + + # pdftops + self.pdftops_prog = xpdf_version( 'pdftops' ) ? 'pdftops' : nil + + # viewers + vw = %w{ gpdf xpdf acroread evince ggv gv kghostview } + 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| + vw2.delete( pg ) if vw2.index( pg ) + } + vw2 = nil if vw2.empty? + self.ps_viewers = vw2 + self.ps_viewer = vw2 ? vw2[ 0 ] : nil + end # if vw + end # case + + # built-in defaults already set during initialization of $settings + + # phase 2: pre-existing configuration + # w32: pdftops_prog + # unix (not osx): pdf_viewers + + read_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 + when 'unix' + if v = $rc_settings[ 'pdf_viewer' ] and is_a_program( v ) + self.pdf_viewer = v + self.pdf_viewers.unshift( v ) unless self.pdf_viewers.index( v ) + end # if + if v = $rc_settings[ 'ps_viewer' ] and is_a_program( v ) + self.ps_viewer = v + self.ps_viewers.unshift( v ) unless self.ps_viewers.index( v ) + end # if + if self.ps_viewers and not self.pdf_viewers + self.pdf_viewers = self.ps_viewers.dup + self.pdf_viewer = self.ps_viewer + end # if + end # case ARCH + + # 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' ] + when /1|yes|true|y|t/i + '1' + when /0|no|false|n|f/i + '0' + end + else + $settings.ignore_pdftops = '0' + end + + self.bb_spread = $rc_settings[ 'bb_spread' ] if + $rc_settings.has_key?( 'bb_spread' ) and + $rc_settings[ 'bb_spread' ] =~ /^[+-]?[\d]+$/ + + end # get_settings + +end # class << $settings + +$settings.get_settings diff --git a/Master/texmf-dist/scripts/epspdf/epspdftk b/Master/texmf-dist/scripts/epspdf/epspdftk new file mode 100755 index 00000000000..6d3465a8c4b --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdftk @@ -0,0 +1,7 @@ +#!/bin/sh +script=`kpsewhich -format=texmfscripts epspdftk.rb` +if test "x$1" = "x"; then + "$script" $HOME +else + "$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 new file mode 100755 index 00000000000..c09509c0c8f --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/epspdftk.rb @@ -0,0 +1,958 @@ +#!/usr/bin/env ruby + +# epspdf conversion utility, GUI frontend + +##### +# Copyright (C) 2006 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! +##### + +#$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' ) + +########################################## + +# load conversion engine. epspdf also loads epspdfrc, +# which detects platform and available converters. + +require 'epspdf' + +$VERBOSE = nil + +#require 'pp' + +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}" +end + +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' + 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? ) + end # case ARCH + return nil +end # viewable + +#################################### + +# Tk and custom widgets + +require 'tk' +require 'tkscrollbox' + +# For event field strings, which codify event details, see +# the bind man page from the tk man pages (Ubuntu: tk8.x-doc package) + +#################################### + +# combobox adapted from Takaaki Tateishi +# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/18167 + +# literal content of an xbm file, created e.g. with the GIMP + +$DOWN_ARROW_IMG = < 30, 'bd' => 1, 'highlightthickness' => 0 ) + image = TkBitmapImage.new( 'data' => $DOWN_ARROW_IMG ) + @bt_arrow = TkButton.new( @frame, 'bd' => 1, 'image' => image, + 'highlightthickness' => 0, 'command' => proc{ cmd_scrollbox } ) + @entry.pack( 'side' => 'left', 'fill' => 'x', 'expand' => 'yes' ) + @bt_arrow.pack( 'side' => 'right' ) + + # drop-down listbox + + @tframe = TkToplevel.new( @frame ) + @tframe.overrideredirect( 1 ) # no window manager decorations + @tframe.transient + @tframe.withdraw + @scrollbox = TkScrollbox.new( @tframe, 'width' => 30, 'border' => 1 ) + @scrollbox.pack( 'fill' => 'both', 'expand' => 'yes' ) + @scrollbox.bind( 'Any-Leave', proc{ hide_scrollbox } ) + # "%y", "%P": event field string; see bind manual from tk8.x-docs + @scrollbox.bind( 'Double-1', proc{ |y| select_this( y ) }, "%y" ) + @scrollbox.bind( 'Return', proc{ |y| select_this( y ) }, "%y" ) + + @entry.bind( 'FocusOut', proc{ entry_proc } ) + @entry.bind( 'Return', proc{ entry_proc } ) + @entry.bind( 'Double-1', proc{ entry_proc } ) + + delegate( :width, @entry, @scrollbox ) + + configure params if params + + end # initialize_composite + + def cmd_scrollbox + case @tframe.state + when "withdrawn" + show_scrollbox( @entries ) + else + hide_scrollbox + end + end + + def show_scrollbox( entries = nil ) + width = TkWinfo.width( @frame ) + height = 5 * TkWinfo.height( @entry ) + rootx = TkWinfo.rootx( @frame ) + rooty = TkWinfo.rooty( @frame ).to_i + TkWinfo.height( @frame ).to_i + geometry = "#{width}x#{height}+#{rootx}+#{rooty}" + @tframe.geometry( geometry ) + @tframe.deiconify + entries.each{ |entry| @scrollbox.insert( "end", entry ) } if entries + end + + def hide_scrollbox + @tframe.withdraw + @scrollbox.delete( 0, "end" ) + @entry.focus + end + + def select_this( y ) + i = @scrollbox.nearest( y ) + s = @scrollbox.get( i ) + @entry.delete( 0, 'end' ) + @entry.insert( 0, s ) + @is_valid.call( s ) # activates side effects + hide_scrollbox + end + + def entry_proc + #puts @entry.value + if @is_valid.call( @entry.value ) + @entries.unshift( @entry.value ).sort! \ + unless @entries.index( @entry.value ) + @tframe.withdraw unless @tframe.state == 'withdrawn' + else + Tk.bell + @entry.focus( true ) + end + end + + def get_entry + @entry.value + end + + def set_entry( s ) + @entry.delete( 0, 'end' ) + @entry.insert( 'end', s ) if s + end + +end # TkACombobox + +#################################### + +# checkboxes and radioboxes with built-in variables. +# use string- rather than symbol keys when creating these widgets. + +def zero_one( v ) # For Tcl/Tk, everything is a string + case v + when /t(rue)?|y(es)?|1/i + '1' + when /f(alse)?|n(o)?|0/i + '0' + when 1 + '1' + when 0 + '0' + else + nil + end +end + +class TkACheck < TkFrame + + include TkComposite + + def initialize_composite( params = {} ) + + Kernel::fail StandardError, "TkACheck doesn\'t allow \'variable\' key" \ + if params.has_key?( 'variable' ) + + v = params.delete( 'value' ) + @value = TkVariable.new( zero_one( v ) ) + + @ck = TkCheckButton.new( @frame, :variable => @value \ + ).pack( :padx => 0, :pady => 0, :ipadx => 0, :ipady => 0 ) + + delegate( 'DEFAULT', @ck ) + + configure params unless params.empty? + + end # initialize_composite + + def value + @value.value + end + + def value=( v ) + @value.value = zero_one( v ) + end + +end # TkACheck + +class TkRadios < TkFrame + + include TkComposite + + def initialize_composite( params = {} ) + + Kernel::fail StandardError, "TkRadios doesn\'t allow \'variable\' key" \ + if params.has_key?( 'variable' ) + + @value = TkVariable.new( params.delete( 'value' ) ) + @values = params.delete( 'values' ) + @packing = params.delete( 'packing' ) + @buttons = [] + + if ( @values.kind_of? Hash ) + @values.each_key { |k| + @buttons << TkRadioButton.new( @frame, + :text => @values[k] || k, + :variable => @value, + :value => k + ).pack( @packing ) + } + elsif ( @values.kind_of? Array ) + @values.each { |k| + @buttons << TkRadioButton.new( @frame, + :text => k, + :variable => @value, + :value => k + ).pack( @packing ) + } + else + Kernel::fail StandardError, "TkRadios requires a values array or hash" + end + + delegate( 'DEFAULT', @frame ) + delegate( 'command', *@buttons ) + delegate( 'state', *@buttons ) + + configure( params ) unless params.empty? + + end # initialize_composite + + def value + @value.value + end + + def value=( v ) + @value.value = v + end + + def get_button_state( v ) + @buttons.each { |b| + if b.value == v + return b.cget( 'state' ) + end + } + return nil + end + + def set_button_state( v, s ) + @buttons.each { |b| + if b.value == v + b.configure( 'state' => s ) + @value.value = nil if s == 'disabled' and @value.value == v + end + } + end + +end # TkRadios + +$root = TkRoot.new { title "PostScript- and pdf conversions" } + +################################## + +# Initial tests: no gs => bail out; no viewers => warning + +if not $settings.gs_prog + Tk.messageBox( + :icon=>'error', + :type=>'ok', + :parent=>$root, + :message=>"No Ghostscript found; aborting..." + ) + abort +end + +if not $settings.pdf_viewer + Tk.messageBox( :icon=>'warning', :type=>'ok', :message => + "No PostScript- or pdf viewer found" ) +elsif not $settings.ps_viewer + Tk.messageBox( :icon=>'warning', :type=>'ok', :message => + "No PostScript viewer found" ) +end + +######################################## + +$defaultDir = ENV['PWD'] + +$defaultDir = ARGV[0] if ((ARGV.length > 0) and File.directory?(ARGV[0])) + +$source = PsPdf.new # currently loaded PsPdf object + +$tl_config = nil # configuration screen +$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. +# They don't really have to be declared early. + +# buttons and option widgets +$view_button = nil +$page_radio = nil +$page_entry = nil +$type_radio = nil +$bbox_check = nil + +# widgets which display file info +$source_dir_label = nil +$source_name_label = nil +$source_type_label = nil + +def set_widget_states + # states (normal/disabled) for various widgets. + # their values should already be mutually consistent. + # widgets concerned: + # view / save + # output format / bbox / single page / page no. + + $view_button.configure( :state => + ( viewable( $source ) ? 'normal' : 'disabled' ) ) + $save_button.configure( :state => + ( ( $source.type and $source.type != 'other' ) ? \ + 'normal' : 'disabled' ) ) + + $type_radio.set_button_state( 'ps', ( \ + ( $settings.pdftops_prog and $settings.use_pdftops and + ( $source.type =~ /ps|pdf/ ) ) ? \ + 'normal' : 'disabled' ) ) + + $page_radio.set_button_state( 'all', 'normal' ) + $page_radio.set_button_state( 'single', 'normal' ) + $page_radio.set_button_state( 'all', 'disabled' ) if \ + $type_radio.value == 'eps' + $page_radio.set_button_state( 'single', 'disabled' ) if \ + $type_radio.value == 'ps' + + $page_entry.configure( :state => \ + ( $page_radio.value == 'all' ? 'disabled' : 'normal' ) ) + + $bbox_check.configure( :state => \ + ( $page_radio.value == 'single' or $source.type =~ /eps/ ) \ + ? 'normal' : 'disabled' ) + +end # set_widget_states + +def load_file( path ) + $source = PsPdf.new( 'file' => path ) + # write info to labels + $source_dir_label.configure( :text => File.dirname( path ) ) + $source_name_label.configure( :text => File.basename( path ) ) + $source_type_label.configure( :text => $source.type ) + $source.pdf_pages if ( $source.type == 'pdf' ) + $source_npages_label.configure( :text => ( + case $source.type + when 'pdf' then ( $source.npages ).to_s + when 'eps' then '1' + else '' + end + ) ) + $page_entry.delete( 0, 'end' ) + $page_entry.insert( 'end', '1' ) + set_widget_states +end + +# ipadx and ipady seem ineffective for frames + +FRM_PACK = { + :side => 'top', + :fill => 'x', + :expand => 1, + :padx => 4, + :pady => 4, + :anchor => 'w' +} + +################################## + +# configuration screen (toplevel widget) + +$tl_config = nil + +def ep_config + + if not $tl_config + + $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' ) + TkFrame.new( frm ) { |fm| + TkLabel.new( fm, :text => 'Pdf viewer' ).grid( + :in => fm, :row => 0, :column => 0, + :sticky => 'w', :padx => 2 ) + $pdf_vw_combo = TkACombobox.new( fm, :width => 30 ) + $pdf_vw_combo.is_valid = lambda { |s| is_a_program( s ) } + $pdf_vw_combo.grid( :in => fm, :row => 0, :column => 1, + :pady => 2, :padx => 2, :sticky => 'e' ) + + TkLabel.new( fm, :text => 'PostScript viewer' ).grid( + :in => fm, :row => 1, :column => 0, + :sticky => 'w', :padx => 2 ) + $ps_vw_combo = TkACombobox.new( fm, :width => 30 ) + $ps_vw_combo.is_valid = lambda { |s| is_a_program( s ) } + $ps_vw_combo.grid( :in => fm, :row => 1, :column => 1, + :pady => 2, :padx => 2, :sticky => 'e' ) + }.pack( :side => 'top', :anchor => 'w', :fill => 'x' ) + }.pack( FRM_PACK ) + end # if unix + + ### 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' ) + + if ARCH == 'w32' # others: assume pdftops on search path + TkLabel.new( frm, :text => "Find pdftops" + ).pack( :side => 'top', :anchor => 'w', :padx => 4 ) + + TkFrame.new( frm ) { |fm| + $pdftops_entry = TkEntry.new( fm, :width => 20 + ).pack( 'side'=>'left', :padx => 4 ) + TkButton.new( fm, + :text => 'Browse ...', + :command => lambda { + tryprog = Tk.getOpenFile( + :filetypes => [ [ 'Programs', [ '.exe' ] ] ], + :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 + $pdftops_entry.delete( 0, 'end' ) + $pdftops_entry.insert( 'end', tryprog ) + end # ifthenelse xpdf_version + end # ifthenelse tryprog + } # command lambda + ).pack( :side => 'left' ) # TkButton + }.pack( :side => 'top', :pady => 4, :anchor => 'w' ) + end # ARCH == 'w32' + + $pdftops_check = TkACheck.new( frm, + 'text' => "Use pdftops if available" + ).pack( :side => 'top', :pady => 4, :anchor => 'w' ) + + }.pack( FRM_PACK ) # TkFrame |frm| + + ### pdf 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 + + 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 ) + + ### button frame + + TkFrame.new( $tl_config ) { |frm| + + TkButton.new( frm, + :text => 'Cancel', + :command => lambda { + $tl_config.withdraw + $root.focus + } + ).pack( :padx => 4, :side => 'left', :anchor => 'e' ) + + TkButton.new( frm, + :text => 'Done', + :command => lambda { + # copy settings from widgets to $settings + case ARCH + when 'unix' # viewers + $settings.accept_ps_viewer( $ps_vw_combo.get_entry ) + $settings.accept_pdf_viewer( $pdf_vw_combo.get_entry ) + when 'w32' + $settings.pdftops_prog = $pdftops_entry.get + end + $settings.use_pdftops = ( not $pdftops_check.value == '0' ) + $settings.pdf_target = $pdf_target_radio.value + $settings.pdf_version = $pdf_version_radio.value + $settings.pdf_custom = $pdf_custom_entry.get + $settings.write_settings + $tl_config.withdraw + $root.focus + set_widget_states + } # lambda + ).pack( :side => 'left', :anchor => 'e' ) + + }.pack( :side => 'bottom', :padx => 4, :pady => 4, :anchor => 'e' ) + else + $tl_config.deiconify + end # ifthenelse $tl_config + + # copy data from $settings to widgets + if ARCH == 'unix' + $pdf_vw_combo.set_entry( $settings.pdf_viewer ) + $pdf_vw_combo.entries = $settings.pdf_viewers[0..-1] # deep copy + $ps_vw_combo.set_entry( $settings.ps_viewer ) + $ps_vw_combo.entries = $settings.ps_viewers[0..-1] + elsif ARCH == 'w32' + $pdftops_entry.delete( 0, 'end' ) + $pdftops_entry.insert( 'end', $settings.pdftops_prog ) \ + if $settings.pdftops_prog and not $settings.pdftops_prog.empty? + end # ifthenelse ARCH + $pdftops_check.value = $settings.use_pdftops ? '1' : '0' + $pdf_target_radio.value = $settings.pdf_target + $pdf_version_radio.value = $settings.pdf_version + $pdf_custom_entry.delete( 0, 'end' ) + $pdf_custom_entry.insert( 'end', $settings.pdf_custom ) \ + if not $settings.pdf_custom.empty? + +end # def ep_config + +################################### + +### makeshift help + +$tl_help = nil + +def ep_help + if not $tl_help + $tl_help = TkToplevel.new( $root, :title => 'Epspdftk help' ) + TkFrame.new( $tl_help ) { |tf| + txt = TkText.new( tf, + 'width' => 80, + 'height' => 25 + ) { |t| + TkScrollbar.new( tf, + 'command' => lambda{ |*args| t.yview( *args ) } ) { |sc| + t.yscrollcommand( lambda{ |first, last| sc.set first, last } ) + }.pack( 'side' => 'right', 'fill' => 'y' ) + }.pack( 'expand' => 'yes', 'fill' => 'both' ) + + txt.delete( '1.0', 'end' ) + + # LF ok for Win32 and Mac? Otherwise, split and join with $/ + + File.open( File.dirname( __FILE__ ) + '/epspdf.help', 'r' ) { |f| + $s = f.read + } + + txt.insert( '1.0', $s ) + + }.pack( 'side' => 'top', 'fill' => 'x' ) + + TkButton.new( $tl_help, + :text => 'Cancel', + :command => lambda{ + $tl_help.withdraw + $root.focus + } + ).pack( 'anchor' => 'e', 'padx' => 4, 'pady' => 4 ) + else + $tl_help.deiconify + end # ifthenelse $tl_help + +end # def ep_help + +### some buttons + +TkFrame.new( $root ) { |frm| + + TkButton.new( frm, + :text => "Configure", + :command => lambda { ep_config } + ).pack( :side => 'left', :padx => 4, :pady => 4 ) + + TkButton.new( frm, + :text => 'Help', + :command => lambda { ep_help } + ).pack( :side => 'right', :padx => 4, :pady => 4) + +}.pack( :side => 'top', :fill => 'x' ) # frm + +######################################## + +### status info + +TkFrame.new( $root ){ |frm| + frm.borderwidth 2 + frm.relief 'groove' + + ### status info + + TkFrame.new( frm ) { |fm| + TkLabel.new( fm, + :justify => 'left', + :text => 'Directory' + ).grid( :in => fm, :sticky => 'w', :row => 0, :column => 0 ) + $source_dir_label = TkLabel.new( fm, + :justify => 'left' + ).grid( :in => fm, :sticky => 'w', :row => 0, :column => 1 ) + + TkLabel.new( fm, + :justify => 'left', + :text => 'File' + ).grid( :in => fm, :sticky => 'w', :row => 1, :column => 0 ) + $source_name_label = TkLabel.new( frm, + :justify => 'left' + ).grid( :in => fm, :sticky => 'w', :row => 1, :column => 1 ) + + TkLabel.new( fm, + :justify => 'left', + :text => 'Type' + ).grid( :in => fm, :sticky => 'w', :row => 2, :column => 0 ) + $source_type_label = TkLabel.new( fm, + :justify => 'left' + ).grid( :in => fm, :sticky => 'w', :row => 2, :column => 1 ) + + TkLabel.new( fm, + :justify => 'left', + :text => 'Pages' + ).grid( :in => fm, :sticky => 'w', :row => 3, :column => 0 ) + $source_npages_label = TkLabel.new( fm, + :justify => 'left' + ).grid( :in => fm, :sticky => 'w', :row => 3, :column => 1 ) + + TkGrid.columnconfigure( fm, 0, :weight => 1, :minsize => 60, :pad =>4 ) + TkGrid.columnconfigure( fm, 1, :weight => 3, :minsize => 60, :pad =>4 ) + }.pack( :side => 'top', :anchor => 'w', :padx => 4 ) + +}.pack( FRM_PACK ) + +######################################## + +### conversion options: see also $options, defined in epspdf.rb + +TkFrame.new( $root ) { |frm| + + TkFrame.new( frm ) { |fm| # grayscaling, output format + TkFrame.new( fm ) { |f| # grayscaling + TkLabel.new( f, 'text' => 'Grayscaling' + ).pack( :side => 'top', :anchor => 'w' ) + + gray_options = { + 'gRAY' => 'Try harder to grayscale', + 'gray' => 'Try to grayscale', + 'color' => 'No color conversion' + } + + $gray_radio = TkRadios.new( f, + 'values' => gray_options, + 'value' => 'color', + 'packing' => { 'side' => 'top', 'anchor' => 'w' } + ).pack( :side => 'bottom', :anchor => 'w' ) # $gray_radio + }.pack( :side => 'left', :padx => 4 ) # f: grayscaling + + TkFrame.new( fm ) { |f| # output format + TkLabel.new( f, 'text' => 'Output format' + ).pack( :side => 'top', :anchor => 'w' ) + + $type_radio = TkRadios.new( f, + 'values' => [ 'pdf', 'eps', 'ps' ], + 'value' => 'pdf', + 'command' => lambda { + case 'value' + when 'eps' + $page_radio.value = 'single' + when 'ps' + $page_radio.value = 'all' + $bbox_check.value = '0' + end + set_widget_states + }, + 'packing' => { 'side' => 'top', 'anchor' => 'w' } + ).pack( :side => 'bottom', :anchor => 'w' ) + }.pack( :side => 'right', :padx => 4 ) # f: output format + }.pack( :side => 'top', :anchor => 'n', :fill => 'x' ) + + # dummy widget for extra vertical space + TkLabel.new( frm, :text => ' ' ).pack + + $bbox_check = TkACheck.new( frm, + 'text' => 'Compute tight boundingbox', + 'value' => '0', + 'command' => lambda { + $page_radio.value = 'single' if 'value' == '1' + set_widget_states + } + ).pack( :side => 'top', :padx => 4, :anchor => 'w' ) + + TkLabel.new( frm, :text => ' ' ).pack + + TkFrame.new( frm ) { |fm| + page_options = { 'all' => 'Convert all pages', 'single' => 'Page:' } + $page_radio = TkRadios.new( fm, + 'values' => page_options, + 'packing' => { 'side' => 'left', 'padx' => 4 }, + 'value' => 'single', + 'command' => lambda { + $bbox_check.value = '0' if 'value' == 'all' + set_widget_states + } + ).pack( 'side' => 'left', :anchor => 'nw' ) + + $page_entry = TkEntry.new( fm, + :validate => 'focus', + :vcmd => [ lambda { |s| + ( s =~ /\d+/ ) and + ( s.to_i >= 1 ) and + ( $source.type != 'pdf' or s.to_i <= $source.npages ) + }, "%P" ], + :invcmd => lambda { Tk.bell; $page_entry.focus }, + :width => 5 + ).pack( :side => 'left' ) + $page_entry.delete( 0, 'end' ) + $page_entry.insert( 'end', '1' ) + }.pack( 'side' => 'left', :anchor => 'nw' ) +}.pack( FRM_PACK ) + +######################################## + +### view | open | save | done buttons + +TkFrame.new( $root ) { |frm| + + $view_button = TkButton.new( frm, + :text => 'View', + :state => 'disabled', + :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) + elsif ARCH == 'osx' + fork { exec "open -a Preview \"#{$source.path}\"" } + elsif viewable( $source ) + viewer = + $source.type == 'pdf' ? $settings.pdf_viewer : $settings.ps_viewer + fork { exec "\"#{viewer}\" \"#{$source.path}\"" } + end + } + ).pack( :side=>'left', :anchor => 'w', :padx=>4, :pady=>4 ) + + TkFrame.new( frm ) { |fm| + TkButton.new( fm, + :text => 'Open..', + :command => lambda { + path = Tk.getOpenFile( + :initialdir => $defaultDir, + :filetypes => [ + ['All files', '*'], + ['EPS', ['.eps']], + ['PDF', ['.pdf']], + ['PostScript', ['.ps']] + ], + :parent => $root + ) + if path and ( not path.empty? ) + load_file( path ) + $defaultDir = File.expand_path( File.dirname( path ) ) + end + } + ).pack( :side=>'left', :padx=>4, :pady=>4 ) + + $save_button = TkButton.new( fm, + :text => "Convert and save..", + :command => lambda { + $options.type = $type_radio.value + $options.page = \ + ( ( $page_radio.value == 'single' ) ? $page_entry.value : nil ) + $options.gray = ($gray_radio.value and $gray_radio.value != 'color' ) + $options.gRAY = ($gray_radio.value and $gray_radio.value == 'gRAY' ) + $options.bbox = ( ( $bbox_check.value == '1' ) \ + and ( $page_radio.value == 'single' ) ) + filetypes = case $options.type + when 'pdf' then [ ['Pdf', ['.pdf'] ] ] + when 'ps' then [ ['PostScript', ['.ps'] ] ] + when 'eps' then [ ['EPS (Encapsulated PostScript', ['.eps'] ] ] + end + path = nil + path = Tk.getSaveFile( + :filetypes => filetypes, + :parent => $root, + :initialdir => File.dirname( $source.path ), + :initialfile => File.basename( $source.path, ".*" ) + + '.' + $options.type, + :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 + $cnv_label.configure( + 'text' => "Converting #{$source.path} to \n #{path} ..." + ) + $tl_wait.update + $tl_wait.deiconify + $tl_wait.raise + begin + result = $source.any_to_any( $options ) + rescue EPCallError => exc + mess = "Wrong method call or conversion not supported" + + " or wrong page number" + write_log( mess + $/ + + exc.message + $/ + exc.backtrace.join( $/ ) ) + Tk.messageBox( + 'icon' => 'error', + 'type' => 'ok', + 'parent' => $root, + 'message' => "#{mess}\nSee #{LOGFILE} for details." + ) + rescue EPBBError => exc + mess = "Boundingbox problem" + $/ + + exc.message + write_log( mess + $/ + exc.backtrace.join( $/ ) ) + Tk.messageBox( + 'icon' => 'error', + 'type' => 'ok', + 'parent' => $root, + 'message' => "#{mess}\nSee #{LOGFILE} for details." + ) + rescue EPSystemError => exc + mess = "Problem with system call" + $/ + + exc.message + write_log( mess + $/ + exc.backtrace.join( $/ ) ) + Tk.messageBox( + 'icon' => 'error', + 'type' => 'ok', + 'parent' => $root, + 'message' => "#{mess}\nSee #{LOGFILE} for details." + ) + ensure + $tl_wait.withdraw + end + if result + ccp( result.path, path ) + load_file( path ) + Tk.messageBox( + 'icon' => 'info', + 'type' => 'ok', + 'parent' => $root, + 'message' => "Conversion completed" + ) + end + } + ).pack( :side=>'left', :padx=>0, :pady=>4 ) + + TkButton.new( fm, + :text => "Done", + :command => lambda { $root.destroy } + ).pack( :side => 'left', :padx => 4, :pady => 4 ) + }.pack( :side => 'right', :anchor => 'e' ) +}.pack( :side => 'bottom', :fill => 'x' ) + +set_widget_states + +$root.raise + +Tk.mainloop +cleantemp diff --git a/Master/texmf-dist/scripts/epspdf/makegray.pro b/Master/texmf-dist/scripts/epspdf/makegray.pro new file mode 100644 index 00000000000..67dc5705839 --- /dev/null +++ b/Master/texmf-dist/scripts/epspdf/makegray.pro @@ -0,0 +1,29 @@ +%! +% makegray.pro, PostScript header file for grayscale conversion. + +%%%%% +% Siep Kroonenberg, n dot s dot kroonenberg at rug dot nl +% Public domain. +%%%%% + +% This version only handles some basic color models, +% and doesn't handle image data at all. +% A more robust version would be warmly welcomed. + +%%%%<< /ProcessColorModel /DeviceGray >> setpagedevice +userdict begin +% .11*B + .59*G + .3*R +/setrgbcolor { + 0.11 mul exch 0.59 mul add exch 0.3 mul add + systemdict begin setgray end +} def +% 1.0 - min(1.0, .3*C + .59*M + .11*Y + B) +/setcmykcolor { + exch 0.11 mul add + exch 0.59 mul add + exch 0.3 mul add + dup 1 gt {pop 1} if + 1 exch sub + systemdict begin setgray end +} def +end -- cgit v1.2.3