Как правильно получить изображение номенклатуры и вывести его в печатную форму документа в 1С?

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

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

Анализ типичных ошибок при работе с изображениями

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

  1. Хранение ссылок вместо самих данных: В справочнике Номенклатура реквизит ФайлКартинки обычно содержит не сам графический файл, а ссылку на элемент справочника (например, СправочникСсылка.Файлы или СправочникСсылка.НоменклатураПрисоединенныеФайлы).
  2. Использование хранилища значений: Физически файл сохраняется либо в специальном регистре сведений (например, ПрисоединенныеФайлы с ресурсом ХранимыйФайл типа ХранилищеЗначений), либо в томах на диске сервера. Чтобы получить картинку, необходимо извлечь двоичные данные методом Получить().
  3. Попытка поместить картинку в ячейку табличной части: Табличная часть документа на форме предназначена для отображения структурированных данных (строки, числа, ссылки). Попытка вставить двоичные данные или объект Картинка напрямую в колонку формы документа без использования специализированных элементов отображения приводит к ошибкам или пустому результату. Изображение для коммерческого предложения должно выводиться непосредственно в макет печатной формы.
  4. Ошибочное обращение к объектам метаданных: Попытка написать конструкцию вида Новый Картинка(ПрисоединенныеФайлы.ХранимыйФайл) вызывает ошибку Поле объекта не обнаружено, так как имя ПрисоединенныеФайлы без предварительного чтения конкретной записи регистра является менеджером, у которого нет ресурсов.
  5. Множественные серверные вызовы: Обращение к серверу за каждым отдельным реквизитом строки (единица измерения, описание, фото) замедляет работу формы. Все данные необходимо получать за один серверный вызов.

Оптимизация получения данных на форме документа

Рассмотрим правильный подход к автозаполнению реквизитов строки при изменении номенклатуры. Вместо нескольких вызовов сервера объединим получение всех данных в одну функцию с директивой &НаСервереБезКонтекста, возвращающую структуру.

Посмотрим на пример клиент-серверного взаимодействия:


&НаКлиенте
Процедура ОборудованиеНоменклатураПриИзменении(Элемент)
    Стр = Элементы.Оборудование.ТекущиеДанные;
    Если Стр = Неопределено Тогда
        Возврат;
    КонецЕсли;

    ДанныеНоменклатуры = ПолучитьРеквизитыНоменклатуры(Стр.Номенклатура);
    
    Стр.ЕдиницаИзмерения = ДанныеНоменклатуры.ЕдиницаИзмерения;
    Стр.Описание = ДанныеНоменклатуры.Описание;
    Стр.Группа = ДанныеНоменклатуры.Родитель;
    // В табличную часть достаточно сохранить ссылку на файл, а не саму картинку
    Стр.ФайлКартинки = ДанныеНоменклатуры.ФайлКартинки;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьРеквизитыНоменклатуры(Знач СсылкаНоменклатура)
    Результат = Новый Структура;
    Результат.Вставить("ЕдиницаИзмерения", СсылкаНоменклатура.ЕдиницаИзмерения);
    Результат.Вставить("Описание", СсылкаНоменклатура.Комментарий);
    Результат.Вставить("Родитель", СсылкаНоменклатура.Родитель);
    Результат.Вставить("ФайлКартинки", СсылкаНоменклатура.ФайлКартинки);
    Возврат Результат;
КонецФункции

Обратите внимание: сохранять саму картинку или ее двоичные данные в табличную часть документа не требуется. Это неоправданно увеличивает объем базы данных. Достаточно иметь ссылку на номенклатуру или ссылку на файл, а само изображение извлекать непосредственно в момент формирования печатной формы.

Извлечение двоичных данных картинки

Разберем по шагам, как извлечь двоичные данные изображения из базы перед выводом на печать.

Способ 1. Использование процедур БСП (Библиотеки Стандартных Подсистем)

Если конфигурация разработана на основе БСП, файлы могут храниться как в базе данных, так и в томах на сервере. Для универсального получения двоичных данных рекомендуется использовать функции подсистемы работы с файлами:


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

