Автоматизация процесса извлечения страниц из PDF-документа

ИНФОРМАЦИОННЫЕ ТЕХНОЛОГИИ

УДК 004.4

В. Г. ТРОНИН, А. О. КУРАНОВ

АВТОМАТИЗАЦИЯ ПРОЦЕССА ИЗВЛЕЧЕНИЯ СТРАНИЦ ИЗ PDF-ДОКУМЕНТА

Рассматривается процесс автоматизации многостраничного извлечения документов с применением консольного программного обеспечения, языком сценариев Microsoft PowerShell и встроенного функционала Adobe Acrobat DC. Излагаемый материал рассчитан на широкий круг пользователей, стремящихся автоматизировать регулярные процессы в секторе делопроизводства, оптимизировать временные затраты на подготовку электронных версий научных изданий для публикации в системе eLIBRARY. Текст статьи может рассматриваться как практическое дополнение к официальной документации пользователя системы Articulus.

Постановка вопроса на тему рациональности создания процедур автоматизации сборки загрузочных пакетов продолжает оставаться актуальной даже при наличии системы разметки Articulus. Рассуждения на эту тему должны выстраиваться в разных плоскостях с объективной оценкой всех отрицательных сторон проекта индивидуально для каждого автора. Время и объём обрабатываемой информации - ключевые элементы в принятии решения этому по вопросу. Например, выполняя разметку монографии, мы сможем затратить меньше времени, чем оформление сборника трудов конференции или тезисов докладов (в которых изобилие выходных сведений, большое число статей с высокой периодичность (с интервалом 3-5 страниц каждая). Ручная обработка больших массивов данных неминуемо влечёт за собой человеческий фактор - утомление, и как следствие, создание ошибок по невнимательности.

Среди наиболее распространённых недочётов можно выделить следующие: неправильный формат ввода даты проведения конференции, избыточные символы в словах, разрывы строк в библиографическом списке, пропуск по заполнению отдельных рубрик, семантические ошибки в рубриках, неправильно загруженные файлы статей. Несмотря на внушительный перечень отрицательных факторов, сформировать процедуру полной автоматизации сборки загрузочного пакета до сих пор не представляется возможным по следующим причинам: нет возможности провести автоматическую идентификацию автора в фоновом режиме без IP-адреса университета; создание нового проекта сопровождается присвоением (ему) уникального идентификационного номера [ключа] (при этом алгоритм генерации шестизначного числа остаётся неизвестным).

Если сгенерировать ключ рандомным (random) методом (например, произвольно набрать на клавиатуре шесть чисел, воспользоваться программой или API языка программирования), мы создаём условия для возможного возникновения коллизии: совпадение ключей проектов разных авторов, что неминуемо приведёт к санкциям со стороны администраторов eLIBRARY (уникальный ключ должен исключать всякого рода совпадения). В дополнение всему вышесказанному, система Articulus записывает дополнительную информацию в файл описания проекта (source.xml | например, количество статей в проекте), которая официально незадокументирована для сторонних пользователей. Пропуск одного из ключей дополнительной информации приведёт к аналогичному результату. Как итог, отдельные процедуры для записи данных в системе необходимо выполнять в ручном режимеи только через систему Articulus.

Обязательным техническим требованием для размещения журнала в РИНЦ является его обработка в разметке XML [1]. Решая спектр задач в области повышения эффективности представления в РИНЦ научного журнала «Вестник УлГТУ», в статье освещаются варианты автоматизации постатейного извлечения страниц из PDF-документа (с целью их дальнейшей загрузки в систему Articulus).

© Тронин В. Г., Куранов А. О., 2018

1. Создание постатейных файлов из единого PDF-файла с помощью консольной программы

и библиотеки

Одним из самых трудоёмких процессов в работе является постатейное извлечение материалов из единого файла сборника трудов конференции, журналов или тезисов докладов. Об этом свидетельствует опыт оцифровки печатных версий журнала «Вестник УлГТУ» для его последующей публикации в РИНЦ. В. Г. Тронин в своей статье пишет: «долгое время занимает процесс вырезания статей из PDF-файла с журналом» [1], что лишний раз доказывает вышесказанное.

Одни авторы используют функциональные возможности специализированного программного обеспечения (например, самым популярным является Adobe Acrobat), другие пользуются сервисами редактирования PDF-документов в сети Internet (например, сотрудники УлГТУ используют сервис IPDF2SPLIT [1]). Использование последних часто приводит к нежелательным результатам. Например, многие сервисы в процессе извлечения страниц(ы) преобразуют её в растровое изображение, тем самым исключая возможность редактирования контента в дальнейшем и значительно увеличивая итоговый размер файла. Не меньшие сложности может создать обязательная процедура экспорта содержания PDF-документа для разметки. Система Articulus предоставляет авторам возможность загрузить источник информации для разметки в двух форматах (на выбор): HTML и текстовый.

Наиболее часто авторы выбирают формат HTML. Это вызвано тем, что при таком методе преобразования сохраняется визуальное форматирование и возможность редактирования материалов за счёт использования HTML и CSS в результирующем файле (*.html), правда, в этом случае значительно возрастает его размер. Например, сборник (без графических материалов) в формате PDF может быть в пределах ~ 2,5 Мб, после преобразования в формат HTML его объём увеличится в 2-3 раза. Дело в том, что формат PDF использует по умолчанию сжатие без потерь на основе алгоритмов LZ77 и Хаффмана (именуемое в программировании методом Deflate). Большой размер файла, выступающего в качестве источника информации для разметки, значительно увеличивает время рендеринга контента во вкладке «Источник» в системе Articulus (это актуально, если в процессе разметки происходит частое переключение между вкладками) и, что самое важное, увеличивает в равной степени размер итогового загрузочного пакета вашего проекта. Например, если размер загрузочного пакета составляет ~ 40 Мб, вы можете испытывать проблемы с его загрузкой в систему eLIBRARY. Мы рекомендуем использовать текстовый формат как наиболее универсальный и минимальный с точки зрения размера файла вариант. Выполняя экспорт, например, таблицы или математической формулы в текстовый формат, мы не сможем сохранить их изначальное форматирование и представление (в отличие от формата HTML, где развитый инструмент визуализации и технология MathML). По факту это и не требуется, потому что поле «Текст» системы Articulus не поддерживает форматирование подобных объектов. В любом случае, независимо от выбранного вами формата, мы настоятельно рекомендуем проверять результаты экспорта данных на корректность и размерность результирующего файла.

1Если вы являетесь пользователем GNU/Linux (или *nix подобных систем), можете рассмотреть программу pdfseparate (входит в пакет библиотеки Poppler). К главному недостатку программы можно отнести постраничное извлечение (когда каждая страница извлекаемого диапазона сохраняется в отдельный файл). Например, извлекая 12 страниц из документа, вы получите 12 файлов в формате PDF, которые потом нужно объединить в единый файл.

2 Программа является кроссплатформенной. Поддерживает x32 и x64 архитектуры. Распространяется по лицензиям GNU Affero General Public License и Artifex Commercial License.Официальный сайт: www.ghostscript.com

или отсутствию отображения символов вовсе); останов выполнения задачи извлечения, если в странице присутствуют ошибки или параметры, которые программа не может корректно обработать (как правило, некорректная верстка контента в программе MSWord). Рассмотрим стандартную команду извлечения диапазона страниц из PDF-документа:

