Нанесение штампа на PDF файл при регистрации (входящий номер и дата)

Программирование - Практика программирования

Данный код реализует возможность автоматического нанесения штампа на PDF файл при регистрации (входящий номер и дата).

UPD 30.05 
Добавил параметр функции ДелатьБольшие - это позволяет ограничить установку штампа на файлы до 5Мб, если этого не сделать можно на больших входящих повесить сервак.
Письма с большими файлами можно (при необходимости) штрихкодировать вызывая функцию вручную, для этого я в меню команд Входящего документа (Форма элемента) добавил свою команду "Нанести штамп".
Добавил изменение, которое проставляет штамп только на первой странице файла. Так лучше.

Основной текст статьи:
Обязательное условие - установленный на сервере ImageMagic, Ghostscript. У меня версия ImageMagick-6.9.1-Q8, работает стабильно, как на счет других версий - не знаю.

Процедура размещена в общем модуле, обращение к ней происходит по дополнительному обработчику бизнес-события "Регистрация входящего документа".

Единственный минус, который я сейчас вижу - сильное увеличение размера файла PDF после нанесения штампа, в ситуации когда дисковое пространство стоит копейки, этот минус несущественный.

Кроме штампа я еще решил наносить штрих-код, его рисую вместе с числовым представлением на случай если придется его считать, а сканер "не возьмёт", тогда его можно будет идентифицировать по номеру кода.

Штрих-код присваивается элементу справочника - входящему документу, а не файлу, так мне кажется правильнее.

Штамп наносится только на файлы, которые помечены в карточке как "скан-копии оригинала", кроме того к версии добавляется автоматический комментарий, который указывает, что версия уже "проштампована" и не требует повторной обработки.

Текст функции привожу как есть

