Разработчики при проектировании интерфейсов на управляемых формах часто сталкиваются с неприятной особенностью платформы «1С:Предприятие 8»: при выводе изображений в ячейки табличных частей, таблиц или деревьев значений стандартные свойства масштабирования работают некорректно. Настройки элемента формы, такие как РазмерКартинки (значения Пропорционально, Авторазмер, Черепица) или Масштабировать, зачастую попросту игнорируются, если картинка находится внутри строки динамической таблицы.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем ограничения платформы и рассмотрим несколько эффективных способов решения — от современных штатных механизмов до альтернативных вариантов построения интерфейса.
Поведение платформы 1С при отрисовке картинок в строках табличного поля жестко привязано к оптимизации интерфейса и производительности рендеринга. Давайте разберем два основных сценария, с которыми сталкивается разработчик:
Автоматическое и качественное пропорциональное масштабирование динамических картинок «на лету» внутри ячеек таблиц штатными свойствами отображения в 1С изначально не было предусмотрено. Поэтому нам приходится применять программные методы подготовки изображений или пересматривать архитектуру интерфейса.
Если в старых версиях платформы (до 8.3.14) разработчикам приходилось использовать внешние компоненты, библиотеки Windows (GDI/WIA) или утилиты командной строки, то в современных релизах появился отличный кроссплатформенный инструмент — объект встроенного языка ОбрабатываемаяКартинка.
Этот объект позволяет изменять физический размер (разрешение) картинки прямо на стороне сервера (включая сервера под управлением ОС Linux). Мы можем пропорционально сжать картинку до нужного размера перед тем, как поместить её в реквизит дерева значений.
Рассмотрим пример кода, который сжимает исходное изображение до ширины 64 пикселя с сохранением пропорций:
&НаСервере
Функция ПолучитьСжатуюКартинку(ДвоичныеДанныеКартинки) Экспорт
// Создаем объект Картинка из исходных двоичных данных
ИсходнаяКартинка = Новый Картинка(ДвоичныеДанныеКартинки);
// Инициализируем объект для обработки
Обработка = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// Устанавливаем целевой размер.
// Второй параметр (высота) передаем как Неопределено —
// в этом случае платформа смасштабирует высоту пропорционально ширине.
Обработка.УстановитьРазмер(64, Неопределено);
// Получаем измененную картинку
РезультатКартинка = Обработка.ПолучитьКартинку();
Возврат РезультатКартинка;
КонецФункции
После этого полученную сжатую картинку можно преобразовать в двоичные данные, поместить во временное хранилище и передать адрес в соответствующую колонку дерева значений. При фиксированной высоте строки таблицы (например, значение высоты строки 3 или 4) такое превью отобразится идеально ровно и без искажений.
Представим ситуацию, когда в базе данных хранится большое количество картинок (например, 75 000 изображений номенклатуры, как у автора темы). Если мы будем масштабировать эти картинки с помощью ОбрабатываемаяКартинка «на лету» прямо при заполнении дерева значений или при выводе строк на экран, это приведет к катастрофическому падению производительности.
Сервер будет перегружен операциями ресайза, а пользователь столкнется с задержками (фризами) при открытии формы и прокрутке дерева. Чтобы избежать этого, реализуем правильную архитектуру хранения:
ХранилищеЗначения для хранения уменьшенной копии (миниатюры/превью) изображения. Оптимальный размер превью — 64х64 или 128х128 пикселей.Посмотрим на пример кода обработки, выполняющей предварительное создание превью:
&НаСервере
Процедура СгенерироватьПревьюДляВсехКартинок()
Выборка = Справочники.НоменклатураПрисоединенныеФайлы.Выбрать();
Пока Выборка.Следующий() Цикл
// Получаем файл из базы данных
ДвоичныеДанныеФайла = Выборка.ФайлХранилище.Получить();
Если ТипЗнч(ДвоичныеДанныеФайла) <> Тип("ДвоичныеДанные") Тогда
Продолжить;
КонецЕсли;
Попытка
// Масштабируем изображение
КартинкаОбъект = Новый Картинка(ДвоичныеДанныеФайла);
Обработка = Новый ОбрабатываемаяКартинка(КартинкаОбъект);
Обработка.УстановитьРазмер(128, 128); // Фиксированный квадратный размер для сетки
Миниатюра = Обработка.ПолучитьКартинку();
// Записываем миниатюру в базу данных (в специальный реквизит)
ОбъектФайла = Выборка.ПолучитьОбъект();
ОбъектФайла.ХранилищеПревью = Новый ХранилищеЗначения(Миниатюра.ПолучитьДвоичныеДанные());
ОбъектФайла.Записать();
Исключение
// Обработка ошибок, если файл оказался не картинкой или поврежден
ЗаписьЖурналаРегистрации("РесайзКартинок", УровеньЖурналаРегистрации.Предупреждение,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Если по каким-то причинам изменять базу данных или генерировать превью нельзя, можно применить альтернативный паттерн проектирования интерфейса. Вместо того чтобы пытаться втиснуть картинку в каждую строку дерева значений, сделаем дерево максимально компактным (без колонки с картинкой), а само изображение будем выводить в отдельной области формы.
Для этого выполним следующие шаги:
Строка, содержащим адрес во временном хранилище).РазмерКартинки в значение Пропорционально. На одиночных элементах (вне таблиц) это свойство работает безупречно.ПриАктивизацииСтроки. При перемещении пользователя по строкам дерева будем оперативно считывать картинку текущей номенклатуры и помещать её адрес в поле картинки на форме.Посмотрим на программную реализацию этого подхода:
&НаКлиенте
Процедура ДеревоНоменклатурыПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элементы.ДеревоНоменклатуры.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Вызываем серверный метод для получения адреса картинки текущей номенклатуры
АдресКартинкиНаФорме = ПолучитьАдресКартинкиНаСервере(ТекущиеДанные.Номенклатура);
Иначе
АдресКартинкиНаФорме = "";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьАдресКартинкиНаСервере(Знач ТекущаяНоменклатура)
// Получаем двоичные данные изображения из базы данных
ДвоичныеДанные = ПолучитьДвоичныеДанныеКартинкиНоменклатуры(ТекущаяНоменклатура);
Если ДвоичныеДанные <> Неопределено Тогда
// Помещаем во временное хранилище и возвращаем адрес для отображения на форме
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанные);
КонецЕсли;
Возврат "";
КонецФункции
Этот способ крайне дружелюбен к производительности. Картинка считывается и передается на клиент только для одной — текущей — позиции номенклатуры, а дерево значений остается быстрым и информативным.
Для продвинутых разработчиков, которым принципиально важно выводить полноценный интерактивный каталог с крупными картинками непосредственно в табличном виде, существует обходной путь через использование элемента формы с видом Поле HTML-документа.
В этом сценарии мы формируем дерево или таблицу программно на сервере в виде HTML-кода с использованием CSS-стилей. В разметке HTML масштабирование картинок под размеры ячейки реализуется невероятно просто с помощью стандартных CSS-свойств, например:
<style>
.grid-image {
max-width: 100%;
max-height: 80px;
object-fit: contain;
}
</style>
Платформа 1С отобразит сгенерированный HTML-код внутри поля формы, сохранив все заданные пропорции картинок. При этом интерактивность (клики по строкам, выбор элементов) можно обрабатывать с помощью встроенных механизмов перехвата событий HTML-документа.
Подведем итог: несмотря на очевидную недоработку платформы в части автоматического масштабирования картинок внутри таблиц «из коробки», у разработчиков есть арсенал мощных инструментов. Для современных конфигураций идеальным выбором будет сочетание объекта ОбрабатываемаяКартинка и механизма кэширования превью, а для интерфейсной оптимизации отлично подойдет вывод картинки текущей строки в отдельную область формы.