Листинг 1

gswin64.exe -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -dSAFER

-dFirstPage=0 -dLastPage=0 -sOutputFile="/path/<file>.pdf" "/path/<source_file>.pdf"

Программе необходимо передать следующие ключевые параметры: начальную (-dFirstPage) и последнюю страницы(-dLastPage) извлекаемого диапазона; результирующий файл (-sOutputFile); исходный файл (source_file.pdf). Исключите из пути к PDF-файлам названия директорий на кириллице. Мы настоятельно рекомендуем применять в названиях имён результирующих файлов начальные и конечные страницы диапазона извлекаемых страниц (например, 12-21.pdf). Во-первых, это принятая практика в рамках УлГТУ, где «файлу присваивается название, содержащее номера отсканированных страниц - начальной и конечной» [1]. Во-вторых, удобство процесса загрузки PDF-документа для каждой статьи и последующего сопоставления с данными в рубрике страницы во вкладке «Файлы» (в системе Articulus).

Вместо GS авторы статьи рекомендуют использовать библиотеку PDFBox. Несмотря на то, что требуется установка виртуальной машины Java в операционной системе пользователя, библиотека компенсирует это следующим: развитым функционалом (включая развитое API для Java-разработчиков); лаконичность команд; экспорт PDF-файла в текстовый формат (или HTML); скорость выполнения задачи; документация, доступная для понимания разработчику или специалисту по автоматизации (в отличие от GS, где требуются профилирующие знания из смежных областей); отсутствуют недостатки GS. Рассмотрим стандартную команду извлечения диапазона страниц из PDF-документа с помощью библиотеки PDFBox:

Листинг2

java -jar pdfbox-app-x.y.z.jarPDFSplit -startPage0 -endPage0<source_file>.pdf

