resueltos - ¿Cómo puedo saber la resolución del PDF escaneado desde un script de shell?
scripts bash ejemplos (7)
Tengo una gran colección de documentos escaneados en formato PDF y deseo escribir un guión de shell que convierta cada documento al formato DjVu . Algunos documentos se escanearon a 200 ppp, algunos a 300 ppp y otros a 600 ppp. Como DjVu es un formato basado en píxeles, quiero asegurarme de usar la misma resolución en el archivo DjVu de destino que se utilizó para el escaneo.
¿Alguien sabe qué programa puedo ejecutar, o cómo puedo escribir un programa, para determinar qué resolución se utilizó para producir un PDF escaneado? (El número de píxeles también podría funcionar, ya que casi todos los documentos son de 8,5 por 11 pulgadas).
Aclaración después de las respuestas: soy consciente de las dificultades destacadas por Breton, y estoy dispuesto a admitir que el problema en general está mal planteado, pero no estoy preguntando sobre documentos PDF generales . Mis documentos particulares salieron de un escáner. Contienen una imagen escaneada por página, la misma resolución en cada página. Si convierto el PDF a PostScript, puedo hojearlo a mano y encontrar las dimensiones de los píxeles fácilmente; Probablemente podría encontrar tamaños de imagen con más trabajo. Y si tuviera una necesidad desesperada, podría modificar la pila de diccionarios que usa gs
; Hace mucho tiempo, escribí un intérprete para PostScript Nivel 1.
Todo eso es lo que trato de evitar.
Gracias a la ayuda recibida, he publicado una respuesta a continuación:
- Extraiga el recuadro delimitador del PDF utilizando la
identify
, tomando solo el resultado de la primera página, y entendiendo que las unidades serán puntos PostScript, de los cuales hay 72 a una pulgada. - Extrae imágenes de la primera página usando
pdfimages
. - Obtenga altura y ancho de imagen. Esta vez
identify
dará el número de píxeles. - Agregue las áreas totales de las imágenes para obtener el número de puntos al cuadrado.
- Para obtener una resolución, calcule las áreas del cuadro delimitador en pulgadas al cuadrado, divida los puntos al cuadrado por pulgadas al cuadrado, tome la raíz cuadrada y redondee al múltiplo más cercano de 10.
La respuesta completa con script está debajo. Lo estoy usando en fuego real y funciona genial. Gracias Harlequin por pdfimages
y Spiffeah por la alerta sobre múltiples imágenes por página (es raro, pero he encontrado algunos).
Demasiado tiempo para poner en un comentario, pero ni ImageMagick ni GraphicsMagic están listos para el trabajo; cada respuesta es incorrecta :
: nr@yorkie 1932 ; gm identify -format "x=%x y=%y w=%w h=%h" drh*rec*pdf
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
x=0 y=0 w=612 h=792
: nr@yorkie 1933 ; identify -format "x=%x y=%y w=%w h=%h" drh*rec*pdf
x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792x=72 Undefined y=72 Undefined w=612 h=792
: nr@yorkie 1934 ;
Los parámetros correctos para este documento es que cada página escaneada tiene 5100 píxeles de ancho y 6600 píxeles de alto, lo cual no es sorprendente ya que se trata de un escaneo 8.5-por-11 a 600 ppp. El resultado de ImageMagic es asombrosamente poco profesional.
No downvotes porque intentabas ser útil, pero *Magick
no funciona.
Si se ha creado un pdf escaneando, solo debería haber una imagen asociada a cada página. Puede encontrar cada resolución de imagen para cada imagen de página analizando el pdf utilizando las bibliotecas iText (Java) o iTextSharp (el puerto .net) fácilmente.
Si desea transferir su propia utilidad para hacer esto, haga algo como lo siguiente en iTextSharp:
PdfReader reader = new PdfReader(filename);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfDictionary pg = reader.GetPageN(i);
PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
PdfDictionary xobjs = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
if (xobjs != null)
{
foreach (PdfName xObjectKey in xobjs.Keys)
{
PdfObject xobj = xobjs.Get(xObjectKey);
PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(xobj);
PdfName subtype = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
if (subtype.Equals(PdfName.IMAGE))
{
PdfNumber width = (PdfNumber)tg.Get(PdfName.WIDTH);
PdfNumber height = (PdfNumber)tg.Get(PdfName.HEIGHT);
MessageBox.Show("image on page [" + i + "] resolution=[" + width +"x" + height + "]");
}
}
}
}
reader.Close();
Aquí para cada página leemos cada XObjeto de subtipo Image y obtenemos los valores WIDTH y HEIGHT. Esta será la resolución de píxel de la imagen que el escáner ha incrustado en el pdf.
Tenga en cuenta que la escala de esta imagen para que coincida con la resolución de la página (como en el tamaño de la página procesada en Acrobat - A4, Carta, etc.) se realiza por separado en la secuencia de contenido de la página, que se representa como un subconjunto de postscript, y mucho más difícil de encontrar sin analizar la posdata.
Tenga en cuenta que hay algunos escáneres que incrustarán la imagen escaneada como una cuadrícula de imágenes más pequeñas (para algún tipo de optimización de tamaño, supongo). Entonces, si ves algo así como 50 imágenes pequeñas apareciendo para cada página, esa podría ser la razón.
Espero que esto ayude de alguna manera si tienes que usar tu propia utilidad.
Supongo que los escaneos se incluyen como imágenes en el PDF, por lo que podría usar pdfimages
para extraerlos primero. Luego, identify
debería ser capaz de encontrar los datos correctos.
PDF es un formato independiente de resolución, es una pregunta sin sentido. Es posible que haya escaneado algunos mapas de bits a una resolución particular, y esos mapas de bits se incrustan individualmente dentro del pdf, pero el PDF en sí mismo puede contener imágenes en múltiples resoluciones, así como también gráficos vectoriales independientes de resolución. No hay forma de saber sin abrir el pdf y examinar cada objeto dentro de él.
Edición para continuar exponiendo el problema:
Puede haber tenido suerte, y el software que usó para escanear los documentos incrustó algunos metadatos sobre esto, pero no apueste. Es poco probable que estos metadatos sean estándar. En cuanto a analizar el pdf, querrá una biblioteca preescrita, como ghostscript. El problema es que PDF no es realmente un formato sino un subconjunto específico del lenguaje de programación PostScript, y una forma acordada de comprimir / compilar este subconjunto junto con algunos binarios. Por lo tanto, leer un PDF es más complicado que otros tipos de formatos de imagen, ya que implica escribir un intérprete de idiomas, no tan sencillo.
El mejor enfoque es tirar las manos y rendirse, o realmente mirar con dureza a Ghostscript y ver si puede obtener la respuesta.
Aquí están los elementos de esta respuesta:
-
pdfimages
extraerá imágenes para que se descubra el número de puntos. -
identify
dará el tamaño de la imagen en unidades de puntos PostScript (72 a la pulgada) - Debido a que algunos escáneres pueden dividir una sola página en varias imágenes de diferentes tamaños y formas, la clave es sumar las áreas de todas las imágenes. Dividir los puntos cuadrados por pulgadas cuadradas y tomar la raíz cuadrada produce la respuesta.
A continuación se muestra un script de Lua que resuelve el problema. Probablemente podría haber usado un caparazón simple, pero capturar el ancho y la altura habría sido una molestia mayor.
#!/usr/bin/env lua
require ''osutil''
require ''posixutil''
require ''mathutil''
local function runf(...) return os.execute(string.format(...)) end
assert(arg[1], "no file on command line")
local function dimens(filename)
local cmd = [[identify -format "return %w, %h/n" $file | sed 1q]]
cmd = cmd:gsub(''$file'', os.quote(filename))
local w, h = assert(loadstring(os.capture(cmd)))()
assert(w and h)
return w, h
end
assert(#arg == 1, "dpi of just one file")
for _, pdf in ipairs(arg) do
local w, h = dimens(pdf) -- units are points
local insquared = w * h / (72.00 * 72.00)
local imagedir = os.capture ''mktemp -d''
assert(posix.isdir(imagedir))
runf(''pdfimages -f 1 -l 1 %s %s 1>&2'', os.quote(pdf),
os.quote(imagedir .. ''/img''))
local dotsquared = 0
for file in posix.glob(imagedir .. ''/img*'') do
local w, h = dimens(file) -- units are pixels
dotsquared = dotsquared + w * h
end
os.execute(''rm -rf '' .. os.quote(imagedir))
local dpi = math.sqrt(dotsquared / insquared)
if true then
io.stderr:write(insquared, " square inches/n")
io.stderr:write(dotsquared, " square dots/n")
io.stderr:write(dpi, " exact dpi/n")
io.stderr:write(math.round(dpi, 10), " rounded dpi/n")
end
print(math.round(dpi, 10))
end
El PDF Spy de Apago le informará la resolución real de las imágenes en un PDF junto con muchas otras cosas. Es un producto comercial, pero tiene una demo de 10 días.
pdfimages
tiene una opción -list
que le da ancho de alto en píxeles y también y-ppi
y x-ppi
.
pdfimages -list tmp.pdf
page num type width height color comp bpc enc interp object ID x-ppi y-ppi size ratio
--------------------------------------------------------------------------------------------
1 0 image 3300 2550 gray 1 1 ccitt no 477 0 389 232 172K 17%
2 1 image 3300 2550 gray 1 1 ccitt no 3 0 389 232 103K 10%
3 2 image 3300 2550 gray 1 1 ccitt no 7 0 389 232 236K 23%
4 3 image 3300 2550 gray 1 1 ccitt no 11 0 389 232 210K 20%
5 4 image 3300 2550 gray 1 1 ccitt no 15 0 389 232 250K 24%
6 5 image 3300 2550 gray 1 1 ccitt no 19 0 389 232 199K 19%
7 6 image 3300 2550 gray 1 1 ccitt no 23 0 389 232 503K 49%
8 7 image 3300 2550 gray 1 1 ccitt no 27 0 389 232 154K 15%
9 8 image 3300 2550 gray 1 1 ccitt no 31 0 389 232 21.5K 2.1%
10 9 image 3300 2550 gray 1 1 ccitt no 35 0 389 232 286K 28%
11 10 image 3300 2550 gray 1 1 ccitt no 39 0 389 232 46.8K 4.6%
12 11 image 3300 2550 gray 1 1 ccitt no 43 0 389 232 55.5K 5.4%
13 12 image 3300 2550 gray 1 1 ccitt no 47 0 389 232 35.0K 3.4%
14 13 image 3300 2550 gray 1 1 ccitt no 51 0 389 232 26.9K 2.6%
15 14 image 3300 2550 gray 1 1 ccitt no 55 0 389 232 66.5K 6.5%
16 15 image 3300 2550 gray 1 1 ccitt no 59 0 389 232 73.9K 7.2%
17 16 image 3300 2550 gray 1 1 ccitt no 63 0 389 232 47.0K 4.6%
18 17 image 3300 2550 gray 1 1 ccitt no 67 0 389 232 30.1K 2.9%
19 18 image 3300 2550 gray 1 1 ccitt no 71 0 389 232 70.3K 6.8%
20 19 image 3300 2550 gray 1 1 ccitt no 75 0 389 232 46.0K 4.5%
21 20 image 3300 2550 gray 1 1 ccitt no 79 0 389 232 28.9K 2.8%
22 21 image 3300 2550 gray 1 1 ccitt no 83 0 389 232 72.7K 7.1%
23 22 image 3300 2550 gray 1 1 ccitt no 87 0 389 232 47.5K 4.6%
24 23 image 3300 2550 gray 1 1 ccitt no 91 0 389 232 30.1K 2.9%