Как я могу определить разрешение отсканированного PDF-файла из сценария оболочки?
у меня есть большая коллекция документов, отсканированных в формате PDF, и я хочу написать shell-скрипт, который будет конвертировать каждый документ DjVu. Некоторые документы были отсканированы на 200dpi, некоторые на 300dpi, а некоторые на 600dpi. Поскольку DjVu-это пиксельный формат, я хочу быть уверен, что использую то же разрешение в целевом файле DjVu, что и при сканировании.
кто-нибудь знает, какую программу я могу запустить или как я могу написать программу, чтобы определить, какое разрешение использовался для создания отсканированного PDF? (Количество пикселей также может работать, так как почти все документы 8,5 на 11 дюймов.)
уточнение после ответов: я знаю о трудностях, выделенных Бретоном, и я готов признать, что проблема в целом плохо поставлена, но я не спрашиваю о общие PDF-документов. Мои документы были взяты со сканера. Они содержат одно отсканированное изображение на страницу, одинаковое разрешение каждой страницы. Если я преобразую PDF в PostScript я могу вручную копаться и легко находить размеры пикселей; вероятно, я мог бы найти размеры изображений с большей работой. И если в отчаянной необходимости я мог бы изменить стек словаря, который gs
используется; давным-давно я написал интерпретатор для уровня PostScript 1.
все это то, чего я пытаюсь избежать.
благодаря полученной помощи я опубликовал ответ ниже:
- извлеките ограничивающую рамку из PDF с помощью
identify
, принимая только выходные данные для первой страницы и понимая, что единицы будут точками PostScript, из которых 72 на дюйм. - извлечение изображений с первой страницы с помощью
pdfimages
. - получить высоту и ширину изображения. На этот раз
identify
даст количество пикселей. - добавить в общей сумме районах изображений, чтобы получить количество точек в квадрате.
- чтобы получить разрешение, вычислите области ограничивающей рамки в дюймах в квадрате, разделите точки в квадрате на дюймы в квадрате, возьмите квадратный корень и округлите до ближайшего кратного 10.
полный ответ со скриптом ниже. Я использую его в live fire, и он отлично работает. Спасибо Арлекину за pdfimages
и Spiffeah для предупреждения о нескольких изображениях на странице (это редко, но я нашел некоторые).
7 ответов
Я думаю, что сканирование включено в качестве изображений в PDF, поэтому вы можете использовать pdfimages
сначала извлечь их. Затем:identify
должны быть в состоянии найти правильные данные.
Если pdf был создан путем сканирования, то должно быть только одно изображение, связанное с каждой страницей. Вы можете найти каждое разрешение изображения для каждого изображения страницы, проанализировав pdf с помощью iText(Java) или iTextSharp(порт .net) библиотеки легко.
Если вы хотите свернуть свою собственную утилиту для этого, сделайте что-то вроде следующего в 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();
здесь для каждой страницы мы читаем через каждый XObject изображения подтипа и получите значения ширины и высоты. Это будет пиксельное разрешение изображения, которое сканер встроил в pdf-файл.
обратите внимание, что масштабирование этого изображения в соответствии с разрешением страницы (как и в размере страницы, отображаемой в Acrobat - A4, Letter и т. д.) выполняется отдельно в потоке содержимого страницы, который представлен как подмножество postscript, и гораздо сложнее найти без разбора postscript.
имейте в виду, что есть некоторые сканеры, которые будут вставлять отсканированное изображение в виде сетки меньших изображений (для какой-то оптимизации размера я предполагаю). Поэтому, если вы видите что-то вроде 50 маленьких изображений, появляющихся на каждой странице, это может быть причиной.
надеюсь, это каким-то образом поможет, если вам нужно свернуть свою собственную утилиту.
вот элементы этого ответа:
-
pdfimages
будет извлекать изображения, так что количество точек может быть обнаружено. -
identify
даст размер изображения в единицах PostScript точек (72 на дюйм) - поскольку некоторые сканеры могут разделить одну страницу на несколько изображений разных размеров и форм, ключ должен добавить районах всех изображений. Деление квадратных точек на квадратные дюймы и взятие квадрата корень дает ответ.
Ниже приведен сценарий Lua, который решает проблему. Вероятно, я мог бы использовать простую оболочку, но захват ширины и высоты был бы большей неприятностью.
#!/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
pdfimages
есть -list
опция, которая дает ширину высоты в пикселях, а также y-ppi
и 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%
слишком долго, чтобы поместить в комментарий, но ни ImageMagick, ни GraphicsMagic не подходят для этой работы;каждый ответ неправильный:
: 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 ;
правильными параметрами для этого документа является то, что каждая отсканированная страница имеет ширину 5100 пикселей и высоту 6600 пикселей, неудивительно, что это был 8.5-by-11, отсканированный на 600dpi. Выход из ImageMagic удивительно непрофессионально.
нет downvotes, потому что вы пытались быть полезными, но *Magick
не работают.
PDF-это независимый от разрешения формат, это бессмысленный вопрос. Возможно, вы сканировали некоторые растровые изображения с определенным разрешением, и эти растровые изображения индивидуально встроены в pdf, но сам PDF может содержать изображения с несколькими разрешениями, а также независимую от разрешения векторную графику. Нет никакого способа узнать, не взломав pdf-файл и не изучив каждый объект внутри него.
редактирование для продолжения изложения проблемы:
вы можете повезло, и программное обеспечение, которое вы использовали для сканирования документов, внедрило некоторые метаданные об этом, но не ставьте на это. Такие метаданные вряд ли будут стандартными. Насколько парсинга PDF, вы хотели заготовки библиотеке - таких как Ghostscript. Проблема в том, что PDF-это не формат, а определенное подмножество языка программирования PostScript и согласованный способ сжатия/компиляции этого подмножества вместе с некоторыми двоичными файлами. Таким образом, чтение PDF сложнее чем другие типы форматов изображений, так как это предполагает написание интерпретатора языка - не так просто.
лучший подход - либо поднять руки и сдаться, либо действительно посмотреть на ghostscript и посмотреть, сможете ли вы получить ответ.
PDF-шпион Apago расскажет вам об остром разрешении изображений в PDF вместе с множеством других вещей. Это коммерческий продукт, но имеет 10-дневную демонстрацию.