Pergunta

Dado um conjunto de arquivos PDF entre os quais algumas páginas são cor e os restantes são a preto e branco, existe algum programa para encontrar-se entre as páginas dadas que são cor e que são a preto e branco? Isso seria útil, por exemplo, na impressão de uma tese, e só gastar extra para imprimir as páginas a cores. Os pontos de bónus para alguém que leva em conta impressão frente e verso, e envia uma página preto e branco apropriado para a impressora de cor, se for são seguidos por uma página colorida no lado oposto.

Foi útil?

Solução

Este é um dos mais questões interessantes que eu já vi! Concordo com alguns dos outros lugares que a prestação de um bitmap e, em seguida, analisar o bitmap será a solução mais confiável. Para PDFs simples, aqui está uma abordagem mais rápida, mas menos completo.

  1. Parse cada página PDF
  2. Procure directivas cor (g, rg, k, sc, scn, etc)
  3. Procure imagens embutidas, analisar para a cor

Meu solução abaixo faz # 1 e metade da # 2. A outra metade da # 2 seria de acompanhar com cor definida pelo usuário, que envolve olhar as entradas / ColorSpace na página e decodificação-los - contact me offline Se isso é interessante para você, como é muito factível, mas não em 5 minutos.

Primeiro, o programa principal:

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";
   }
}

E então aqui está o processador auxiliar que directivas alças cor em cada página:

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(@_); }

Outras dicas

Novas versões do Ghostscript (versão 9.05 e posterior) incluem um "dispositivo" chamado inkcov. Ele calcula a cobertura de tinta de cada página (não para cada imagem) em ciano (C), magenta (M), amarelo (Y) e os valores de preto (K), onde 0,00000 meios de 0%, e 1.00000 meios 100% (ver < em> Detectar todas as páginas que contêm cor ).

Por exemplo:

$ 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

Se os valores CMY não são 0, em seguida, a página é cor.

Para emitir apenas as páginas que contenham cores usar este oneliner útil:

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

É possível usar a Imagem Magick identify ferramenta. Se usado em páginas de PDF que converte a primeira página a uma imagem raster. Se a página continha cor pode ser testado utilizando a opção -format "%[colorspace]", que para o meu PDF impresso quer Gray ou RGB. IMHO identify (ou o que nunca ferramenta que utiliza no fundo;? Ghostscript). Faz escolher o espaço de cor dependendo dos presentes da cor

Um exemplo é:

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

onde página é a página a partir de 0, não 1. Se a seleção página não é usado todas as páginas serão recolhidas para um, o que não é o que você quer.

Eu escrevi o seguinte script BASH que usa pdfinfo para obter o número de páginas e, em seguida, faz um loop sobre eles. Produzir as páginas que são na cor. Eu também adicionou um recurso para o documento dupla face em que você pode precisar de uma página não-colorido parte traseira também.

Usando o espaço emitido lista separada das páginas PDF coloridas podem ser extraídos usando 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

O script de Martin Scharrer é grande. Ele contém um pequeno bug: Se conta duas páginas que contêm cor e são duas vezes diretamente consecutivo. Eu reparei isso. Além disso, o roteiro agora conta as páginas e lista as páginas em escala de cinza para impressão em duas paginada. Também imprime as páginas separados por vírgula, então a saída pode ser diretamente usados ??para imprimir a partir de um visualizador de PDF. Eu adicionei o código, mas você pode baixá-lo aqui também .

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

ImageMagick tem alguns built-in métodos para comparação de imagem.

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

Há alguns APIs Perl para ImageMagick, talvez por isso, se você habilmente combiná-las com um PDF ao conversor de imagem pode encontrar uma maneira de fazer seu teste de preto e branco.

Gostaria de tentar fazê-lo assim, embora possa haver outras soluções mais fáceis, e estou curioso para ouvi-los, eu só quero dar-lhe tentar:

  1. Curva através de todas as páginas
  2. Extrair as páginas para uma imagem
  3. Verifique a gama de cores da imagem

Para a contagem de páginas, você provavelmente pode traduzir que sem muito esforço para Perl . É basicamente um regex. É também disse que:

r "(/ Type) \ s? (/ Página) [/> \ s]"

Você simplesmente tem que contar quantas vezes esta expressão regular ocorre no arquivo PDF, menos os que você vezes encontrar a string "<>" (Idades vazias que não são prestados).

Para extrair a imagem, você pode usar ImageMagick fazer que . Ou consulte esta questão .

Finalmente, para conseguir se é preto e branco, isso depende se você quer dizer, literalmente, preto e branco ou em tons de cinza. Para preto e branco, você só deve ter, assim, preto e branco em toda a imagem. Se você quiser ver tons de cinza, agora, realmente não é minha especialidade, mas eu acho que você poderia ver se as médias do vermelho, o verde eo azul são próximos uns dos outros ou se a imagem original e uma tons de cinza convertido um são próximos uns dos outros

.

Hope dá algumas dicas para ajudá-lo a ir mais longe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top