5

我所知道的几乎不足以在这个数字世界中生存。

我有许多一页的附言文件(图形/图像),我希望将其转换为 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 位适配,但它不起作用(如果我理解https 的话,可能是因为它在我的机器上调用了一些 pypdf 脚本,而不是 calibre 提供的修补脚本: //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 )

上述 32 位方法适用于高质量文件,例如由 PSTricks 或 Maple 的标准 2D 绘图驱动程序生成的 Postscript level 3,但不适用于较旧的文件,例如。由 Maple 的经典情节驱动程序制作的后记 2 级(如果有的话)。

我找到了一些此类文件的解决方法。它包括使用 (MiKTeX) LaTeX 发行版中的 epstopdf。它适用于那些 Maple 经典文件。不幸的是,它不适用于我几年前使用 PSTricks 和其他软件(如 Matlab)生成的其他一些后记文件。

所以我需要进行一些转换并选择那些有效的。我想知道你是否有一些建议可以让我的生活更轻松。如果我能解决 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)是后记文件本身提供的边界框(我通过复制粘贴移动到第二行)它是与 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 程序和评论之间有些混淆。PostScript 程序中任何以'%' 开头的行都是注释,对程序的运行没有影响。所以 BoundingBox 评论根本不会做任何事情。

如果可以的话,我请求不同。取一个后记文件,删除 %%Bounding Box,保存并在 Ghostview 中打开它。Ghostview 会抛出错误消息,然后在不使用边界框信息的情况下显示它,例如被大量空白包围的图形,而不是被边界框紧紧包围。所以,是的,这条评论至少在 Ghostview 中起到了作用。删除 %%Bounding Box 后,如果您随后使用 Calibre/pdfmanipulate 裁剪 pdf,则在使用 %%Bounding Box 的情况下会错误地裁剪它。所以这个“注释”在显示和裁剪的上下文中非常有用。

请注意,不需要它是文件的第二行.....

它由 Adob​​e 推荐。引用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 通过首先提取 BoundingBox 来完成 2 遍。这将为您提供 4 个数字,即边界框的左下角和右上角(如果我没记错的话)。然后,您创建一个“翻译”PostScript 操作来向下和向左移动页面的内容(使其从左下角 0,0 开始)。您还可以创建一个页面设备请求来设置页面大小,该大小由宽度 = 右 - 左和高度 = 上 - 下给出。将原始文件连同 PostScript 运算符一起输入到 Ghostscript 并选择 pdfwrite 设备,您将获得一个 PDF 文件。

如果您有一个方便的批处理文件示例,那就太好了。我已经看到了几个基于 pdfwrite 的示例,但我尝试过的都没有。魔鬼在细节中。

就边界框而言,它可能是一个错误,或者可能是文件做了一个标记,可能在外部位置使用了白色墨水。在这种情况下,边界框设备仍会将其视为页面内容的一部分。您可能可以看到它不是,但设备不能。考虑一下页面是否首先填充了深色背景,然后使用白色墨水勾勒出内容。

这些文件都是用 Matlab、Maple、PSTricks 等软件创建的,在 %%Bounding Box 给出的区域之外不太可能(但显然并非不可能)出现不可见的白色标记。

在许多情况下,%%Bounding Box 注释包含所有需要的信息,我想要 Ghostscript 或 Caliber 或 pdfwrite 或任何使用该信息的人。

如果不进一步了解您想要做什么,并且最好查看一个或多个有问题的文件,我就无法提供全面的解决方案。

那很容易,我怎样才能发布一个后记文件供您查看?它是 420 KB。

谢谢肯,希望我们能找到一个可行的解决方案。

编辑 3. 我已经确定了问题的很大一部分。

我的后记文件有以下边界框,非常接近最佳裁剪:%%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"
)
4

5 回答 5

4

评论空间不足,无法添加此内容,因此恐怕我要发布另一个答案....

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

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

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

1pass.ps

这会从源 PostScript 文件中读取 BoundingBox 行,并使用它来设置页面大小和偏移量。您可以通过设置“SourceFileName”来传递要使用的文件名,例如,使用您提供的文件:

