¿Cómo convertir un pdf en color a blanco y negro?

18

Me gustaría transformar un pdf con texto en color e imágenes en otro pdf solo en blanco y negro, para reducir sus dimensiones. Además, me gustaría mantener el texto como texto, sin transformar los elementos de las páginas en imágenes. Intenté el siguiente comando:

convert -density 150 -threshold 50% input.pdf output.pdf

encontré en otra pregunta, un enlace , pero hace lo que no quiero: el texto en la salida se transforma en una imagen pobre y ya no es seleccionable. Lo intenté con Ghostscript:

gs      -sOutputFile=output.pdf \
        -q -dNOPAUSE -dBATCH -dSAFER \
        -sDEVICE=pdfwrite \
        -dCompatibilityLevel=1.3 \
        -dPDFSETTINGS=/screen \
        -dEmbedAllFonts=true \
        -dSubsetFonts=true \
        -sColorConversionStrategy=/Mono \
        -sColorConversionStrategyForImages=/Mono \
        -sProcessColorModel=/DeviceGray \
        $1

pero me da el siguiente mensaje de error:

./script.sh: 19: ./script.sh: output.pdf: not found

¿Hay alguna otra forma de crear el archivo?

BowPark
fuente
Esto se ve tan bien superuser.com/questions/200378/...
slackmart
Tenga cuidado al usar algunos de los enfoques de superusuario, convierten el PDF a una versión rasterizada, por lo que ya no son gráficos vectoriales.
slm
1
¿Es ese el guión completo que ejecutaste? No lo parece, ¿podrías publicar el guión completo?
terdon

Respuestas:

23

El ejemplo de gs

El gscomando que está ejecutando arriba tiene un final $1que generalmente está destinado a pasar argumentos de línea de comando a un script. Así que no estoy seguro de lo que realmente intentaste, pero supongo que intentaste poner ese comando en un script script.sh:

#!/bin/bash

gs      -sOutputFile=output.pdf \
        -q -dNOPAUSE -dBATCH -dSAFER \
        -sDEVICE=pdfwrite \
        -dCompatibilityLevel=1.3 \
        -dPDFSETTINGS=/screen \
        -dEmbedAllFonts=true \
        -dSubsetFonts=true \
        -sColorConversionStrategy=/Mono \
        -sColorConversionStrategyForImages=/Mono \
        -sProcessColorModel=/DeviceGray \
        $1

Y ejecútelo así:

$ ./script.sh: 19: ./script.sh: output.pdf: not found

No estoy seguro de cómo configurar este script, pero debe ser ejecutable.

$ chmod +x script.sh

Sin embargo, algo definitivamente no parece correcto con ese script. Cuando lo probé, recibí este error:

Error irrecuperable: comprobación de rango en .putdeviceprops

Una alternativa

En lugar de ese script, usaría este de la pregunta SU en su lugar.

#!/bin/bash

gs \
 -sOutputFile=output.pdf \
 -sDEVICE=pdfwrite \
 -sColorConversionStrategy=Gray \
 -dProcessColorModel=/DeviceGray \
 -dCompatibilityLevel=1.4 \
 -dNOPAUSE \
 -dBATCH \
 $1

Luego ejecútelo así:

$ ./script.bash LeaseContract.pdf 
GPL Ghostscript 8.71 (2010-02-10)
Copyright (C) 2010 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 2.
Page 1
Page 2
slm
fuente
Tienes razón, hay algo mal con el script: "algo" en este caso sería lo sProcessColorModelque debería ser dProcessColorModelen su lugar.
Sora.
8

Encontré un script aquí que puede hacer esto. Requiere gslo que pareces tener pero también pdftk. No ha mencionado su distribución, pero en los sistemas basados ​​en Debian, debería poder instalarla con

sudo apt-get install pdftk

Puede encontrar RPM para ello aquí .

Una vez que haya instalado pdftk, guarde el script como graypdf.shy ejecútelo así:

./greypdf.sh input.pdf

