2009-03-13 8 views
55

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

+0

Другие предложения, доступные в этом подобный вопрос на TeX stackexchange http://tex.stackexchange.com/questions/53493/detecting-all -файлы, которые содержат цвет – Gareth

+0

Удивительный вопрос. Благодарю. – Geoff

ответ

27

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

  1. Анализировать каждую страницу PDF
  2. Ищет цвета директивы (г, гк, к, подкожный, сюжетный и т.д.)
  3. Look для встроенных изображений, анализ для цвета

Моего решением ниже делает # 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

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

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

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

2

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

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

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

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

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

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

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

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

+1

Чтобы узнать кол-во страниц: perl -le'use CAM :: PDF; print CAM :: PDF-> new ("my.pdf") -> numPages ' –

15

можно использовать Image Magick инструмент identify. Если он используется на страницах 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 
+2

Рассмотрите этот файл TeX: 'hello world \ bye'. Вывод 'ident -format '% [colorspace]" "$ FILE.pdf [0]" 'is' sRGB', а с 'gs -o - -sDEVICE = inkcov $ FILE.pdf" '(предлагается [здесь] (http://tex.stackexchange.com/a/61216/31416)) Я получаю «0.00000 0.00000 0.00000 0.00020 CMYK OK», что является более разумным. – giordano

+0

Вы можете избежать зависимости от 'pdfinfo', проверив, (если это случается, оно даже сообщает вам количество страниц.) –

+0

... которое оно также делает на странице «-1». –

3

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

Приветствия, 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 
12

Новые версии Ghostscript (версии 9.05 и более поздних версий) включают в себя "устройство" под названием inkcov. Он рассчитывает покрытие чернил каждой страницы (не для каждого изображения) в значениях Cyan (C), Magenta (M), Yellow (Y) и Black (K), где 0,00000 означает 0%, а 1.00000 означает 100% (см. Detecting all pages which contain color).

Например:

$ 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' 
+0

Существует опечатка, которая SO не позволит мне правильно, потому что это всего лишь односимвольное изменение: s должно быть gs. Кроме того, этот метод не обязательно работает так, как ожидалось, файлы pdf, созданные inkscape, например, всегда имеют ненулевой CMY, даже если изображение чисто серого. –

+0

Спасибо I исправлена ​​опечатка – Matteo

 Смежные вопросы

  • Нет связанных вопросов^_^