Question

Étant donné un ensemble de fichiers PDF dont certaines pages sont en couleur et les autres en noir & amp; blanc, y a-t-il un programme à découvrir parmi les pages données qui sont en couleur et qui sont en noir & amp; blanc? Cela serait utile, par exemple, pour imprimer une thèse et ne dépenser qu'un extra pour imprimer les pages en couleur. Des points en prime pour une personne prenant en compte l’impression recto verso et envoyant une page noir et blanc appropriée à l’imprimante couleur si elle est suivie d’une page couleur du côté opposé.

Était-ce utile?

La solution

C’est l’une des questions les plus intéressantes que j’ai vues! Je suis d'accord avec certains des autres articles qui font du rendu en bitmap puis de l'analyse du bitmap 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 intégrées, analyser la couleur

Ma solution ci-dessous concerne le n ° 1 et la moitié du n ° 2. L'autre moitié du n ° 2 serait de faire un suivi 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 possible. 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 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(@_); }

Autres conseils

Les versions les plus récentes de Ghostscript (versions 9.05 et supérieures) 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 < em> Détection de toutes les pages contenant des couleurs ).

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

Pour afficher uniquement les pages contenant des couleurs, utilisez cet outil 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'

Il est possible d'utiliser l'outil Image Magick identify. S'il est utilisé sur des pages PDF, il convertit d'abord la page en une image raster. Si la page contenant la couleur peut être testée en utilisant l'option -format "%[colorspace]", qui pour mon PDF est imprimée soit Gray ou RGB. IMHO pdfinfo (ou quel que soit l'outil qu'il utilise en arrière-plan; Ghostscript?) Choisit l'espace colorimétrique en fonction des cadeaux présents.

Voici un exemple:

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

où PAGE est la page commençant par 0 et non par 1. Si la sélection de page n'est pas utilisée, toutes les pages seront réduites à une seule, ce qui n'est pas ce que vous voulez.

J'ai écrit le script BASH suivant qui utilise pdftk pour obtenir le nombre de pages, puis les parcourt en boucle. Sortie des pages en couleur. J'ai également ajouté une fonctionnalité pour les documents recto verso qui nécessitait peut-être également une page verso non colorée.

À l'aide de la liste séparée par des espaces, les pages PDF en couleur peuvent être extraites à l'aide de <=>:

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

Le scénario 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é ça. De plus, le script compte maintenant les pages et répertorie les pages en niveaux de gris pour une impression à double page. En outre, il imprime 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 le télécharger ici , également .

Salut, 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. Par conséquent, si vous les combinez intelligemment avec un convertisseur de PDF en image, vous pouvez trouver le moyen de créer votre & noir; test blanc.

J'essaierais de le faire comme ça, bien qu'il y ait peut-être d'autres solutions plus faciles, et je suis curieux de les entendre, je veux juste l'essayer:

  1. Parcourez toutes les pages
  2. Extraire les pages dans une image
  3. Vérifiez la gamme de couleurs de l'image

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

  

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

     

Vous devez simplement compter combien   fois cette expression régulière se produit   dans le fichier PDF, moins le temps que vous   trouver la chaîne " < > "   (âges vides qui ne sont pas rendus).

Pour extraire l'image, vous pouvez utiliser ImageMagick pour effectuer que . Ou consultez cette question .

Enfin, pour savoir s’il s’agit de noir et blanc, cela dépend si vous voulez dire littéralement noir et blanc ou en niveaux de gris. Pour le noir et blanc, vous ne devriez avoir que du noir et du blanc dans toute l'image. Si vous voulez voir les niveaux de gris, ce n’est vraiment pas ma spécialité, mais je suppose que vous pouvez voir si les moyennes des couleurs rouge, vert et bleu sont proches l’un de l’autre ou si l’image originale et un les niveaux de gris convertis sont proches les uns des autres.

J'espère que cela vous donnera des indices pour vous aider à aller plus loin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top