На входе библиотека принимает всего три ключевых параметра: -startPage (начальная страница), -endPage (конечная страница) и файл источник (source_file.pdf). Параметр PDFSplit указывает библиотеке на тип вызываемой функции (в официальной документации этот параметр относится к «command-lineutilities» и доступен как «standard Java application»). Символы xj.x соответствуют версии используемой библиотеки. Однократное выполнение команды актуально для решения одноразовых задач (например, извлечь одну главу из монографии). Если необходимо извлечение многостраничных материалов из одного документа или коллекции (например, статьи в журнале или тезисы докладов конференции), тогда имеет смысл создать процедуру автоматизации. Рассмотрим практический пример скрипта автоматизации извлечения многостраничных документов из PDF-файла (этот сценарий используется в Управлении научных исследований УлГТУ для постатейной обработки электронных версий научных изданий).

Листинг 3

# Корневой каталог проекта $root = "<folder_path>"

# Имя файла (без указания расширения) $file = "<file_name>"

# Адрес файла массива страниц в формате CSV $CSVpath = "$root\<file_name>.csv"

# Разделитель для чтения данных из CSV-файла $delimiter = ";"

# Указатель начальных и конечных страниц $headers = @

# Адрес исходногоPDF-файла $sourcePDF = "$root\$file.pdf"

# Адрес результирующего PDF-файла и его промежуточное имя

$bindPDF = "$root\$file-1.pdf"

# Адрес директории хранения извлеченных страниц в формате PDF

$destinationPath = "$ root\STORAGE"

# Чтение массива страниц из CSV-файла

$CSV = Import-Csv -Delimiter $delimiter -Path $CSVpath -Header $headers

# Процедура извлечения страниц из PDF-документа по списку массива из CSV-файла

# Читаем строку из CSV-файла

ForEach ($itemin $CSV) {

# Получаем начальную страницу

$PageStart = $item.PageStart

# Получаем конечную страницу

$PageEnd = $item.PageEnd

# Формируем имя PDF-файла, которое состоит из (начальной и конечной) извлекаемых страницы

$fileName = $PageStart + "-" + $PageEnd + ".pdf"

# Формируем список параметров для библиотеки PDFBox и записываем его в массив

$PDFBox = @("-jar", "$root\pdfbox-app-2.0.9.jar", "PDFSplit", "-startPage",

$PageStart, "-endPage", $PageEnd, $sourcePDF)

# Выводим на консоль информацию о диапазоне извлекаемых страниц

$info = "Страницы: {0}" -f ($fileName)

Write-Host $info

# Запускаем виртуальную машину Java и передаем команду на выполнение jar-файла

& "java" $PDFBox

# Переименовываем результирующий PDF-файл

Rename-Item -Path $bindPDF -NewName $fileName

# Перемещаем результирующийPDF-файл в конечную директорию

Move-Item -Path ($root+''+$fileName) -Destination $destinationPath

}

Если в системе пользователя установлен Adobe Acrobat DC, можно воспользоваться его функциональными возможностями для решения аналогичной задачи. Рассмотрим порядок решения этой задачи.

2. Создание постатейных файлов из единого PDF-файла в программе Adobe Acrobat DC.

Создание CSV-файла диапазона страниц.

Первоначальной задачей является создание списка диапазона страниц всех извлекаемых статей из нашего сборника. Это единственный этап без автоматизации, который требует от пользователя максимального внимания и безошибочной работы. Для упрощения процедуры мы рекомендуем воспользоваться любым табличным процессором (в рамках статьи, авторы используют MSExcel). Условимся, что в колонке «А» мы заполняем начальные станицы каждой статьи, а в колонке «B» конечные (рис. 1).

Рис. 1. Данные перед экспортом в CSV из MS Excel

Конечно, вы можете использовать примитивный текстовый редактор, однако визуальное структурирование данных в табличном процессоре упрощает восприятие, сопровождение и редактирование информации (это становится актуально, если над этим процессом занято несколько человек, работающих на разных платформах и удалении по геолокации; имеет место записывать комментарии и устанавливать метки). Отметим, что количество строк в таблице должно равняться количеству статей в сборнике. Сохраним результат в формате CSV (англ. Comma-Separated Values - значения, разделённые запятыми). Если в таблице присутствует дополнительная информации, её необходимо удалить.

Для решения этой задачи воспользуемся языком сценариев PowerShell, на которой напишем следующую процедуру (её можно использовать многократно, если сохранить в файл с расширением *.ps1 и выполнять из Windows PowerShell ISE или командной оболочки Windows PowerShell):

Листинг 4

# Читаем CSV-файл и перезаписываем данные в одну строку

