При разработке прайс-листов, каталогов товаров или других печатных форм часто возникает необходимость вывести изображения номенклатуры. В 1С картинки обычно хранятся в реквизитах с типом ХранилищеЗначений. Если попытаться вывести такие данные напрямую в ячейку табличного документа, платформа выдаст ошибку или выведет пустую область. Давайте подробно разберем по шагам, как правильно подготовить макет, извлечь картинку из базы данных и вывести ее на печать без потери производительности. При необходимости можно воспользоваться готовым решением для формирования прайс-листа с картинками в УНФ и Рознице.
Сначала проанализируем частую ошибку: разработчики пытаются присвоить картинку ячейке макета, задавая ей тип параметра. На самом деле, картинка в табличном документе 1С не может быть вставлена напрямую в ячейку как обычный текст.
Для вывода изображений используется специальный графический объект. Рассмотрим, как его добавить:
РисунокТовара). Именно по этому имени мы будем обращаться к объекту из программного кода.Посмотрим на частую проблему: если фотографии в базе имеют разный размер и разрешение (что бывает почти всегда), при выводе в прайс-лист они могут перекрывать соседние ячейки или растягивать строки, ломая всю верстку документа.
Чтобы этого избежать, выполним настройку свойств нашего объекта в макете:
РеальныйРазмер с ограничением области, но Пропорционально предпочтительнее для прайс-листов).Теперь разберем программную часть. В цикле обхода выборки запроса нам нужно получить данные из хранилища и передать их в наш графический объект. Метод Получить() применяется непосредственно к значению хранилища, извлеченному из базы.
Проанализируем ситуацию: у некоторых товаров может не быть фотографии. Если мы попытаемся присвоить рисунку значение Неопределено, система выдаст ошибку. Поэтому обязательно используем проверку типов.
Посмотрим на правильный пример кода заполнения области с картинкой:
// Получаем секцию макета
ОбластьДанные = Макет.ПолучитьОбласть("Данные");
// ... (выполнение запроса и начало цикла обхода выборки) ...
Пока Выборка.Следующий() Цикл
// Заполняем обычные текстовые параметры
ОбластьДанные.Параметры.Заполнить(Выборка);
// Получаем данные из хранилища
ИзвлеченнаяКартинка = Выборка.Картинка.Получить();
// Проверяем, что получена именно картинка, а не Неопределено или пустая ссылка
Если ТипЗнч(ИзвлеченнаяКартинка) = Тип("Картинка") Тогда
// Обращаемся к рисунку по имени, которое задали в конфигураторе
ОбластьДанные.Рисунки.РисунокТовара.Картинка = ИзвлеченнаяКартинка;
Иначе
// Если картинки в базе нет, выводим пустую картинку, чтобы очистить объект от предыдущего товара
ОбластьДанные.Рисунки.РисунокТовара.Картинка = Новый Картинка;
КонецЕсли;
// Выводим готовую область в итоговый табличный документ
ТабДок.Вывести(ОбластьДанные);
КонецЦикла;
Выясним причину, по которой сервер 1С может "зависнуть" при формировании большого прайс-листа. В первом сообщении темы автор получает поле с типом ХранилищеЗначений прямо в основном тексте запроса: Номенклатура.ТипПродукции.Картинка.Файл КАК Картинка.
В 1С это считается крайне плохой практикой. При таком подходе платформа попытается выгрузить бинарные данные ВСЕХ фотографий сразу в оперативную память сервера. Если в прайс-листе тысяча позиций с качественными фото, серверу просто не хватит оперативной памяти, и он упадет с ошибкой.
Как делать правильно:
В запросе необходимо получать только ссылку на объект (например, справочник или регистр), в котором лежит файл. А уже внутри цикла Пока Выборка.Следующий() Цикл обращаться к реквизиту хранилища через эту ссылку.
Рассмотрим исправленный подход к запросу и выборке:
// В запросе получаем только ссылку на присоединенный файл!
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.ТипПродукции.Картинка КАК СсылкаНаФайлКартинки
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Фирма = &Фирма";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбластьДанные.Параметры.Заполнить(Выборка);
// Получаем файл порционно, только для текущего товара
Если ЗначениеЗаполнено(Выборка.СсылкаНаФайлКартинки) Тогда
// Обращаемся к реквизиту "Файл" (типа ХранилищеЗначений) через ссылку
ИзвлеченнаяКартинка = Выборка.СсылкаНаФайлКартинки.Файл.Получить();
Если ТипЗнч(ИзвлеченнаяКартинка) = Тип("Картинка") Тогда
ОбластьДанные.Рисунки.РисунокТовара.Картинка = ИзвлеченнаяКартинка;
Иначе
ОбластьДанные.Рисунки.РисунокТовара.Картинка = Новый Картинка;
КонецЕсли;
Иначе
ОбластьДанные.Рисунки.РисунокТовара.Картинка = Новый Картинка;
КонецЕсли;
ТабДок.Вывести(ОбластьДанные);
КонецЦикла;
При таком алгоритме тяжелые бинарные данные будут считываться из базы данных порциями (по одному файлу за итерацию) и сразу же передаваться в табличный документ, не перегружая кэш и оперативную память сервера 1С. Это обеспечит стабильную работу обработки даже на огромных объемах номенклатуры. Для этой задачи также можно использовать внешнюю обработку для формирования прайс-листа с картинками в УТ 11.