Pat*_*ckT 5 pdf postscript ghostscript eps calibre
我知道在这个数字世界中几乎无法生存.
我有很多单页的postscript文件(图形/图像)我想转换为pdf并自动裁剪到一个窄盒子.我现在在Windows上(我也使用linux,所以不要犹豫,为linux发布代码)
我过去通过组合Ghostscript gswin32c.exe和Calibre pdfmanipulate.exe获得了成功.这对许多人来说可能是一种熟悉的方法.
但由于几个原因,这种方法已经变得充满了问题.
我"升级"到64位gswin64c.exe后出现了一个问题.32位版本gswin32c.exe仍可在我的系统上运行,所以我不能抱怨太多.
处理可能编码不当的postscript文件时出现了另一个问题.似乎至少有两个问题,但我不确定哪个(如果有的话)是负责任的,或两者都是.一个问题是边界框线,例如%% BoundingBox:135 179 484 587并不总是放在从顶部开始的第二行.我明白这可能是一个问题.另一个问题是上面的边界框对应于Ghostscript中的"纵向"方向,但裁剪遵循"横向"方向.我还没有发现的另一个问题是,对于某些文件来说,裁剪似乎很随机.
所以这是我的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 )
Run Code Online (Sandbox Code Playgroud)
上述32位方法适用于高质量文件,例如PSTricks或Maple标准2D绘图驱动程序生成的Postscript level 3,但不适用于旧文件,例如.Postscript 2级(如果那样)由Maple的经典情节驱动程序产生.
我找到了一些这样的文件的解决方法.它包括使用(MiKTeX)LaTeX发行版中的epstopdf.它适用于那些Maple经典文件.不幸的是,它不适用于我几年前使用PSTricks和Matlab等其他软件生成的其他一些postscript文件.
因此,我需要进行多次转换并选择有效的转换.我想知道你是否会提出让我的生活更轻松的建议.如果我可以修复BoundingBox和Portrait/Landscape问题,我应该非常满意.
我提前感谢您的任何建议.Linux建议是可以接受的.我倾向于寻求一种解决方案,可以通过一次"返回"键来处理文件的多样性.
当然,我正在寻找一种无损类型的裁剪,一种仅仅是解释边界框,而不是将其转换为(可能)低质量的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之后出现了一个问题"你还没有说出问题所在,你有没有把它报告为bug?如果人们不报告错误,他们就不会得到修复......
我在这里给出了描述问题和错误报告的链接:https://bugs.launchpad.net/ubuntu/+source/calibre/+bug/800551,http : //www.mobileread.com/forums/archive/ index.php/t-103097.html,我的问题完全相同.
你似乎在PostScript程序和评论之间有些混淆.PostScript程序中以'%'开头的任何行都是注释,对程序的操作没有影响.所以BoundingBox评论根本不会做任何事情.
我愿不同意,如果可以的话.获取一个postscript文件,删除%% Bounding Box,保存并在Ghostview中打开它.Ghostview会抛出错误消息,然后在不使用边界框信息的情况下显示它,例如,周围有很多空白区域而不是被边界框紧紧包围的图形.所以是的,这个评论至少在Ghostview中做了一些事情.删除了%% Bounding Box后,如果你使用Calibre/pdfmanipulate来裁剪pdf,那么在有%% Bounding Box工作的情况下,它会错误地裁剪它.所以这个"评论"在显示和裁剪的上下文中非常有用.
注意,不要求它是文件的第二行.....
它是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是什么,只是为了找到页面的真正边界框?
是.
我不清楚你的'无损'裁剪是什么意思,如果你裁剪的内容你必须清楚地丢失一些东西,即使它只是空白......
我的意思是我不希望裁剪过程"整理"整个图像"光栅化"(或任何它所谓的,你会知道这个术语).裁剪出来的文件部分对我没用,所以这不是什么损失.作物中的文件部分应与原始文件具有相同的质量.这是一般的想法.
你可以在这里找到关于这方面的评论,这是我找到有用信息的地方, http://www.charlietanksley.net/philtex/reading-pdfs-on-portables/
如果你知道要裁剪的尺寸,它很容易在一次通过中进行转换,
不,我不知道大小,这就是为什么我会花这么长时间让软件为我计算它,这显然不是一件简单的事情,因为Ghostscript和epstopdf并不总是同意最佳作物,一个得到它一些文件的权利,但其他文件没有,另一个文件适合其他文件但不适合某些文件...
如果您不知道大小,那么您可以使用Ghostscript在2次传递中通过首先提取BoundingBox来完成.这将获得4个数字,边界框的左下角和右上角(如果我没记错的话).然后创建一个"翻译"PostScript操作,将页面内容向下和向左移动(使其从0左下角开始).您还可以创建页面设备请求来设置页面大小,大小由width = right - left和height = top - bottom给出.将原始文件与PostScript操作符一起提供给Ghostscript并选择pdfwrite设备,您将获得一个PDF文件.
如果您有一个方便的话,批处理文件示例会很棒.我已经看到几个基于pdfwrite的例子,没有我尝试过的例子.魔鬼在细节.
就边界框而言,它可能是一个错误,或者可能是文件制作标记,可能使用外部位置的白色墨水.在这种情况下,边界框设备仍将其视为页面内容的一部分.您可能会看到它不是,但设备不能.考虑页面是否首先填充深色背景,并使用白色墨水勾勒出内容.
这些文件都是用Matlab,Maple,PSTricks等软件创建的,并且不太可能(但显然不是不可能)在%% Bounding Box给出的区域外面会有不可见的白色标记.
在许多情况下,%% 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)
Run Code Online (Sandbox Code Playgroud)
我明白了:
%% 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)
Run Code Online (Sandbox Code Playgroud)
我得到以下边界框:
%% 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"
)
Run Code Online (Sandbox Code Playgroud)
评论中没有足够的空间来添加此内容,所以恐怕我要发布另一个答案......
PDF 文件的 BoundingBox 看起来很假的原因是 PDF 转换过程的一个特性。默认情况下,它会旋转页面,直到大部分文本处于水平位置,对于此文件(并且我假设其他文件也存在相同问题),这会导致顺时针旋转 90 度。
当然,这意味着边界框也会旋转,并且检查值表明这就是发生的情况。因此 BoundingBox对于旋转的 PDF 文件是正确的。
现在,我通过私人电子邮件提供了几个 PostScript 程序,以下是我放置的内容:
这将从源 PostScript 文件中读取 BoundingBox 行,并使用它来设置页面大小和偏移量。您可以通过设置 'SourceFileName' 传入要使用的文件名,例如,使用您提供的文件:
gs -sDEVICE=pdfwrite -sSourceFileName=classic.ps -o out.pdf 1pass.ps
Run Code Online (Sandbox Code Playgroud)
将生成一个名为 out.pdf 的文件,该文件是读取 BoundingBox 并将页面裁剪为该大小的 PDF 文件的结果。
%!PS
%% 重新定义 setpagedevice 以防止 PostScript 程序进行更改
%% 但以不同的名称保存一份副本,以便我们可以使用它。
/Oldsetpagedevice /setpagedevice 加载 def
/setpagedevice {pop} 绑定 def
(要处理的文件是) print SourceFileName ==
/SourceFile SourceFileName (r) 文件定义
/BoxString 65535 字符串定义
/LLx 0 定义
/LLy 0 定义
/URx 0 定义
/URy 0 定义
/FoundBox false def
/获取值{
token { % 读取 PostScript 标记
/LLx exch def % 现在假设它是一个数字
令牌{
/LLy 交换 def
令牌{
/URx 交换 def
令牌{
/URy 交换 def
pop % 删除任何剩余的字符串数据
true % 返回成功代码
}{
(无法从字符串中读取数字)==
false % 返回失败代码
} 如果别的
}{
(无法从字符串中读取数字)==
false % 返回失败代码
} 如果别的
}{
(无法从字符串中读取数字)==
false % 返回失败代码
} 如果别的
} {
(无法从字符串中读取数字)==
false % 返回失败代码
} 如果别的
} 绑定定义
{
SourceFile BoxString readline {
(%%BoundingBox:) 锚搜索 {
pop %% 丢弃匹配的字符串
GetValues %%提取BBox
/FoundBox exch def %% 记录成功/失败
exit %% 退出此循环
} {
pop %% 丢弃字符串,不匹配
} 如果别的
} {
(找不到 %%BoundingBox 注释)==
exit %% 没有更多数据,退出循环
} 如果别的
} 环形
SourceFile closefile %% 关闭文件
发现框{
(LLx = ) 打印 LLx ==
(LLy = ) 打印 LLy ==
(URx = ) 打印 URx ==
(URy = ) 打印 URy ==
> 旧设置页面设备
LLx 否定 LLy 否定 翻译
源文件名运行
} 如果
这旨在按照您当前的工作方式使用,它有两个优点1pass.ps:
%%BoundingBox。它的缺点是您必须处理每个文件两次,一次获取边界框,一次创建 PDF 文件。
这需要两个参数,包含 bbox 设备输出的文件名和要转换的文件名。再次,使用您发送的文件,您将像这样使用它:
gs \
-sDEVICE=bbox \
classic.ps 2> bounding.txt
Run Code Online (Sandbox Code Playgroud)
gs \
-sDEVICE=pdfwrite \
-sBoxFileName=bounding.txt \
-sPostScriptFileName=classic.ps \
-o out.pdf \
2pass.ps
Run Code Online (Sandbox Code Playgroud)
PostScript 代码classic.ps:
%!PS
%% 重新定义 setpagedevice 以防止 PostScript 程序进行更改
%% 但以不同的名称保存一份副本,以便我们可以使用它。
/Oldsetpagedevice /setpagedevice 加载 def
/setpagedevice {pop} 绑定 def
(文件中的边界框参数) print BoxFileName ==
(要处理的文件是) print PostScriptFileName ==
/BoxFile BoxFileName (r) 文件定义
/BoxString 256 字符串定义
/HiResBoxString 256 字符串定义
/LLx 0 定义
/LLy 0 定义
/URx 0 定义
/URy 0 定义
BoxFile BoxString readline % 从文件中读取第一行
{
/BoxString exch def % 重新定义字符串为我们读取的字符串
}{
(在换行符读取%%BoundingBox之前遇到EOF)==刷新
} 如果别的
BoxFile HiResBoxString readline % 从文件中读取第一行
{
/HiResBoxString exch def % 重新定义字符串为我们读取的字符串
}{
(在换行符读取%%HiResBoundingBox之前遇到EOF)==刷新
} 如果别的
BoxFile closefile % 关闭文件
BoxString (%%BoundingBox:) 锚点搜索
{
pop % 去掉数学字符串
token { % 读取 PostScript 标记
/LLx exch def % 假设它是一个数字
令牌{
/LLy 交换 def
令牌{
/URx 交换 def
令牌{
/URy 交换 def
pop % 删除任何剩余的字符串数据
}{
(无法从字符串中读取数字)==
} 如果别的
}{
(无法从字符串中读取数字)==
} 如果别的
}{
(无法从字符串中读取数字)==
} 如果别的
} {
(无法从字符串中读取数字)==
} 如果别的
}{
print(不包含 BoundingBox)==
} 如果别的
(LLx = ) 打印 LLx ==
(LLy = ) 打印 LLy ==
(URx = ) 打印 URx ==
(URy = ) 打印 URy ==
> 旧设置页面设备
LLx 否定 LLy 否定 翻译
PostScriptFileName 运行
| 归档时间: |
|
| 查看次数: |
7454 次 |
| 最近记录: |