УСТАНОВКА И НАСТРОЙКА LIBREOFFICE SDK 7.0 В ОПЕРАЦИОННОЙ СИСТЕМЕ WINDOWS С КОМПИЛЯЦИЕЙ ПРИМЕРОВ ДЛЯ ЯЗЫКА С++
1 Установка и настройка LibreOffice SDK
Для установки работы LibreOffice SDK 7.0 в операционной системе Windows $($x64$)$ потребуются следующие компоненты:
- LibreOffice 7.0 $($SDK работает совместно с LibreOffice и использует те же библиотеки$)$;
- C++ компилятор $($Microsoft C++ Compiler, Microsoft Visual Studio 2010 или более поздняя версия, или его Express версия. Необходим для разработки компонентов или приложений на C ++$)$;
- GNU make $($версии 3.79.1 или выше, используется для сборки примеров SDK$)$;
- zip tool $($версии 2.3 или выше, используется для создания пакетов UNO$)$;
- cat and sed $($утилиты cat и set используются для создания некоторых модулей расширений$)$;
- JDK $($версии 1.5 или выше. Применяется опционально, необходим для разработки компонентов или приложений на Java$)$;
- Microsoft .NET Framework SDK $($версии 1.0 или выше. Используется опционально и требуется для создания приложений CLI, т.е. программ, написанных на таких языках, как C # или VB.NET$)$.
Рассмотрим процесс установки и настройки LibreOffice SDK 7.0, сборки примеров и базовые возможности работы с LibreOffice 7.0.
1.1 Установка LibreOffice 7.0 и LibreOffice SDK 7.0
Осуществим установку LibreOffice SDK 7.0 для разработки на С++ и сборку тестового примера, предоставляемого вместе с SDK.
Скачиваем инсталяционные пакеты LibreOffice 7.0 и LibreOffice SDK 7.0 с официального сайта разработчика используя торрент-файл $($рисунки 1, 2$)$.

Рисунок 1 — Скачивание торрент-файла LibreOffice 7.0.4

Рисунок 2 — Скачивание торрент-файла LibreOffice SDK 7.0.4
Осуществляем установку LibreOffice 7.0. Так как для сборки примеров будет использоваться GNU make, имеющий проблемы с распознаванием пробелов в путях к файлам, отказывается от типичного типа установки и выбираем установку с настойкой $($рисунок 3$)$. В настройке отказываемся от стандартного пути установки в C:\Program Files\LibreOffice\ и указываем свой без пробелов и специальных символов $($рисунок 4$)$.

Рисунок 3 — Установка LibreOffice 7.0.4

Рисунок 4 — Выбор директории для установки LibreOffice 7.0.4
После завершения установки LibreOffice 7.0. запускаем инсталяционный файл LibreOffice SDK 7.0. Установщик автоматически определяет положение LibreOffice и предлагает установить SDK в эту же папку $($рисунок 5$)$. При необходимости следует указать свой путь установки, исключая пробелы и специальные символы в названиях директорий.

Рисунок 5 — Установка LibreOffice SDK 7.0.4
Для дальнейшей настройки LibreOffice SDK 7.0 установим необходимые компоненты. Инструкцию для LibreOffice SDK 7.0 на английском языке можно найти в соответствующей директории в виде .html-файла $($рисунок 6$)$.

Рисунок 6 — Инструкция для LibreOffice SDK 7.0.4
1.2 Установка MinGW
Осуществим установку MinGW содержащего GNU make и утилиты cat и sed. Для этого перейдем на официальный сайт MinGW $($рисунок 7$)$. После чего перейдем в раздел Downloads и скачаем инсталяционный файл для операционной системы Windows $($рисунок 8$)$.

Рисунок 7 — Сайт MinGW

Рисунок 8 — Скачивание инсталяционного файла MinGW
Осуществляем установку MinGW, указывая путь для установки без пробелов и специальных символов $($рисунок 9$)$. Выбираем базовые настройки с базовой установкой msys $($рисунок 10$)$.

Рисунок 9 — Установка MinGW

Рисунок 10 — Выбор устанавливаемых компонентов MinGW
1.3 Установка zip-3.0
Далее скачиваем инсталяционный файл zip-3.0 с рекомендуемого ресурса. Осуществляем установку указывая путь к директории для установки без пробелов и спецсимволов $($рисунок 11$)$.

Рисунок 11 — Установка zip-3.0
1.4 Установка JDK $($опционально$)$
При необходимости работы с Java следует скачать инсталяционный пакет JDK для операционной системы Windows $($x64$)$ с официального сайта разработчика и выполнить его установку.
1.5 Конфигурирование LibreOffice SDK 7.0
После выполнения указанных приготовлений переходим в папку с установленным LibreOffice SDK 7.0 $($рисунок 12$)$ и запускаем из командной строки файл setsdkenv_windows.bat $($рисунок 13$)$.

Рисунок 12 — Файл с настройками среды окружения LibreOffice SDK 7.0.4

Рисунок 13 — Запуск файла с настройками среды окружения LibreOffice SDK 7.0.4
На первоначальном этапе необходимо выполнить настройку SDK. Для этого указываем пути файлам и директориям требуемых для работы SDK компонентов $($в ряде случаев можно выбрать путь предлагаемый по умолчанию, см. рисунок 14$)$.
а$)$ путь к LibreOffice SDK $($в данном случае совпадает с предлагаемым по умолчанию$)$:
C:\LibreOffice\sdk
б$)$ путь к LibreOffice $($в данном случае совпадает с предлагаемым по умолчанию$)$:
C:\LibreOffice\sdk
в$)$ путь к GNU make:
С:\MinGW\msys\1.0\bin
г$)$ путь к zip-3.0:
C:\zip-3.0\bin
д$)$ путь к утилите cat:
c:\MinGW\msys\1.0\bin
е$)$ путь к утилите sed:
c:\MinGW\msys\1.0\bin
ж$)$ путь к C++ компилятору:
C:\Program Files $($x86$)$\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64
з$)$ Путь к директории с компилятором для С# и VB.NET $($в данном случае не требуется, но предлагается программой настройки SDK по умолчанию$)$:
C:\Windows\Microsoft.NET\Framework64\v2.0.50727
и$)$ путь к JDK $($в нашем случае не требуется$)$;
к$)$ папка для собранных компонентов или примеров LibreOffice SDK $($в данном случае совпадает с предлагаемым по умолчанию$)$:
С:\libreoffice7.0_sdk
Также выбираем автоматическое развертывание компонентов UNO $($Automatic deployment of UNO components $($YES/NO$)$ $[$YES$]$: YES$)$.
В результате получим настройки представленные на рисунке 14.

