Как объединить вывод картинки для всех характеристик номенклатуры в отчете СКД

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

Анализ проблемы дублирования изображений при выводе характеристик

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

При большом объеме каталога (более 20 000 позиций) такой подход вызывает критическое падение производительности. Каждая попытка добавить новый рисунок через коллекцию ДокументРезультат.Рисунки.Добавить() и обработать графический элемент приводит к перегрузке оперативной памяти и замедлению формирования отчета. Проанализируем, почему это происходит и как правильно организовать вывод единого изображения для всей группы характеристик одной номенклатуры.

Способ 1. Программное отслеживание смены номенклатуры в цикле вывода

Выясним причину дублирования в программном коде. Если обработка табличного документа выполняется вручную в цикле вывода процессора компоновки, необходимо контролировать момент перехода от одного товара к другому. Если текущая обрабатываемая строка принадлежит той же номенклатуре, что и предыдущая, повторное получение двоичных данных и добавление рисунка следует пропустить.

Разберем по шагам алгоритм решения с использованием контрольной переменной ТекНоменклатура:

  1. Перед началом цикла вывода инициализируем служебную переменную заведомо отсутствующим значением (например, текстовым маркером "$").
  2. На каждом шаге цикла проверяем, совпадает ли ссылка ЗначениеВыводимыхДанных с ТекНоменклатура.
  3. Если значения совпадают, значит, выводится очередная характеристика того же товара — создание картинки пропускается.
  4. Если значение изменилось, считываем двоичные данные изображения с помощью функции ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(), добавляем рисунок в ДокументРезультат.Рисунки, запоминаем текущую номенклатуру в ТекНоменклатура и позиционируем картинку в табличном документе.

Посмотрим на пример реализации данного алгоритма в коде 1С:


// Инициализация контрольной переменной перед циклом вывода
ТекНоменклатура = "$";

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

ПроцессорВывода.ЗакончитьВывод();

Функция получения двоичных данных из реквизита ФайлКартинки выглядит следующим образом:


Функция ПолучитьДвоичныеДанныеКартинкиПоНоменклатуре(Номенклатура)
    
    Если Не ЗначениеЗаполнено(Номенклатура) Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    ФайлКартинки = Номенклатура.ФайлКартинки;
    Если ЗначениеЗаполнено(ФайлКартинки) Тогда
        Попытка
            Возврат ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(ФайлКартинки);
        Исключение
            Возврат Неопределено;
        КонецПопытки;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Важное условие: Для корректной работы этого метода порядок сортировки в запросе или в настройках СКД должен строго начинаться с поля Номенклатура, и только затем включать Характеристика. В противном случае чередование товаров приведет к лишним срабатываниям условия и повторному выводу изображений.

Способ 2. Настройка структуры группировок СКД и пользовательских макетов

Рассмотренный выше вариант с использованием ДокументРезультат.Рисунки.Добавить() создает графические объекты поверх таблицы. При объемах в 20 000 строк это приводит к разрастанию размера файла и высокой нагрузке на клиентское приложение. В СКД проблему объединения ячеек под картинку можно решить без ручной работы с объектами рисунков.

Разберем порядок настройки структуры СКД:

  1. Настройка структуры отчета: В окне настроек СКД создаем иерархию группировок. Верхнеуровневой группировкой делаем Номенклатура, а внутри нее создаем подчиненную группировку Характеристика (или детальные записи).
  2. Состав выбранных полей: Переносим поле с картинкой (или вычисляемое поле) исключительно в выбранные поля верхнеуровневой группировки Номенклатура. В подчиненную группировку выводим только спецификацию (характеристику, артикул характеристики, цену, остаток).
  3. Оформление макета: На вкладке «Макеты» задаем макет группировки для номенклатуры. Для ячейки с картинкой настраиваем вертикальное объединение ячеек по всей высоте строк подчиненных характеристик. Платформа самостоятельно сформирует единый блок с картинкой слева и списком характеристик справа.

Способ 3. Оптимизация производительности и кэширование изображений

Проанализируем критически важные аспекты производительности при работе с большими объемами данных:

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


// Пример использования кэша картинок
КэшКартинок = Новый Соответствие;

// В цикле получения данных:
ДвоичныеДанные = КэшКартинок[СсылкаНаФайл];
Если ДвоичныеДанные = Неопределено Тогда
    ДвоичныеДанные = ПрисоединенныеФайлы.ПолучитьДвоичныеДанныеФайла(СсылкаНаФайл);
    КэшКартинок.Вставить(СсылкаНаФайл, ДвоичныеДанные);
КонецЕсли;

2. Использование миниатюр (Thumbnails): Не следует выводить исходные файлы изображений высокого разрешения в табличные отчеты. Для отчетов подготавливайте сжатые копии фиксированного размера (например, 100x100 пикселей). Это сократит объем используемой оперативной памяти в десятки раз.

3. Вывод через свойства оформления ячейки: В современных версиях платформы 1С:Предприятие 8.3 рекомендуется помещать двоичные данные или объекты Картинка непосредственно в свойство ячейки Область.Картинка вместо создания отдельных элементов поверх слоя таблицы. Это обеспечивает корректное масштабирование и быстрое формирование отчета.

← На главную