63 votes

Comment puis-je savoir si PDF pages sont en couleur ou en noir et blanc?

Étant donné un ensemble de fichiers PDF dont certaines pages sont en couleur et le reste en noir et blanc, est-il un programme pour trouver chez les pages sont en couleur et qui sont en noir et blanc? Ce serait utile, par exemple, dans l'impression d'une thèse, et seules les dépenses supplémentaires pour l'impression de la couleur des pages. Les points Bonus pour quelqu'un qui tient compte de l'impression recto verso, et envoie un approprié de page noir et blanc à la couleur de l'imprimante si elle est suivie d'une page de couleur sur le côté opposé.

29voto

Chris Dolan Points 5435

C'est l'une des questions les plus intéressantes que j'ai vu! Je suis d'accord avec certains des autres postes que le rendu d'une image et d'analyser l'image bitmap sera la solution la plus fiable. Pour de simples fichiers Pdf, ici, est plus rapide mais moins complète de l'approche.

  1. Analyser chaque page PDF
  2. Recherchez les directives de couleur (g, rg, k, sc, scn, etc)
  3. Regardez pour les images incorporées, analyser pour la couleur

Ma solution ci-dessous n' #1 et la moitié de #2. L'autre moitié du n ° 2 serait de suivi avec la couleur définie par l'utilisateur, ce qui implique la recherche de la /Palette des entrées dans la page et de décodage -- me contacter en mode hors connexion si ce qui est intéressant pour vous, car il est très faisable, mais pas dans les 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 voici l'aide de moteur de rendu, 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(@_); }

15voto

Martin Scharrer Points 822

Il est possible d'utiliser l' Image Magick outil identify. S'il est utilisé sur les pages de PDF convertit la première page d'une image raster. Si la page contient la couleur peut être testé à l'aide de l' -format "%[colorspace]" option, qui pour mon PDF imprimer Gray ou RGB. À mon humble avis, identify (ou ce que jamais l'outil qu'il utilise dans l'arrière-plan; Ghostscript?) ne choisissez la couleur en fonction de la présence de la couleur.

Un exemple est:

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

lorsque la PAGE est la page à partir de 0 et non pas 1. Si la page de sélection n'est pas utilisé toutes les pages doivent être ramenés à un seul, ce qui n'est pas ce que vous voulez.

J'ai écrit ce script BASH qui utilise pdfinfo pour obtenir le nombre de pages et puis des boucles au-dessus d'eux. De la sortie des pages qui sont en couleur. J'ai également ajouté une fonctionnalité pour les double faces d'un document où vous pourriez avoir besoin d'une non-couleur du verso de la page.

À l'aide de la sortie liste séparée par des espaces, la couleur des pages PDF peuvent être extraites à l'aide d' 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

3voto

iamtimeshift Points 78

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 reprises. J'ai corrigé ça. En outre, le script en compte aujourd'hui les pages et les listes de niveaux de gris des pages pour la double page de l'impression. Aussi, il imprime les pages séparées par des virgules, de sorte que la sortie peut être directement utilisé pour l'impression à partir d'une visionneuse de PDF. J'ai ajouté le code, mais vous pouvez le télécharger ici, trop.

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

2voto

Cory Points 37551

ImageMagick intègre des méthodes de comparaison d'images.

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

Il y a quelques Perl Api pour ImageMagick, alors peut-être si vous habilement de les combiner avec un PDF en Image convertisseur vous pouvez trouver un moyen de le faire en noir et blanc de test.

2voto

lpfavreau Points 5622

Je voudrais essayer de le faire comme ça, même s'il pourrait y avoir d'autres solutions plus simples, et je suis curieux de les entendre, j'ai juste envie de l'essayer:

  1. Boucle sur toutes les pages
  2. Extraire les pages à une image
  3. De vérifier la gamme de couleurs de l'image

Pour le nombre de pages, vous pouvez probablement traduire que sans trop d'effort, Perl. En gros, c'est une regex. Il est également dit que:

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

Il vous suffit de compter le nombre de fois cette expression régulière se produit dans le fichier PDF, moins le temps de vous rechercher la chaîne "<>" (vide des âges qui ne sont pas rendus).

Pour extraire l'image, vous pouvez utiliser ImageMagick pour faire que. Ou voir à cette question.

Enfin, pour obtenir qu'il est noir et blanc, ça dépend si tu veux dire littéralement en noir et blanc ou en niveaux de gris. Pour le noir et blanc, vous ne devriez avoir, bien, le noir et le blanc dans toute l'image. Si vous voulez voir en niveaux de gris, maintenant, c'est vraiment pas ma spécialité, mais je suppose que vous pourriez voir si les moyennes de le rouge, le vert et le bleu sont proches les uns des autres ou si l'image d'origine et un converti en niveaux de gris sont proches les uns des autres.

Espérons qu'il donne quelques conseils pour vous aider à aller plus loin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X