Рисунок 14 — Настройка среды окружения LibreOffice SDK 7.0.4
После завершения настройки создается и запускается отдельный setsdkenv_windows.bat файл, хранящий заданную конфигурацию и расположенный в директории C:\Users\RPLM\AppData\Roaming\libreoffice7.0_sdk. При выводе информации мы видим сообщение об ошибке $($рисунок 15$)$.

Рисунок 15 — Ошибка при поиске .bat-файла Microsoft Visual Studio
Ошибка связана с особенностями указания путей в setsdkenv_windows.bat. Для исправления ошибки необходимо внести изменения в данный файл, для чего переходим в директорию C:\Users\RPLM\AppData\Roaming\libreoffice7.0_sdk и вносим требуемые изменения $($рисунки 16, 17$)$. Ищем переменную OO_SDK_CPP_HOME:
set OO_SDK_CPP_HOME=C:\Program Files $($x86$)$\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64
и добавляем к ней еще одну:
set OO_SDK_CPP_HOME_VCVARS=c:\Program Files $($x86$)$\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
После чего ищем строку:
if defined OO_SDK_CPP_HOME call «%OO_SDK_CPP_HOME%\VCVARS32.bat»
и заменяем на:
if defined OO_SDK_CPP_HOME call «%OO_SDK_CPP_HOME_VCVARS%\vcvarsx86_amd64.bat»
Следует учесть, что в общем случае, выбор вызываемого .bat файла из директории c:\Program Files $($x86$)$\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build зависит от собираемого примера, требуемых им библиотек и типа рабочей машины $($x86 / x64$)$.

Рисунок 16 — Изменение в файле настроек LibreOffice SDK 7.0.4

