Как объединить несколько файлов TIFF в один многостраничный документ в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе автоматизации документооборота, сканирования или обработки архивных документов программисты часто сталкиваются с задачей объединения нескольких графических файлов формата TIFF в один единый многостраничный документ. Формат TIFF (Tagged Image File Format) уникален тем, что, в отличие от JPEG или PNG, он изначально поддерживает многостраничность. Это делает его крайне удобным для хранения сканов договоров, первичных документов и бухгалтерской отчетности.

В этой статье мы подробно разберем, как решить задачу объединения таких файлов в среде 1С:Предприятие. Мы проанализируем популярные решения с использованием внешних утилит, укажем на критические ошибки производительности, которые часто совершают разработчики, и рассмотрим современный нативный способ решения этой задачи без привлечения стороннего программного обеспечения.

Анализ проблемы и разбор неоптимального решения

Рассмотрим стандартную ситуацию, с которой столкнулся автор темы на форуме. Имеется каталог с набором одностраничных файлов TIFF (например, полученных с потокового сканера), имена которых начинаются с префикса Вх. Задача состоит в том, чтобы собрать их все в один файл Результат.tiff.

В ходе обсуждения участники пришли к следующему коду для последовательного объединения файлов с помощью консольной утилиты ImageMagick:


Первая = Истина;
Для каждого Стр1 Из НайденныеФайлы Цикл
    Нстр = ТЧФайлов.Добавить();
    Нстр.ФайлTIFF = Стр1.Имя;    
    
    Если Первая = Истина Тогда         
        ЗапускОбъединения = (КомандаПрограммы + " " + Стр1.Имя + " " + ИмяФайла);
        ЗапуститьПриложение(ЗапускОбъединения, ИмяКаталога, Истина, КодВозврата);
        Первая = Ложь;
        Продолжить;
    КонецЕсли; 
    
    // Внимание: в этой строке на форуме содержится синтаксическая ошибка!
    ЗапускОбъединения = (КомандаПрограммы + " " + ИмяФайла + " " + Стр.ИмяФайла + " " + ИмяФайла);
    ЗапуститьПриложение(ЗапускОбъединения, ИмяКаталога, Истина, КодВозврата);
КонецЦикла;

Давайте подробно проанализируем этот код и выясним, почему использовать его в реальных рабочих базах категорически не рекомендуется.

Во-первых, в коде присутствует явная опечатка. В строке формирования команды используется переменная Стр и обращение к свойству ИмяФайла, хотя в цикле обход идет по переменной Стр1, а имя файла хранится в свойстве Имя или ПолноеИмя системного объекта Файл. При попытке выполнить этот код система 1С выдаст ошибку времени выполнения (Runtime Error).

Во-вторых, и это самое главное, предложенный алгоритм страдает катастрофическим падением производительности при росте количества объединяемых файлов. Давайте разберем по шагам, что происходит на диске при каждой итерации цикла:

  1. На первой итерации создается базовый файл Результат.tiff, содержащий первую страницу.
  2. На второй итерации утилита convert.exe считывает с диска Результат.tiff (1 страница), считывает второй файл, декодирует их в оперативной памяти, объединяет и записывает обратно на диск файл Результат.tiff (уже 2 страницы).
  3. На сотой итерации утилита считывает файл Результат.tiff (в котором уже накоплено 99 страниц), полностью декодирует его структуру, считывает сотый файл, производит объединение и записывает на диск новый файл объемом в 100 страниц.

В результате мы получаем квадратичную сложность алгоритма по дисковым операциям записи. При обработке большого пакета документов (например, 200–300 листов с высоким разрешением) сервер 1С начнет испытывать колоссальную нагрузку на дисковую подсистему, а сам процесс объединения может затянуться на долгие минуты, вызывая зависание сеанса пользователя или фонового задания.

Оптимальное объединение через ImageMagick в один вызов

Как совершенно справедливо заметил один из участников форума, внешняя утилита ImageMagick способна самостоятельно работать с масками файлов и выполнять склейку за один проход, без необходимости поочередного перебора файлов в цикле 1С.

Рассмотрим, как правильно составить команду для консоли. Вместо того чтобы вызывать утилиту N раз, мы можем передать ей маску файлов и путь к результирующему файлу. Утилита сама найдет все подходящие исходники, считает их в память в один поток и запишет готовый многостраничный TIFF на диск ровно один раз.

Обратите внимание, что синтаксис зависит от используемой версии ImageMagick:

Ниже представлен правильный и эффективный шаблон кода 1С для вызова утилиты ImageMagick за один проход:


ИмяКаталога = "D:\Temp\2020\";
МаскаФайлов = "Вх*.tiff";
ИмяРезультата = "Результат.tiff";

ПутьКПрограмме = "C:\Program Files\ImageMagick-7.1.0-Q16-HDRI\magick.exe";

// Формируем параметры запуска. Все пути к файлам обязательно оборачиваем в двойные кавычки,
// чтобы избежать проблем, если в путях к папкам будут содержаться пробелы.
ПараметрыЗапуска = """" + ИмяКаталога + МаскаФайлов + """ """ + ИмяКаталога + ИмяРезультата + """";

ПолнаяКоманда = """" + ПутьКПрограмме + """ " + ПараметрыЗапуска;

