Как узнать, являются ли страницы PDF цветными или черно-белыми?
-
22-07-2019 - |
Вопрос
Учитывая набор PDF-файлов, среди которых некоторые страницы цветные, а остальные черно-белые, существует ли какая-либо программа, позволяющая определить, какие страницы являются цветными, а какие черно-белыми?Это было бы полезно, например, при распечатке диссертации и дополнительных затратах только на печать цветных страниц.Бонусные баллы для тех, кто учитывает двустороннюю печать и отправляет соответствующую черно-белую страницу на цветной принтер, если за ней следует цветная страница на противоположной стороне.
Решение
Это один из самых интересных вопросов, которые я видел! Я согласен с некоторыми другими постами, что рендеринг в растровое изображение и последующий анализ растрового изображения будут наиболее надежным решением. Для простых 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(@_); }
Другие советы
Более новые версии Ghostscript (версия 9.05 и более поздние) включают в себя " устройство " ; называется инков. Он рассчитывает покрытие чернилами каждой страницы (не для каждого изображения) в значениях Cyan (C), Magenta (M), Yellow (Y) и Black (K), где 0,00000 означает 0%, а 1,00000 означает 100% (см. < em> Обнаружение всех страниц, содержащих цвет ).
Например:
$ 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, то страница является цветной.
Чтобы просто выводить страницы, содержащие цвета, используйте этот удобный инструмент:
$ 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
. ИМХО pdfinfo
(или какой-нибудь инструмент, который он использует в фоновом режиме; Ghostscript?) Выбирает цветовое пространство в зависимости от присутствия цвета.
Пример:
identify -format "%[colorspace]" $FILE.pdf[$PAGE]
где PAGE - страница, начинающаяся с 0, а не 1. Если выбор страницы не используется, все страницы будут свернуты в одну, а это не то, что вам нужно.
Я написал следующий BASH-скрипт, который использует 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
Сценарий Мартина Шаррера великолепен.Он содержит небольшую ошибку:Он считает две страницы, содержащие цвет и дважды идущие подряд.Я это исправил.Кроме того, скрипт теперь подсчитывает страницы и выводит список страниц в оттенках серого для двухстраничной печати.Кроме того, он печатает страницы, разделенные запятыми, поэтому выходные данные можно напрямую использовать для печати из программы просмотра PDF.Я добавил код, но вы можете его скачать. здесь, слишком.
Аплодисменты Сдвиг по времени
#!/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
ImageMagick имеет несколько встроенных методов для сравнения изображений.
Я бы попробовал сделать это так, хотя могут быть и другие более простые решения, и мне интересно их услышать, я просто хочу попробовать:
- Пролистнуть все страницы
- Извлеките страницы в изображение
- Проверьте цветовой диапазон изображения
Что касается количества страниц, вы, вероятно, можете перевести что без особых усилий с Perl.По сути, это регулярное выражение.Это также сказал что:
r"(/Type)\s?(/Page)[/>\s]"
Нужно просто посчитать, сколько раз это регулярное выражение в PDF-файле, за вычетом раз, когда вы Найдите строку "<>" (пустые эпохи, которые не отображаются).
Чтобы извлечь изображение, вы можете использовать ИзображениеМагия делать что.Или посмотреть этот вопрос.
Наконец, чтобы понять, является ли изображение черно-белым, зависит от того, имеете ли вы в виду буквально черно-белое или оттенки серого.Что касается черно-белого изображения, то на всем изображении должно быть только черно-белое изображение.Если вы хотите увидеть оттенки серого, то это не моя специальность, но я думаю, вы могли бы увидеть, близки ли средние значения красного, зеленого и синего друг к другу или исходное изображение и преобразованный в оттенки серого один близко друг к другу.
Надеюсь, что это даст некоторые подсказки, которые помогут вам идти дальше.