Рисунок 17 — Изменение в файле настроек LibreOffice SDK 7.0.4
1.6 Сборка примера на С++
Для тестирования осуществим сборку простейшего примера для С++ $($counter$)$. Необходимо отметить, что из-за различий в интерпретации различных специальных символов и команд GNU make и вызываемыми утилитами в операционной системе Windows x64 $($например, линковщиком$)$ в процессе сборки приходится вносить изменения в Makefile. Для успешной сборки примера потребуется дополнить Makefile следующими строками в разделе переменные $($рисунок 18$)$
ifeq "\$$($OS$)$" "WIN"
LIBRARY_LINK_FLAGS = -DLL
COMP_LINK_FLAGS = \$$($LIBRARY_LINK_FLAGS$)$ /DEF:\$$($OO_SDK_HOME$)$/settings/component.uno.def
EXE_LINK_FLAGS = -MAP /OPT:NOREF /SUBSYSTEM:CONSOLE /BASE:0x1b000000 /DEBUGTYPE:cv \$$($LIBO_SDK_LDFLAGS_STDLIBS$)$
ifeq "\$$($DEBUG$)$" "yes"
LIBRARY_LINK_FLAGS+ = /DEBUGTYPE:cv /DEBUG
EXE_LINK_FLAGS+ = /DEBUG
else
EXE_LINK_FLAGS = -MAP /OPT:NOREF /SUBSYSTEM:CONSOLE /BASE:0x1100000
endif
endif

Рисунок 18 — Изменение в Makefile примера
Строку, отвечающую за генерацию файлов из .idl-файла, примера изменить $($дополнить следующим образом, рисунок 19$)$:
ifeq "\$$($OS$)$" "WIN"
\$$($COMP_TYPEFLAG$)$ : \$$($COMP_RDB$)$ \$$($SDKTYPEFLAG$)$
-\$$($MKDIR$)$ \$$($subst /,\$$($PS$)$,\$$($@D$)$$)$
-\$$($DEL$)$ \$$($subst \\,\,\$$($subst /,\$$($PS$)$,\$$($COMP_TYPEFLAG$)$$)$$)$
\$$($CPPUMAKER$)$ -Gc -O\$$($OUT_COMP_INC$)$ \$$($TYPESLIST$)$ \$$($COMP_RDB$)$ -X \$$($URE_TYPES$)$ \$$($IDLFILES$)$
echo flagged > \$@
else
\$$($COMP_TYPEFLAG$)$ : \$$($COMP_RDB$)$ \$$($SDKTYPEFLAG$)$
-\$$($MKDIR$)$ \$$($subst /,\$$($PS$)$,\$$($@D$)$$)$
-\$$($DEL$)$ \$$($subst \\,\,\$$($subst /,\$$($PS$)$,\$$($COMP_TYPEFLAG$)$$)$$)$
\$$($CPPUMAKER$)$ -Gc -O\$$($OUT_COMP_INC$)$ \$$($TYPESLIST$)$ \$$($COMP_RDB$)$ -X \$$($URE_TYPES$)$
echo flagged > \$@
endif

Рисунок 19 — Изменение в Makefile примера
Для успешного завершения Makefile необходимо будет взять в одинарные кавычки сообщения в самом конце, для экранирования спецсимволов, выдающих сообщение об ошибке в операционной системе Windows $($рисунок 20$)$. Хотя создание исполняемого файла $($.exe$)$ успешно выполнено уже до этого.

Рисунок 20 — Изменение в Makefile примера
Для успешного запуска исполняемого файла могут дополнительно потребоваться библиотеки LibreOffice 7.0 $($в данном случае cppu3.dll, cppuhelper3MSC.dll, sal3.dll$)$, поэтому необходимо указать к ним путь, добавив в переменные среды окружения PATH $($рисунок 21$)$.

Рисунок 21 — Добавление пользовательской переменной среды окружения
Следует учесть, что для связывания с некоторыми библиотеками, при запуске примеров, потребуется прописать дополнительные переменные. Например для использования библиотеки mergedlo.dll необходимо добавить системную переменную LO_LIB_DIR = c:/LibreOffice/program $($рисунок 22$)$.