# Заменяем символы CRLF на символ-разделитель COMMA $stream = (Get-Content "<\path\file.csv>") -join ','

# Заменяем символ SEMICOLON на символ-разделитель COMMA $pagesArray = $stream.Replace

# Удаляем избыточные символы $pagesArray.Trim

# Перезаписываем результат в исходный файл, сохраняя encoding файла по умолчанию $pagesArray | Out-File -filepath "<\path\file.csv>" -Encoding Default

Сохраняя обратную совместимость с PowerShell версии 3, мы не используем параметр -NoNewline (исключающий из текстового файла «newlinecharacters») команды Out-File, который поддерживается более новыми версиями командной оболочки. Вы можете автоматизировать эту задачу в рамках инструментария разработчика табличного процессора (например, VBA для MSExcel).

Процедура автоматизации.

Обоснование решения задачи можно представить логическими блоками (подзадачами). Рассмотрим каждый из них в отдельности и логической последовательности (вместе с текстом сценария):

1-й блок: устанавливаем «watermark»

Главным недостатком любой процедуры извлечения статей из документов является потеря информации об источнике (название издания или научном мероприятии). С нашей точки зрения это критично для сборников трудов конференций и периодических научных изданий, где в колонтитулах часто не указываются ключевые выходные сведения. Если пользователь работает с электронными научными материалами в рамках системы eLIBRARY, он всегда имеет возможность вернуться к источнику и получить всю необходимую информацию. Ситуация изменяется, если пользователь отправил файл материалов на email; распечатал или передал печатный вариант другому лицу (который утратил часть страниц); электронный вариант текста многократно менял локацию в рамках системы, сети, рабочих станций (например, отправлена копия другому пользователю, не зарегистрированному в eLIBRARY). Размещение на каждой странице «watermark» позволяет решить эту проблему. В рамках нашей статьи мы автоматизируем размещение «водяного знака» на каждой странице электронной версии сборника. Для этого напишем следующий скрипт:

Листинг 5