КодВозврата = 0;
ЗапуститьПриложение(ПолнаяКоманда, ИмяКаталога, Истина, КодВозврата);

Если КодВозврата = 0 Тогда
    Сообщить("Объединение файлов успешно завершено!");
Иначе
    Сообщить("При объединении файлов возникла ошибка. Код возврата: " + Строка(КодВозврата));
КонецЕсли;

Этот метод работает в сотни раз быстрее циклического перебора, так как дисковые операции сводятся к минимуму. Однако у него остается один существенный недостаток: необходимость установки стороннего ПО (ImageMagick) на каждый рабочий компьютер пользователя или на сервер приложений 1С, а также настройка прав операционной системы на запуск исполняемых файлов из кода 1С.

Современное решение: нативное объединение средствами 1С (Платформа 8.3.15+)

Начиная с версии платформы 1С:Предприятие 8.3.15, разработчики получили мощный инструмент для работы с изображениями — объект ОбрабатываемаяКартинка. Этот объект позволяет выполнять базовые операции с графикой (изменение размера, поворот, конвертация форматов) непосредственно в коде 1С без использования сторонних внешних компонент или консольных утилит.

С помощью ОбрабатываемаяКартинка мы можем собрать многостраничный TIFF полностью в оперативной памяти сервера или клиента. Посмотрим, как это реализовать на практике.

Разберем готовый программный код:


// Определяем исходные параметры
КаталогИсточника = "D:\Temp\2020";
МаскаПоиска = "Вх*.tiff";
ПутьКРезультату = "D:\Temp\2020\Результат.tiff";

// Шаг 1. Находим все файлы по маске
НайденныеФайлы = НайтиФайлы(КаталогИсточника, МаскаПоиска, Ложь);

Если НайденныеФайлы.Количество() = 0 Тогда
    ВызватьИсключение "Не найдено ни одного файла для объединения по маске " + МаскаПоиска;
КонецЕсли;

// Шаг 2. Заполняем массив объектами "Картинка"
МассивКартинок = Новый Массив;
Для каждого Файл Из НайденныеФайлы Цикл
    // Считываем файл с диска как объект Картинка и добавляем в массив
    ТекущаяКартинка = Новый Картинка(Файл.ПолноеИмя);
    МассивКартинок.Добавить(ТекущаяКартинка);
КонецЦикла;

// Шаг 3. Инициализируем объект "ОбрабатываемаяКартинка"
// Передаем в конструктор массив наших картинок и указываем целевой формат TIFF
Обрабатываемая = Новый ОбрабатываемаяКартинка(МассивКартинок, ФорматКартинки.TIFF);

// Шаг 4. Получаем результирующее многостраничное изображение
РезультирующаяКартинка = Обрабатываемая.ПолучитьКартинку();

// Шаг 5. Записываем файл на диск
РезультирующаяКартинка.Записать(ПутьКРезультату);

Сообщить("Успешно объединено файлов: " + Строка(МассивКартинок.Количество()));

Рассмотрим подробнее преимущества этого подхода:

Легковесная альтернатива для старых версий платформ — утилита tiffcp

Если ваша информационная база по-прежнему работает на платформе версии ниже 8.3.15, а устанавливать тяжелый графический пакет ImageMagick (который весит более 100 МБ в установленном виде) нет возможности, хорошей альтернативой будет использование специализированной утилиты tiffcp.

Утилита tiffcp входит в состав официального свободно распространяемого набора библиотек LibTIFF. Она весит менее 1 мегабайта и предназначена исключительно для копирования и конкатенации (объединения) TIFF-файлов.

Для объединения файлов с ее помощью используется следующий синтаксис запуска:


// Специфика синтаксиса tiffcp позволяет перечислить все исходные файлы через пробел, 
// а в конце указать имя результирующего файла.
ЗапускКоманды = "D:\LibTIFF\tiffcp.exe D:\Temp\2020\Вх*.tiff D:\Temp\2020\Результат.tiff";
ЗапуститьПриложение(ЗапускКоманды, , Истина);

Если же вам требуется программный отбор файлов в коде 1С перед их склеиванием, вы можете использовать параметр добавления -a (append). В отличие от ImageMagick, утилита tiffcp -a не перекодирует файл заново при добавлении страницы, а просто физически дописывает структуру новой страницы в конец существующего файла. Это делает циклическое добавление страниц через tiffcp -a очень быстрым и безопасным для дисков процессом.

Резюме и рекомендации

Подводя итоги, при решении задачи объединения графических документов в 1С рекомендуем придерживаться следующих правил:

  1. Если версия вашей платформы 1С:Предприятие 8.3.15 и выше — всегда используйте нативный объект ОбрабатываемаяКартинка. Это наиболее надежный, безопасный и современный способ, который избавит вас от проблем при миграции сервера на Linux или при обновлении операционных систем.
  2. Если вы вынуждены работать на старых версиях платформы, избегайте циклического вызова внешних утилит для дозаписи файлов по одной странице. Старайтесь передавать всю маску файлов для склейки за один вызов программы.
  3. При использовании внешнего ПО отдавайте предпочтение легковесным специализированным утилитам вроде tiffcp, если вам не требуется сложная обработка изображений (изменение цветовой палитры, наложение фильтров и т.д.), которую предоставляет ImageMagick.
← На главную