给定一组PDF文件,其中一些页面是彩色的,其余的是黑白的,是否有任何程序可以在给定的页面中查找颜色,哪些是黑白?例如,这可以用于打印论文,并且仅花费额外的费用来打印彩色页面.考虑到双面打印的人的奖励积分,并且如果彩色打印机后面是彩色页面,则向彩色打印机发送适当的黑白页面.
这是我见过的最有趣的问题之一!我同意其他一些渲染到位图的帖子,然后分析位图将是最可靠的解决方案.对于简单的PDF,这是一种更快但不太完整的方法.
解析每个PDF页面
寻找颜色指令(g,rg,k,sc,scn等)
寻找嵌入的图像,分析颜色
我的解决方案是#1和#2的一半.#2的另一半将是跟进用户定义的颜色,这包括查找页面中的/ ColorSpace条目并解码它们 - 如果您对此感兴趣,请离线联系我,因为它非常可行但不是5分钟.
首先是主程序:
use CAM::PDF; my $infile = shift; my $pdf = CAM::PDF->new($infile); PAGE: for my $p (1 .. $pdf->numPages) { my $tree = $pdf->getPageContentTree($p); if (!$tree) { print "Failed to parse page $p\n"; next PAGE; } my $colors = $tree->traverse('My::Renderer::FindColors')->{colors}; my $uncertain = 0; for my $color (@{$colors}) { my ($name, @rest) = @{$color}; if ($name eq 'g') { } elsif ($name eq 'rgb') { my ($r, $g, $b) = @rest; if ($r != $g || $r != $b) { print "Page $p is color\n"; next PAGE; } } elsif ($name eq 'cmyk') { my ($c, $m, $y, $k) = @rest; if ($c != 0 || $m != 0 || $y != 0) { print "Page $p is color\n"; next PAGE; } } else { $uncertain = $name; } } if ($uncertain) { print "Page $p has user-defined color ($uncertain), needs more investigation\n"; } else { print "Page $p is grayscale\n"; } }
然后是帮助渲染器处理每个页面上的颜色指令:
package My::Renderer::FindColors; sub new { my $pkg = shift; return bless { colors => [] }, $pkg; } sub clone { my $self = shift; my $pkg = ref $self; return bless { colors => $self->{colors}, cs => $self->{cs}, CS => $self->{CS} }, $pkg; } sub rg { my ($self, $r, $g, $b) = @_; push @{$self->{colors}}, ['rgb', $r, $g, $b]; } sub g { my ($self, $gray) = @_; push @{$self->{colors}}, ['rgb', $gray, $gray, $gray]; } sub k { my ($self, $c, $m, $y, $k) = @_; push @{$self->{colors}}, ['cmyk', $c, $m, $y, $k]; } sub cs { my ($self, $name) = @_; $self->{cs} = $name; } sub cs { my ($self, $name) = @_; $self->{CS} = $name; } sub _sc { my ($self, $cs, @rest) = @_; return if !$cs; # syntax error if ($cs eq 'DeviceRGB') { $self->rg(@rest); } elsif ($cs eq 'DeviceGray') { $self->g(@rest); } elsif ($cs eq 'DeviceCMYK') { $self->k(@rest); } else { push @{$self->{colors}}, [$cs, @rest]; } } sub sc { my ($self, @rest) = @_; $self->_sc($self->{cs}, @rest); } sub SC { my ($self, @rest) = @_; $self->_sc($self->{CS}, @rest); } sub scn { sc(@_); } sub SCN { SC(@_); } sub RG { rg(@_); } sub G { g(@_); } sub K { k(@_); }
较新版本的Ghostscript(版本9.05及更高版本)包含一个名为inkcov的"设备".它计算青色(C),品红色(M),黄色(Y)和黑色(K)值中每页(不是每个图像)的墨水覆盖率,其中0.00000表示0%,而1.00000表示100%(参见检测)所有包含颜色的页面).
例如:
$ gs -q -o - -sDEVICE=inkcov file.pdf 0.11264 0.11605 0.11605 0.09364 CMYK OK 0.11260 0.11601 0.11601 0.09360 CMYK OK
如果CMY值不为0,则页面为彩色.
要输出包含颜色的页面,请使用这个方便的oneliner:
$ gs -o - -sDEVICE=inkcov file.pdf |tail -n +4 |sed '/^Page*/N;s/\n//'|sed -E '/Page [0-9]+ 0.00000 0.00000 0.00000 / d'
可以使用Image Magick工具identify
.如果在PDF页面上使用,它会首先将页面转换为光栅图像.如果包含颜色的页面可以使用-format "%[colorspace]"
选项进行测试,该选项适用于我的PDF打印Gray
或RGB
.恕我直言identify
(或它在背景中使用的工具; Ghostscript?)确实根据颜色的呈现选择颜色空间.
一个例子是:
identify -format "%[colorspace]" $FILE.pdf[$PAGE]
其中PAGE是从0开始的页面,而不是1.如果未使用页面选择,则所有页面将折叠为一个,这不是您想要的.
我编写了以下BASH脚本,用于pdfinfo
获取页面数,然后循环遍历它们.输出彩色页面.我还为双面文档添加了一个功能,您可能还需要一个非彩色的背面页面.
使用输出的空格分隔列表,可以使用pdftk
以下方法提取彩色PDF页面:
pdftk $FILE cat $PAGELIST output color_${FILE}.pdf
#!/bin/bash FILE=$1 PAGES=$(pdfinfo ${FILE} | grep 'Pages:' | sed 's/Pages:\s*//') GRAYPAGES="" COLORPAGES="" DOUBLECOLORPAGES="" echo "Pages: $PAGES" N=1 while (test "$N" -le "$PAGES") do COLORSPACE=$( identify -format "%[colorspace]" "$FILE[$((N-1))]" ) echo "$N: $COLORSPACE" if [[ $COLORSPACE == "Gray" ]] then GRAYPAGES="$GRAYPAGES $N" else COLORPAGES="$COLORPAGES $N" # For double sided documents also list the page on the other side of the sheet: if [[ $((N%2)) -eq 1 ]] then DOUBLECOLORPAGES="$DOUBLECOLORPAGES $N $((N+1))" #N=$((N+1)) else DOUBLECOLORPAGES="$DOUBLECOLORPAGES $((N-1)) $N" fi fi N=$((N+1)) done echo $DOUBLECOLORPAGES echo $COLORPAGES echo $GRAYPAGES #pdftk $FILE cat $COLORPAGES output color_${FILE}.pdf