В процессе автоматизации документооборота часто возникает задача массовой (пакетной) печати PDF-файлов, которые прикреплены к документам или хранятся во внешних томах. Платформа 1С:Предприятие постоянно развивается, предлагая новые инструменты, однако вопрос взаимодействия с внешними файлами формата PDF остается актуальным. В этой статье мы подробно разберем несколько способов решения этой задачи: от классического использования COM-объектов до современных возможностей платформы и сторонних утилит.
Этот метод считается одним из самых доступных, так как Adobe Reader установлен на большинстве рабочих станций. Разберем ситуацию, когда нам необходимо отправить список файлов на конкретный принтер в фоновом режиме. Основная сложность здесь заключается в том, что Adobe Reader после печати часто остается открытым в процессах Windows, поэтому нам придется программно отслеживать завершение задания и закрывать приложение.
Проанализируем программный код, который позволяет автоматизировать этот процесс. Сначала мы определим путь к исполняемому файлу Adobe Reader через реестр Windows, затем отправим файлы на печать и проконтролируем очередь печати через WMI (Windows Management Instrumentation).
// Процедура выполняет попытку напечатать pdf-файлы из списка в фоновом режиме
Процедура ФоноваяПечатьPDFФайлов(МассивФайлов, ИмяПринтера = "") Экспорт
WshShell = Новый COMОбъект("WScript.Shell");
// Пытаемся найти путь к Adobe Reader в реестре
Попытка
ПутьAdobeReader = WshShell.RegRead("HKCR\Software\Adobe\Acrobat\Exe\");
Исключение
Сообщить("Программа Adobe Reader не найдена!", СтатусСообщения.Важное);
Возврат;
КонецПопытки;
// Подключаемся к службе управления заданиями печати
oLocator = Новый COMОбъект("WbemScripting.SWbemLocator");
oService = oLocator.ConnectServer("", "", "", "");
oService.Security_.impersonationlevel = 3;
oService.Security_.Privileges.AddAsString("SeLoadDriverPrivilege");
Для каждого Файл Из МассивФайлов Цикл
// Формируем команду: /N - новый экземпляр, /T - печать на принтер
Команда = ПутьAdobeReader + " /N /T " + """" + Файл.ПолноеИмя + """" + ?(ЗначениеЗаполнено(ИмяПринтера), " " + """" + ИмяПринтера + """", "");
WshShell.Run(Команда, 0);
// Мониторим добавление задания в очередь (ждем до 15 секунд)
ЗаданиеДобавлено = Ложь;
ТекущееВремя = ТекущаяДата();
Пока Не ЗаданиеДобавлено И ТекущаяДата() < ТекущееВремя + 15 Цикл
ОбработкаПрерыванияПользователя();
Для каждого ЗаданиеПечати Из oService.InstancesOf("Win32_PrintJob") Цикл
ЗаданиеДобавлено = (ЗаданиеПечати.Document = Файл.Имя);
КонецЦикла;
КонецЦикла;
КонецЦикла;
// Ожидаем, пока очередь печати полностью очистится
Пока (oService.InstancesOf("Win32_PrintJob").Count > 0) Цикл
// Можно добавить ограничение по времени
КонецЦикла;
// Завершаем процесс Adobe Reader, чтобы он не висел в памяти
ИмяПроцесса = "AcroRd32.exe"; // Или динамически извлечь из ПутьAdobeReader
WshShell.Run("taskkill /f /im " + ИмяПроцесса, 0);
КонецПроцедуры
Важный момент: использование taskkill — это "жесткий" метод. В многопользовательской среде терминального сервера это может закрыть приложения у других пользователей, если не фильтровать процессы по ID или владельцу.
Если на компьютере установлен Adobe Acrobat Professional, мы можем воспользоваться более элегантным способом — через специализированный COM-объект AcroExch. Это позволяет управлять параметрами печати напрямую, без использования командной строки.
Выясним, какие преимущества дает этот подход. Мы можем настроить "тихую" печать (silent mode), выбрать конкретный лоток принтера и масштабирование страницы. Рассмотрим пример кода:
Процедура ПечатьЧерезAcrobatPro(ПутьКФайлу, ИмяПринтера)
Попытка
App = Новый COMОбъект("AcroExch.App");
PDDoc = Новый COMОбъект("AcroExch.PDDoc");
Исключение
Сообщить("Adobe Acrobat Pro не установлен");
Возврат;
КонецПопытки;
App.Hide(); // Скрываем окно приложения
Если PDDoc.Open(ПутьКФайлу) Тогда
JSO = PDDoc.GetJSObject();
PrintParams = JSO.GetPrintParams();
// Настраиваем параметры: печать без диалогов
PrintParams.interactive = PrintParams.constants.interactionLevel.silent;
PrintParams.printerName = ИмяПринтера;
// Установка масштабирования "По размеру области печати"
PrintParams.pageHandling = PrintParams.constants.handling.shrink;
JSO.print(PrintParams); // Отправка на печать
PDDoc.Close();
КонецЕсли;
App.Exit();
App = Неопределено;
КонецПроцедуры
Рассмотрим альтернативу тяжелым продуктам Adobe. Программа SumatraPDF — это бесплатный и компактный просмотрщик, который идеально подходит для пакетной печати через командную строку. Она не требует установки (может работать как portable-версия) и корректно завершает работу после выполнения команды.
Алгоритм действий будет следующим:
SumatraPDF.exe в каталоге исполняемых файлов 1С или в общих ресурсах.ЗапуститьПриложение().
// Пример вызова SumatraPDF
ПутьКПрограмме = "C:\Utils\SumatraPDF.exe";
ПараметрыЗапуска = "-print-to """ + ИмяПринтера + """ -silent """ + ПолноеИмяФайла + """";
ЗапуститьПриложение(ПутьКПрограмме + " " + ПараметрыЗапуска, , Истина); // Истина - ждать завершения
Преимущества SumatraPDF: высокая скорость, отсутствие лишних процессов в памяти и стабильная работа с современными принтерами.
Начиная с версии 8.3.14, 1С перешла на использование движка Chromium в объекте ПолеHTMLДокумента. Это открыло возможность программного взаимодействия с PDF-документами прямо в формах 1С.
Разберем, как это работает. Мы можем загрузить файл в невидимое поле HTML и вызвать стандартную команду печати браузера. Однако стоит учитывать, что "тихая" печать без вывода окна выбора принтера в данном случае может потребовать специфических настроек операционной системы или ключей запуска платформы.
В последних релизах платформы (начиная с 8.3.16) появились мощные средства для работы с PDF — объект PDFДокумент. Если у вас 100 отдельных файлов, отправка их по одному может привести к тому, что документы разных пользователей перемешаются в лотке принтера.
Посмотрим на стратегию решения: объединяем все нужные PDF в один временный файл и печатаем его одним заданием.
// Пример объединения PDF в 1С
ОбщийДокумент = Новый PDFДокумент;
Для каждого Файл Из СписокФайлов Цикл
ВременныйPDF = Новый PDFДокумент(Файл.Путь);
// Добавляем страницы из текущего файла в общий
Для НомерСтраницы = 1 По ВременныйPDF.КоличествоСтраниц() Цикл
ОбщийДокумент.ВставитьСтраницу(ВременныйPDF, НомерСтраницы);
КонецЦикла;
КонецЦикла;
ОбщийДокумент.Записать(ПутьКОбщемуФайлу);
// Далее печатаем один ПутьКОбщемуФайлу любым из способов выше
Выясним, какой метод выбрать в зависимости от условий:
SumatraPDF, так как она не требует графического интерфейса и легко управляется через параметры запуска.WScript.Shell, но с обязательной проверкой наличия установленного ПО.PDFДокумент, чтобы минимизировать количество заданий в спулере принтера.lp, которая является стандартом для печати в среде Unix/Linux.Таким образом, комбинируя новые возможности платформы 1С и проверенные временем внешние утилиты, можно создать надежную систему пакетной печати любой сложности.