Способ 2. Прямое чтение из регистра сведений

Если хранение организовано в регистре сведений ПрисоединенныеФайлы, где измерением выступает ПрисоединенныйФайл, а ресурсом ХранимыйФайл с типом ХранилищеЗначений, проанализируем получение данных через отбор:


ДвоичныеДанные = Неопределено;
Если ЗначениеЗаполнено(СсылкаНаФайл) Тогда
    Отбор = Новый Структура("ПрисоединенныйФайл", СсылкаНаФайл);
    ЗначенияРесурсов = РегистрыСведений.ПрисоединенныеФайлы.Получить(Отбор);
    
    Если ЗначенияРесурсов.ХранимыйФайл <> Неопределено Тогда
        ДвоичныеДанные = ЗначенияРесурсов.ХранимыйФайл.Получить();
    КонецЕсли;
КонецЕсли;

Вывод изображения в макет печатной формы

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

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

Посмотрим на реализацию процедуры печати в модуле менеджера документа:


Процедура Печать(ТабДок, Ссылка) Экспорт

    Макет = Документы.КоммерческоеПредложение.ПолучитьМакет("Печать");
    
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |    КП.Номер КАК Номер,
        |    КП.Дата КАК Дата,
        |    КП.Контрагент КАК Контрагент,
        |    КП.Оборудование.(
        |        НомерСтроки КАК НомерСтроки,
        |        Номенклатура КАК Номенклатура,
        |        Номенклатура.ФайлКартинки КАК ФайлКартинки,
        |        Количество КАК Количество,
        |        Цена КАК Цена,
        |        Сумма КАК Сумма
        |    ) КАК ТЧ_Оборудование
        |ИЗ
        |    Документ.КоммерческоеПредложение КАК КП
        |ГДЕ
        |    КП.Ссылка В (&Ссылка)";
        
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Выборка = Запрос.Выполнить().Выбрать();
    
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьСтрокаШапка = Макет.ПолучитьОбласть("ОборудованиеШапка");
    ОбластьОборудование = Макет.ПолучитьОбласть("Оборудование");
    
    ТабДок.Очистить();
    
    Пока Выборка.Следующий() Цикл
        
        ТабДок.Вывести(ОбластьЗаголовок);
        ОбластьШапка.Параметры.Заполнить(Выборка);
        ТабДок.Вывести(ОбластьШапка);
        
        ТабДок.Вывести(ОбластьСтрокаШапка);
        
        ВыборкаСтрок = Выборка.ТЧ_Оборудование.Выбрать();
        Пока ВыборкаСтрок.Следующий() Цикл
            
            ОбластьОборудование.Параметры.Заполнить(ВыборкаСтрок);
            
            // Сбрасываем картинку перед обработкой текущей строки
            ОбластьОборудование.Рисунки.Фото.Картинка = Новый Картинка;
            ОбластьОборудование.Рисунки.Фото.РазмерКартинки = РазмерКартинкиТабличногоДокумента.Пропорционально;
            
            Если ЗначениеЗаполнено(ВыборкаСтрок.ФайлКартинки) Тогда
                
                // Получаем запись из регистра сведений
                Отбор = Новый Структура("ПрисоединенныйФайл", ВыборкаСтрок.ФайлКартинки);
                ДанныеФайла = РегистрыСведений.ПрисоединенныеФайлы.Получить(Отбор);
                
                Если ДанныеФайла.ХранимыйФайл <> Неопределено Тогда
                    ДвоичныеДанные = ДанныеФайла.ХранимыйФайл.Получить();
                    Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
                        ОбластьОборудование.Рисунки.Фото.Картинка = Новый Картинка(ДвоичныеДанные);
                    КонецЕсли;
                КонецЕсли;
                
            КонецЕсли;
            
            ТабДок.Вывести(ОбластьОборудование);
            
        КонецЦикла;
        
    КонецЦикла;

КонецПроцедуры

Такой подход исключает ошибки обращения к менеджерам объектов, защищает форму от утечек памяти и гарантирует корректное позиционирование изображений номенклатуры в готовом печатном документе.

← На главную