Рассмотрим распространенную ситуацию при разработке отчетов в платформе 1С:Предприятие. При формировании прайс-листов, каталогов продукции или отчетов по остаткам возникает необходимость выводить изображение товара. Однако, если для номенклатуры используются характеристики (например, размеры обуви или цвета одежды), стандартный вывод элементов в цикле компоновки может приводить к тому, что изображение повторно создается и выводится для каждой отдельной характеристики.
При большом объеме каталога (более 20 000 позиций) такой подход вызывает критическое падение производительности. Каждая попытка добавить новый рисунок через коллекцию ДокументРезультат.Рисунки.Добавить() и обработать графический элемент приводит к перегрузке оперативной памяти и замедлению формирования отчета. Проанализируем, почему это происходит и как правильно организовать вывод единого изображения для всей группы характеристик одной номенклатуры.
Выясним причину дублирования в программном коде. Если обработка табличного документа выполняется вручную в цикле вывода процессора компоновки, необходимо контролировать момент перехода от одного товара к другому. Если текущая обрабатываемая строка принадлежит той же номенклатуре, что и предыдущая, повторное получение двоичных данных и добавление рисунка следует пропустить.
Разберем по шагам алгоритм решения с использованием контрольной переменной ТекНоменклатура:
"$").ЗначениеВыводимыхДанных с ТекНоменклатура.ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(), добавляем рисунок в ДокументРезультат.Рисунки, запоминаем текущую номенклатуру в ТекНоменклатура и позиционируем картинку в табличном документе.Посмотрим на пример реализации данного алгоритма в коде 1С:
// Инициализация контрольной переменной перед циклом вывода
ТекНоменклатура = "$";
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
// Проверяем наличие значения для вывода картинки
Если ЗначениеЗаполнено(ЗначениеВыводимыхДанных) Тогда
Если ЗначениеВыводимыхДанных = ТекНоменклатура Тогда
// Для той же номенклатуры картинку повторно не создаем
Картинка = "";
Иначе
// Новая номенклатура: добавляем объект картинки
Рис = ДокументРезультат.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рис.РазмерКартинки = РазмерКартинки.АвтоРазмер;
Индекс = ДокументРезультат.Рисунки.Индекс(Рис);
// Получаем двоичные данные файла картинки
ДвоичныеДанные = ПолучитьДвоичныеДанныеКартинкиПоНоменклатуре(ЗначениеВыводимыхДанных);
ТекНоменклатура = ЗначениеВыводимыхДанных;
Если ДвоичныеДанные <> Неопределено Тогда
ДокументРезультат.Рисунки[Индекс].Картинка = Новый Картинка(ДвоичныеДанные);
// Находим область-маркер для позиционирования
ОбластьДляКартинки = ДокументРезультат.НайтиТекст("%Картинка%");
Если ОбластьДляКартинки <> Неопределено Тогда
ВысотаКартинки = ПолучитьВысотуКартинки(КомпоновщикНастроек.Настройки);
ОбластьДляКартинки.ВысотаСтроки = ?(ВысотаКартинки = 0, 70, ВысотаКартинки);
Если ВысотаКартинки > 0 Тогда
ОбластьДляКартинки.ШиринаКолонки = ВысотаКартинки;
КонецЕсли;
ДокументРезультат.Рисунки[Индекс].Расположить(ОбластьДляКартинки);
ОбластьДляКартинки.Текст = "%КартинкаДобавлена%";
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
Функция получения двоичных данных из реквизита ФайлКартинки выглядит следующим образом:
Функция ПолучитьДвоичныеДанныеКартинкиПоНоменклатуре(Номенклатура)
Если Не ЗначениеЗаполнено(Номенклатура) Тогда
Возврат Неопределено;
КонецЕсли;
ФайлКартинки = Номенклатура.ФайлКартинки;
Если ЗначениеЗаполнено(ФайлКартинки) Тогда
Попытка
Возврат ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(ФайлКартинки);
Исключение
Возврат Неопределено;
КонецПопытки;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Важное условие: Для корректной работы этого метода порядок сортировки в запросе или в настройках СКД должен строго начинаться с поля Номенклатура, и только затем включать Характеристика. В противном случае чередование товаров приведет к лишним срабатываниям условия и повторному выводу изображений.
Рассмотренный выше вариант с использованием ДокументРезультат.Рисунки.Добавить() создает графические объекты поверх таблицы. При объемах в 20 000 строк это приводит к разрастанию размера файла и высокой нагрузке на клиентское приложение. В СКД проблему объединения ячеек под картинку можно решить без ручной работы с объектами рисунков.
Разберем порядок настройки структуры СКД:
Номенклатура, а внутри нее создаем подчиненную группировку Характеристика (или детальные записи).Номенклатура. В подчиненную группировку выводим только спецификацию (характеристику, артикул характеристики, цену, остаток).Проанализируем критически важные аспекты производительности при работе с большими объемами данных:
1. Кэширование двоичных данных: Обращение к базе данных или файловому хранилищу через ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла() на каждой итерации является ресурсоемкой операцией. Сохраняйте уже прочитанные картинки в объект Соответствие, где ключом выступает ссылка на номенклатуру или файл, а значением — объект Картинка.
// Пример использования кэша картинок
КэшКартинок = Новый Соответствие;
// В цикле получения данных:
ДвоичныеДанные = КэшКартинок[СсылкаНаФайл];
Если ДвоичныеДанные = Неопределено Тогда
ДвоичныеДанные = ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(СсылкаНаФайл);
КэшКартинок.Вставить(СсылкаНаФайл, ДвоичныеДанные);
КонецЕсли;
2. Использование миниатюр (Thumbnails): Не следует выводить исходные файлы изображений высокого разрешения в табличные отчеты. Для отчетов подготавливайте сжатые копии фиксированного размера (например, 100x100 пикселей). Это сократит объем используемой оперативной памяти в десятки раз.
3. Вывод через свойства оформления ячейки: В современных версиях платформы 1С:Предприятие 8.3 рекомендуется помещать двоичные данные или объекты Картинка непосредственно в свойство ячейки Область.Картинка вместо создания отдельных элементов поверх слоя таблицы. Это обеспечивает корректное масштабирование и быстрое формирование отчета.