Come faccio a sapere se le pagine PDF sono a colori o in bianco e nero?
-
22-07-2019 - |
Domanda
Dato un insieme di file PDF tra cui alcune pagine sono a colori e le rimanenti sono nere & amp; bianco, c'è qualche programma per scoprire tra le pagine date che sono a colori e che sono ampli & neri; bianca? Ciò sarebbe utile, ad esempio, per stampare una tesi e spendere solo extra per stampare le pagine a colori. Punti bonus per qualcuno che tiene conto della stampa fronte-retro e invia una pagina in bianco e nero appropriata alla stampante a colori se è seguita da una pagina a colori sul lato opposto.
Soluzione
Questa è una delle domande più interessanti che ho visto! Concordo con alcuni degli altri post sul fatto che il rendering in bitmap e l'analisi della bitmap saranno la soluzione più affidabile. Per PDF semplici, ecco un approccio più veloce ma meno completo.
- Analizza ogni pagina PDF
- Cerca le direttive sui colori (g, rg, k, sc, scn, ecc.)
- Cerca immagini incorporate, analizza per colore
La mia soluzione di seguito fa il n. 1 e la metà del n. 2. L'altra metà del numero 2 sarebbe quella di seguire con il colore definito dall'utente, che implica la ricerca delle voci / ColorSpace nella pagina e la decodifica - contattami offline se questo è interessante per te, poiché è molto fattibile ma non in 5 minuti.
Prima il programma principale:
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";
}
}
Ed ecco il renderizzatore di helper che gestisce le direttive dei colori su ogni pagina:
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(@_); }
Altri suggerimenti
Le versioni più recenti di Ghostscript (versione 9.05 e successive) includono un " dispositivo " ; chiamato inkcov. Calcola la copertura dell'inchiostro di ogni pagina (non per ogni immagine) nei valori di ciano (C), magenta (M), giallo (Y) e nero (K), dove 0,00000 significa 0% e 1.00000 significa 100% (vedere < em> Rilevamento di tutte le pagine che contengono colore ).
Ad esempio:
$ 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 i valori CMY non sono 0, la pagina è colorata.
Per generare semplicemente le pagine che contengono colori, usa questo pratico 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'
È possibile usare lo strumento Image Magick identify
. Se utilizzato su pagine PDF, converte prima la pagina in un'immagine raster. Se la pagina conteneva il colore può essere testato usando l'opzione -format "%[colorspace]"
, che per il mio PDF è stata stampata Gray
o RGB
. IMHO pdfinfo
(o quale strumento usa mai in background; Ghostscript?) Sceglie lo spazio colore in base ai regali di colore.
Un esempio è:
identify -format "%[colorspace]" $FILE.pdf[$PAGE]
dove PAGE è la pagina che inizia da 0, non 1. Se la selezione della pagina non viene utilizzata, tutte le pagine verranno compresse in una sola, che non è quello desiderato.
Ho scritto il seguente script BASH che utilizza pdftk
per ottenere il numero di pagine e quindi passarci sopra. Stampa delle pagine a colori. Ho anche aggiunto una funzione per il documento fronte-retro in cui potresti aver bisogno di una pagina posteriore non colorata.
Utilizzando l'elenco separato dallo spazio generato, è possibile estrarre le pagine PDF colorate utilizzando <=>:
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
La sceneggiatura di Martin Scharrer è fantastica. Contiene un bug minore: conta due pagine che contengono colore e sono direttamente due volte consecutive. L'ho risolto. Inoltre lo script ora conta le pagine ed elenca le pagine in scala di grigi per la stampa a doppia pagina. Inoltre, stampa le pagine separate da virgola, quindi l'output può essere utilizzato direttamente per la stampa da un visualizzatore PDF. Ho aggiunto il codice, ma puoi scaricarlo anche qui .
Saluti, 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 ha alcuni metodi integrati per il confronto delle immagini.
http://www.imagemagick.org/Usage/compare/#type_general
Ci sono alcune API Perl per ImageMagick, quindi forse se le combini abilmente con un convertitore da PDF ad immagine puoi trovare un modo per fare il tuo ampli & nero; test bianco.
Vorrei provare a farlo in questo modo, anche se potrebbero esserci altre soluzioni più semplici, e sono curioso di ascoltarli, voglio solo provarlo:
- Scorri tutte le pagine
- Estrai le pagine in un'immagine
- Verifica la gamma di colori dell'immagine
Per il conteggio delle pagine, puoi probabilmente tradurre che senza troppi sforzi in Perl . È fondamentalmente una regex. È anche detto che:
&R quot; (/ Type) \ s (/ pagina) [/ gt &; \ S]? Quot &;
Devi semplicemente contare quanti volte si verifica questa espressione regolare nel file PDF, meno le volte trova la stringa " < > " (età vuote che non vengono rese).
Per estrarre l'immagine, puoi usare ImageMagick per fare che . Oppure vedi questa domanda .
Infine, per capire se è bianco e nero, dipende se intendi letteralmente bianco e nero o scala di grigi. Per il bianco e nero, dovresti avere solo bianco e nero in tutta l'immagine. Se vuoi vedere la scala di grigi, ora, non è davvero la mia specialità ma immagino che potresti vedere se le medie di rosso, verde e blu sono vicine tra loro o se l'immagine originale e un scala di grigi convertita sono vicini l'uno all'altro.
Spero che ti dia qualche suggerimento per aiutarti ad andare oltre.