我几乎不知道在这个数字世界中生存。
我有很多单页的postscript文件(图形/图像)我希望转换为pdf并自动裁剪到一个窄框。我现在在Windows上(我也使用linux,所以不要犹豫,为linux发布代码)
我过去通过组合Ghostscript gswin32c.exe和Calibre pdfmanipulate.exe获得了成功。这可能是许多人熟悉的方法。
但由于几个原因,这种方法已经充满了问题。
在升级"之后出现了一个问题。到64位gswin64c.exe。 32位版本gswin32c.exe仍可在我的系统上运行,所以我不能抱怨太多。
处理可能编码不当的postscript文件时出现了另一个问题。似乎至少有两个问题,但我不确定哪个(如果有的话)是负责任的,或者两个都是。一个问题是边界框线,例如 %% BoundingBox:135 179 484 587 并不总是放在从顶部开始的第二行。我明白这可能是一个问题。另一个问题是上面的边界框对应于一个"肖像"在Ghostscript中的定位,但裁剪遵循" Landscape"取向。我还没有发现的另一个问题是,对于某些文件来说,裁剪似乎很随机。
所以这是我的32位方法(适用于高质量文件),然后是64位自适应,它不起作用(可能是因为它在我的机器上调用了一些pypdf脚本而不是口径提供的修补脚本,如果我理解https://bugs.launchpad.net/ubuntu/+source/calibre/+bug/800551和http://www.mobileread.com/forums/archive/index.php/t-103097.html,但我只是在猜测,并且无论如何都不知道解决方法):
@echo off echo batch processing with Latex ps2pdf followed by Ghostscript gswin64c.exe and Calibre2 pdfmanipulate.exe for %%I in (*.ps,*.eps) do ( "C:\Program Files\MiKTeX 2.9\miktex\bin\x64\ps2pdf" %%I ) for %%I in (*.pdf) do ( "C:\Program Files (x86)\Ghostscript\gs9.00\bin\gswin32c.exe" -dSAFER -dNOPAUSE -dBATCH
-sDEVICE#bbox "%%I" 2> bounding "C:\Program Files (x86)\Calibre2\pdfmanipulate.exe" crop -o "%%~nICropped32.pdf" -b bounding "%%I" pause "C:\Program Files\Ghostscript\gs9.04\bin\gswin64c.exe" -dSAFER -dNOPAUSE -dBATCH
-sDEVICE#bbox "%%I" 2> bounding "C:\Program Files (x86)\Calibre2\pdfmanipulate.exe" crop -o "%%~nICropped64.pdf" -b bounding "%%I" pause )
上述32位方法适用于高质量文件,例如:后记3级由PSTricks或Maple的标准2D绘图驱动程序生成,但不适用于较旧的文件,例如。后记2级(如果那样)由Maple的经典情节驱动程序产生。
我找到了一些此类文件的解决方法。它包括使用(MiKTeX)LaTeX发行版中的epstopdf。它适用于那些Maple经典文件。不幸的是,它并不适用于我几年前用PSTricks和其他软件如Matlab生成的其他一些postscript文件。
所以我需要进行几次转换并选择有效的转换。我想知道你是否会提出让我的生活更轻松的建议。如果我能修复BoundingBox和Portrait / Landscape问题,我应该非常满意。
我提前感谢您的任何建议。 Linux建议是可以接受的。我倾向于寻求一种解决方案,它可以在一次推送" return"键。
当然,我正在寻找一种无损类型的裁剪,一种仅仅是解释边界框,而不是将其转换为(可能)低质量的PDF格式。
编辑:我忘了说。当我将gswin32c / pdfmanipulate应用于高质量的3级postscript文件时,该文件名为" bounding"填写以下信息:%% BoundingBox:34 128 567 667 %% HiResBoundingBox:34.364390 128.875004 566.054069 666.071980
在上面的示例中,文件已经被裁剪掉了。请注意%% BoundingBox和%% HiResBoundingBox
之间的接近程度但是应用于低质量等级2(或者它声称是)postscript文件,"边界"文件填写:
%% BoundingBox:189 137 574 467 %% HiResBoundingBox:189.485994 137.843996 573.299983 466.668478
但边界框确实应该是 %% BoundingBox:135 179 484 587 上面的(135 179 484 587)是postscript文件本身提供的边界框(我通过复制粘贴移动到第二行),它与纵向方向上由Ghostview / Ghostscript解释的边界框一致。
但它完全被Ghostscript忽略了......
我不知道189 137 574 467来自哪里 - 这是非常错误的......
编辑2.我想澄清几点,回答肯的问题:
嗨肯,谢谢你的回复,
抱歉,如果我的问题不清楚 - 尽管如此,你似乎已经理解了它的要点 - 让我依次回答你的问题:
我不确定您使用2个应用程序的原因,应该可以使用Ghostscript执行整个转换。
我没有找到使用Ghostscript完成所有操作的方法,所以我用另一种方式。我在这里找到了Ghostscript / Calibrate的建议,http://www.mobileread.com/forums/archive/index.php/t-72885.html,以及其他地方,尝试了它,直到最近才起作用。
我并不是说不可能用Ghostscript做到这一切,我只是说我找不到办法。
"在我升级"之后出现了一个问题。到64位gswin64c.exe" 您还没有说出问题所在,您是否将其报告为错误?如果人们不报告错误,他们就不会得到修复......
我在这里提供了描述问题和错误报告的链接:https://bugs.launchpad.net/ubuntu/+source/calibre/+bug/800551, http://www.mobileread.com/forums/archive/index.php/t-103097.html, 我的问题完全相同。
我愿不同意,如果可以的话。获取一个postscript文件,删除%% Bounding Box,保存并在Ghostview中打开它。 Ghostview抛出错误消息,然后在不使用边界框信息的情况下显示它,例如,一个由很多白色空间围绕而不是被边界框紧紧包围的人物。所以是的,这个评论至少在Ghostview中做了一些事情。删除%% Bounding Box后,如果您随后使用Calibre / pdfmanipulate裁剪pdf,则在%% Bounding Box工作的情况下会错误地裁剪它。所以这个"评论"在显示和裁剪的上下文中非常有用。您似乎在PostScript程序和评论之间存在一些混淆。 PostScript程序中的任何行开头'%'是评论,对程序的运行没有影响。因此,BoundingBox评论根本不会做任何事情。
请注意,不要求它是文件的第二行.....
Adobe推荐。引自adobe,
"第二个必需的DSC标题注释提供有关的信息 EPS文件的大小必须存在,以便包含应用程序 正确转换和剪辑EPS文件。这是边界框注释。"
http://partners.adobe.com/public/developer/en/ps/5002.EPSF_Spec.pdf
Adobe说"必须。"就个人而言,只要我能从我的eps中产生适当限制的pdf,我就不会那么在乎它。
一般情况下,Ghostscript会忽略DSC注释,但是如果将ProcessDSC设置为true,那么它将非常有限地使用它(主要是用于设置页面大小的BoundingBox注释)。
使用pdfmanipulate,它会在正确裁剪的pdf和不正确裁剪的pdf之间产生差异。
继续前进。您说您正在使用LaTeX ps2pdf,如果您已经有一个PostScript文件,您可以将其发送到Ghostscript以转换为PDF。我不清楚在这种情况下你究竟使用Ghostscript是什么,只是为了找到页面的真正边界框?
是
我不清楚你的意思是什么?无损'裁剪,如果你裁剪内容你必须清楚地丢失一些东西,即使它只是空白......
我的意思是我不希望裁剪过程“光栅化”#34; (或者无论它叫什么,你都会知道这个术语)整个图像。裁剪出来的文件部分对我没用,所以它并没有太大的损失。作物中的文件部分应与原始文件具有相同的质量。这是一般的想法。
你可以在这里找到关于此的评论,这是我找到有用信息的地方, http://www.charlietanksley.net/philtex/reading-pdfs-on-portables/
如果您知道要裁剪的尺寸,它很容易在一次通过中进行转换,
不,我不知道大小,这就是为什么我会花这么长时间让软件为我计算它,这显然不是一件简单的事,因为Ghostscript并且epstopdf并不总是同意最佳作物,一个是正确的一些文件,而不是其他文件,另一个是正确的其他文件,但不适合一些......
如果您不知道大小,那么只需使用Ghostscript就可以通过首先提取BoundingBox来完成2次传递。这将获得4个数字,边界框的左下角和右上角(如果我没记错的话)。然后,您创建一个'翻译' PostScript操作将页面内容向下和向左移动(使其从0,0左下角开始)。您还可以创建页面设备请求来设置页面大小,大小由width = right - left和height = top - bottom给出。将原始文件与PostScript操作符一起提供给Ghostscript并选择pdfwrite设备,您将获得一个PDF文件。
如果您有一个方便的话,批处理文件示例会很棒。我已经看到了几个基于pdfwrite的例子,但我没有尝试过这些例子。魔鬼在细节中。
就边界框而言,它可能是一个错误,或者可能是文件制作标记,可能使用外部位置的白色墨水。在这种情况下,边界框设备仍将其视为页面内容的一部分。您可能会发现它不是,但设备不能。考虑页面是否首先填充了深色背景,并使用白色墨水勾勒出内容。
这些文件都是用Matlab,Maple,PSTricks等软件创建的,并且不太可能(但显然不是不可能)在%% Bounding Box给出的区域外面会有不可见的白色标记。 / p>
在许多情况下,%% Bounding Box注释包含所需的所有信息,我喜欢Ghostscript或Calibre或pdfwrite或任何人使用该信息。
如果不了解更多关于您想要做的事情,并且理想地看到一个或多个有问题的文件,我无法提供全面的解决方案。
这将非常简单,我如何发布一个postscript文件供您查看?它是420千字节。
谢谢Ken,我们希望我们能找到一个可行的解决方案。
编辑3.我发现了问题的很大一部分。
我的postscript文件有以下边界框,非常接近最佳裁剪: %% BoundingBox:135 179 484 587
当我运行Ghostscript gswin64c / gswin32c来计算边界框时,即
for %%I in (*.ps,*.eps) do ("C:\Program Files\Ghostscript\gs9.04\bin\gswin64c.exe" -dSAFER -dNOPAUSE -dBATCH -dAutoRotatePages=/None -sDEVICE#bbox "%%I" 2> bounding)
我明白了:
%% BoundingBox:145 189 475 574 %% HiResBoundingBox:145.331574 189.485994 474.155986 573.299983
当我运行ps2pdf后跟Ghostscript gswin64c,即
for %%I in (*.ps,*.eps) do ("C:\Program Files\MiKTeX 2.9\miktex\bin\x64\ps2pdf" %%I)
for %%I in (*.pdf) do ("C:\Program Files\Ghostscript\gs9.04\bin\gswin64c.exe" -dSAFER -dNOPAUSE -dBATCH -dAutoRotatePages=/None -sDEVICE#bbox "%%I" 2> bounding)
我得到以下边界框:
%% BoundingBox:189 137 574 467 %% HiResBoundingBox:189.395994 137.843996 573.299983 466.668478
所以问题是ps2pdf从ps到pdf的转换引入了边界框信息的变化,导致裁剪错误。所以用其他东西替换ps2pdf,比如eps2pdf解决了这里的问题。当然还有其他解决方案。如Ken和luser droog所建议的那样,特别有价值的是涉及Ghostcript的解决方案。他们非常有价值(并且优于我的快速修复)建议如下。这样的事情起作用了:
for %%I in (*.eps,*.ps) do ("C:\Program Files\MiKTeX 2.9\miktex\bin\x64\epstopdf" %%I)
for %%I in (*.pdf) do (
"C:\Program Files\Ghostscript\gs9.04\bin\gswin64c.exe" -dSAFER -dNOPAUSE -dBATCH -dAutoRotatePages=/None -sDEVICE#bbox "%%I" 2> bounding
"C:\Program Files (x86)\Calibre2\pdfmanipulate.exe" crop -o "%%~nICropped.pdf" -b bounding "%%I"
)
答案 0 :(得分:4)
如果只是强制执行,BoundingBox注释将执行您想要的操作,您可以使用文本扫描程序替换对ghostscript的第一次调用。
这是上面脚本的sh版本(不能代表那些Windows路径名!)
for i in *.pdf ;
do
gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=bbox "$i" 2> bounding ;
pdfmanipulate crop -o "${i%.pdf}-cropped.pdf" -b bounding "$i" ;
done
您可以将其修改为使用grep
,如下所示:
for i in *.pdf ;
do
grep '%%BoundingBox' "$i" > bounding ;
pdfmanipulate crop -o "${i%.pdf}-cropped.pdf" -b bounding "$i" ;
done
如果我在Windows上尝试这样做,我会安装cygwin并使用相同的脚本。
答案 1 :(得分:4)
评论中的空间不足以添加此内容,所以我担心我还会发布另一个答案....
由于PDF转换过程的特性,BoundingBox看起来对PDF文件造成伪造的原因。默认情况下,它旋转页面,直到大部分文本是水平的,对于这个文件(并且我假设其他文件具有相同的问题),这导致顺时针旋转90度。
这当然也意味着边界框也会旋转,并且对值的检查表明这就是发生的事情。因此,对于旋转的PDF文件,BoundingBox是正确的。
现在,我通过私人电子邮件提供了几个PostScript程序,这就是我所说的:
这将从源PostScript文件中读取BoundingBox行,并使用它来设置页面大小和偏移量。您通过使用您提供的文件设置'SourceFileName'例如传递要使用的文件的名称:
gs -sDEVICE=pdfwrite -sSourceFileName=classic.ps -o out.pdf 1pass.ps
将生成一个名为out.pdf的文件,该文件是读取BoundingBox的结果,并转换为PDF文件,页面被裁剪为该大小。
%!PS %% redefine setpagedevice to prevent changes by the PostScript program %% But keep a copy under a different name, so we cna use it. /Oldsetpagedevice /setpagedevice load def /setpagedevice {pop} bind def (File to process is ) print SourceFileName == /SourceFile SourceFileName (r) file def /BoxString 65535 string def /LLx 0 def /LLy 0 def /URx 0 def /URy 0 def /FoundBox false def /GetValues { token { % read a PostScript token /LLx exch def % Assume its a number for now token { /LLy exch def token { /URx exch def token { /URy exch def pop % Get rid of any remaining string data true % return success code }{ (Failed to read a number from the string) == false % return failure code } ifelse }{ (Failed to read a number from the string) == false % return failure code } ifelse }{ (Failed to read a number from the string) == false % return failure code } ifelse } { (Failed to read a number from the string) == false % return failure code } ifelse } bind def { SourceFile BoxString readline { (%%BoundingBox:) anchorsearch { pop %% discard matching string GetValues %% extract BBox /FoundBox exch def %% Note success/failure exit %% exit this loop } { pop %% discard string, no match } ifelse } { (Failed to find a %%BoundingBox comment) == exit %% No more data, exit loop } ifelse } loop SourceFile closefile %% close the file FoundBox { (LLx = ) print LLx == (LLy = ) print LLy == (URx = ) print URx == (URy = ) print URy == > Oldsetpagedevice LLx neg LLy neg translate SourceFileName run } if
这是用于您当前工作的方式,它比1pass.ps
有两个优势:
%%BoundingBox
注释的文件。它的缺点是你必须处理每个文件两次,一次是获取边界框,一次是创建PDF文件。
这需要两个参数,包含bbox设备输出的文件名,以及要转换的文件的名称。再次,使用您发送的文件,您将使用它:
gs \
-sDEVICE=bbox \
classic.ps 2> bounding.txt
gs \
-sDEVICE=pdfwrite \
-sBoxFileName=bounding.txt \
-sPostScriptFileName=classic.ps \
-o out.pdf \
2pass.ps
classic.ps
的PostScript代码:
%!PS %% redefine setpagedevice to prevent changes by the PostScript program %% But keep a copy under a different name, so we cna use it. /Oldsetpagedevice /setpagedevice load def /setpagedevice {pop} bind def (Bounding Box parameters in file ) print BoxFileName == (File to process is ) print PostScriptFileName == /BoxFile BoxFileName (r) file def /BoxString 256 string def /HiResBoxString 256 string def /LLx 0 def /LLy 0 def /URx 0 def /URy 0 def BoxFile BoxString readline % Read first line from file { /BoxString exch def % redefine string to be the one we read }{ (Encountered EOF before newline reading %%BoundingBox) == flush } ifelse BoxFile HiResBoxString readline % Read first line from file { /HiResBoxString exch def % redefine string to be the one we read }{ (Encountered EOF before newline reading %%HiResBoundingBox) == flush } ifelse BoxFile closefile % close the file BoxString (%%BoundingBox:) anchorsearch { pop % Get rid of the mathcing string token { % read a PostScript token /LLx exch def % Assume its a number token { /LLy exch def token { /URx exch def token { /URy exch def pop % Get rid of any remaining string data }{ (Failed to read a number from the string) == } ifelse }{ (Failed to read a number from the string) == } ifelse }{ (Failed to read a number from the string) == } ifelse } { (Failed to read a number from the string) == } ifelse }{ print (does not contain a BoundingBox) == } ifelse (LLx = ) print LLx == (LLy = ) print LLy == (URx = ) print URx == (URy = ) print URy == > Oldsetpagedevice LLx neg LLy neg translate PostScriptFileName run
答案 2 :(得分:2)
“我过去通过组合Ghostscript gswin32c.exe和Calibre pdfmanipulate.exe获得了成功。这可能是一个 许多人熟悉这种方法。“
我不确定你为什么使用2个应用程序,应该可以只使用Ghostscript执行整个转换。
“我升级到64位gswin64c.exe后出现了一个问题”
您还没有说出问题所在,您是否将其报告为错误?如果人们不报告错误,他们就不会得到修复......
您似乎在PostScript程序和评论之间存在一些混淆。 PostScript程序中以'%'开头的任何行都是注释,并且对程序的操作具有 no 效果。因此,BoundingBox注释根本不会做任何事情。
也就是说,有一个约定(Document Structure Convention,简称DSC),它描述了在DSC处理器可以使用的PostScript文件中嵌入注释的方法。有一些规则描述了如何构建程序以使其工作。如果一个PostScript程序开始%!PS-Abode-m.n,其中m和n是整数,那么它声明自己是一个符合DSC的程序,它所遵循的版本是数字'm.n'。在这种情况下,PostScrip tinterpreter不会使用BoundingBox注释,但DSC处理器可能会使用它。请注意,不要求它是文件的第二行.....
一般情况下,Ghostscript会忽略DSC注释,但是如果将ProcessDSC设置为true,那么它将非常有限地使用它(主要是用于设置页面大小的BoundingBox注释)。
继续前进。您说您正在使用LaTeX ps2pdf,如果您已经有一个PostScript文件,您可以将其发送到Ghostscript以转换为PDF。我不清楚在这种情况下你究竟使用Ghostscript是什么,只是为了找到页面的真正边界框?
我不清楚你的'无损'裁剪是什么意思,如果你裁剪的内容你必须清楚地丢失一些东西,即使它只是空白......
如果您知道要裁剪的大小,它很容易在一次传递中进行转换,如果您不知道大小,那么您可以仅使用Ghostscript在2次传递中通过首先提取BoundingBox来完成完成了。这将获得4个数字,边界框的左下角和右上角(如果我没记错的话)。然后你创建一个'翻译' PostScript操作将页面内容向下和向左移动(使其从0,0左下角开始)。您还可以创建页面设备请求来设置页面大小,大小由width = right - left和height = top - bottom给出。将原始文件与PostScript操作符一起提供给Ghostscript并选择pdfwrite设备,您将获得一个PDF文件。
就边界框而言,它可能是一个错误,或者可能是文件制作标记,可能使用外部位置的白色墨水。在这种情况下,边界框设备仍将其视为页面内容的一部分。您可能会看到它不是,但设备不能。考虑页面是否首先填充了深色背景,并使用白色墨水勾勒出内容。
如果不了解更多关于您想要做的事情,并且理想地看到一个或多个有问题的文件,我无法提供全面的解决方案。
答案 3 :(得分:2)
可以在DSC上简单介绍一下,关于Ghostview的观点是正确的,但Ghostview是:
我的评论适用于PostScript语言,意思是解释Ghostscript忽略这些评论的原因。
关于“第二次要求评论”的观点;它必须存在(对于DSC符合性),它不一定是第二行。虽然听到一些应用程序错误地要求,但我并不会感到惊讶。
作为一般规则,Ghostscript的pdfwrite PDF输出设备不会将任何内容转换为栅格。有一些罕见的例外,通常涉及不寻常的字体类型或颜色空间,或者在支持透明度之前将具有透明度的PDF转换为PDF版本(例如PDF / A或PDF / X)。
创建一个PDF文件,根据需要从Ghostscript中裁剪:
gswin32c ^
-o out.pdf ^
-sDEVICE=pdfwrite ^
-dPAGEWIDTHPOINTS=xx -dPAGEHEIGHTPOINTS=yy ^
-dFIXEDMEDIA ^
-c "-x -y translate" ^
-f input.ps
如果PostScript文件尚未包含此信息,则必须从先前调用的返回BoundingBox计算xx,yy,x和y。鉴于你上面说的话,情况似乎就是这样。
在一般情况下:
更好的解决方案可能是编写一个PostScript程序来进行设置,这很容易做到。
您可以将文件通过电子邮件发送至'ken.sharp AT artifex.com',或使用任何方便的文件传输工具向我发送URL。我最感兴趣的是返回的BoundingBox不是你所期望的......
我确实查看了上面发布的网址,但我看不到有人描述64位版本的Ghostscript问题。作为最后一个问题,您使用的是哪个版本的Ghostscript?
答案 4 :(得分:0)
关于caliber / pdfmanipulate.exe的答案
caliber已从最近的版本中删除了pdfmanipulate.exe。我发现我必须回到版本0.8.66才能获得pdfmanipulate,我下载了便携版本:calibre-portable-0.8.66.zip