Comment savoir si les pages PDF sont en couleur ou en noir et blanc?

Étant donné un ensemble de fichiers PDF dont certaines pages sont en couleur et les autres en noir et blanc, existe-t-il un programme parmi les pages données qui sont en couleur et en noir et blanc? Cela serait utile, par exemple, pour imprimer une thèse et ne dépenser que des frais supplémentaires pour imprimer les pages en couleur. 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é.

C’est l’une des questions les plus intéressantes que j’ai vues! Je suis d’accord avec certains des autres articles selon lesquels le rendu sur une image bitmap et l’parsing du bitmap seront la solution la plus fiable. Pour les PDF simples, voici une approche plus rapide mais moins complète.

  1. Analyser chaque page PDF
  2. Recherchez les directives de couleur (g, rg, k, sc, scn, etc.)
  3. Rechercher des images incorporées, parsingr les couleurs

Ma solution ci-dessous fait n ° 1 et la moitié de n ° 2. L’autre moitié de # 2 serait de suivre avec 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 5 minutes.

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

Il est possible d’utiliser l’outil Image Magick . S’il est utilisé sur des pages PDF, il convertit d’abord la page en image raster. Si la couleur contenue dans la page peut être testée à l’aide de l’ -format "%[colorspace]" , pour mon fichier PDF imprimé en Gray ou en RGB . IMHO identify (ou quel que soit l’outil utilisé en arrière-plan; Ghostscript?) Choisit l’espace colorimésortingque en fonction des couleurs disponibles.

Un exemple est:

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

où PAGE est la page à partir de 0, pas 1. Si la sélection de la page n’est pas utilisée, toutes les pages seront réduites à une, ce qui n’est pas ce que vous voulez.

J’ai écrit le script BASH suivant qui utilise pdfinfo pour obtenir le nombre de pages, puis les boucle. Sortie des pages en couleur. J’ai également ajouté une fonctionnalité pour le document recto-verso dans lequel vous pourriez également avoir besoin d’une page de fond non colorée.

En utilisant la liste séparée par des espaces, les pages PDF colorées peuvent être extraites à l’aide de 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 

Les versions plus récentes de Ghostscript (version 9.05 et ultérieure) incluent un “périphérique” 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 Détection toutes les pages qui contiennent de la couleur ).

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 CMJ ne sont pas 0, la page est en couleur.

Pour simplement afficher les pages contenant des couleurs, utilisez ce 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' 

Le script de Martin Scharrer est génial. Il contient un bug mineur: il compte deux pages qui contiennent de la couleur et sont directement consécutives deux fois. J’ai corrigé cela. En outre, le script compte maintenant les pages et répertorie les pages en niveaux de gris pour une impression double-paginée. Il imprime également les pages séparées par des virgules, de sorte que la sortie peut être directement utilisée pour imprimer à partir d’un visualiseur PDF. J’ai ajouté le code, mais vous pouvez aussi le télécharger ici .

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 a des méthodes intégrées pour la comparaison d’images.

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

Il existe certaines API Perl pour ImageMagick, alors peut-être que si vous les combinez intelligemment avec un convertisseur PDF vers Image, vous pouvez trouver un moyen de faire votre test noir et blanc.

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

  1. Boucle à travers toutes les pages
  2. Extraire les pages sur une image
  3. Vérifier la gamme de couleurs de l’image

Pour le nombre de pages, vous pouvez probablement traduire cela sans trop d’effort pour Perl. C’est fondamentalement une regex. On dit aussi que:

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

Vous devez simplement compter combien de fois cette expression régulière se produit dans le fichier PDF, moins les fois où vous trouvez la chaîne “<>” (les âges vides ne sont pas rendus).

Pour extraire l’image, vous pouvez utiliser ImageMagick pour le faire. Ou voir cette question .

Enfin, pour savoir si elle est en noir et blanc, cela dépend si vous voulez dire littéralement en noir et blanc ou en niveaux de gris. Pour le noir et blanc, vous ne devriez avoir, bien sûr, que du noir et blanc dans toute l’image. Si vous voulez voir des niveaux de gris, maintenant, ce n’est vraiment pas ma spécialité mais je suppose que vous pourriez voir si les moyennes du rouge, du vert et du bleu sont proches les unes des autres ou si l’image originale et une échelle de gris convertie sont proches de L’un et l’autre.

J’espère que cela vous aidera à aller plus loin.