批量转换和裁剪后记到pdf

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/800551http://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)

Ken*_*enS 4

评论中没有足够的空间来添加此内容,所以恐怕我要发布另一个答案......

PDF 文件的 BoundingBox 看起来很假的原因是 PDF 转换过程的一个特性。默认情况下,它会旋转页面,直到大部分文本处于水平位置,对于此文件(并且我假设其他文件也存在相同问题),这会导致顺时针旋转 90 度。

当然,这意味着边界框也会旋转,并且检查值表明这就是发生的情况。因此 BoundingBox对于旋转的 PDF 文件是正确的。

现在,我通过私人电子邮件提供了几个 PostScript 程序,以下是我放置的内容:

1pass.ps

这将从源 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 否定 翻译  
  源文件名运行  
} 如果  

2pass.ps

这旨在按照您当前的工作方式使用,它有两个优点1pass.ps

  1. 它适用于 PDF 文件、PostScript 文件以及不包含注释的文件%%BoundingBox
  2. 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 运行