Рисунок 22 — Добавление системной переменной LO_LIB_DIR
Для пуска и использования части примеров необходимо иметь запущенный слушатель LibreOffice 7.0 $($может быть не указано в руководстве разработчика предоставляемом вместе с примерами$)$. Запуск осуществляется путем ввода в отдельном терминале следующей команды $($рисунок 23$)$:
soffice "--accept=socket,host=localhost,port=2083;urp;StarOffice.ServiceManager"

Рисунок 23 — Запуск слушателя LibreOffice 7.0
2 Сборка примеров с помощью CMake
Для разработки в среде MS Visual Studio 2017, возможности сборки проекта в других операционных системах и разработки с использованием QT выполним сборку примера с помощью CMake. Для этого создадим в папке с исходным файлом файл CMakeLists.txt. Для сборки в файле CMakeLists.txt зададим пути к директориям, где лежат необходимые для сборки проекта файлы и библиотеки из LibreOffice 7.0 и LidreOffice SDK 7.0 $($рисунок 24$)$.

Рисунок 24 — Пути к директориям LibreOffice 7.0 и LidreOffice SDK 7.0
При составлении CMake листа следует не забыть подключить необходимые для сборки библиотеки QT и LibreOffice $($рисунок 25$)$.

Рисунок 25 — Подключение библиотек
При запуске СМake указываем директорию с исходными файлами и CМake листом $($он должен находится в той же директории$)$ и директорию, в которую будем собирать наш проект $($рисунок 26$)$.

Рисунок 26 — Указание папок с исходными
При этом следует задать приложение, используемое для генерации проекта, и тип платформы $($рисунок 27$)$.

Рисунок 27 — Приложение, используемое для генерации проекта, и тип платформы
После чего необходимо выполнить конфигурирование проекта, при этом если какие-то необходимые зависимости или пути не будут найдены, то их следует задать вручную, и повторить конфигурирование. Например, указать расположение qmake.exe и директории нахождения cmake-файлов конфигурации Qt5 $($Qt5Config.cmake, рисунок 28$)$. При этом остальные необходимые директории $($Qt5Core, Qt5Gui, Qt5WIdgets, Qt5Xml$)$ найдутся автоматически.

Рисунок 28 — Расположение qmake.exe и Qt5Config.cmake
3 Открытие и создание документа с помощью LibreOffice SDK 7.0 c API UNO под MS Visual Studio 2017
Работа с LibreOffice 7.0 осуществляется с помощью UNO $($Universal Network Objects$)$ компонентной модели, основанной на интерфейсах и обеспечивающей взаимодействие объектов, созданных с применением различных технологий $($OLE/COM, CLI, Web$)$ и языков программирования.
Для работы с документами в LibreOffice 7.0 необходимо работающий сервер офиса. Для этого следует ввести в отдельной командной строке следующую команду $($рисунок 29$)$:
soffice "--accept=socket,host=localhost,port=2083;urp;StarOffice.ServiceManager"

