Почему увеличивается размер двоичных данных картинки в форматированном документе и как это предотвратить

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

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

Анализ проблемы и воспроизведение ситуации

Проанализируем типовой сценарий, в котором проявляется данное поведение платформы. Создадим управляемую форму со следующими реквизитами:

  1. ФорматированныйДокумент (тип ФорматированныйДокумент), выведенный на форму с полем ввода и командной панелью.
  2. Флаг (тип Булево), выведенный в виде флажка (чекбокса).

Посмотрим на поведение в отладчике. Сначала добавляем изображение в форматированный документ и проверяем размер двоичных данных картинки:


РазмерИсходный = ФорматированныйДокумент.Элементы[0].Элементы[0].Картинка.ПолучитьДвоичныеДанные().Размер();

На данном этапе метод возвращает ожидаемый объем, соответствующий исходному файлу (например, сжатому JPEG или PNG). Однако стоит переключить флажок на клиенте и снова обратиться к серверу с контекстом формы, как при следующем получении двоичных данных размер вырастает в несколько раз. Если же изменять значение реквизита исключительно на сервере без клиентской передачи, размер картинки остается неизменным.

Причины изменения объема данных при передаче клиент–сервер

Выясним причину такого поведения платформы 1С. Здесь действуют два ключевых фактора:

  1. Сериализация контекста управляемой формы. При возникновении клиент-серверного вызова с передачей контекста (директива &НаСервере) платформа 1С сериализует все реквизиты формы, включая ФорматированныйДокумент.
  2. Внутренняя декомпрессия растра. При передаче объекта Картинка в составе контекста формы платформа не сохраняет оригинальный упакованный бинарный поток исходного файла со всеми его заголовками и метаданными. Вместо этого растровое изображение разворачивается во внутреннее несжатое представление (BMP/ARGB) либо перекодируется платформенным механизмом с параметрами по умолчанию. При последующем вызове метода ПолучитьДвоичныеДанные() на сервере возвращается уже поток пересобранного несжатого растра.

Способ 1. Использование вызовов без контекста формы

Рассмотрим основной способ предотвращения лишней сериализации. Все вспомогательные серверные процедуры, которые вызываются при изменении реквизитов (флажков, полей ввода, списков), следует объявлять с директивой &НаСервереБезКонтекста. В этом случае реквизит ФорматированныйДокумент не передается по сети и не проходит цикл десериализации/пересборки растра.

Посмотрим на пример правильной организации обработчика изменения реквизита на клиенте:


&НаКлиенте
Процедура ФлагПриИзменении(Элемент)
    
    // Передаем на сервер только необходимые примитивные данные
    ОбработатьИзменениеФлагаНаСервере(Объект.Флаг);
    
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ОбработатьИзменениеФлагаНаСервере(ЗначениеФлага)
    
    // Выполняем серверную логику без пересылки контекста формы
    // ФорматированныйДокумент не сериализуется
    
КонецПроцедуры

Способ 2. Явное сжатие картинки перед сохранением

Если избежать контекстных вызовов невозможно и данные уже изменили свой внутренний формат, перед сохранением двоичных данных в файл, том или регистр сведений следует выполнить принудительное перекодирование объекта Картинка в сжатый формат.


&НаСервере
Процедура СохранитьКартинкуВТом(ИсходнаяКартинка, ПутьКФайлу)
    
    // Преобразуем развернутый растр обратно в сжатый JPEG
    КартинкаДляСохранения = ИсходнаяКартинка.Преобразовать(ФорматКартинки.JPEG);
    ДвоичныеДанныеФайла = КартинкаДляСохранения.ПолучитьДвоичныеДанные();
    
    ДвоичныеДанныеФайла.Записать(ПутьКФайлу);
    
КонецПроцедуры

Способ 3. Вынесение встроенных изображений во вложения (CID)

Разберем архитектурный паттерн, используемый в «1С:Библиотеке стандартных подсистем» (БСП) для работы с исходящими электронными письмами. Вместо хранения "тяжелых" двоичных данных внутри тела форматированного документа применяется механизм извлечения изображений:

  1. С помощью метода ПолучитьHTML() из форматированного документа извлекается текст и встроенные Base64-изображения.
  2. Все внедренные изображения сохраняются как отдельные файлы-вложения с присвоением им идентификаторов Content-ID (CID).
  3. В исходном HTML-коде теги вида <img src="data:image/..."> заменяются на <img src="cid:идентификатор">.

Такой подход полностью исключает разрастание контекста формы и исключает проблемы с неконтролируемым увеличением размера писем при их повторном редактировании.

← На главную