&НаСервере
Функция НанестиШтампНаСканКопиюОригина (ДокументСсылка, ДелатьБольшие = Ложь) Экспорт
	
	Документ = ДокументСсылка.ПолучитьОбъект();
	
	стрРезультат = Ложь;
	
	если НЕ ЗначениеЗаполнено(Документ.РегистрационныйНомер) или НЕ ЗначениеЗаполнено(Документ.ДатаРегистрации) тогда
		Возврат стрРезультат;
	конецесли;
	
	Запрос = Новый Запрос;
	
	Запрос.Текст = 
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	Файлы.ТекущаяВерсия,
	|	Файлы.Ссылка КАК Файл,
	|	Файлы.ПометкаУдаления,
	|	Файлы.Зашифрован,
	|	Файлы.ВладелецФайла КАК ВладелецФайла,
	|	ISNULL(СведенияОФайлах.ЯвляетсяОригиналом, ЛОЖЬ) КАК ЯвляетсяОригиналом
	|ИЗ
	|	Справочник.Файлы КАК Файлы
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОФайлах КАК СведенияОФайлах
	|		ПО (СведенияОФайлах.Файл = Файлы.Ссылка)
	|ГДЕ
	|	Файлы.ВладелецФайла = &ВладельцыФайлов
	|	И Файлы.ТекущаяВерсия <> ЗНАЧЕНИЕ(Справочник.ВерсииФайлов.ПустаяСсылка)
	|	И выразить(Файлы.ТекущаяВерсия.Комментарий как строка(17))<> ""Вставка штрихкода""
	|	И НЕ Файлы.ПометкаУдаления И СведенияОФайлах.ЯвляетсяОригиналом = ИСТИНА";
	
	Запрос.Параметры.Вставить("ВладельцыФайлов", Документ.Ссылка);
	
	Результат = Запрос.Выполнить().Выбрать();
	
	Пока Результат.Следующий() цикл
		
		если ВРЕГ(Результат.Файл.ТекущаяВерсия.Расширение) <> ВРЕГ("pdf") тогда
			Продолжить;
		конецесли;
		
		если ДелатьБольшие тогда
			если Результат.Файл.ТекущаяВерсия.Размер > 50000000 тогда
				Продолжить;
			конецесли;							
		иначе
			если Результат.Файл.ТекущаяВерсия.Размер > 5000000 тогда
				Продолжить;
			конецесли;				
		конецесли;
		
		ТипХраненияФайла = Результат.Файл.ТекущаяВерсия.ТипХраненияФайла;
		ИмяФайлаСПутем = ПолучитьИмяВременногоФайла(Результат.Файл.ТекущаяВерсия.Расширение);		
		
		Если ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
			
			ХранилищеФайла = РаботаСФайламиВызовСервера.ПолучитьХранилищеФайлаИзИнформационнойБазы(Результат.Файл.ТекущаяВерсия);
			ДвоичныеДанныеФайла = ХранилищеФайла.Получить();
			ДвоичныеДанныеФайла.Записать(ИмяФайлаСПутем);
			
		Иначе 
			
			Если НЕ Результат.Файл.ТекущаяВерсия.Том.Пустая() Тогда
				ИмяФайлаСПутемВТоме = ФайловыеФункции.ПолныйПутьТома(Результат.Файл.ТекущаяВерсия.Том) + Результат.Файл.ТекущаяВерсия.ПутьКФайлу; 
				КопироватьФайл(ИмяФайлаСПутемВТоме, ИмяФайлаСПутем);
				Файл = Новый Файл(ИмяФайлаСПутем);
				Файл.УстановитьТолькоЧтение(Ложь);
			КонецЕсли;
			
		КонецЕсли;
		
		ИмяФайлаРезультата = ПолучитьИмяВременногоФайла(Результат.Файл.ТекущаяВерсия.Расширение);
		ИмяФайлаРезультата2 = ПолучитьИмяВременногоФайла(Результат.Файл.ТекущаяВерсия.Расширение);
		
		ПутьКПрограммеКонвертацииPDF = РаботаСФайламиВызовСервера.ПолучитьПутьКПрограммеКонвертацииPDF();
		
		стрПуть = " -density 150 -quality 100 " + ИмяФайлаСПутем + "[0] null: ";
		
		Если ТипЗнч(Результат.Файл.ВладелецФайла) = Тип("СправочникСсылка.ВнутренниеДокументы")
				ИЛИ ТипЗнч(Результат.Файл.ВладелецФайла) = Тип("СправочникСсылка.ВходящиеДокументы")
				ИЛИ ТипЗнч(Результат.Файл.ВладелецФайла) = Тип("СправочникСсылка.ИсходящиеДокументы") Тогда
				
			Штрихкод = ШтрихкодированиеСервер.СформироватьШтрихКод();
			Штрихкод_ориг = ШтрихкодированиеСервер.ПолучитьШтрихКод(Документ.Ссылка);
			если Штрихкод_ориг <> Неопределено тогда
				Штрихкод = Штрихкод_ориг;
			иначе
				ШтрихкодированиеСервер.ПрисвоитьШтрихКод(Документ.Ссылка, Штрихкод);
			конецесли;
			НастройкиШтрихкода = ШтрихкодированиеСервер.ПолучитьПерсональныеНастройкиПоложенияШтрихкодаНаСтранице();
			
			Если НЕ Штрихкод = Неопределено Тогда
				
				ИмяВременногоФайлаКартинки = ПолучитьИмяВременногоФайла("JPG");
				ДвоичныеДанныеИзображения = ШтрихкодированиеСервер.ПолучитьКартинкуШтрихкода(Штрихкод,, НастройкиШтрихкода.ВысотаШК, НастройкиШтрихкода.ПоказыватьЦифры).ПолучитьДвоичныеДанные();				
		        ДвоичныеДанныеИзображения.Записать(ИмяВременногоФайлаКартинки);
				
				Если ДвоичныеДанныеИзображения <> Неопределено Тогда

					стрПуть = стрПуть + "( " + ИмяВременногоФайлаКартинки + " -resize +150% -quality 100 ) -gravity SouthEast -compose multiply -geometry +300+50 -layers composite ";

				конецесли;
			
			конецесли;
		конецесли;
		
		стрПуть = """" + ПутьКПрограммеКонвертацииPDF + """ " + стрПуть + " -font Tahoma -pointsize 12 -draw ""gravity SouthEast text 90,70 '"+ Строка(Документ.РегистрационныйНомер) + "'"" -draw ""gravity SouthEast text 90,40 '"+Строка(Формат(Документ.ДатаРегистрации, "ДЛФ=Д"))+ "'""" + " " + ИмяФайлаРезультата; 
		ЗапуститьПриложение(стрПуть,,Истина);	
		
		стрПуть = " -density 150 -quality 100 " + ИмяФайлаРезультата + " " + ИмяФайлаСПутем + "[1-10000]  " + ИмяФайлаРезультата2;
		стрПуть = """" + ПутьКПрограммеКонвертацииPDF + """ " + стрПуть;
		ЗапуститьПриложение(стрПуть,,Истина);	
		
		ДвоичныеДанныеРезультата = Новый ДвоичныеДанные(ИмяФайлаРезультата2);
		
		АвтозаполнениеШаблоновФайловСервер.ОбновитьВерсиюИзДвоичныхДанных(ДвоичныеДанныеРезультата, Результат.Файл, "Вставка штрихкода");
		
		стрРезультат = Истина;
		
		УдалитьФайлы(ИмяФайлаСПутем);
		УдалитьФайлы(ИмяФайлаРезультата);
		УдалитьФайлы(ИмяФайлаРезультата2);
		УдалитьФайлы(ИмяВременногоФайлаКартинки);
		Файл = Неопределено;
		
	конеццикла;	
	
	Документ = Неопределено;
	
	Возврат стрРезультат;
	
