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

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

47
Данный код реализует возможность автоматического нанесения штампа на 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);
		УдалитьФайлы(ИмяВременногоФайлаКартинки);
		Файл = Неопределено;
		
	конеццикла;	
	
	Документ = Неопределено;
	
	Возврат стрРезультат;
	
КонецФункции

 

47

См. также

Комментарии
Сортировка: Древо
2. user790607 15.05.18 11:32 Сейчас в теме
Интересный функционал, возьму на заметку...
aabogachev; +1 Ответить
3. ivan811 15.05.18 17:44 Сейчас в теме
Я правильно понимаю что меняется входящий pdf файл? То есть например для файл подписанного электронной подписью это сделать уже будет нельзя- подпись будет неверна?
4. aabogachev 105 15.05.18 17:47 Сейчас в теме
(3) не совсем "меняется", а делается новая версия, которая назначается активной. конечно в случае с применением электронной подписи это не сработает, но у нас по крайней мере нет и не предвидится входящих документов заверенных электронной подписью.
5. spezc 484 16.05.18 06:47 Сейчас в теме
В качестве штампа может быть только текст? Картинка может быть? Можно ли такое провернуть с doc, xls?
6. konstruktiv 16.05.18 08:23 Сейчас в теме
(5) штатный 1С: Документооборот из коробки может вставлять в doc картинку штрихкода или вместе с текстом штампа
aabogachev; +1 Ответить
7. Поручик 4109 16.05.18 16:18 Сейчас в теме
Это интересно. В прошлом году парились с этой темой, как бы картинку- штамп в файл pdf засунуть. Так ничего путного не придумали.
8. Lapitskiy 879 17.05.18 03:43 Сейчас в теме
Интересная штука!
А можно гиперссылку вставлять с помощью этой ImageMagic?
10. Kami4 17.05.18 07:08 Сейчас в теме
Интересная фича. В закладку!
11. mylogin 98 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. a.x.a 21.05.18 01:47 Сейчас в теме
Как раз то, что нужно. Спасибо за идею.
14. samvani 05.07.18 08:34 Сейчас в теме
А что с разрешением?
Если отсканированный документ, точнее первый лист, имеет другую размерность. Как ляжет штамп?
Мы реализовали вставку штампа на pdf похожим способом, но делали resize первой страницы под нужный размер, чтобы по координатам прорисовать. Но возникли ошибки при печати: pdf не понимал размер и первая страница печаталась в уменьшенном виде.
15. samvani 05.07.18 08:36 Сейчас в теме
Если бы получить оригинальный размер страницы, тогда можно было бы относительными координатами все нарисовать.
Может есть какая-то возможность получить информацию о размере листа?
Оставьте свое сообщение