如何将两个Postscript文件合并?

8

我正在尝试将两个或多个postscript文件合并为一个。我尝试了串联,但由于每个postscript文件可能具有不同的资源头,所以它不起作用。

有人之前做过这个吗?是否有任何库(商业或开源)可用?我不介意使用C ++,C#甚至Java库。

编辑 这些是大型的postscript文件(超过200 MB),它们的目的仅用于彩色打印(而非在线查看)。

结论

  1. ps2write不是答案,因为它不支持DSC。
  2. 正如reader pipitas正确指出的那样,pswrite生成L1输出。 它不是解决方案。
  3. 使用pdfwrite是可行的。 在此选项中,我们将两个ps转换为PDF,然后将合并的PDF转换为ps。 这种解决方案可能存在问题,因为在转换过程中可能会丢失一些信息。 此外,额外的转换步骤需要额外的资源和时间。
  4. 如果我们不需要查看输出文件,则将两个postscript文件连接在一起,并在文件之间插入以下行“false 0 startjob pop”也是一种解决方案。 (另请参见此链接

总之,合并两个postscript文件的临时解决方案是选项3或4。

6个回答

14

以下是一个Ghostscript命令行的示例,它可以将两个或多个PostScript文件一次性转换并合并为一个PDF文件:

 gswin32c.exe ^
   -o c:/path/to/output.pdf ^
   -sDEVICE=pdfwrite ^
   -dPDFSettings=/Screen ^
   [...more desired parameters (optional)...] ^
   /path/to/first.ps ^
   /path/to/second.ps ^
   /path/to/third.pdf

编辑: 我的第一次尝试错误地假设使用PDF输入文件。 当然,它也适用于PostScript(或甚至混合PS / PDF)... 输出也可以是PS。


1
你这里有很多“转换”:需要我将PostScript转换为PDF,然后将PDF合并回PostScript,再将合并的PDF转换为PostScript ?? -- 这也取决于您的打印服务提供商。有时这些人确实更喜欢PDF(而且PDF更小,因为它被压缩了),有时他们甚至有消耗PDF(而不是PostScript)的打印机。-- 如果您的过程没有完成,您不知道如何调整Ghostscript以获得更好的性能和更高的RAM允许权吗? - Kurt Pfeifle
1
@Syd:pswrite是默认情况下可以写出PostScript Level 1数据的PostScript设备。而PS L1不知道Adobe后来添加到语言中的一些高级操作符,这些操作符在PS L2和PS L3中。因此会产生更大的输出大小(例如通过像素化某些字体类型)。您可以尝试在命令中添加-dLanguageLevel=3。(但是,目前Ghostscript的level 3生成与其level 2相同的输出...) - Kurt Pfeifle
1
@Syd:ps2write 输出设备在字体不可用的情况下也会将字体转换为位图字体(例如,如果嵌入由其许可证禁止)。我现在没有太多时间,但今晚稍后我可能可以设计出完整的命令行,并提供有用的所有选项,以尽量减小 PS 输出文件大小而不影响打印质量。 - Kurt Pfeifle
@Papitas,我会将您的答案标记为最佳答案。根据我的研究,ps2write不支持DSC。正如您所指出的那样,pswrite会产生L1输出。大文件是由光栅化引起的。此时,有两个选择:1)使用pdfwrite将两个ps转换为PDF,然后将合并后的PDF转换为ps。2)连接两个后缀为postscript的文件(在文件之间加上“false 0 startjob pop”)。这两种方法都不理想,但至少能产生可用的输出。在没有更好的解决方案之前,您的建议给了我一个临时解决方案。非常感谢 :) - Syd
嗨pipitas,非常抱歉。我刚刚意识到我一直在错误地拼写你的名字。我的错。我真诚地道歉 :) - Syd
显示剩余3条评论

4

当然,您也可以将各种输入文件(PS、PDF或它们的混合)合并成一个PostScript文件。我将在下一个示例命令行中包含更多的调整参数,这将增加Ghostscript的RAM允许量800 Mb(前提是您有一台具有如此多内存的计算机):

 gswin32c.exe ^
   -o c:/path/to/output.ps ^
   -sDEVICE=ps2write ^
  -c "800000000 setvmthreshold" ^
   [...more desired parameters (optional)...] ^
   /path/to/first.ps ^
   /path/to/second.ps ^
   /path/to/third.ps

你应该说明是哪个应用程序创建了你的PostScript文件,并使用了什么样的设置。只有这样,你才能期望得到更具体的建议。你的PostScript文件可能包含高分辨率图片(例如1200dpi),而你的打印设备可能只支持600dpi。在这种情况下,降低分辨率至600dpi可以使文件大小显著减小,而不必牺牲质量。

谢谢pipitas。看到你用ps2write而不是pswrite的答案。第二个答案让我再加一分给你。我会在下次方便的时候尝试一下。哎呀,关于你的问题,产生postscript的应用程序是第三方供应商产品。 - Syd
@papitas - 在下面添加了我的评论。 - Syd

2

提醒一下,我发现在某种情况下这种方法不起作用-如果除了第一个文件以外的任何文件中有链接,它们在最终合并的PDF中将不正确。

特别是,如果说第二个PDF有一个指向其第二页的链接,它最终会成为指向合并文档的第二页的链接,这不是正确的做法...

请注意,可以免费下载pdftk,它可以正确处理链接。


+1 for pdftk。这里有一个在线网站可以使用:http://www.nublue.co.uk/tools/pdftk - DaveFar

1

正如OP在问题的结论中提到的那样,使用该行将文件连接起来。

false 0 startjob pop

在中间加入应该就可以了。因此,在bash中,可以这样编写:

