При отправке клиентам печатных форм (например, счетов на оплату, актов или накладных) компании часто используют факсимиле — графические изображения печати организации и подписей ответственных лиц. Стандартный механизм сохранения табличного документа в формат PDF, встроенный в платформу 1С:Предприятие, формирует векторный документ. В таком файле текстовые слои остаются доступными для выделения и копирования, а картинки подписей и печатей накладываются отдельными графическими объектами с прозрачным фоном.
Это создает серьезную угрозу информационной безопасности: любой получатель может открыть полученный PDF-файл в векторном редакторе (таком как Adobe Illustrator, CorelDraw) или даже в обычном PDF-редакторе и легко извлечь изображение печати и подписи в исходном качестве. В дальнейшем злоумышленники могут использовать это факсимиле для фальсификации других документов. В этой статье мы подробно разберем, как решить эту проблему и сохранить печатную форму в PDF так, чтобы она представляла собой единую «плоскую» картинку, исключающую извлечение отдельных элементов.
Когда мы вызываем стандартный метод ТабличныйДокумент.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF), платформа преобразует ячейки, текст и рисунки табличного документа в соответствующие векторные и растровые объекты спецификации PDF. Текст сохраняется в виде шрифтовых последовательностей, а факсимиле — в виде внедренного бинарного объекта. Защитить такой документ от копирования штатными средствами старых версий платформы невозможно.
Для создания гарантированно безопасного документа нам необходимо провести растеризацию — процесс преобразования векторного описания страниц в растровое изображение (набор пикселей). Рассмотрим основные способы реализации этой задачи на платформе 1С:Предприятие.
Если перед нами не стоит жесткое требование превратить весь документ именно в картинку, а нужно лишь заблокировать стандартные действия пользователя (копирование текста, извлечение графики, редактирование), мы можем воспользоваться новыми возможностями платформы 1С, появившимися в версии 8.3.21. С помощью объекта ЗаписьPDF можно программно установить ограничения на итоговый файл.
Проанализируем пример кода, устанавливающий защиту на создаваемый PDF-документ:
// Создаем объект защиты и настраиваем ограничения
ПараметрыЗащиты = Новый ПараметрыЗащитыPDF;
ПараметрыЗащиты.ЗапретитьКопированиеТекста = Истина;
ПараметрыЗащиты.ЗапретитьРедактирование = Истина;
ПараметрыЗащиты.ЗапретитьПечать = Ложь; // Разрешаем пользователю только распечатать документ
// Устанавливаем пароль владельца, который необходим для изменения прав доступа к файлу
ПараметрыЗащиты.УстановитьПарольВладельца("СложныйПарольАдминистратора123!");
// Инициируем запись документа с параметрами защиты
ЗаписьPDF = Новый ЗаписьPDF;
ЗаписьPDF.Открыть(ПутьКФайлуPDF, ПараметрыЗащиты);
ЗаписьPDF.Записать(ТабличныйДокумент);
ЗаписьPDF.Закрыть();
Преимущества: Высокая скорость работы, отсутствие необходимости в стороннем программном обеспечении на сервере, файл сохраняет небольшой размер.
Недостатки: Слои физически остаются разделенными. Опытный пользователь или специализированные утилиты по обходу защиты PDF могут извлечь графику факсимиле.
Для создания абсолютно надежного «плоского» PDF-файла, в котором все элементы слиты в единую картинку, мы можем применить двухэтапный процесс на сервере:
В качестве серверного инструмента отлично подходит пакет ImageMagick (совместно с Ghostscript) или утилита pdftoppm (из пакета Poppler-utils), которая работает быстро и стабильно как под Windows, так и под Linux.
Рассмотрим пример реализации на сервере под управлением Windows с использованием утилиты pdftoppm для извлечения страниц и последующей сборки через встроенные механизмы 1С:
// Шаг 1. Сохраняем исходный табличный документ во временный векторный PDF
ВременныйВекторныйPDF = ПолучитьИмяВременногоФайла("pdf");
ТабличныйДокумент.Записать(ВременныйВекторныйPDF, ТипФайлаТабличногоДокумента.PDF);
// Шаг 2. Создаем временную директорию для хранения растровых страниц
КаталогКартинок = ПолучитьИмяВременногоФайла("");
СоздатьКаталог(КаталогКартинок);
// Шаг 3. Запускаем утилиту pdftoppm для конвертации страниц PDF в PNG-изображения
// Параметр "-r 150" задает разрешение в DPI (150-200 вполне достаточно для документов)
ПутьКPdftoppm = "C:\Program Files\poppler\bin\pdftoppm.exe";
ПараметрыЗапуска = "-png -r 150 """ + ВременныйВекторныйPDF + """ """ + КаталогКартинок + "\page""";
ЗапуститьПриложение(ПутьКPdftoppm + " " + ПараметрыЗапуска, , Истина); // Ожидаем завершения процесса
// Шаг 4. Собираем картинки обратно в "плоский" табличный документ силами 1С
ТабДокПлоский = Новый ТабличныйДокумент;
ТабДокПлоский.ПолеСверху = 0;
ТабДокПлоский.ПолеСнизу = 0;
ТабДокПлоский.ПолеСлева = 0;
ТабДокПлоский.ПолеСправа = 0;
НайденныеФайлы = НайтиФайлы(КаталогКартинок, "page-*.png");
Счетчик = 0;
Для Каждого ФайлСтраницы Из НайденныеФайлы Цикл
Счетчик = Счетчик + 1;
// Если страница не первая, принудительно вставляем разрыв
Если Счетчик > 1 Тогда
ТабДокПлоский.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
// Создаем рисунок и загружаем в него растровую страницу
Рисунок = ТабДокПлоский.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = Новый Картинка(ФайлСтраницы.ПолноеИмя);
// Позиционируем рисунок на всю страницу А4
Рисунок.Верх = 0;
Рисунок.Лево = 0;
Рисунок.Ширина = 210; // Ширина А4 в миллиметрах
Рисунок.Высота = 297; // Высота А4 в миллиметрах
Рисунок.РазмернаяКартинка = РазмернаяКартинка.РеальныйРазмер;
КонецЦикла;
// Шаг 5. Записываем итоговый защищенный PDF
ТабДокПлоский.Записать(ПутьКВыходномуФайлуPDF, ТипФайлаТабличногоДокумента.PDF);
// Очищаем временные файлы
УдалитьФайлы(ВременныйВекторныйPDF);
УдалитьФайлы(КаталогКартинок);
Важный нюанс: Обратите внимание на установку полей результирующего табличного документа в значение 0. Это необходимо для того, чтобы внедренные растровые страницы А4 выводились ровно по границам печати и не масштабировались повторно платформой при конвертации.
В современных ИТ-инфраструктурах серверы 1С часто функционируют под управлением операционных систем семейства Linux. В таких условиях удобно использовать легковесные скрипты на языке Python, которые могут быть вызваны из 1С. Для преобразования векторного PDF в растровый можно применить высокопроизводительную библиотеку PyMuPDF (также известную как fitz).
Сначала посмотрим на код самого скрипта Python (rasterize.py):
import sys
import fitz # Импортируем PyMuPDF
def rasterize_pdf(input_path, output_path, dpi=150):
# Открываем исходный векторный документ
doc = fitz.open(input_path)
out_doc = fitz.open()
for page in doc:
# Рендерим страницу в растровое изображение с заданным DPI
pix = page.get_pixmap(dpi=dpi)
# Превращаем картинку в байты формата PNG
img_data = pix.tobytes("png")
# Создаем временный одностраничный PDF из картинки и добавляем его в итоговый документ
img_doc = fitz.open("pdf", pix.pdf_bytes())
out_doc.insert_pdf(img_doc)
# Сохраняем оптимизированный "плоский" файл
out_doc.save(output_path)
out_doc.close()
doc.close()
if __name__ == "__main__":
if len(sys.argv) > 2:
rasterize_pdf(sys.argv[1], sys.argv[2])
Теперь разберем, как вызвать этот скрипт непосредственно из кода 1С:
// Формируем пути к файлам
ВходнойФайл = ПолучитьИмяВременногоФайла("pdf");
ВыходнойФайл = "C:\Saves\Invoice_Protected.pdf";
// Записываем исходный макет
ТабличныйДокумент.Записать(ВходнойФайл, ТипФайлаТабличногоДокумента.PDF);
// Формируем команду запуска скрипта Python
ПутьКСкрипту = "C:\PythonScripts\rasterize.py";
КомандаЗапуска = "python """ + ПутьКСкрипту + """ """ + ВходнойФайл + """ """ + ВыходнойФайл + """";
// Выполняем команду на сервере в режиме ожидания
ЗапуститьПриложение(КомандаЗапуска, , Истина);
// Удаляем временный исходный файл
УдалитьФайлы(ВходнойФайл);
Этот метод работает быстро, кроссплатформенно и не требует создания множества временных файлов изображений на диске, так как вся обработка и конвертация страниц происходит в оперативной памяти сервера.
Мы проанализировали различные варианты защиты документов при сохранении в PDF. Выбор конкретного инструмента зависит от ваших требований к безопасности и окружения:
ЗаписьPDF с параметрами ограничений и паролем.PyMuPDF или связка с утилитой pdftoppm обеспечат гарантированное «слияние» всех текстовых и графических слоев в монолитный рисунок, прочитать который злоумышленники не смогут.