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.

È stato utile?

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.

  1. Analizza ogni pagina PDF
  2. Cerca le direttive sui colori (g, rg, k, sc, scn, ecc.)
  3. 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:

  1. Scorri tutte le pagine
  2. Estrai le pagine in un'immagine
  3. 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top