mkdir merge
for ps in *.ps; do
    cat $ps >> merge/output.ps
    echo "false 0 startjob pop" >> merge/output.ps
done

然而,正如问题中提到的那样,这只有在打印(或PDF转换)时才有用。查看器可能无法显示除第一个ps文件以外的所有内容。更多详细信息可在此处找到。

它在我这里不起作用,使用“evince”打开连接的文档只显示第一个文档。顺便说一句,恭喜你创建了物理SE。 - peterh
@peterh 谢谢,我只是碰巧在对的时间出现在对的地方。我已经在我的答案中添加了免责声明 - 的确,这种方法不适用于大多数查看器,但打印机和PDF转换器应该能够处理它。尽管如此,被采纳的答案可能会更可靠;这只是一个快速的hack,我也只测试过一次... - Tobias Kienzler

1

Linux上的GhostScript附带一个名为psmerge的shell脚本(安装在/usr/bin目录中)。经过一些简单的尝试,似乎这个程序考虑了资源定义。它确实依赖于您的PostScript程序严格遵守Adobe DSC的事实。此处再次重申合法许可下的合并脚本内容:

© Angus J. C. Duggan 1991–1995

#!/usr/bin/perl
eval 'exec perl -S $0 "$@"'
    if $running_under_some_shell;

# psmerge: merge PostScript files produced by same application and setup
# usage: psmerge [-oout.ps] file1.ps file2.ps ...
#
# Copyright (C) Angus J. C. Duggan 1991-1995
# See file LICENSE for details.

use strict;
$^W = 1;
my $prog = ($0 =~ m,([^/\\]*)$,) ? $1 : $0;
my $outfile = undef;

usage() unless @ARGV;

while ($ARGV[0] =~ /^-/) {
   $_ = shift;
   if (/^-o(.+)/) {
      $outfile = $1;
   } elsif (/^-t(horough)?$/) {
      # This doesn't do anything, but we leave it for backward compatibility.
   } else {
      usage();
   }
}

my $gs = find_gs();
if (defined $gs)
{
   # Just invoke gs
   $outfile = '/dev/stdout' unless defined $outfile;
   exec +(qw(gs -q -dNOPAUSE -dBATCH -sDEVICE=pswrite),
      "-sOutputFile=$outfile", '-f', @ARGV);
   die "$prog: exec /usr/bin/gs failed\n";
}
else
{
   warn +("$prog: /usr/bin/gs not found; falling back to old," .
      " less functional behavior\n");
}

if (defined $outfile)
{
   if (!close(STDOUT) || !open(STDOUT, ">$outfile")) {
      print STDERR "$prog: can't open $1 for output\n";
      exit 1;
   }
}

my $page = 0;
my $first = 1;
my $nesting = 0;

my @header = ();
my $header = 1;

my @trailer = ();
my $trailer = 0;

my @pages = ();
my @body = ();

my @resources = ();
my $inresource = 0;

while (<>) {
   if (/^%%BeginFont:/ || /^%%BeginResource:/ || /^%%BeginProcSet:/) {
      $inresource = 1;
      push(@resources, $_);
   } elsif ($inresource) {
      push(@resources, $_);
      $inresource = 0 if /^%%EndFont/ || /^%%EndResource/ || /^%%EndProcSet/;
       } elsif (/^%%Page:/ && $nesting == 0) {
      $header = $trailer = 0;
      push(@pages, join("", @body)) if @body;
      $page++;
      @body = ("%%Page: ($page) $page\n");
       } elsif (/^%%Trailer/ && $nesting == 0) {
      push(@trailer, $_);
      push(@pages, join("", @body)) if @body;
      @body = ();
      $trailer = 1;
      $header = 0;
       } elsif ($header) {
      push(@trailer, $_);
      push(@pages, join("", @body)) if @body;
      @body = ();
      $trailer = 1;
      $header = 0;
       } elsif ($trailer) {
      if (/^%!/ || /%%EOF/) {
         $trailer = $first = 0;
      } elsif ($first) {
         push(@trailer, $_);
      }
       } elsif (/^%%BeginDocument/ || /^%%BeginBinary/ || /^%%BeginFile/) {
      push(@body, $_);
      $nesting++;
       } elsif (/^%%EndDocument/ || /^%%EndBinary/ || /^%%EndFile/) {
      push(@body, $_);
      $nesting--;
       }
}

print @trailer;

sub find_gs
{
   my $path = $ENV{'PATH'} || "";
   my @path = split(':', $path);
   foreach my $dir (@path)
   {
      return "$dir/gs" if -x "$dir/gs";
   }
   undef;
}

sub usage
{
   print STDERR "Usage: $prog [-oout] file...\n";
   exit 1;
}

谢谢您的回复。在Windows世界中,psmerge不可用(不是ghost实用程序的一部分)。可能它可以在cgywin工具集中获得。话虽如此,感谢指出在使用之前必须严格遵守DSC格式(1点)。我的研究表明,许多用户在使用psmerge时并没有取得太多成功。也许我最好只是在后置文件中使用“false 0 startjob pop”命令作为过渡解决方案。 - Syd
2
@Syd:每个文档开头加上一个简单的/saveobj save def,在结尾处加上saveobj restore,这样怎么样?我不确定它是否有等效的效果。 - dreamlax
这句话与“false 0 startjob pop”没有任何区别,但感谢您的建议(+1给您的评论)。 - Syd
psmerge可以在Ubuntu的psutils软件包中获得。 - stdcall

1

我已经成功地合并了100多个PostScript文件(1500多页),使用了%%Begin Document/ %%End Document和false 0 startjob pop方法。

我的问题是,在打印合并后的文件时,打印机在合并的文件之间暂停了20-45秒。

有人遇到过类似的问题吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接