как я могу узнать, являются ли pdf страницы цветными или черно-белыми?

<p>учитывая набор файлов pdf, среди которых некоторые страницы являются цветными, а остальные - черно-белыми, есть ли какая-нибудь программа для определения среди указанных страниц цветных и черно-белых? это было бы полезно, например, при распечатке дипломной работы и дополнительных затратах на печать цветных страниц. бонусные баллы для тех, кто учитывает двустороннюю печать и отправляет соответствующую черно-белую страницу на цветной принтер, если за ней следует цветная страница на противоположной стороне.</p>

<p>это один из самых интересных вопросов, которые я видел! я согласен с некоторыми другими постами, что рендеринг в растровое изображение и последующий анализ растрового изображения будут наиболее надежным решением. для простых pdf-файлов вот более быстрый, но менее полный подход.</p><ol> <li>разбор каждой pdf страницы</li> <li>ищите директивы цвета (g, rg, k, sc, scn и т.д.)</li> <li>ищите встроенные изображения, анализируйте на цвет</li> </ol><p>мое решение ниже делает # 1 и половину # 2. другая половина # 2 будет заключаться в использовании заданного пользователем цвета, который включает поиск записей/colorspace на странице и их расшифровку - свяжитесь со мной в автономном режиме, если это вам интересно, так как это очень выполнимо, но не в 5 минут.</p><p>сначала основная программа:</p><pre><code>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 colorn"; 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 investigationn"; } else { print "page $p is grayscale\n"; } } </code></pre><p>а затем вот вспомогательный рендер, который обрабатывает цветовые директивы на каждой странице:</p><pre><code>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(@\_); } </code></pre>

<p>более новые версии <a href="http://www.ghostscript.com">ghostscript</a> (версия 9.05 и более поздние) включают в себя "устройство" под названием inkcov. он рассчитывает покрытие чернилами каждой страницы (не для каждого изображения) в значениях cyan (c), magenta (m), yellow (y) и black (k), где 0,00000 означает 0%, а 1,00000 означает 100% (см. <em> <a href="https://tex.stackexchange.com/a/61216/7770">обнаружение всех страниц, содержащих цвет</a> </em>).</p><p>например:</p><pre><code>$ 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' </code></pre>

<p>можно использовать инструмент <a href="http://www.imagemagick.org/">image magick</a> <code>identify</code>. при использовании на pdf страницах она сначала преобразуется в растровое изображение. если страница содержала цвет, можно проверить с помощью параметра <code>-format "%[colorspace]"</code>, который для моего pdf напечатан либо <code>gray</code>, либо <code>rgb</code>. imho <code>identify</code> (или какой-либо инструмент, который он использует в фоновом режиме; ghostscript?) выбирает цветовое пространство в зависимости от присутствия цвета.</p><p>примером является:</p><pre><code>identify -format "%[colorspace]" $file.pdf[$page] </code></pre><p>где page - страница, начинающаяся с 0, а не 1. если выбор страницы не используется, все страницы будут свернуты в одну, а это не то, что вам нужно.</p><p>я написал следующий скрипт bash, который использует <code>pdfinfo</code>, чтобы получить количество страниц, а затем перебирает их. вывод страниц, которые в цвете. я также добавил функцию для двустороннего документа, где вам может понадобиться и цветная задняя страница.</p><p>используя список разделенных выходным пробелом, цветные pdf страницы можно извлечь с помощью <code>pdftk</code>:</p><pre><code>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 </code></pre>

<p>сценарий от мартина шаррера великолепен. он содержит незначительную ошибку: он считает две страницы, которые содержат цвет и являются последовательными дважды. я исправил это. кроме того, скрипт теперь подсчитывает страницы и перечисляет страницы в градациях серого для двусторонней печати. кроме того, он печатает страницы через запятую, поэтому выходные данные можно напрямую использовать для печати из средства просмотра pdf. я добавил код, но вы можете скачать его <a href="https://dl.dropbox.com/u/6649639/scripts/identifycoloredpagesinpdf.sh">здесь</a> тоже.</p><p>ура, сдвиг по времени</p><pre><code>#!/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 </code></pre>

<p>imagemagick имеет несколько встроенных методов для сравнения изображений.</p><p> <a href="http://www.imagemagick.org/usage/compare/#type\_general">http://www.imagemagick.org/usage/compare/#type\_general</a> </p><p>существует несколько perl api для imagemagick, поэтому, возможно, если вы умело объедините их с конвертером pdf в image, вы сможете найти способ выполнить черно-белый тест.</p>

<p>я бы попытался сделать это так, хотя могут быть и другие более простые решения, и мне любопытно услышать их, я просто хочу попробовать:</p><ol> <li>перебрать все страницы</li> <li>извлеките страницы в изображение</li> <li>проверьте цветовую гамму изображения</li> </ol><p>для подсчета страниц вы, вероятно, можете перевести <a href="http://code.activestate.com/recipes/496837/">что</a> без особых усилий на perl. это в основном регулярное выражение. это также <a href="http://webui.sourcelabs.com/cups/mail/user/threads/alternative\_way\_to\_find\_no.\_of\_pages\_inside\_pdf%253f.meta">сказал</a> что:</p><blockquote> <p>г "(/ тип)\с? (/ страница) [/>\с]"</p> <p>вам просто нужно посчитать, сколько раз это регулярное выражение встречается в файле pdf, минус количество раз, когда вы находите строку "<>" (пустые возрасты, которые не отображаются).</p> </blockquote><p>чтобы извлечь изображение, вы можете использовать <a href="http://www.imagemagick.org/script/perl-magick.php">imagemagick</a> , чтобы сделать <a href="http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=5243&view=previous">это</a> . или смотрите <a href="https://stackoverflow.com/questions/430707/how-can-i-extract-images-from-a-pdf-file">этот вопрос</a> .</p><p>наконец, чтобы понять, черно-белое ли это, это зависит от того, имеете ли вы в виду буквально черно-белое или оттенки серого. для черного и белого вы должны иметь только черно-белое изображение. если вы хотите увидеть оттенки серого, то это действительно не моя специальность, но я думаю, вы могли бы увидеть, если средние значения красного, зеленого и синего близки друг к другу или если исходное изображение и <a href="http://ubuntuforums.org/showthread.php?t=663059">преобразованы в оттенках серого)</a> один близко друг к другу.</p><p>надеюсь, что это дает некоторые советы, которые помогут вам пойти дальше.</p>