Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Образование документов на основе ODT образцов. ODT to PDF

Anna | 31.05.2014 | нет комментариев

Не так давным-давно мне пришлось столкнуться с нормальной задачей – формировать документы с пользовательскими данными на основе образцов ODT средствами PHP. Звучит крайне банально, но намучиться пришлось крепко. Дело в том, что ни одно из доступных средств, так либо напротив, не подошло. Одни библиотеки формировали документ криво, другие не поддерживали русские шрифты, третьи – двигали картинки в жанре Harlem Shake. Вот и пришлось «велосипедить».

Выходит, задача лаконично:

  1. Обработать ODT образец. Заменить placeholder’ы на пользовательские значения
  2. Конвертировать в pdf. Показать пользователю

ЭТАП 1. Обработать ODT образец. Заменить placeholder’ы

Ни для кого не секрет, что ODT — это обыкновенный архив с xml на борту. Все картинки прячутся в папке, наименование которой может быть любым, лишь бы на нее ссылались в файле изложений. Не будем вдаваться в подробности: довольно лишь сказать, что за стержневой контент документа отвечает content.xml, за «описательную» часть – manifest.xml. Обращаю внимание, что жанры текста нас не волнуют (по крайней мере, в условиях данной задачи). Копнув чуть глубже эти xml’ки выводим алгорифм:

  1. Распаковать архив
  2. Для подмены текста: парсим content.xml, заменяем placeholder’ы на надобные значения
  3. Для изображений: загружаем свои изображения в папку (создаем ее внутри распакованного .odt документа), парсим content.xml, заменяем placeholder’ы на frame вида
    <draw:frame draw:style-name="a0" draw:name="'.$file_name.'" text:anchor-type="as-char" svg:x="0in" svg:y="0in" svg:width="'.$width.'in" svg:height="'.$height.'in" style:rel-width="scale" style:rel-height="scale">
        <draw:image xlink:href="'.self::_ImgDir.DIRECTORY_SEPARATOR.$file_name.'" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
       <svg:title/>
       <svg:desc/>
    </draw:frame>
    

    Дальше, добавляем в конец manifest.xml блок вида

    <manifest:file-entry manifest:full-path="'.self::_ImgDir.DIRECTORY_SEPARATOR.$file_name.'" manifest:media-type="image/'.$ext.'"/>
    
  4. Архивируем итог обратно в ODT.

Алгорифм очевидно упрощен, но действенен и легок. На его основе был написан класс (на коленках) odtFormat. Маленькая справка о том, как им пользоваться:

Инициализация

$odtformat = new odtFormat(“$doc_path”, "$temp_dir");

$doc_path – путь до образца .odt
$temp_dir – папка, в которой будут храниться временные файлы.

Вставка текста

$odtformat->SetText(“$name”, “$value”);

$name – имя placeholder’а
$value – пользовательское значение

Вставка изображения

$odtformat->SetImage(“$name”, “$img_path” ,$width, $height);

$name – имя placeholder’a
$img_path – путь до картинки
$width – желаемая ширина изображения в документе (если не задать – ширина оригинала)
$height – желаемая длина изображения в документе (если не задать – длина оригинала)

Сохранение документа

$odtformat->SaveToDisk(“$path_to_save”);

$path_to_save – куда будем сберегать (путь имя файла)

Остальные способы не привожу, все дозволено увидеть в исходнике. Тем больше, что множество вспомогательных способов взято из публичных источников. Да и сам код примитивен, как две копейки. Приведу лишь некоторые настройки:

const _SeporatorLeft = '{{';

Отделяет placeholder от текста слева

const _SeporatorRight = '}}';

Отделяет placeholder от текста справа

const _ImgDir = 'media';

Имя папки с пользовательскими изображениями
Ну вот, дозволено сказать, что файл .odt, заполненный надобными нам данными, теснее сформирован. Время для второго этапа.

Внимание! Дабы placeholder’ы заменялись правильно, при добавлении их в документ используйте «Очистить формат». Класс применял для MS World 2013. Но что-то мне подсказывает, что оглавление odt идентично и в других версиях.

ЭТАП 2. Конвертировать в pdf. Показ пользователю

Сразу скажу, что безукоризненного решения так и не обнаружил. Решений, по существу, фактически нет. Перерыв «интернеты», наткнулся на горстку тяжеловесов, zend примочек и легко хлама. Так что, расскажу все, как было.
Первым делом, пытался применять онлайн-сервисы. Вначале был Google Docs. Здесь все ясно. Легко показ документа на странице через iframe, чураясь самого конвертирования.
Пример:

<iframe src="http://docs.google.com/viewer?url=http%3A%2F%2F127.0.0.1%2Fa.odt&embedded=true" width="600" height="780" style="border: none;"></iframe>

Минусы:

  • Скорость отображения
  • Кривое форматирование
  • При применении сторонних библиотек для образования odt, возникал необычный белый лист сначала документа
  • Не pdf
  • Онлайн

Плюсы:

  • Простота

Видимо, что данное решение длинно не жило. Стоит взглянуть в сторону Microsoft с их Office Apps. Увлекательным хинтом стало конвертирование pdf как версии для печати (встроенная функция онлайн обслуживания). Таким образом, дозволено средствами Microsoft конвертировать файл и здесь же его показать.
Пример:

<iframe src="http://co1-word-view.officeapps.live.com/wv/WordViewer/request.pdf?WOPIsrc=http%3A%2F%2Fco1%2D15%2Dview%2Dwopi%2Ewopi%2Elive%2Enet%3A808%2Foh%2Fwopi%2Ffiles%2F%40%2FwFileId%3FwFileId%3Dhttp://127.0.0.1/a.odt&type=printpdf" width="600" height="780" style="border: none;"></iframe>

Минусы

  • Безрассудно длинно
  • Решение, само по себе, кривое
  • Непредсказуемое поведение в различных браузерах
  • Так и не удалось избавиться от окна печати
  • Онлайн

Плюсы

  • Добротное конвертирование

Не обнаружив огромнее достойных онлайн-вариантов, решено было применять средства сервера. С этой задачей отлично справляется Libreoffice. У него есть встроенный конвертер документов, работающий из командной строки. Идея заключалась в том, Дабы забрасывать сформированные odt в папку, передавать ее ключом к exec, отображать теснее готовые pdf, лежащие в той же папке. Положим, что apt-get install libreoffice мы теснее сделали. Осталось лишь дописать одну строку кода:

exec(“libreoffice --headless --invisible --convert-to pdf $full_path_to_file --outdir $full_path_to_dir”);

$full_path_to_file – полный путь до файлов (/var/www/*.odt)
$full_path_to_dir – полный путь до папки сохранения (/var/www/result/)

Как показать pdf в iframe, я думаю, вы и сами знаете.

Минусы

  • Необходим доступ к серверу
  • Весомый пакет libreoffice
  • exec (сходственные команды в коде – дело не дюже-то отличное)

Плюсы

  • Невидимый приход в скорости
  • Добротное форматирование
  • Удобство применения готовых документов
  • Безусловно локальное решение

Завершение
При всех недостатках решения — цели исполнены. Верю, что эта статья поможет избежать некоторых сложностей при выполнении сходственной задачи. Каждому успешного кодинга!

Ссылки
Библиотека odtFormat
О LibreOffice

P.S. Умоляю помилования за возмутительное форматирование.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB