В процессе разработки в среде 1С:Предприятие часто возникает задача отправки печатных форм контрагентам по электронной почте или через мессенджеры. Стандартные форматы документов, такие как MXL, требуют наличия установленной платформы или специального просмотрщика, которых у клиента может не быть. Формат PDF является практически общепризнанным стандартом, однако в некоторых сценариях (например, быстрая отправка счета во встроенном теле письма или отправка картинки в мессенджер) требуется получить именно графический файл — JPEG или PNG. Сформированное изображение затем необходимо сохранить в базу данных в реквизит с типом ХранилищеЗначения для последующей обработки на сервере.
Сложность заключается в том, что стандартный метод платформы ТабличныйДокумент.Записать() нативно не поддерживает сохранение напрямую в графические форматы. В этой статье мы подробно рассмотрим и разберем по шагам пять проверенных практических способов решения этой задачи, а также покажем, как правильно поместить готовый файл в ХранилищеЗначения.
Этот способ отлично подходит для работы в фоновых заданиях на сервере под управлением как Windows, так и Linux. Он не требует интерактивного вмешательства пользователя и работает полностью в фоновом режиме. Чтобы обеспечить стабильное обслуживание инфраструктуры при работе таких сервисов, удобно использовать автоматическое обновление и тестирование баз 1С по расписанию.
Суть метода заключается в промежуточном сохранении табличного документа в формат PDF с последующим вызовом внешней консольной утилиты для рендеринга страниц в графические файлы. Мы воспользуемся популярной связкой ImageMagick и Ghostscript или напишем легковесный скрипт на Python.
Рассмотрим по шагам программный код на стороне 1С для реализации этого механизма:
// 1. Формируем пути ко временным файлам
ИмяВременногоPDF = ПолучитьИмяВременногоФайла("pdf");
ИмяВременнойКартинки = ПолучитьИмяВременногоФайла("png");
// 2. Сохраняем табличный документ в PDF стандартным методом платформы
ТабДок.Записать(ИмяВременногоPDF, ТипФайлаТабличногоДокумента.PDF);
// 3. Формируем команду для консольного конвертера ImageMagick
// Параметр -density задает разрешение (dpi), 150-300 вполне достаточно для четкого текста
// Параметр -quality определяет качество сжатия
СтрокаЗапуска = "convert -density 150 """ + ИмяВременногоPDF + """ -quality 90 """ + ИмяВременнойКартинки + """";
// 4. Запускаем приложение в фоновом режиме с ожиданием завершения
КодВозврата = Неопределено;
ЗапуститьПриложение(СтрокаЗапуска, , Истина, КодВозврата);
Если КодВозврата = 0 Тогда
// Картинка успешно сформирована. Если документ был многостраничным,
// ImageMagick создаст файлы вида ИмяВременнойКартинки-0.png, ИмяВременнойКартинки-1.png и т.д.
// Проанализируем полученный результат и прочитаем данные.
Иначе
ВызватьИсключение "Ошибка конвертации табличного документа в картинку при помощи ImageMagick!";
КонецЕсли;
Если на сервере установлен Python, мы можем использовать библиотеку pdf2image. Код скрипта-конвертера будет предельно лаконичным, а вызвать его можно также через метод ЗапуститьПриложение().
Рассмотрим еще один кроссплатформенный вариант, который не задействует формат PDF. Здесь промежуточным форматом выступит стандартный HTML5, который платформа 1С умеет формировать "из коробки".
Алгоритм действий выглядит следующим образом:
wkhtmltoimage или запускаем браузер Google Chrome (или Яндекс.Браузер) в так называемом "headless" режиме (без отображения графического интерфейса) для создания скриншота страницы.Посмотрим на пример реализации вызова Google Chrome из кода 1С:
ИмяВременногоHTML = ПолучитьИмяВременногоФайла("html");
ИмяВременнойКартинки = ПолучитьИмяВременногоФайла("png");
// Сохраняем табличный документ в формате HTML5
ТабДок.Записать(ИмяВременногоHTML, ТипФайлаТабличногоДокумента.HTML5);
// Формируем команду запуска браузера Chrome в фоновом режиме для создания скриншота
СтрокаЗапуска = "chrome --headless --disable-gpu --screenshot=""" + ИмяВременнойКартинки + """ """ + ИмяВременногоHTML + """";
ЗапуститьПриложение(СтрокаЗапуска, , Истина);
Преимущество данного метода заключается в высокой точности позиционирования элементов табличного документа, так как современные браузеры отлично справляются с рендерингом HTML-разметки любой сложности.
Выясним, как решить задачу на серверах под управлением ОС Windows с помощью проверенного временем бесплатного инструмента — библиотеки "Йоксель". Этот компонент умеет напрямую работать с табличными документами и конвертировать их в графику без использования сторонних графических утилит.
Для работы этого метода предварительно требуется зарегистрировать COM-объект в операционной системе. Код интеграции в 1С выглядит следующим образом:
// Сохраняем табличный документ во временный файл Excel
ПутьКXLS = ПолучитьИмяВременногоФайла("xls");
ТабДок.Записать(ПутьКXLS, ТипФайлаТабличногоДокумента.XLS);
Попытка
// Создаем COM-объект Йоксель
Йоксель = Новый COMОбъект("Йоксель");
ЙДокумент = Йоксель.СоздатьТабличныйДокумент();
ЙДокумент.Открыть(ПутьКXLS, 2); // Параметр 2 означает формат Excel
// Настраиваем конвертер графики
ЙКонвертер = Йоксель.СоздатьGraphicConverter();
ЙКонвертер.УстановитьДокумент(ЙДокумент);
ПутьККартинке = ПолучитьИмяВременногоФайла("png");
// Записываем документ в графический формат PNG
ЙКонвертер.Записать(ПутьККартинке, "PNG");
Исключение
ЗаписьЖурналаРегистрации("Конвертация в PNG", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось сконвертировать документ через Йоксель. Проверьте регистрацию COM-компонента.";
КонецПопытки;
Важное примечание: Хотя Йоксель является крайне быстрым инструментом, он работает исключительно в среде Windows и требует регистрации DLL-файла в реестре операционной системы. Это делает его малоприменимым для современных кроссплатформенных инсталляций на базе Linux.
Если задача выполняется на стороне клиента (в тонком или толстом клиенте под управлением ОС Windows), мы можем использовать виртуальный принтер. Популярные программы, такие как Bullzip PDF Printer или PDFCreator, позволяют эмулировать печать физического принтера напрямую в файлы графических форматов.
Разберем по шагам, как отправить печатную форму на такой принтер из кода 1С:
// Указываем точное имя установленного в системе виртуального принтера
ТабДок.ИмяПринтера = "Bullzip PDF Printer";
// Настраиваем автоматическую отправку на печать без вывода диалогового окна выбора принтера
ТабДок.Напечатать(Истина);
Главный недостаток данного метода — необходимость предварительной индивидуальной настройки драйверов принтера на каждом рабочем месте пользователя, а также его полная неработоспособность в фоновых заданиях на сервере, где отсутствует графическое интерактивное окружение. В случаях, когда необходимо автоматизировать действия пользователя в графическом интерфейсе или настроить печать без API, может быть применена платформа для создания программных роботов.
Наиболее современным, быстрым и технологичным способом является использование специализированных внешних компонент Native API, написанных на C++ или C#. Такие компоненты подключаются непосредственно в конфигурацию 1С как общий макет и работают в оперативной памяти как под Windows, так и под Linux.
Они способны мгновенно отрендерить переданный им макет MXL или готовый двоичный файл PDF напрямую в массив байтов (картинку), минуя запись промежуточных файлов на жесткий диск, что существенно повышает производительность и безопасность системы. Для реализации такого подхода можно использовать инструмент для экспорта печатных форм в растровые и векторные изображения.
Независимо от того, какой из вышеперечисленных способов вы выбрали для формирования графического файла на диске, следующим шагом будет его чтение и запись в базу данных 1С. При использовании 1С:Бухгалтерии 3.0 такая техническая реализация может дополнить систему автоматического создания счетов и договоров по электронной почте для ускорения обмена документами.
Проанализируем пример кода, который считывает файл с диска, помещает его в ХранилищеЗначения с максимальной степенью сжатия, записывает в базу данных и производит очистку временных файлов:
// Предположим, что в переменной ПутьКФайлуКартинки хранится путь к нашему PNG-файлу
Если ФайлСуществует(ПутьКФайлуКартинки) Тогда
// Шаг 1. Читаем картинку в двоичные данные
ДвоичныеДанныеКартинки = Новый ДвоичныеДанные(ПутьКФайлуКартинки);
// Шаг 2. Создаем Хранилище Значения с максимальным уровнем сжатия данных (9)
ХранилищеКартинки = Новый ХранилищеЗначения(ДвоичныеДанныеКартинки, Новый СжатиеДанных(9));
// Шаг 3. Записываем хранилище в реквизит объекта (например, справочника ПрисоединенныеФайлы или Документа)
НовыйОбъект = Справочники.ПрисоединенныеФайлы.СоздатьЭлемент();
НовыйОбъект.Наименование = "ПечатнаяФорма.png";
НовыйОбъект.ФайлХранилище = ХранилищеКартинки;
НовыйОбъект.Записать();
// Шаг 4. Обязательно удаляем временный файл с диска для предотвращения засорения системы
Попытка
УдалитьФайлы(ПутьКФайлуКартинки);
Исключение
// Логируем ошибку удаления, если файл занят другим процессом
ЗаписьЖурналаРегистрации("ОчисткаВременныхФайлов", УровеньЖурналаРегистрации.Предупреждение, , , "Не удалось удалить файл: " + ПутьКФайлуКартинки);
КонецПопытки;
КонецЕсли;
Выясним важную техническую деталь, касающуюся выбора формата итогового изображения. Для сохранения текстовых документов, таблиц и печатных форм 1С настоятельно рекомендуется использовать формат PNG, а не JPEG. На это есть две веские причины: