2009-03-13 9 views
55

Étant donné un ensemble de fichiers PDF parmi lesquels certaines pages sont en couleur et les autres sont en noir & blanc, existe-t-il un programme pour trouver parmi les pages données qui sont en couleur et qui sont en noir & blanc? Cela serait utile, par exemple, dans l'impression d'une thèse, et seulement dépenser plus pour imprimer les pages de couleur. Des points bonus pour quelqu'un qui prend en compte l'impression recto verso, et envoie une page en noir et blanc appropriée à l'imprimante couleur si elle est suivie d'une page couleur sur le côté opposé.Comment savoir si les pages PDF sont en couleur ou en noir et blanc?

+0

Autres suggestions disponibles dans cette question similaire sur TeX StackExchange http://tex.stackexchange.com/questions/53493/detecting-all -pages-which-contain-color – Gareth

+0

Question géniale. Merci. – Geoff

Répondre

27

C'est l'une des questions les plus intéressantes que j'ai vues! Je suis d'accord avec certains des autres messages qui rendent à un bitmap, puis l'analyse de l'image bitmap sera la solution la plus fiable. Pour les PDF simples, voici une approche plus rapide mais moins complète.

  1. Parse chaque page PDF
  2. Rechercher des directives de couleur (g, rg, k, sc, scn, etc.)
  3. Rechercher des images intégrées, d'analyser la couleur

Ma solution ci-dessous fait # 1 et la moitié de # 2. L'autre moitié de # 2 consisterait à suivre la couleur définie par l'utilisateur, ce qui implique de rechercher les entrées/ColorSpace dans la page et de les décoder - contactez-moi hors ligne si cela vous intéresse, car c'est très faisable mais pas dans 5 minutes.

D'abord le programme 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"; 
    } 
} 

Et puis est ici le moteur de rendu d'aide qui gère les directives de couleur sur chaque page:

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 dispose de méthodes intégrées de comparaison d'images.

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

Il existe une API Perl pour ImageMagick, alors peut-être si vous combinez intelligemment ces derniers avec un convertisseur PDF vers l'image que vous pouvez trouver un moyen de faire votre noir essai blanc &.

2

Je voudrais essayer de le faire comme ça, bien qu'il puisse y avoir d'autres solutions plus simples, et je suis curieux de les entendre, je veux juste donner essayer:

  1. boucle à travers toutes les pages
  2. Extraire les pages à une image
  3. Vérifiez la gamme de couleurs de l'image

pour le nombre de pages, vous pouvez probablement traduire that sans trop d'effort pour Perl. C'est fondamentalement une regex. Il est également said que:

r "(/ Type) \ s (/ Page) [/> \ s]?"

Il vous suffit de compter combien de fois cette expression régulière se produit dans le fichier PDF, moins les fois où vous trouver la chaîne "<>" (âges vides qui ne sont pas rendus).

Pour extraire l'image, vous pouvez utiliser ImageMagick pour faire that. Ou voir this question. Enfin, pour savoir si c'est noir et blanc, cela dépend si vous voulez dire littéralement noir et blanc ou échelle de gris. Pour le noir et blanc, vous devriez seulement, bien, noir et blanc dans toute l'image. Si vous voulez voir les niveaux de gris, maintenant, ce n'est vraiment pas ma spécialité mais je suppose que vous pouvez voir si les moyennes du rouge, du vert et du bleu sont proches ou si l'image originale et une grayscale converted sont proches de chaque autre.

Espérons que cela donne quelques conseils pour vous aider à aller plus loin.

+1

Pour obtenir le nombre de pages: perl -le'use CAM :: PDF; print CAM :: PDF-> new ("my.pdf") -> numPages ' –

15

Il est possible d'utiliser l'outil Image Magickidentify. S'il est utilisé sur des pages PDF, il convertit d'abord la page en image tramée. Si la page couleur contenue peut être testé en utilisant l'option -format "%[colorspace]", qui pour mon PDF a imprimé soit Gray ou RGB. IMHO identify (ou quel que soit l'outil qu'il utilise en arrière-plan; Ghostscript?) Ne choisit l'espace de couleurs en fonction des cadeaux de couleur.

Un exemple est:

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

où PAGE est le départ de la page de 0, pas 1. Si la sélection de page n'est pas utilisé toutes les pages sont effondrés à un, ce qui est pas ce que vous voulez.

J'ai écrit le script BASH suivant qui utilise pdfinfo pour obtenir le nombre de pages et ensuite les boucles. Sortir les pages qui sont en couleur. J'ai également ajouté une fonction pour le document recto-verso où vous pourriez avoir besoin d'une page arrière non colorée.

Utilisation de la liste séparée de l'espace les pages en sortie PDF en couleur peuvent être extraites en utilisant 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

Considérons ce fichier TeX: 'hello world \ bye'. La sortie de 'identify -format"% [colorspace] "" $ FILE.pdf [0] "' est 'sRGB', alors qu'avec' gs -o - -DEDEVICE = inkcov $ FILE.pdf "' (suggéré [ici] (http://tex.stackexchange.com/a/61216/31416)) J'obtiens '0.00000 0.00000 0.00000 0.00020 CMYK OK' ce qui est plus raisonnable – giordano

+0

Vous pouvez éviter la dépendance sur' pdfinfo' en vérifiant si 'identify' bails sur une page inexistante (quand cela arrive, il vous indique même le nombre de pages.) –

+0

... ce qu'il fait aussi sur la page "-1" –

3

Le script de Martin SCHARRER est grande. Il contient un bug mineur: Il compte deux pages qui contiennent des couleurs et sont directement consécutives deux fois. J'ai réparé ça. En outre, le script compte maintenant les pages et répertorie les pages en niveaux de gris pour l'impression en double page. En outre, il imprime les pages séparées par des virgules, de sorte que la sortie peut directement être utilisée pour l'impression à partir d'une visionneuse PDF. J'ai ajouté le code, mais vous pouvez également le télécharger en cliquant sur le bouton here.

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 
12

versions plus récentes de Ghostscript (version 9.05 et versions ultérieures) comprennent un "dispositif" appelé inkcov. Il calcule la couverture d'encre de chaque page (pas pour chaque image) en valeurs Cyan (C), Magenta (M), Jaune (Y) et Noir (K), où 0.00000 signifie 0% et 1.00000 signifie 100% (voir Detecting all pages which contain color).

Par exemple:

$ 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 

Si les valeurs ne sont pas CMY 0, la page est la couleur.

Pour que la sortie des pages qui contiennent des couleurs utilisent cette oneliner pratique:

$ 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

Il y a une faute de frappe, ce que SO ne me laissera pas correct car il ne s'agit que d'un caractère: s doit être gs. De plus, cette méthode ne fonctionne pas forcément comme prévu, les fichiers pdf créés par inkscape, par exemple, ont toujours un CMJ non nul même si l'image est purement en niveaux de gris –

+0

Correction de la faute de frappe – Matteo

Questions connexes