Файлы PDF поддерживают внедрение в тело документа картинки с описанием, что файл PDF подписан и самой электронной подписи прямо в файл.
В платформе это реализовано начиная с версии 8.3.16. На Инфостарт есть статья на эту тему Подпись PDF в новой версии 8.3.16, но мне механизм не подошёл по ряду причин - код написан для выполнения на сервере, а при реальном использовании Крипто-ПРО ставится на клиент и вызовы должны быть соответственно на клиенте.
Грабли, на которые наступил:
* Подпись работает не для всех PDF файлов - PDF, который создан из 1С средствами 1С работает корректно, а вот PDF, сформированный другим приложением, иногда не отрабатывает.
* В качестве штампа используется Табличный документ - можно использовать вместо него картинку
* Время на добавление подписи на нормальном компьютере i7-10510U, 16Гб - 1,2 секунды, 98% времени вызов ЗаписьPDF.ЗаписатьПодпись. Есть предположение, что это время на взаимодействие с КриптоПро и концептуально его не ускорить.
Собственно сам код:
&НаКлиенте
Процедура Подписать(Команда)
ПутьКФайлыПодписанный = СтрЗаменить(ПутьКФайлу, ".pdf", "_signed.pdf");
КопироватьФайл(ПутьКФайлу, ПутьКФайлыПодписанный);
ДанныеСертификата = ДанныеСертификата(Сертификат);
Штамп = Штамп(ДанныеСертификата.Наименование, ДанныеСертификата.ДанныеСертификата);
МенеджерКриптографии = Новый МенеджерКриптографии(ДанныеСертификата.ИмяПрограммы, "", ДанныеСертификата.ТипПрограммы);
МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = Пароль;
ПодписьPDF = Новый ОписаниеПодписиPDF;
ПодписьPDF.Имя = "ПодписьДоговора";
ПодписьPDF.Сертификат = Новый СертификатКриптографии(ДанныеСертификата.ДанныеСертификата);
ПодписьPDF.ТипПодписи = ТипПодписиPDF.Сертифицирующая;
ПодписьPDF.БлокировкаДокумента = Истина;
ПодписьPDF.Верх = -10;
ПодписьPDF.Лево = 50;
ЗаписьPDF = Новый ЗаписьPDF();
ЗаписьPDF.Открыть(ПутьКФайлыПодписанный);
ЗаписьPDF.ЗаписатьПодпись(МенеджерКриптографии, ПодписьPDF, Штамп);
ЗаписьPDF.Закрыть();
КонецПроцедуры
&НаСервереБезКонтекста
Функция ДанныеСертификата(Сертификат)
ДанныеСертификата = Новый Структура("Наименование, ДанныеСертификата, ИмяПрограммы, ТипПрограммы");
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Сертификат", Сертификат);
Запрос.Текст =
"ВЫБРАТЬ
| Наименование,
| ДанныеСертификата,
| Программа.ИмяПрограммы КАК ИмяПрограммы,
| Программа.ТипПрограммы КАК ТипПрограммы,
| Организация.НаименованиеСокращенное КАК ОрганизацияНаименованиеСокращенное
|ИЗ
| Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования
|ГДЕ
| Ссылка = &Сертификат";
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ЗаполнитьЗначенияСвойств(ДанныеСертификата, Выборка);
ДанныеСертификата.ДанныеСертификата = Выборка.ДанныеСертификата.Получить();
ДанныеСертификата.Наименование = Выборка.ОрганизацияНаименованиеСокращенное + ", " + Выборка.Наименование;
КонецЕсли;
Возврат ДанныеСертификата;
КонецФункции
&НаСервереБезКонтекста
Функция Штамп(НаименованиеСертификата, ДанныеСертификата)
Штамп = Новый ТабличныйДокумент;
Сертификат = Новый СертификатКриптографии(ДанныеСертификата);
Область = Штамп.Область(1, 1, 1, 1);
Область.Текст = НаименованиеСертификата + Символы.ПС
+ Формат(ТекущаяДата(), "ДФ='dd.MM.yyyy HH:mm ""(MSK)""'")
+ ", Сертификат № "
+ СтрЗаменить(Сертификат.СерийныйНомер, " ", "");
Цвет = WebЦвета.Синий;
Линия = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
Область.ЦветТекста = Цвет;
Область.ЦветРамки = Цвет;
Область.ГраницаСверху = Линия;
Область.ГраницаСнизу = Линия;
Область.ГраницаСлева = Линия;
Область.ГраницаСправа = Линия;
Штамп.Область(, 1, , 1).ШиринаКолонки = 62;
Штамп.Область(2,1,2,1).Текст = " ";
Возврат Штамп;
КонецФункции