Как я узнаю, являются ли страницы PDF цветными или черно-белыми? - PullRequest
59 голосов
/ 13 марта 2009

Учитывая набор файлов PDF, среди которых некоторые страницы являются цветными, а остальные - черно-белыми, есть ли какая-нибудь программа для поиска среди указанных страниц цветных и черно-белых? Это было бы полезно, например, при распечатке дипломной работы и дополнительных затратах на печать цветных страниц. Бонусные баллы для тех, кто учитывает двустороннюю печать и отправляет соответствующую черно-белую страницу на цветной принтер, если за ней следует цветная страница на противоположной стороне.

Ответы [ 6 ]

29 голосов
/ 15 марта 2009

Это один из самых интересных вопросов, которые я видел! Я согласен с некоторыми другими постами, что рендеринг в растровое изображение и последующий анализ растрового изображения будут наиболее надежным решением. Для простых PDF-файлов вот более быстрый, но менее полный подход.

  1. Разбор каждой страницы PDF
  2. Ищите директивы цвета (g, rg, k, sc, scn и т. Д.)
  3. Поиск встроенных изображений, анализ на цвет

Мое решение ниже # 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(@_); }
16 голосов
/ 06 февраля 2015

Более новые версии Ghostscript (версия 9.05 и более поздние) включают в себя «устройство» под названием inkcov. Он рассчитывает покрытие чернилами каждой страницы (не для каждого изображения) в значениях Cyan (C), Magenta (M), Yellow (Y) и Black (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, то страница является цветной.

Чтобы просто выводить страницы, содержащие цвета, используйте этот удобный вкладыш:

$ 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'
15 голосов
/ 27 апреля 2012

Можно использовать инструмент Image Magick identify. При использовании на страницах PDF он сначала преобразует страницу в растровое изображение. Если страница содержала цвет, можно проверить, используя параметр -format "%[colorspace]", который для моего PDF напечатан либо Gray, либо RGB. ИМХО identify (или какой-нибудь инструмент, который он использует в фоновом режиме; Ghostscript?) Выбирает цветовое пространство в зависимости от присутствия цвета.

Пример:

identify -format "%[colorspace]" $FILE.pdf[$PAGE]

где PAGE - страница, начинающаяся с 0, а не 1. Если выбор страницы не используется, все страницы будут свернуты в одну, а это не то, что вам нужно.

Я написал следующий скрипт BASH, который использует pdfinfo для получения количества страниц, а затем перебирает их. Вывод страниц, которые в цвете. Я также добавил функцию для двустороннего документа, где вам может понадобиться и цветная задняя страница.

Используя выведенный пробел разделенный список, цветные PDF-страницы можно извлечь, используя 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 голосов
/ 14 ноября 2012

Сценарий от Мартина Шаррера великолепен. Он содержит незначительную ошибку: он считает две страницы, которые содержат цвет и являются последовательными дважды. Я исправил это. Кроме того, скрипт теперь подсчитывает страницы и перечисляет страницы в градациях серого для двусторонней печати. Кроме того, он печатает страницы через запятую, поэтому выходные данные можно напрямую использовать для печати из средства просмотра PDF. Я добавил код, но вы также можете загрузить его здесь .

Ура, TimeShift

#!/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
2 голосов
/ 13 марта 2009

Я бы попытался сделать это так, хотя могут быть и другие более простые решения, и мне любопытно услышать их, я просто хочу попробовать:

  1. Перебрать все страницы
  2. Извлечение страниц в изображение
  3. Проверка цветовой гаммы изображения

Для подсчета страниц вы, вероятно, можете перевести , что , без особых усилий на Perl. Это в основном регулярное выражение. Также сказал , что:

г "(/ тип) \ s? (/ Страница) [/> \ s]"

Вы просто должны посчитать, сколько раз происходит это регулярное выражение в файле PDF, минус раз вы найти строку "<>" (пустые возрасты, которые не отображаются).

Чтобы извлечь изображение, вы можете использовать ImageMagick , чтобы сделать , что . Или посмотрите этот вопрос .

Наконец, чтобы выяснить, черно-белое ли это, это зависит от того, имеете ли вы в виду буквально черно-белое или оттенки серого. Для черного и белого вы должны иметь только черно-белое изображение. Если вы хотите увидеть оттенки серого, то это действительно не моя специальность, но я думаю, вы могли бы увидеть, близки ли средние значения красного, зеленого и синего цветов или же преобразовано исходное изображение и в оттенках серого один рядом друг с другом.

Надеюсь, он даст некоторые советы, которые помогут вам пойти дальше.

2 голосов
/ 13 марта 2009

ImageMagick имеет несколько встроенных методов для сравнения изображений.

http://www.imagemagick.org/Usage/compare/#type_general

Существует несколько Perl API для ImageMagick, так что, возможно, если вы умело объедините их с конвертером PDF в изображение, вы сможете найти способ выполнить черно-белый тест.

...