Рисунок 29 — Запуск сервера LibreOffice 7.0
Инициализируем переменную - строку подключения к компоненту UNO:
OUString sConnectionString$($"uno:socket,host=localhost,port=2083;urp;StarOffice.ServiceManager"$)$;
Получаем контекст удаленного офиса запущенного экземпляра офиса:
Reference <XComponentContext> xComponentContext$($::cppu::defaultBootstrap_InitialComponentContext$($$)$$)$;
Получаем диспетчер служб из контекста компонента:
Reference <XMultiComponentFactory> xMultiComponentFactoryClient$($xComponentContext->getServiceManager$($$)$$)$;
Создаем экземпляр компонента, который поддерживает указанные службы для клиента:
auto xInterface = xMultiComponentFactoryClient→createInstanceWithContext$($"com.sun.star.bridge.UnoUrlResolver", xComponentContext$)$;
Reference <XUnoUrlResolver> resolver$($xInterface, UNO_QUERY$)$;
Разрешаем контекст компонента из офиса используя заданный URL UNO:
try
{
xInterface = Reference <XInterface> $($resolver->resolve$($sConnectionString$)$, UNO_QUERY$)$;
}
catch $($Exception& e$)$
{
cout << "Error: cannot establish a connection using '" << OUStringToOString$($sConnectionString, RTL_TEXTENCODING_ASCII_US$)$.getStr$($$)$ << "':\n";
cout << OUStringToOString$($e.Message, RTL_TEXTENCODING_ASCII_US$)$.getStr$($$)$ << endl;
exit$($1$)$;
}
Получаем контекст серверного компонента, как свойство фабрики компонентов офиса:
Reference <XPropertySet> xPropSet$($xInterface, UNO_QUERY$)$;
xPropSet->getPropertyValue$($"DefaultContext"$)$ >>= xComponentContext;
Получаем сервис менеджера из офиса:
Reference <XMultiComponentFactory> xMultiComponentFactoryServer$($xComponentContext->getServiceManager$($$)$$)$;
Создаем экземпляр компонента, который поддерживает указанные службы для фабрики компонентов офиса:
auto xComponentLoader = Desktop::create$($xComponentContext$)$;
Имея подключение к серверу LibreOffice 7.0 и UNO API, с целью тестирования выполним основные операции с текстовым документом: открытие, создание нового, вставка изображения, конвертация документа в PDF.
3.1 Открытие существующего документа
Рассмотрим тестовый пример открытия существующего документа:
OUString sDocUrl;
osl::FileBase::getFileURLFromSystemPath$($OUString$($L"C:/LibreOffice/sdk/examples/cpp/DocumentLoader/4 Установка LibreOfiice SDK 7.0.docx"$)$, sDocUrl$)$;
auto xWriterLoadComponent = xComponentLoader→loadComponentFromURL$($sDocUrl, OUString::$($"_blank"$)$, 0, Sequence <::com::sun::star::beans::PropertyValue>$($$)$$)$;
Reference <XTextDocument> xTextDocumentFirst$($xWriterLoadComponent, UNO_QUERY$)$;
В результате открывается уже существующий документ находящийся по адресу: C:/LibreOffice/sdk/examples/cpp/DocumentLoader/4 Установка LibreOfiice SDK 7.0.docx при этом следует отметить, что для того, чтобы избежать проблем с кириллицей и пробелами в путях адрес надо подавать в виде строки в кодировке Unicode $($рисунок 30$)$.

Рисунок 30 — Открытие существующего документа
В конце следует удалить созданный менеджер сервисов:
Reference <XComponent>::query$($xMultiComponentFactoryClient$)$->dispose$($$)$;
3.2 Создание нового документа
Создадим новый документ и вставим в него несколько тестовых строк. Как и в предыдущем примере, имея подключение к серверу LibreOffice 7.0, создаем подключение к UNO API. Затем создаем новый документ.
auto xWriterWriteComponent = xComponentLoader→loadComponentFromURL$($OUString$($"private:factory/swriter"$)$, OUString$($"_blank"$)$, 0, Sequence <::com::sun::star::beans::PropertyValue>$($$)$$)$;
Reference <XTextDocument> xTextDocument$($xWriterWriteComponent, UNO_QUERY$)$;
Добавим документ в текст:
auto xText = xTextDocument->getText$($$)$;
auto xTextCursor = xText->createTextCursor$($$)$;
xTextCursor->setString$($OUString$($"Hello world!"$)$+"\n"$)$;
Вставим текст перед ранее введенным текстом:
xTextCursor = xText->createTextCursor$($$)$;
xTextCursor->setString$($OUString$($"All around the world."$)$+"\n"$)$;
Добавим текст в конце документа:
xTextCursor->gotoEnd$($0$)$;
xTextCursor->setString$($OUString$($"World you are beautiful!"$)$$)$;
В результате будет создан документ, представленный на рисунке 31.