Creará un archivo llamado input-gray.pdf. Incluyo todo el script aquí para evitar la descomposición del enlace:

# convert pdf to grayscale, preserving metadata
# "AFAIK graphicx has no feature for manipulating colorspaces. " http://groups.google.com/group/latexusersgroup/browse_thread/thread/5ebbc3ff9978af05
# "> Is there an easy (or just standard) way with pdflatex to do a > conversion from color to grayscale when a PDF file is generated? No." ... "If you want to convert a multipage document then you better have pdftops from the xpdf suite installed because Ghostscript's pdf to ps doesn't produce nice Postscript." http://osdir.com/ml/tex.pdftex/2008-05/msg00006.html
# "Converting a color EPS to grayscale" - http://en.wikibooks.org/wiki/LaTeX/Importing_Graphics
# "\usepackage[monochrome]{color} .. I don't know of a neat automatic conversion to monochrome (there might be such a thing) although there was something in Tugboat a while back about mapping colors on the fly. I would probably make monochrome versions of the pictures, and name them consistently. Then conditionally load each one" http://newsgroups.derkeiler.com/Archive/Comp/comp.text.tex/2005-08/msg01864.html
# "Here comes optional.sty. By adding \usepackage{optional} ... \opt{color}{\includegraphics[width=0.4\textwidth]{intro/benzoCompounds_color}} \opt{grayscale}{\includegraphics[width=0.4\textwidth]{intro/benzoCompounds}} " - http://chem-bla-ics.blogspot.com/2008/01/my-phd-thesis-in-color-and-grayscale.html
# with gs:
# http://handyfloss.net/2008.09/making-a-pdf-grayscale-with-ghostscript/
# note - this strips metadata! so:
# http://etutorials.org/Linux+systems/pdf+hacks/Chapter+5.+Manipulating+PDF+Files/Hack+64+Get+and+Set+PDF+Metadata/
COLORFILENAME=$1
OVERWRITE=$2
FNAME=${COLORFILENAME%.pdf}
# NOTE: pdftk does not work with logical page numbers / pagination;
# gs kills it as well;
# so check for existence of 'pdfmarks' file in calling dir;
# if there, use it to correct gs logical pagination
# for example, see
# http://askubuntu.com/questions/32048/renumber-pages-of-a-pdf/65894#65894
PDFMARKS=
if [ -e pdfmarks ] ; then
PDFMARKS="pdfmarks"
echo "$PDFMARKS exists, using..."
# convert to gray pdf - this strips metadata!
gs -sOutputFile=$FNAME-gs-gray.pdf -sDEVICE=pdfwrite \
-sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray \
-dCompatibilityLevel=1.4 -dNOPAUSE -dBATCH "$COLORFILENAME" "$PDFMARKS"
else # not really needed ?!
gs -sOutputFile=$FNAME-gs-gray.pdf -sDEVICE=pdfwrite \
-sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray \
-dCompatibilityLevel=1.4 -dNOPAUSE -dBATCH "$COLORFILENAME"
fi
# dump metadata from original color pdf
## pdftk $COLORFILENAME dump_data output $FNAME.data.txt
# also: pdfinfo -meta $COLORFILENAME
# grep to avoid BookmarkTitle/Level/PageNumber:
pdftk $COLORFILENAME dump_data output | grep 'Info\|Pdf' > $FNAME.data.txt
# "pdftk can take a plain-text file of these same key/value pairs and update a PDF's Info dictionary to match. Currently, it does not update the PDF's XMP stream."
pdftk $FNAME-gs-gray.pdf update_info $FNAME.data.txt output $FNAME-gray.pdf
# (http://wiki.creativecommons.org/XMP_Implementations : Exempi ... allows reading/writing XMP metadata for various file formats, including PDF ... )
# clean up
rm $FNAME-gs-gray.pdf
rm $FNAME.data.txt
if [ "$OVERWRITE" == "y" ] ; then
echo "Overwriting $COLORFILENAME..."
mv $FNAME-gray.pdf $COLORFILENAME
fi
# BUT NOTE:
# Mixing TEX & PostScript : The GEX Model - http://www.tug.org/TUGboat/Articles/tb21-3/tb68kost.pdf
# VTEX is a (commercial) extended version of TEX, sold by MicroPress, Inc. Free versions of VTEX have recently been made available, that work under OS/2 and Linux. This paper describes GEX, a fast fully-integrated PostScript interpreter which functions as part of the VTEX code-generator. Unless specified otherwise, this article describes the functionality in the free- ware version of the VTEX compiler, as available on CTAN sites in systems/vtex.
# GEX is a graphics counterpart to TEX. .. Since GEX may exercise subtle influence on TEX (load fonts, or change TEX registers), GEX is op- tional in VTEX implementations: the default oper- ation of the program is with GEX off; it is enabled by a command-line switch.
# \includegraphics[width=1.3in, colorspace=grayscale 256]{macaw.jpg}
# http://mail.tug.org/texlive/Contents/live/texmf-dist/doc/generic/FAQ-en/html/FAQ-TeXsystems.html
# A free version of the commercial VTeX extended TeX system is available for use under Linux, which among other things specialises in direct production of PDF from (La)TeX input. Sadly, it���s no longer supported, and the ready-built images are made for use with a rather ancient Linux kernel.
# NOTE: another way to capture metadata; if converting via ghostscript:
# http://compgroups.net/comp.text.pdf/How-to-specify-metadata-using-Ghostscript
# first:
# grep -a 'Keywo' orig.pdf
# /Author(xxx)/Title(ttt)/Subject()/Creator(LaTeX)/Producer(pdfTeX-1.40.12)/Keywords(kkkk)
# then - copy this data in a file prologue.ini:
#/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse
#[/Author(xxx)
#/Title(ttt)
#/Subject()
#/Creator(LaTeX with hyperref package + gs w/ prologue)
#/Producer(pdfTeX-1.40.12)
#/Keywords(kkkk)
#/DOCINFO pdfmark
#
# finally, call gs on the orig file,
# asking to process pdfmarks in prologue.ini:
# gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 \
# -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -dBATCH -dDOPDFMARKS \
# -sOutputFile=out.pdf in.pdf prologue.ini
# then the metadata will be in output too (which is stripped otherwise;
# note bookmarks are preserved, however). 
terdon
fuente
3

