Ghostscript:如何自动裁剪STDIN到“边界框”并写入PDF?

时间:2016-12-14 09:46:43

标签: pdf stdin crop ghostscript bounding-box

这里已经有很多关于使用Ghostscript裁剪文档的问题和答案。 但是,答案与我的确切需求不符,并且仍然让我感到困惑。 我预计会有一个选项,例如“-AutoCropToBBox”或类似的东西。

为了澄清,作为一个边界框,我理解最小的矩形框,它完全包含所有(非白色(?))打印对象。

此外,我希望/必须使用打印机端口重定向(RedMon)通过从任何应用程序打印到Postscript打印机来生成裁剪的PDF。 因此,在Win7 / 64bit下,我设置了重定向的端口属性: Redirected port properties Win7/64bit

输出重定向到 C:\Windows\system32\cmd.exe

该计划的论据是:

/c gswin64c.exe -sDEVICE=pdfwrite -o -sOutputFile="%1".pdf -

“%1”包含filename的用户输入。有了这个,我得到一整页PDF。精细!

但是如何添加裁剪选项?

其他问题: 如果我有一个多页文档,这样的(自动)裁剪是否适用于每个页面?或者是否可以选择保持相同,例如像第一页或所有页面的最大边界框?

另一个相关问题: 提示文件名的窗口总是弹出我正在打印的应用程序后面。总是把它带到前线的任何想法?

另一个问题: 有Perl脚本“ps2eps”和程序bbox.exe(见http://ctan.org/pkg/ps2eps)。据说Ghostscript(或ps2epsi)是在计算错误的边界框。这(仍然)是真的吗?

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

你的第一个问题是,PostScript程序通常被编写为期望被渲染到特定的媒体大小,并且通常不会紧密地限制它。白色空间对于可读性非常重要。

通常,您生成的PostScript程序将请求特定的媒体大小,解释器将尽力匹配。如果它无法匹配,那么它将使用策略尝试尽可能接近,并缩放整个内容以适应该媒体。

如果打印机在完成之前不知道所需的尺寸,则不能指望打印机执行任何这些操作,并且在渲染完所有标记内容之前,您无法确定边界框。确实有些文件通常是EPS文件有一个%% BoundingBox注释但是......这是一个注释,它在PostScript中没有任何效果,它有利于那些不想解释PostScript的应用程序。

这就是为什么你想要的简单开关不存在,它会破坏解释器的正常功能,以便渲染。

因此,您需要做的第一件事是确定内容的边界框。正如Stefan所说,你可以通过使用bbox设备来做到这一点。就此而言,据我所知,bbox设备可以产生准确的输出。如果没有,那么我们将非常感谢错误报告证明它,以便我们可以解决它。如果人们不报告错误我们应该如何了解它们?令人失望的是看到有人传播FUD而不是帮忙搞错误报告.......

ps2epsi不是Ghostscript,它是一个糟糕而又开朗的脚本,我不会用它。但是.....如果原始的PostScript在堆栈上留下了东西,那么它最终将成为损坏的(或无效的)EPS文件,并且在尝试使用它之前应修复原始的PostScript,因为它会破坏任何尝试的PostScript程序使用它(例如,如果您将EPS包含在docuemnt中然后打印它)。

因此,如果您正在使用Ghostscript,并且想要使用PostScript程序并从中获取EPS,请使用eps2write设备。坦白地说它不会有任何关注的预览。

现在如果我没记错bbox设备(和eps2write)记录所有标记操作,你不能简单地记录所有非白色标记操作;如果白色覆盖页面上的现有标记怎么办?如果媒体白色怎么办?请注意,如果使用Ghostscript渲染到PNG,则输出的未触摸部分是透明的,而白色标记则不是。

因此,无论颜色如何,bbox都是所有标记操作的范围。唯一的其他方法是渲染内容并计算非白色像素。但这仅适用于特定分辨率,更改分辨率,精确的边界框也可能会发生变化。

一旦你有了边框,你可以告诉Ghostscript使用那么大的媒体。请注意,您几乎肯定会必须翻译原点,因为内容不太可能在左下角紧密开始。您将需要-dDEVICEWIDTHPOINTS和-dDEVICEHEIGHTPOINTS来设置介质大小,您需要使用-c和-f发送PostScript以适当地更改原点。在简单的情况下,'-x -y translate'就足够了,但如果程序执行initgraphics,你将不得不设置一个BeginPage程序来改变初始CTM。

如果使用-dDEVICEWIDTHPOINTS等设置媒体大小,则所有页面的大小都相同。如果您不想这样,那么您需要编写一个BeginPage过程来单独调整每个页面的大小(您还需要挂钩setpagedevice并从字典中删除/ PageSize条目。

我不知道为什么Windows将对话框放在活动窗口后面,它似乎已经开始使用Windows 7(或可能是Vista)。我没有看到任何改变方法,因为我不确定是什么产生了对话.......

我个人建议您尝试通过Ghostscript的eps2write设备运行原始文件的两步方法,然后使用pdfwrite设备和-dEPSCrop开关获取EPS并创建PDF文件。双重转换很糟糕,但其他解决方案更糟糕。请注意,EPS文件不能是多页的,因此您必须从n页PostScript程序创建'n'EPS文件,然后提供一个命令行,列出每个EPS文件作为输入到pdfwrite device。

获取示例文件并在尝试编写脚本之前从命令行尝试此操作。

答案 1 :(得分:0)

正如我从@KenS解释中所理解的那样:

  1. eps2write的工作方式,它可能没有或不会或实际上不能产生最小可能的边界框
  2. 需要通过-sDEVICE = bbox
  3. 分为两个步骤

    因此,我现在最终使用以下过程“打印”具有正确最小可能边界框的PDF:

    将重定向的打印机端口重定向到cmd.exe    C:\Windows\system32\cmd.exe

    该计划的论点:

     /c gswin64c.exe -q -o "%1".ps -sDEVICE=ps2write - && gswin64c.exe -q -dBATCH -dNOPAUSE -sDEVICE=bbox -dLastPage=1 "%1".ps 2>&1 >nul | perl.exe C:\myFiles\CropPS2PDF.pl "%1"
    

    不幸的是,它需要一个小的Perl脚本(让我们称之为:CropPS2PDF.pl):

    #!usr/bin/perl -w
    use strict;
    my $FileName = $ARGV[0];
    $/ = undef;
    my $Crop = <STDIN>; 
    
    $Crop =~ /%%BoundingBox: (\d+) (\d+) (\d+) (\d+)/s;   # get the bbox coordinates
    my ($llx, $lly, $urx, $ury) = ($1, $2, $3, $4);
    print "\n$FileName: $llx, $lly, $urx, $ury \n";   # print just to check
    
    my $Command = qq{gswin64c.exe -q -o $FileName.pdf -sDEVICE=pdfwrite -c "[/CropBox [$llx $lly $urx $ury]" -c " /PAGE pdfmark" -f $FileName.ps};
    
    print $Command;    # print just to check
    system($Command);    # execute command
    

    似乎工作...... :-) 欢迎改进。

    我的问题仍然存在:

    1. 没有Perl,这可以以某种方式完成吗?只是Win7,cmd.exe和Ghostscript?
    2. 有没有办法不将PS文件写入磁盘我不需要?当然,我之后也可以使用Perl脚本删除它。