Рисунок 31 — Новый созданный документ
В конце, как и в примере выше, следует удалить созданный менеджер сервисов:
Reference <Xcomponent>::query$($xMultiComponentFactoryClient$)$→dispose$($$)$;
3.3 Вставка изображения в документ
Создадим новый тестовый документ и вставим в него изображение.
В начале создаем новый документ, по аналогии с пунктом 3.2.
auto xWriterWriteComponent = xComponentLoader→loadComponentFromURL$($OUString$($"private:factory/swriter"$)$,OUString$($"_blank"$)$, 0, Sequence <::com::sun::star::beans::PropertyValue>$($$)$$)$;
Reference <XTextDocument> xTextDocument$($xComponent, UNO_QUERY$)$;
Инициализируем переменную, содержащую URL вставляемого изображения:
OUString GraphicURL;
osl::FileBase::getFileURLFromSystemPath$($OUString$($L"C:/LibreOffice/sdk/examples/cpp/DocumentLoader/testImage.bmp"$)$, GraphicURL$)$;
Создаем набор свойств вставляемого объекта $($изображения$)$:
Reference <XMultiServiceFactory> xMultiServiceFactory$($xTextDocument, UNO_QUERY$)$;
Reference <XPropertySet> xGraphic$($xMultiServiceFactory→createInstance$($OUString$($RTL_CONSTASCII_USTRINGPARAM$($"com.sun.star.text.GraphicObject"$)$$)$$)$, UNO_QUERY$)$;
Т.к. высота и ширина вставляемого изображения задаются исходя из значения величины указываемого параметра 1 единица = 1/100 мм , подаем их в свойства в виде переменных с коэффициентом coefficient учитывающим разрешение изображения 96 точек/дюйм $($следует отметить, что разрешение тестовой картинки составляет 512 x 366 пикселей$)$. В случае необходимости установить размер картинки, отличный от натуральной величины, данный коэффициент может быть скорректирован:
auto coefficient = 25.4 * 100 / 96;
auto imageWidth = 512 * coefficient;
auto imageHeight = 366 * coefficient;
xGraphic->setPropertyValue$($OUString$($"GraphicURL"$)$, makeAny$($GraphicURL$)$$)$;
xGraphic->setPropertyValue$($OUString$($"Width"$)$, Any$($$($sal_Int32$)$imageWidth$)$$)$;
xGraphic->setPropertyValue$($OUString$($"Height"$)$, Any$($$($sal_Int32$)$imageHeight$)$$)$;
Вставляем изображение в документ с указанной позиции курсора:
auto xText = xTextDocument->getText$($$)$;
auto xTextCursor = xText->createTextCursor$($$)$;
Reference <XTextContent> xTextContent$($xGraphic, UNO_QUERY$)$;
auto xTextRange = xTextCursor->getEnd$($$)$;
xText->insertTextContent$($xTextRange, xTextContent, false$)$;
В конце, как и в примере выше, следует удалить созданный менеджер сервисов:
Reference <XComponent>::query$($xMultiComponentFactoryClient$)$→dispose$($$)$;
Результат — изображение в полную величину можно увидеть в открывшемся документе $($рисунок 32$)$.

Рисунок 32 - Вставленное в текстовый документ изображение
3.4 Конвертация документа в PDF
Откроем документ в LibreOffice7.0 и выполним его конвертацию в PDF.
Открытие документа осуществляется в соответствии с разделом 3.1.
Создаем компонент Xstorable, позволяющий сохранять документы в различные форматы:
Reference <XStorable> xStorable$($xTextDocument, UNO_QUERY$)$;
Создаем набор свойств компонента:
Sequence <PropertyValue> xTextPDFProps$($3$)$;
xTextPDFProps$[$0$]$.Name = OUString$($"FilterName"$)$;
xTextPDFProps$[$0$]$.Value = makeAny$($OUString$($"writer_pdf_Export"$)$$)$;
xTextPDFProps$[$1$]$.Name = OUString$($"Overwrite"$)$;
xTextPDFProps$[$1$]$.Value = Any$($true$)$;
xTextPDFProps$[$2$]$.Name = OUString$($"SelectPdfVersion"$)$;
xTextPDFProps$[$2$]$.Value = Any$($$($sal_Int32$)$1$)$;
Инициализируем переменную, хранящую URL сохраняемого в PDF документа:
OUString sPDFUrl;
osl::FileBase::getFileURLFromSystemPath$($OUString$($L"C:/LibreOffice/sdk/examples/cpp/DocumentLoader/4 Установка LibreOfiice SDK 7.0.pdf"$)$, sPDFUrl$)$;
Сохраняем документ в PDF-формат:
xStorable->storeToURL$($sPDFUrl, xTextPDFProps$)$;
В конце, как и в примере выше, удаляем созданный менеджер сервисов:
Reference <Xcomponent>::query$($xMultiComponentFactoryClient$)$→dispose$($$)$;
Созданный PDF документ можно увидеть на рисунке 33.

Рисунок 33 — Созданный PDF документ