При автоматизации рассылки документов (счетов, актов, протоколов) из старых версий платформы, таких как 1С:Предприятие 7.7, программисты часто сталкиваются с задачей тихого (фонового) сохранения табличного документа в формат PDF без участия пользователя. Рассмотрим подробнее, с какими сложностями можно столкнуться при использовании виртуальных принтеров и внешних компонент, разберем причины возникновения ошибок и выясним, как правильно выстроить процесс генерации и отправки файлов.
Проанализируем классическую ситуацию: разработчик устанавливает бесплатный виртуальный принтер PDFCreator, настраивает программную печать табличного документа на этот принтер, но после формирования файла автоматически открывается программа для просмотра PDF (например, устанавливаемый в комплекте PDF Architect). Это прерывает фоновый процесс рассылки и требует ручного закрытия окна.
В оригинальном коде разработчика печать выглядит следующим образом:
ПутьКФайлу=("C:\рассылка\"+Имяфайла);
Таб0 = СоздатьОбъект("ТабличныйДокумент");
Таб0.ЗагрузитьИзТаблицы(Таб);
Таб0.ПараметрыПечати.ИмяПринтера = "PDFCreator";
Таб0.ПараметрыПечати.АвтоМасштаб = 1;
Таб0.Напечатать(0);
Самое простое и эффективное решение проблемы всплывающих окон — полное удаление сопутствующей программы-просмотрщика через Панель управления Windows. Если PDF Architect или аналогичное приложение деинсталлировано, виртуальный принтер просто сформирует файл и сложит его в заданную папку, так как ему будет нечего запускать для предпросмотра.
Также при правильном подходе (через COM-объект принтера) можно напрямую передать параметр, запрещающий открытие файла после создания, например, установив свойство OpenViewer = 0 в объекте настроек.
Разберем по шагам логику, которая часто приводит к путанице. В коде после вызова метода Напечатать(0) программист пытается сразу переименовать созданный файл:
Таб0.Напечатать(0);
ФС.ПереименоватьФайл("C:\рассылка\protocol.pdf",ИмяФайла,1);
ФС.УдалитьФайл("C:\рассылка\protocol.pdf");
При выполнении этого кода файл переименовывается только при повторном запуске процедуры. Почему так происходит? Выясним причину.
Проблема кроется в асинхронной работе виртуального принтера Windows. Метод 1С отправляет задание в очередь печати операционной системы и моментально переходит к выполнению следующей строчки кода. Однако процессу PDFCreator требуется время (доли секунды или даже секунды) на рендеринг, преобразование графики и запись файла на жесткий диск. В момент, когда 1С вызывает ФС.ПереименоватьФайл, нужного файла на диске физически еще не существует, либо он заблокирован процессом принтера. При повторном запуске скрипта 1С находит старый файл protocol.pdf, оставшийся от предыдущего цикла, и успешно переименовывает его, но это в корне неверный алгоритм.
Как правильно: Работать с PDFCreator необходимо через его COM-интерфейс (PDFCreator.JobQueue или PDFCreator.clsPDFCreator в зависимости от версии программы). Это позволит скрипту 1С напрямую задать нужное конечное имя файла до начала печати, дождаться завершения формирования документа и только после этого продолжить выполнение кода.
Посмотрим на альтернативный метод формирования PDF — без виртуальных принтеров, напрямую из платформы с помощью популярной бесплатной библиотеки Йоксель. Этот метод работает стабильнее, так как происходит синхронно внутри процесса 1С.
Рассмотрим пример генерации PDF с использованием графического конвертера Йоксель:
ТабЭлемент=СоздатьОбъект("ТабличныйДокумент");
ТабЭлемент.ЗагрузитьИзТаблицы(Таб);
Имя="Сч"+Строка(НомерДок)+"_"+Формат(ДатаДок,"ДДДММГГ");
// Очистка имени от недопустимых символов
Имя=СтрЗаменить(Имя,".","-");
Имя=СтрЗаменить(Имя,"/","-");
Имя=СтрЗаменить(Имя,"\","-");
Имя=СтрЗаменить(Имя," ","");
Каталог="D:\SendMail\";
ИмяФайла=Каталог+Имя+".PDF";
Конвертер = СоздатьОбъект("Йоксель.ГрафическийКонвертер.PDF");
Конвертер.ВысотаСтраницы = 16840; //А4
Конвертер.ШиринаСтраницы = 11907; //А4
Конвертер.КоличествоБитНаПиксел = 24;
Конвертер.Документ = ТабЭлемент;
// Установка полей (в твипах)
Конвертер.ПолеСлева = 600;
Конвертер.ПолеСверху = 600;
Конвертер.ПолеСправа = 600;
Конвертер.ПолеСнизу = 600;
Конвертер.ЗаписатьВФайл(ИмяФайла);
При использовании вышеуказанного кода с Йокселем часто возникает ситуация: в 1С документ выглядит на одну страницу, а в сгенерированном PDF добавляется пустой лист. Проанализируем причину. Лишняя пустая страница возникает из-за жестко заданных параметров ширины листа (11907) и отступов (ПолеСправа, ПолеСлева = 600). Если реальная таблица из 1С вместе с заданными полями хотя бы на один пиксель превышает физические размеры формата А4, конвертер переносит пустоту на следующий лист. Решением является программное уменьшение размеров полей (до 200-300 твипов) или включение автоматического масштабирования перед конвертацией.
Если печатные формы разные (одни портретной ориентации, другие альбомной), нам необходимо программно определить это и поменять местами переменные ВысотаСтраницы и ШиринаСтраницы. В платформе 1С 7.7 параметры сформированной таблицы можно считать с помощью штатной функции до передачи в конвертер:
ТабЭлемент.ПараметрыСтраницы(Ориентация, ...).Ориентация платформа поместит число (обычно 1 — Портрет, 2 — Ландшафт).Если Ориентация = 2 Тогда и поменяйте местами ширину и высоту.Если Йоксель по каким-то причинам не подходит (например, искажает сложные шрифты или картинки), разработчики часто применяют Bullzip PDF Printer. Для работы с ним в 1С также используется встроенный COM-объект Bullzip.PDFPrinterSettings, который отлично поддается программной настройке.
Важный нюанс: современные версии BullzipPDF в бесплатной редакции вставляют на страницы документа красные строчки (водяные знаки). Для коммерческого использования без покупки лицензии программисты рекомендуют искать старые версии дистрибутива (например, BullzipPDFPrinter_6_0_0_865) или использовать отличную бесплатную альтернативу — PDF24 Creator, который полностью бесплатен для бизнеса, не оставляет рекламных штампов и поддерживает автоматизацию печати.
Когда PDF-файл корректно сформирован, его нужно отправить. Разберем способы, применимые для среды 1С 7.7:
КомандаСистемы() с параметрами файлов.