КонецФункции

 

См. также

Комментарии
2. Сан Саныч (user790607) 15.05.18 11:32 Сейчас в теме
Интересный функционал, возьму на заметку...
aabogachev; +1 Ответить
3. иван лопатин (ivan811) 15.05.18 17:44 Сейчас в теме
Я правильно понимаю что меняется входящий pdf файл? То есть например для файл подписанного электронной подписью это сделать уже будет нельзя- подпись будет неверна?
4. Алексей Богачев (aabogachev) 93 15.05.18 17:47 Сейчас в теме
(3) не совсем "меняется", а делается новая версия, которая назначается активной. конечно в случае с применением электронной подписи это не сработает, но у нас по крайней мере нет и не предвидится входящих документов заверенных электронной подписью.
5. Ildar Gabdrakhmanov (spezc) 475 16.05.18 06:47 Сейчас в теме
В качестве штампа может быть только текст? Картинка может быть? Можно ли такое провернуть с doc, xls?
6. Денис (konstruktiv) 16.05.18 08:23 Сейчас в теме
(5) штатный 1С: Документооборот из коробки может вставлять в doc картинку штрихкода или вместе с текстом штампа
aabogachev; +1 Ответить
7. Сергей Ожерельев (Поручик) 4085 16.05.18 16:18 Сейчас в теме
Это интересно. В прошлом году парились с этой темой, как бы картинку- штамп в файл pdf засунуть. Так ничего путного не придумали.
8. Алексей Лапицкий (Lapitskiy) 875 17.05.18 03:43 Сейчас в теме
Интересная штука!
А можно гиперссылку вставлять с помощью этой ImageMagic?
10. White Dr. (Kami4) 17.05.18 07:08 Сейчас в теме
Интересная фича. В закладку!
11. И А (mylogin) 97 17.05.18 11:39 Сейчас в теме
Автор забыл упомянуть, что помимо ImageMagick необходимо будет установить Ghostscript, Magick работает с pdf через него.

Единственный минус, который я сейчас вижу - сильное увеличение размера файла PDF после нанесения штампа, в ситуации когда дисковое пространство стоит копейки, этот минус несущественный.


Use -type optimize to ensure the image is written in the smallest possible file size. - это должно помочь.
Так же через -type можно задать цветовой режим изображения, например если не нужны цвета, то можно использовать "оттенки серого" , -type Grayscale или -type GrayscaleMatte - с альфа-каналом для поддержки прозрачности. Это во первых ускорит работу скрипта, во вторых естественно уменьшится размер выходного файла.

Делал подобное, но для штампов ЭЦП. У меня файлы формировались на лету, только для просмотра и печати, эти версии не сохранялись по понятным причинам.
aabogachev; +1 Ответить
12. Роман Ложкин (webester) 28 17.05.18 12:18 Сейчас в теме
(0)Тоже не смогли осилить ком объект? Я устал с ним воевать :( тоже делал через выполнить.
aabogachev; +1 Ответить
13. Aleksey Khokhlov (a.x.a) 21.05.18 01:47 Сейчас в теме
Как раз то, что нужно. Спасибо за идею.
Оставьте свое сообщение