Как определить разрешение отсканированного PDF из сценария оболочки? - PullRequest
10 голосов
/ 17 января 2009

У меня есть большая коллекция документов, отсканированных в формате PDF, и я хочу написать сценарий оболочки, который преобразует каждый документ в формат DjVu . Некоторые документы были отсканированы с разрешением 200 т / д, некоторые с разрешением 300 т / д, а некоторые - с разрешением 600 т / д. Поскольку DjVu является пиксельным форматом, я хочу быть уверенным, что в целевом файле DjVu используется то же разрешение, которое использовалось для сканирования.

Кто-нибудь знает, какую программу я могу запустить или как я могу написать программу, чтобы определить, какое разрешение использовалось для создания отсканированного PDF? (Количество пикселей может также работать, так как почти все документы имеют размер 8,5 на 11 дюймов.)


Разъяснение после ответов: я знаю о трудностях, отмеченных Бретоном, и я готов признать, что проблема в целом некорректна, но я не спрашиваю о общем PDF документы. Мои конкретные документы вышли из сканера. Они содержат одно отсканированное изображение на странице, одинаковое разрешение на каждой странице. Если я конвертирую PDF в PostScript, я могу легко передвигаться и легко находить размеры в пикселях; Я мог бы, вероятно, найти размеры изображения с большим количеством работы. И в случае крайней необходимости я мог бы изменить стек словарей, который использует gs; давно я написал интерпретатор для PostScript уровня 1.

Все это то, чего я пытаюсь избежать.


Благодаря полученной помощи я разместил ответ ниже:

  1. Извлеките ограничивающую рамку из PDF, используя identify, взяв только выходные данные для первой страницы и поняв, что единицами измерения будут точки PostScript, из которых от 72 до дюйма.
  2. Извлечение изображений с первой страницы с помощью pdfimages.
  3. Получить высоту и ширину изображения. На этот раз identify даст количество пикселей.
  4. Добавьте общее количество областей изображений, чтобы получить количество точек в квадрате.
  5. Чтобы получить разрешение, вычислите области ограничительной рамки в квадратах в дюймах, разделите точки в квадрате на квадратные дюймы, возьмите квадратный корень и округлите до ближайшего кратного 10.

Полный ответ со сценарием ниже. Я использую его в живом огне, и он прекрасно работает. Спасибо Арлекину за pdfimages и Спиффеа за оповещение о нескольких изображениях на странице (это редко, но я нашел некоторые).

Ответы [ 7 ]

5 голосов
/ 17 января 2009

Если 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 подтипа Image и получаем значения WIDTH и HEIGHT. Это будет разрешение в пикселях изображения, встроенного сканером в файл PDF.

Обратите внимание, что масштабирование этого изображения в соответствии с разрешением страницы (например, размером страницы, отображаемой в Acrobat - A4, Letter и т. Д.) Выполняется отдельно в потоке содержимого страницы, который представлен в виде подмножество постскриптума, и гораздо труднее найти его без разбора постскриптума.

Имейте в виду, что есть некоторые сканеры, которые встраивают отсканированное изображение в виде сетки меньших изображений (я полагаю, для некоторой оптимизации размера). Так что, если вы видите что-то вроде 50 маленьких изображений, появляющихся на каждой странице, это может быть причиной.

Надеюсь, это поможет вам, если вам нужно запустить собственную утилиту.

5 голосов
/ 18 сентября 2015

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%
4 голосов
/ 23 февраля 2009

Вот элементы этого ответа:

  • 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
4 голосов
/ 17 января 2009

Полагаю, что отсканированные изображения включены в PDF в виде изображений, поэтому вы можете сначала использовать pdfimages для их извлечения. Тогда identify сможет найти правильные данные.

2 голосов
/ 17 января 2009

Слишком долго, чтобы поместить в комментарий, но ни 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 на 11 сканировалось разрешение 600 точек на дюйм. Вывод из ImageMagic поразительно непрофессиональный.

Нет отрицательных голосов, потому что вы пытались быть полезными, но *Magick не работает.

0 голосов
/ 02 октября 2009

Apago PDF Spy расскажет вам точное разрешение изображений в PDF вместе со многими другими материалами. Это коммерческий продукт, но с 10-дневной демонстрацией.

0 голосов
/ 17 января 2009

PDF - это независимый от разрешения формат, это бессмысленный вопрос. Возможно, вы отсканировали несколько растровых изображений с определенным разрешением, и эти растровые изображения по отдельности встроены в PDF, но сам PDF может содержать изображения с различным разрешением, а также независимую от разрешения векторную графику. Нет способа узнать, не взломав pdf и не изучив каждый объект внутри него.

Редактирование, чтобы продолжить разъяснение проблемы:

Возможно, вам повезло, и в программное обеспечение, которое вы использовали для сканирования документов, были встроены некоторые метаданные об этом, но не стоит на этом ставить. Такие метаданные вряд ли будут стандартными. Что касается синтаксического анализа pdf, вам нужна заранее написанная библиотека - например, ghostscript. Проблема в том, что PDF на самом деле не столько формат, сколько заданное подмножество языка программирования PostScript и согласованный способ сжатия / компиляции этого подмножества вместе с некоторыми двоичными файлами. Таким образом, чтение PDF является более сложным, чем другие типы графических форматов, поскольку включает в себя написание интерпретатора языка - не так просто.

Лучший подход - либо поднять руки и сдаться, либо действительно внимательно посмотреть на ghostscript и посмотреть, сможете ли вы получить это, чтобы сказать вам ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...