Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Это один из самых интересных вопросов, которые я видел! Я согласен с некоторыми другими сообщениями, что рендеринг в растровое изображение, а затем анализ растрового изображения будет самым надежным решением. Для простых 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(@_); }

Ответ 2

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

Пример:

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

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

Я написал следующий BASH script, который использует 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

Более новые версии Ghostscript (версия 9.05 и более поздние) включают "устройство", называемое чернилами. Он вычисляет покрытие чернил каждой страницы (не для каждого изображения) в значениях 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, страница цветная.

Чтобы просто выводить страницы, содержащие цвета, используйте этот удобный 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'

Ответ 4

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

Cheers, 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

Ответ 5

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

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

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

Ответ 6

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

  • Прокрутка по всем страницам
  • Извлеките страницы в изображение
  • Проверьте цветовой диапазон изображения

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

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

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

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

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

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