При работе с 1С часто возникает задача по взаимодействию с внешними файлами, и PDF-документы не исключение. В частности, мы столкнулись с необходимостью изменять существующие PDF-файлы, которые содержат как заполняемые поля (формы), так и статический текст, который требуется программно дополнить или заменить информацией из 1С. Такая задача может быть осложнена требованиями к работе на сервере и вопросами лицензирования используемого программного обеспечения. Рассмотрим подробнее возможные подходы и их особенности.
Исходная проблема заключалась в том, чтобы заполнить в PDF не только интерактивные поля, но и обычный текст, который изначально размечен как переменные (например, v8Отпуск_планПериод_х). При этом часть документа должна заполняться человеком, а другая — данными из 1С. Важно также учитывать необходимость серверного формирования таких файлов для последующей отправки, что накладывает дополнительные ограничения на выбор инструментов.
Первый, и наиболее очевидный, путь — это использование COM-объектов Adobe Acrobat Pro, если он установлен на клиентской машине или сервере. Этот подход позволяет обращаться к функционалу Adobe Acrobat через 1С и манипулировать элементами PDF-документа, в частности, его заполняемыми полями.
Принцип работы:
AcroExch.App) и сам PDF-документ (AcroExch.PDDoc).AFormAut.App) получаем доступ к коллекции полей документа.Рассмотрим пример кода, который демонстрирует заполнение полей формы в PDF-документе из 1С с использованием Adobe Acrobat Pro:
// Создаем COM-объект для документа PDF
doc = Новый COMОбъект("AcroExch.PDDoc");
// Открываем временный файл PDF. Предполагается, что ИмяВременногоФайла уже содержит путь к PDF.
// Для серверного или цикличного использования, возможно, потребуется каждый раз записывать исходный макет во временный файл.
ВременныйФайлДляРедактирования = ПолучитьИмяВременногоФайла("pdf");
// ДвоичныеДанныеМакета - это ДвоичныеДанные вашего исходного PDF-макета
ДвоичныеДанныеМакета.Записать(ВременныйФайлДляРедактирования);
doc.Open(ВременныйФайлДляРедактирования);
// Создаем COM-объект для приложения Adobe Acrobat.
// Обратите внимание, что AcroExch.App является приложением, которое может быть скрыто или видимо.
AcroExchApp = Новый COMОбъект("AcroExch.App");
AcroExchApp.Hide(); // Скрываем окно приложения Adobe Acrobat, если оно появляется
// Для работы с формами также может потребоваться объект AVDoc
AcroExchAVDoc = Новый COMОбъект("AcroExch.AVDoc");
// Открываем документ через AVDoc. Это может быть необходимо для доступа к некоторым функциям.
// doc.OpenAVDoc(ВременныйФайлДляРедактирования); - этот вызов может быть избыточен или конфликтовать, если doc уже открыт.
// Более корректно использовать метод OpenFromPDDoc для AVDoc, если уже есть PDDoc.
// Однако, в примере выше использовано прямое открытие, что также может работать в зависимости от версии.
// Пусть avDoc будет результатом doc.OpenAVDoc(ВременныйФайлДляРедактирования) или создадим AVDoc и свяжем с PDDoc.
// В данном случае, изначальный код использовал avDoc = doc.OpenAVDoc(ИмяВременногоФайла);
// Придерживаемся логики автора:
avDoc = AcroExchAVDoc.Open(ВременныйФайлДляРедактирования, ""); // Открываем AVDoc, связывая его с файлом.
// Создаем COM-объект для работы с формами PDF
form = Новый COMОбъект("AFormAut.App");
// Получаем коллекцию полей формы документа
Fields = form.Fields;
// Итерируем по всем полям формы
Для Каждого Field Из Fields Цикл
// Проверяем имя поля для заполнения данных из 1С
Если Лев(Field.Name, 21) = "v8Отпуск_планКолДней_" Тогда
// Заполняем поле формы данными из 1С.
// Вместо СлЧисло = ГСЧ.СлучайноеЧисло(1); используем реальные данные.
Field.Value = "Количество дней отпуска из 1С";
КонецЕсли;
// Пример, как сделать поле только для чтения, если в его имени есть "IsReadOnly"
Если СтрНайти(Field.Name, "IsReadOnly") > 0 Тогда
Field.IsReadOnly = True;
КонецЕсли;
КонецЦикла;
// Сохраняем измененный PDF-документ
ResultSave = doc.Save(1, ВременныйФайлДляРедактирования); // 1 означает сохранить как копию, можно сохранить в исходный файл
// Закрываем открытые объекты для освобождения ресурсов
doc.Close();
avDoc.Close(0); // 0 - не сохранять изменения (так как уже сохранили через doc.Save)
// Закрываем все документы в приложении Adobe Acrobat и завершаем работу приложения
AcroExchApp.CLoseAllDocs();
AcroExchApp.Exit();
Ограничения и проблемы:
CreateTextSelect и GetNumText позволяет читать текст, но не заменять его напрямую.Для обхода лицензионных ограничений Adobe и расширения функциональности по работе с PDF, мы можем рассмотреть сторонние библиотеки, разработанные специально для программного взаимодействия с PDF-файлами. Эти библиотеки часто предоставляют более гибкие возможности, включая изменение произвольного текста, добавление элементов, подпись и т.д.
Debenu Quick PDF Library является одной из популярных библиотек для работы с PDF. Она предоставляет COM-интерфейс, что делает её относительно простой для использования из 1С через Новый COMОбъект(). Эта библиотека предлагает широкий спектр функций для манипуляции PDF-документами.
Возможности Debenu:
Особенности интеграции с 1С:
Библиотека обычно поставляется в виде DLL-файла, который необходимо зарегистрировать в системе (например, с помощью regsvr32). После регистрации мы можем создать объект библиотеки в 1С:
// Создаем COM-объект для Debenu Quick PDF Library.
// Имя объекта может отличаться в зависимости от версии и способа регистрации.
// Например: "QuickPDF.PDFLibrary" или "Debenu.QuickPDF.Library"
QP = Новый COMОбъект("QuickPDF.PDFLibrary");
Далее мы можем использовать методы объекта QP для работы с PDF. Например, для открытия документа, поиска и замены текста, работы с полями форм и сохранения изменений.
Решение проблемы с кириллицей:
При работе с Debenu Quick PDF Library может возникнуть проблема с отображением кириллицы, когда текст исчезает при снятии курсора с поля. Эту проблему можно решить, установив специальное свойство для документа. Мы используем методы GetNeedAppearances() и SetNeedAppearances():
// Получаем текущее значение свойства NeedAppearances
GetNeedAppearances_Result = QP.GetNeedAppearances();
// Устанавливаем свойство NeedAppearances в 1.
// Это свойство указывает, что внешние виды полей формы должны генерироваться автоматически,
// что часто помогает с корректным отображением текста, включая кириллицу.
SetNeedAppearances_Result = QP.SetNeedAppearances(1);
Преимущества:
Foxit также предлагает свои SDK для работы с PDF, доступные на различных языках программирования: .NET, C, C++, Java. Foxit PhantomPDF, как и Adobe Acrobat Pro, предоставляет богатые возможности редактирования.
Интеграция с 1С:
Прямая интеграция Foxit SDK в 1С может быть более сложной, чем с Debenu, особенно если SDK представлен в виде C++ DLL, не имеющей прямого COM-интерфейса. Попытки использовать ПодключитьВнешнююКомпоненту() или regsvr32 напрямую для таких библиотек могут не увенчаться успехом, так как 1С ожидает определенный интерфейс для внешних компонент.
Для использования Foxit SDK из 1С, вероятно, потребуются дополнительные шаги:
Новый COMОбъект().Особенности:
Для серверных задач, особенно тех, которые требуют высокой гибкости, мультиплатформенности или работы со сложными библиотеками, наиболее надежным и архитектурно правильным решением является создание отдельного микросервиса. Этот микросервис будет заниматься всей логикой работы с PDF, а 1С будет лишь взаимодействовать с ним по стандартным протоколам (например, HTTP).
Принцип работы:
Преимущества такого подхода:
Рассмотрим несколько языков и библиотек, подходящих для создания такого микросервиса:
Java является отличным выбором для создания микросервисов благодаря своей зрелой экосистеме и производительности. Для работы с PDF в Java доступны мощные открытые библиотеки.
Мы можем использовать фреймворк, такой как Spring Boot, для быстрого создания RESTful-сервиса на Java, который будет принимать PDF-файл и данные от 1С, обрабатывать их с помощью PDFBox и возвращать результат.
Python также популярен для автоматизации и создания микросервисов. Для работы с PDF в Python существует несколько библиотек:
С помощью таких фреймворков, как Flask или FastAPI, можно легко создать простой HTTP-сервис на Python.
Если инфраструктура в основном Windows, C# и ASP.NET Core являются естественным выбором. Существуют коммерческие (например, Syncfusion PDF, Aspose.PDF) и некоторые бесплатные (например, PdfSharp) библиотеки для работы с PDF в .NET, которые предоставляют все необходимые функции.
Go набирает популярность для создания высокопроизводительных микросервисов. Есть библиотеки для работы с PDF, например, signintech/pdft, которые позволяют выполнять различные операции.
Взаимодействие 1С с микросервисом:
Из 1С мы можем использовать стандартные объекты для HTTP-запросов, например, HTTPЗапрос и HTTPСоединение, чтобы отправить файл и данные на микросервис и получить обратно измененный PDF:
// Пример отправки файла и данных на микросервис
Функция ОтправитьPDFНаСервис(ИмяФайлаPDF, ДанныеДляЗаполнения)
HTTPСоединение = Новый HTTPСоединение("localhost", 8080); // Адрес и порт вашего микросервиса
// Формируем тело запроса
ТелоЗапроса = Новый ДвоичныеДанные(ИмяФайлаPDF); // Сам PDF-файл
// Можно добавить параметры формы, если микросервис ожидает их
// Например, через ФормаДанных = Новый Соответствие(); ФормаДанных.Вставить("field1", "value1");
// и затем использовать МногофункциональныйHTTPЗапрос.УстановитьТелоИзФормыДанных()
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/pdf"); // Или multipart/form-data если есть доп. параметры
HTTPЗапрос = Новый HTTPЗапрос("/process-pdf", Заголовки); // Путь к эндпоинту сервиса
HTTPЗапрос.УстановитьТело(ТелоЗапроса);
Попытка
Ответ = HTTPСоединение.Отправить(HTTPЗапрос);
Если Ответ.КодСостояния = 200 Тогда
// Успешно, получаем измененный PDF
ИзмененныйPDF = Ответ.ПолучитьТелоКакДвоичныеДанные();
Возврат ИзмененныйPDF;
Иначе
Сообщить("Ошибка обработки PDF: " + Ответ.КодСостояния + " " + Ответ.ПолучитьТелоКакСтроку());
Возврат Неопределено;
КонецЕсли;
Исключение
Сообщить("Ошибка при отправке запроса: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
// Пример использования:
// ИзмененныйPDF = ОтправитьPDFНаСервис("C:\Исходный.pdf", Новый Структура("Поле1", "Значение1"));
// Если ИзмененныйPDF <> Неопределено Тогда
// ИзмененныйPDF.Записать("C:\Измененный.pdf");
// КонецЕсли;
Платформа 1С имеет собственные возможности для работы с PDF-документами, но они, как правило, ориентированы на сохранение и просмотр, а не на полноценное редактирование произвольного текста в уже существующем файле.
ДокументPDF: В более новых версиях платформы (начиная с 8.3.21) появился объект ДокументPDF. Он предоставляет возможности для предварительного просмотра, навигации по документу, работы с вложениями. Однако, его функционал для редактирования произвольного текста или полей форм в существующем PDF остается ограниченным. Он больше предназначен для взаимодействия с PDF на уровне пользователя и программного доступа к его структуре (например, для чтения метаданных или обработки вложений), но не для его глубокой модификации.Таким образом, для решения задачи по изменению содержимого существующего PDF, встроенные средства 1С, скорее всего, будут недостаточны.
При выборе подхода к изменению PDF из 1С, мы рекомендуем учитывать следующие моменты:
SetNeedAppearances(1) для Debenu).В целом, проблема изменения PDF из 1С не имеет универсального "серебряного шара". Мы вынуждены выбирать между простотой реализации (OLE с Adobe), гибкостью сторонних библиотек (Debenu, Foxit) и надежностью архитектурных решений (микросервисы), исходя из конкретных требований проекта и имеющихся ресурсов.