También tenía algunos archivos PDF en color escaneados y archivos PDF en escala de grises que quería convertir a bw. Intenté usarlo gscon el código que se muestra aquí , y la calidad de imagen es buena con el texto en PDF todavía allí. Sin embargo, ese código gs solo se convierte en escala de grises (como se preguntó en la pregunta) y todavía tiene un gran tamaño de archivo. convertproduce resultados muy pobres cuando se usa directamente.

Quería archivos PDF con buena calidad de imagen y tamaño de archivo pequeño. Habría intentado la solución de terdon, pero no pude acceder pdftka centOS 7 usando yum (al momento de escribir).

Mi solución se utiliza gspara extraer archivos bmp en escala de grises del pdf, convertpara limitar esos bmps a bw y guardarlos como archivos tiff, y luego img2pdf para comprimir las imágenes tiff y combinarlas en un solo pdf.

Intenté ir directamente a tiff desde el pdf, pero la calidad no es la misma, por lo que guardo cada página en bmp. Para un archivo pdf de una página, converthace un gran trabajo desde bmp a pdf. Ejemplo:

gs -sDEVICE=bmpgray -dNOPAUSE -dBATCH -r300x300 \
   -sOutputFile=./pdf_image.bmp ./input.pdf

convert ./pdf_image.bmp -threshold 40% -compress zip ./bw_out.pdf

