it-swarm.com.ru

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

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

59
Anil

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

Более новые версии 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'
16
Matteo

Можно использовать инструмент Image Magickidentify. При использовании на PDF страницах она сначала преобразуется в растровое изображение. Если страница содержала цвет, можно проверить с помощью параметра -format "%[colorspace]", который для моего PDF напечатан либо Gray, либо RGB. IMHO 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
15
Martin Scharrer

Сценарий от Мартина Шаррера великолепен. Он содержит незначительную ошибку: он считает две страницы, которые содержат цвет и являются последовательными дважды. Я исправил это. Кроме того, скрипт теперь подсчитывает страницы и перечисляет страницы в градациях серого для двусторонней печати. Кроме того, он печатает страницы через запятую, поэтому выходные данные можно напрямую использовать для печати из средства просмотра 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
3
iamtimeshift

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

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

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

2
Cᴏʀʏ

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

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

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

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

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

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

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

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

2
lpfavreau