parsing - recursos - ¿Cómo sé si las páginas PDF son de color o en blanco y negro?
se ha producido un error al imprimir el documento (6)
Dado un conjunto de archivos PDF entre los que algunas páginas son de color y el resto son en blanco y negro, ¿hay algún programa para encontrar entre las páginas determinadas que son de color y que son en blanco y negro? Esto sería útil, por ejemplo, para imprimir una tesis y solo gastar más para imprimir las páginas en color. Puntos de bonificación para alguien que tiene en cuenta la impresión a doble cara, y envía una página en blanco y negro apropiada a la impresora en color si es seguida por una página de color en el lado opuesto.
¡Esta es una de las preguntas más interesantes que he visto! Estoy de acuerdo con algunas de las otras publicaciones que la representación en un mapa de bits y luego analizar el mapa de bits será la solución más confiable. Para archivos PDF simples, este es un enfoque más rápido pero menos completo.
- Analizar cada página PDF
- Busque las directivas de color (g, rg, k, sc, scn, etc.)
- Busque imágenes incrustadas, analice por color
Mi solución a continuación hace # 1 y la mitad de # 2. La otra mitad del n. ° 2 sería hacer un seguimiento con el color definido por el usuario, lo que implica buscar las entradas de / ColorSpace en la página y decodificarlas. Contáctame sin conexión si esto te resulta interesante, ya que es muy factible pero no 5 minutos.
Primero el programa 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";
}
}
Y luego, aquí está el renderizador de ayuda que maneja las directivas de color en cada página:
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(@_); }
El guión de Martin Scharrer es genial. Contiene un error menor: cuenta dos páginas que contienen color y son directamente consecutivas dos veces. Lo arreglé Además, el guión ahora cuenta las páginas y enumera las páginas en escala de grises para la impresión de doble página. También imprime las páginas separadas por comas, por lo que la salida se puede usar directamente para imprimir desde un visor de PDF. He agregado el código, pero también puedes descargarlo here .
Saludos, 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
Es posible utilizar la herramienta de identify
Image Magick . Si se usa en páginas PDF, convierte la página primero en una imagen ráster. Si la página que contiene el color puede probarse con la opción -format "%[colorspace]"
, que para mi PDF se imprimirá en Gray
o RGB
. En mi humilde opinión, (¿o alguna herramienta que use en segundo plano, Ghostscript?) Elige el espacio de color dependiendo de los regalos de color.
Un ejemplo es:
identify -format "%[colorspace]" $FILE.pdf[$PAGE]
donde PAGE es la página que comienza desde 0, no 1. Si no se utiliza la selección de página, todas las páginas se colapsarán en una, que no es lo que desea.
Escribí el siguiente script BASH que usa pdfinfo
para obtener el número de páginas y luego pasa por encima de ellas. Salida de las páginas que están en color. También agregué una función para documentos de doble cara en la que también podría necesitar una página trasera no coloreada.
Utilizando la lista de espacios separados por salida, las páginas en PDF coloreadas pueden extraerse usando 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
ImageMagick tiene algunos métodos integrados para la comparación de imágenes.
http://www.imagemagick.org/Usage/compare/#type_general
Existen algunas API de Perl para ImageMagick, así que tal vez si combinas inteligentemente estas con un convertidor de PDF a Imagen, puedes encontrar la forma de hacer tu prueba en blanco y negro.
Intentaría hacerlo así, aunque podría haber otras soluciones más fáciles, y tengo curiosidad por escucharlas, solo quiero intentarlo:
- Pasa por todas las páginas
- Extrae las páginas a una imagen
- Verificar el rango de color de la imagen
Para el conteo de páginas, probablemente puedas traducir that sin demasiado esfuerzo a Perl. Básicamente es una expresión regular. También se said que:
r "(/ Tipo) / s? (/ Página) [/> / s]"
Simplemente debe contar cuántas veces se produce esta expresión regular en el archivo PDF, menos las veces que encuentre la cadena "<>" (edades vacías que no se representan).
Para extraer la imagen, puede usar ImageMagick para hacer that . O mira esta pregunta
Finalmente, para saber si es en blanco y negro, depende si se refiere literalmente a blanco y negro o escala de grises. Para blanco y negro, solo debería tener, bueno, blanco y negro en toda la imagen. Si quieres ver la escala de grises, ahora no es mi especialidad, pero supongo que podrías ver si los promedios del rojo, el verde y el azul están cerca uno del otro o si la imagen original y una convertida en escala de grises están cerca de El uno al otro.
Espero que te dé algunos consejos para ayudarte a llegar más lejos.
Las versiones más nuevas de Ghostscript (versión 9.05 y posterior) incluyen un "dispositivo" llamado inkcov. Calcula la cobertura de tinta de cada página (no para cada imagen) en valores Cian (C), Magenta (M), Amarillo (Y) y Negro (K), donde 0.00000 significa 0% y 1.00000 significa 100% (consulte Detección todas las páginas que contienen color ).
Por ejemplo:
$ 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 los valores CMY no son 0, entonces la página es de color.
Para imprimir solo las páginas que contienen colores, utiliza este útil encuadernador:
$ 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''