Para varias páginas, gspuede combinar varios archivos PDF en uno, pero img2pdfproduce un tamaño de archivo más pequeño que gs. Los archivos tiff deben descomprimirse como entrada para img2pdf. Tenga en cuenta que para un gran número de páginas, los archivos intermedios bmp y tiff tienden a ser de gran tamaño. pdftko joinpdfsería mejor si pueden fusionar archivos PDF comprimidos de convert.

Me imagino que hay una solución más elegante. Sin embargo, mi método produce resultados con muy buena calidad de imagen y un tamaño de archivo mucho más pequeño. Para recuperar el texto en bw pdf, ejecute OCR nuevamente.

Mi script de shell usa gs, convert e img2pdf. Cambie los parámetros (número de páginas, ppp de escaneo,% umbral, etc.) enumerados al principio según sea necesario, y ejecútelos chmod +x ./pdf2bw.sh. Aquí está el script completo (pdf2bw.sh):

#!/bin/bash

num_pages=12
dpi_res=300
input_pdf_name=color_or_grayscale.pdf
bw_threshold=40%
output_pdf_name=out_bw.pdf
#-------------------------------------------------------------------------
gs -sDEVICE=bmpgray -dNOPAUSE -dBATCH -q -r$dpi_res \
   -sOutputFile=./%d.bmp ./$input_pdf_name
#-------------------------------------------------------------------------
for file_num in `seq 1 $num_pages`
do
  convert ./$file_num.bmp -threshold $bw_threshold \
          ./$file_num.tif
done
#-------------------------------------------------------------------------
input_files=""

for file_num in `seq 1 $num_pages`
do
  input_files+="./$file_num.tif "
done

img2pdf -o ./$output_pdf_name --dpi $dpi_res $input_files
#-------------------------------------------------------------------------
# clean up bmp and tif files used in conversion

for file_num in `seq 1 $num_pages`
do
  rm ./$file_num.bmp
  rm ./$file_num.tif
done
La navaja de Occam
fuente
1

RHEL6 y RHEL5, que ambos Ghostscript de línea de base en 8.70, no podían usar las formas del comando dado anteriormente. Suponiendo que un script o una función espere que el archivo PDF sea el primer argumento "$ 1", lo siguiente debería ser más portátil:

gs \
    -sOutputFile="grey_$1" \
    -sDEVICE=pdfwrite \
    -sColorConversionStrategy=Mono \
    -sColorConversionStrategyForImages=/Mono \
    -dProcessColorModel=/DeviceGray \
    -dCompatibilityLevel=1.3 \
    -dNOPAUSE -dBATCH \
    "$1"

Donde el archivo de salida tendrá el prefijo "grey_".

RHEL6 y 5 pueden usar CompatibilityLevel = 1.4, que es mucho más rápido, pero apuntaba a la portabilidad.

Rico
fuente
Los desarrolladores dicen ( 1 , 2 , 3 , 4 ) que no hay sColorConversionStrategyForImagescambio.
Igor
Gracias, @Igor. ¡No tengo idea de dónde obtuve ese fragmento! Sé con certeza que lo probé y funcionó en ese momento . (Y esa es la razón por la que siempre debe proporcionar referencias para su código)
Rich
1
Ese "parámetro falso" parece ser increíblemente popular entre la web. GS ignora los interruptores desconocidos (lo cual es triste), por lo que funciona de todos modos.
Igor
1

Obtengo resultados confiables al limpiar archivos PDF escaneados con un buen contraste con este script;

#!/bin/bash
# 
# $ sudo apt install poppler-utils img2pdf pdftk imagemagick
#
# Output is still greyscale, but lots of scanner light tone fuzz removed.
#

pdfimages $1 pages

ls ./pages*.ppm | xargs -L1 -I {} convert {}  -quality 100 -density 400 \
  -fill white -fuzz 80% -auto-level -depth 4 +opaque "#000000" {}.jpg

ls -1 ./pages*jpg | xargs -L1 -I {} img2pdf {} -o {}.pdf

pdftk pages*.pdf cat output ${1/.pdf/}_bw.pdf

rm pages*
Bijou Smith
fuente