this.addWatermarkFromText({

cText: 'ВУЗОВСКАЯ НАУКА В СОВРЕМЕННЫХ УСЛОВИЯХ\гСборник материалов 52-й научно-технической конференции\гЧасть 1. 2018 г.УлГТУ \rhttp://venec.ulstu.ru/lib/disk/2017/263.pdf', cFont: 'Times-Bold', nFontSize: 10, bOnTop: true, bOnPrint: true, nHorizValue: 70, nVertValue: -10,

nHorizAlign: app.constants.align.left, nVertAlign: app.constants.align.top, // Цветовая модель Grayscale с интенсивностью 0.7 aColor: ['G', 0.7] });

Параметр cFont накладывает ограничения на выбор шрифтов (нельзя прописать любой шрифт, установленный в операционной системе пользователя). Гарантированно применяются только те шрифтовые гарнитуры, которые перечислены в официальной документации API и представлены в PostScript нотации. Параметр bOnTop принимает булево значение, где true сообщает программе команду отобразить «watermark» поверх всего контента на странице (так называемое «z-ordering» позиционирование). Параметр bOnPrint сохраняет «watermark» при печати отдельных страниц или всего документа. Параметры nHorizValue и nVertValue передают значения (в пикселях) горизонтального и вертикального позиционирования «watermark» (отметим, что при значениях, равных 0, происходит центрирование «водяного знака» относительно горизонтали и вертикали страницы документа). Могут принимать signed и unsigned типы. В качестве дополнительных параметров позиционирования используют nHorizAlign и nVertAlign (так называемые параметры выравнивания). Отдельное внимание заслуживает параметр aColor. Значение параметра распределяется от 0 до 1. В тексте скрипта мы использовали цветовую модель Grayscale, чтобы соответствовать принятым техническим нормативам внутри университета («сканирование бумажной версии журнала в оттенках серого» [1]). Если перед вами стоит задача применить к тексту «watermark» корпоративный цвет (или один из таковых), можно придерживаться следующего порядка расчёта. Например, преобразовать значения цвета RGB(84,112,144) к значениям параметра aColor. Каждый цвет в модели RGB выражается числовым диапазоном от 0 до 255. Выразим значение 1 параметра aColor как 100%. Отсюда: 255 : 100% = 2,55 (константа). Соответственно:

R(84) : 2,55 = 32,94 ~ 0.32 g(112) : 2,55 = 44,8 ~ 0.44 в(144) : 2,55 = 56,47 ~ 0.56 aColor: ['RGB', 0.32, 0.44, 0.56]

Это не исчерпывающий набор параметров для управления «водяным знаком». API позволяет установить диапазон страниц, для которых применяется «watermark» (nStart\nEnd), это актуально для изданий, где материалы распределены по секциям; масштабирование (nScale); угол наклона (nRotation);

прозрачность (nOpacity); выбрать внешний источник (addWatermarkFromFile). Стремитесь разместить «watermark» так, чтобы он входил в запечатываемую область страницы. Иначе, если пользователь примет решение распечатать страницу, текстовый блок «водяного знака» будет частично или полностью утрачен.

2-й блок: добавляем ссылку на полную версию сборника

Добавление этого элемента на страницы PDF-документа позволяет исследователю открыть (и загрузить) полную версию научного издания, независимо от доступа к системе eLIBRARY. Решение этой задачи принимает следующий вид:

Листинг б

varlinkCoords = [x1,y1,x2,y2]; varURLBook = this.addLink(n, linkCoords);

URLBook.setAction("app.launchURL('http://venec.ulstu.ru/lib/disk/2017/263.pdf,)"); URLBook.borderColor = color.red; URLBook.borderWidth = 1;

Классическая реализация ссылки на внешний (web) ресурс в рамках стандарта PDF не имеет аналогии с вариантами представления ссылок в текстовых процессорах и языках разметки гипертекста. Спецификация PDF определяет ссылку как объект-область с кратким набором параметров визуализации. Типовым решением является наложение объекта-области на семантические статические объекты содержания страницы (такие объекты, которые представляют собою текст, графические элементы, данные в табличном формате). Ключевым является метод addLink, который принимает в качестве параметров массив координат объекта-области(х1,y1,x2,y2) и номер страницы (n).

3-й блок: чтение массива (страниц) из CSV-файла.

Получаем массив данных из csv-файла, используя методы readFileIntoStream и stringFromStream объекта util. Отметим, что эти методы можно использовать для работы с данными в формате XML.

Листинг 7

varfilePath = '/C/Users/Kuranoff/file.csv'; varfileStream = util.readFileIntoStream(filePath); varpages = util.stringFromStream(fileStream);

4-й блок: извлечение страниц и сохранение результата.

Ключевым элементом в тексте сценария является переменная pages

Листинг 8

try {

// Результирующий адрес для сохранения извлеченного PDF-файла

varsFolder = '<foLder_path>';

// Адрес директории для сохранения

varsPath = '<foLder_path>';

// Счетчик цикла

vari = О;

// Начальная страница диапазона извлечения varpS = О;

// Конечная страница диапазона извлечения varpE = О;

// Нечетная страница

varoddPage = 0;

// Четная страница

varevenPage = 0;

// Имя результирующегоРйР-файла

varspreadNAME = '<fiLe_name>';

// Массив страниц, полученный из CSV-файла

varpagesPDFDoc = pages;

/* Процедура извлечения страниц из PDF-документа.

Длина массива делится на 2 (две страницы в каждом диапазоне, где указываются извлекаемые начальная и конечная страницы). Результатом выражения будет число (количество) извлекаемых диапазонов. Это число есть предельное число итераций, достаточное для выполнения задачи. */ for (i; i < (pagesPDFDoc / 2); i++) { // 1. Назначаем имя PDF-файла для извлекаемых страниц spreadNAME = pagesPDFDoc[oddPage].toString() + '-' \

+ pagesPDFDoc[evenPage].toString() + '.pdf'; // 2. Формируем путь для сохранения PDF-файла sFolder = sPath + spreadNAME;

// 3. Получаем начальные и конечные страницы диапазона из массива pS = pagesPDFDoc[oddPage]; pE = pagesPDFDoc[evenPage+1]; /* 4. Процедура извлечения страниц диапазона.

Отметим, что нумерация страниц в PDF начинается с 0 */ app.doc.extractPages({nStart: pS-1, nEnd: pE-1, cPath: sFolder});

}

} catch(e) { console.println('Ошибка:' + e); }

СПИСОК ЛИТЕРАТУРЫ

1. Тронин В. Г. Включение журнала «Вестник УлГТУ» в РИНЦ // Вестник УлГТУ. - 2013. - №3. - С. 59-63.

2. Виноградов А. Б., Шишкин В. В. Создание электронных учебных пособий в программе Acrobat: учебное пособие. - Ульяновск: УлГТУ, 2003. - 168 с.

Тронин Вадим Георгиевич, кандидат технических наук, начальник научно-исследовательского отдела УлГТУ, доцент кафедры «Информационные системы». Сфера научных интересов - наукометрия, моделирование вычислительных сетей на прикладном уровне, технологии эффективного управления.

Куранов Александр Олегович, младший научный сотрудник научно-исследовательского отдела УлГТУ.

Поступила 18.06.2018 г.