给定一组PDF文件,其中一些页面是彩色的,其余的是黑色和白色,是否有任何程序可以在给定的页面中找出颜色,哪些是黑色和&白色?例如,这可以用于打印论文,并且仅花费额外的费用来打印彩色页面。考虑到双面打印的人的奖励积分,并向彩色打印机发送适当的黑白页面(如果后面是对面的彩色页面)。
答案 0 :(得分:29)
这是我见过的最有趣的问题之一!我同意其他一些渲染到位图的帖子,然后分析位图将是最可靠的解决方案。对于简单的PDF,这是一种更快但不太完整的方法。
我的解决方案是#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(@_); }
答案 1 :(得分:16)
较新版本的Ghostscript(版本9.05及更高版本)包含&#34;设备&#34;叫墨水。它计算青色(C),品红色(M),黄色(Y)和黑色(K)值中每页(不是每个图像)的墨水覆盖率,其中0.00000表示0%,而1.00000表示100%(参见< EM> Detecting all pages which contain color 的)。
例如:
$ 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'
答案 2 :(得分:15)
可以使用Image Magick工具identify
。如果在PDF页面上使用,它会首先将页面转换为光栅图像。如果包含颜色的页面可以使用-format "%[colorspace]"
选项进行测试,我的PDF打印选项Gray
或RGB
。恕我直言identify
(或它在后台使用的工具; Ghostscript?)确实根据颜色的呈现选择颜色空间。
一个例子是:
identify -format "%[colorspace]" $FILE.pdf[$PAGE]
其中PAGE是从0开始的页面,而不是1.如果未使用页面选择,则所有页面都将折叠为1,这不是您想要的。
我编写了以下BASH脚本,该脚本使用pdfinfo
来获取页面数,然后循环遍历它们。输出彩色页面。我还为双面文档添加了一个功能,您可能还需要一个非彩色的背面页面。
使用输出的空格分隔列表,可以使用pdftk
:
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
答案 3 :(得分:3)
Martin Scharrer的剧本很棒。它包含一个小错误:它包含两个包含颜色的页面,并且直接连续两次。我修好了。此外,脚本现在计算页面并列出双页打印的灰度页面。它还以逗号分隔打印页面,因此输出可以直接用于从PDF查看器打印。我已添加了代码,但您也可以下载here。
干杯, 时移
#!/bin/bash
if [ $# -ne 1 ]
then
echo "USAGE: This script needs exactly one paramter: the path to the PDF"
kill -SIGINT $$
fi
FILE=$1
PAGES=$(pdfinfo ${FILE} | grep 'Pages:' | sed 's/Pages:\s*//')
GRAYPAGES=""
COLORPAGES=""
DOUBLECOLORPAGES=""
DOUBLEGRAYPAGES=""
OLDGP=""
DOUBLEPAGE=0
DPGC=0
DPCC=0
SPGC=0
SPCC=0
echo "Pages: $PAGES"
N=1
while (test "$N" -le "$PAGES")
do
COLORSPACE=$( identify -format "%[colorspace]" "$FILE[$((N-1))]" )
echo "$N: $COLORSPACE"
if [[ $DOUBLEPAGE -eq -1 ]]
then
DOUBLEGRAYPAGES="$OLDGP"
DPGC=$((DPGC-1))
DOUBLEPAGE=0
fi
if [[ $COLORSPACE == "Gray" ]]
then
GRAYPAGES="$GRAYPAGES,$N"
SPGC=$((SPGC+1))
if [[ $DOUBLEPAGE -eq 0 ]]
then
OLDGP="$DOUBLEGRAYPAGES"
DOUBLEGRAYPAGES="$DOUBLEGRAYPAGES,$N"
DPGC=$((DPGC+1))
else
DOUBLEPAGE=0
fi
else
COLORPAGES="$COLORPAGES,$N"
SPCC=$((SPCC+1))
# 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))"
DOUBLEPAGE=$((N+1))
DPCC=$((DPCC+2))
#N=$((N+1))
else
if [[ $DOUBLEPAGE -eq 0 ]]
then
DOUBLECOLORPAGES="$DOUBLECOLORPAGES,$((N-1)),$N"
DPCC=$((DPCC+2))
DOUBLEPAGE=-1
elif [[ $DOUBLEPAGE -gt 0 ]]
then
DOUBLEPAGE=0
fi
fi
fi
N=$((N+1))
done
echo " "
echo "Double-paged printing:"
echo " Color($DPCC): ${DOUBLECOLORPAGES:1:${#DOUBLECOLORPAGES}-1}"
echo " Gray($DPGC): ${DOUBLEGRAYPAGES:1:${#DOUBLEGRAYPAGES}-1}"
echo " "
echo "Single-paged printing:"
echo " Color($SPCC): ${COLORPAGES:1:${#COLORPAGES}-1}"
echo " Gray($SPGC): ${GRAYPAGES:1:${#GRAYPAGES}-1}"
#pdftk $FILE cat $COLORPAGES output color_${FILE}.pdf
答案 4 :(得分:2)
ImageMagick有一些内置的图像比较方法。
http://www.imagemagick.org/Usage/compare/#type_general
ImageMagick有一些Perl API,所以如果你巧妙地将它们与PDF到图像转换器结合起来,你可以找到一种方法来做你的黑&amp;白色测试。
答案 5 :(得分:2)
我会尝试这样做,虽然可能还有其他更简单的解决方案,而且我很想听到它们,我只是想尝试一下:
对于页数,您可以在不费力的情况下将that翻译成Perl。它基本上是一个正则表达式。它也是said:
R “(/类型)\ S(/页)[/&GT; \ S]?”
你只需计算多少 这个正则表达式出现的次数 在PDF文件中,减去你的次数 找到字符串“&lt;&gt;” (未呈现的空白年龄)。
要提取图片,您可以使用ImageMagick执行that。或者查看this question。
最后,要确定它是黑白还是白色,这取决于你的字面意思是黑白还是灰度。对于黑色和白色,您应该只在所有图像中都有黑色和白色。如果你想看灰度,现在,它真的不是我的专长,但我想你可以看到红色,绿色和蓝色的平均值是否彼此接近,或者原始图像和grayscale converted一个相互接近。
希望它能提供一些帮助你走得更远的提示。
答案 6 :(得分:0)
这是Windows的ghostscript解决方案,需要GnuWin(http://gnuwin32.sourceforge.net/packages/grep.htm)的grep:
单色(黑白)页面:
gswin64c -q -o - -sDEVICE=inkcov DOCUMENT.pdf | grep "^ 0.00000 0.00000 0.00000" | find /c /v ""
彩色页面:
gswin64c -q -o - -sDEVICE=inkcov DOCUMENT.pdf | grep -v "^ 0.00000 0.00000 0.00000" | find /c /v ""
总页数(您可以从任何pdf阅读器中轻松获得这一页):
gswin64c -q -o - -sDEVICE=inkcov DOCUMENT.pdf | find /c /v ""