Como faço para saber se as páginas em PDF são cores ou a preto-e-branco?
-
22-07-2019 - |
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.
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.
- Parse cada página PDF
- Procure directivas cor (g, rg, k, sc, scn, etc)
- 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:
- Curva através de todas as páginas
- Extrair as páginas para uma imagem
- 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.