gs -sDEVICE=pdfwrite -sSourceFileName=classic.ps -o out.pdf 1pass.ps

将生成一个名为 out.pdf 的文件,该文件是读取 BoundingBox 的结果,并转换为 PDF 文件,页面裁剪为该大小。

%!PS  

%% 重新定义 setpagedevice 以防止 PostScript 程序更改  
%% 但是保留一个不同名称的副本,所以我们可以使用它。  
/Oldsetpagedevice /setpagedevice 加载定义  
/setpagedevice {pop} 绑定定义  

(要处理的文件是) print SourceFileName ==  

/SourceFile SourceFileName (r) 文件定义  
/BoxString 65535 字符串定义  
/LLx 0 定义  
/LLy 0 定义  
/URx 0 定义  
/URy 0 定义  
/FoundBox 错误定义  

/GetValues {  
  token { % 读取 PostScript 令牌  
    /LLx exch def % 现在假设它是一个数字  
    令牌{  
      /LLy 交换定义  
      令牌{  
        /URx 交换定义  
        令牌{  
          /URy exch 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 ==  
  > Oldsetpagedevice  
  LLx 否定 LLy 否定翻译  
  源文件名运行  
} 如果  

2pass.ps

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

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

PostScript 代码classic.ps

%!PS  

%% 重新定义 setpagedevice 以防止 PostScript 程序更改  
%% 但是保留一个不同名称的副本,所以我们可以使用它。  
/Oldsetpagedevice /setpagedevice 加载定义  
/setpagedevice {pop} 绑定定义  

(文件中的边界框参数) 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 交换定义  
      令牌{  
        /URx 交换定义  
        令牌{  
          /URy exch def  
          pop % 去掉所有剩余的字符串数据  
        }{  
          (无法从字符串中读取数字)==  
        } 如果别的  
      }{  
        (无法从字符串中读取数字)==  
      } 如果别的  
    }{  
      (无法从字符串中读取数字)==  
    } 如果别的  
  } {  
    (无法从字符串中读取数字)==  
  } 如果别的  
}{  
  打印(不包含边界框)==  
} 如果别的  

(LLx = ) 打印 LLx ==  
(LLy = ) 打印 LLy ==  
(URx = ) 打印 URx ==  
(URy = ) 打印 URy ==  

> Oldsetpagedevice  
LLx 否定 LLy 否定翻译  

PostScriptFileName 运行  
于 2012-01-06T14:58:35.800 回答
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 并使用相同的脚本。

于 2012-01-04T19:19:23.243 回答
2

“过去,我通过结合 Ghostscript gswin32c.exe 和 Calibre pdfmanipulate.exe 取得了成功。这可能是这里许多人熟悉的方法。”

我不确定您为什么使用 2 个应用程序,应该可以仅使用 Ghostscript 执行整个转换。

“我“升级”到 64 位 gswin64c.exe 后出现了一个问题”

您还没有说问题是什么,您是否将其报告为错误?如果人们不报告错误,他们就不会得到修复......

您似乎在 PostScript 程序和评论之间有些混淆。PostScript 程序中任何以'%' 开头的行都是注释,对程序的运行没有影响。所以 BoundingBox 评论根本不会做任何事情。

也就是说,有一个约定(文档结构约定,简称 DSC)描述了一种在 DSC 处理器可以使用的 PostScript 文件中嵌入注释的方法。有一些规则描述了程序必须如何构建才能使其工作。如果 PostScript 程序以 %!PS-Abode-mn 开头,其中 m 和 n 是整数,则它声明自己是符合 DSC 的程序,并且它符合的版本是数字“mn”。在这种情况下,PostScrip tinterpreter 不会使用 BoundingBox 注释,但 DSC 处理器可能会使用它。请注意,不需要它是文件的第二行.....

一般来说,Ghostscript 会忽略 DSC 注释,但是如果您将 ProcessDSC 设置为 true,那么它将非常有限地使用它(主要是 BoundingBox 注释来设置页面大小)。

继续。您说您使用的是 LaTeX ps2pdf,如果您已经有 PostScript 文件,您可以将其发送到 Ghostscript 以转换为 PDF。我不清楚在这种情况下您到底在使用 Ghostscript 做什么,只是为了找到页面的真正边界框?

我不清楚你所说的“无损”裁剪是什么意思,如果你裁剪内容,你必须清楚地丢失一些东西,即使它只是空白......

如果您知道要裁剪的大小,则可以很容易地一次完成转换,如果您不知道大小,那么您可以只使用 Ghostscript 通过首先提取 BoundingBox 来完成 2 次转换。这将为您提供 4 个数字,即边界框的左下角和右上角(如果我没记错的话)。然后,您创建一个“翻译”PostScript 操作来向下和向左移动页面的内容(使其从左下角 0,0 开始)。您还可以创建一个页面设备请求来设置页面大小,该大小由宽度 = 右 - 左和高度 = 上 - 下给出。将原始文件连同 PostScript 运算符一起输入到 Ghostscript 并选择 pdfwrite 设备,您将获得一个 PDF 文件。

就边界框而言,它可能是一个错误,或者可能是文件做了一个标记,可能在外部位置使用了白色墨水。在这种情况下,边界框设备仍会将其视为页面内容的一部分。您可能可以看到它不是,但设备不能。考虑一下页面是否首先填充了深色背景,然后使用白色墨水勾勒出内容。

如果不进一步了解您想要做什么,并且最好查看一个或多个有问题的文件,我就无法提供全面的解决方案。

于 2012-01-03T16:58:50.610 回答
2

好的,简要介绍一下 DSC,您关于 Ghostview 的观点是正确的,但 Ghostview 是:

  1. 不是 Ghostscript 的一部分(尽管这可能令人惊讶)
  2. DSC 感知应用程序。

我的评论适用于 PostScript 语言,意思是解释为什么 Ghostscript 会忽略这些评论。

关于“第二条必填评论”的要点;它必须存在(为了符合 DSC),它不必是第二行。尽管听到某些应用程序错误地要求这样做我并不感到惊讶。

作为一般规则,Ghostscript 的 pdfwrite PDF 输出设备不会将任何内容转换为光栅。有一些罕见的例外,通常涉及不寻常的字体类型或颜色空间,或者在将具有透明度的 PDF 转换为支持透明度之前的 PDF 版本(例如 PDF/A 或 PDF/X)时。

要从 Ghostscript 创建根据需要裁剪的 PDF 文件:

 gswin32c ^
  -o out.pdf ^
  -sDEVICE=pdfwrite ^
  -dPAGEWIDTHPOINTS=xx -dPAGEHEIGHTPOINTS=yy ^
  -dFIXEDMEDIA ^
  -c "-x -y translate" ^
  -f input.ps

如果您的 PostScript 文件尚未包含此信息,则您必须从先前调用的返回 BoundingBox 计算 xx、yy、x 和 y。鉴于你上面所说的,情况似乎是这样。

在一般情况下:

  • xx = urx - llx,
  • yy = ury - lly,
  • x = llx,
  • y = lly

一个更好的解决方案可能是编写一个 PostScript 程序来进行设置,这很容易做到。

您可以通过电子邮件将文件发送到“ken.sharp AT artifex.com”,或使用任何方便的文件传输工具,然后将 URL 邮寄给我。我最感兴趣的是返回的 BoundingBox 不是您所期望的......

我确实查看了您在上面发布的 URL,但没有看到描述 64 位版本 Ghostscript 问题的 URL。最后一个问题,您使用的是哪个版本的 Ghostscript?

于 2012-01-04T16:12:02.847 回答
0

关于calibre/pdfmanipulate.exe的回答

calibre 已从最近的版本中删除了 pdfmanipulate.exe。我发现我必须回到版本 0.8.66 才能获得 pdfmanipulate,我下载了便携版:calibre-portable-0.8.66.zip

于 2012-10-24T23:07:40.680 回答