При разработке печатных форм часто возникает задача вывода графической информации, которая хранится непосредственно в базе данных. Это могут быть логотипы компаний, подписи ответственных лиц, фотографии товаров или, как в нашем случае, карты геометки, полученные через внешние API. Основная сложность для начинающих разработчиков заключается в том, что изображение в базе хранится в специальном формате ХранилищеЗначения, который нельзя просто "вывести" в ячейку как текст.
В этой статье мы подробно разберем, как правильно извлечь картинку из реквизита документа и отобразить ее в табличном документе. Мы пройдем путь от подготовки макета до написания программного кода вывода.
Представим ситуацию: у нас есть документ, в котором реализовано получение карты через сервис Яндекс.Карты. Картинка сохраняется в реквизит Картинка с типом ХранилищеЗначения. Нам необходимо модифицировать существующий макет печати, чтобы в области подвала (Footer) отображалась эта карта. Рассмотрим типичный код сохранения изображения, который часто используется в управляемых формах:
&AtServer
Procedure BeforeWriteAtServer(Cancel, CurrentObject, WriteParameters)
If IsTempStorageURL(PictureMap) Then
// Помещаем картинку из временного хранилища в реквизит объекта
CurrentObject.Picture = New ValueStorage(GetFromTempStorage(PictureMap));
EndIf;
EndProcedure
Проблема заключается в том, что при попытке просто заполнить параметры макета через Параметры.Заполнить(Выборка), в печатной форме вместо картинки выводится текст "Picture ValueStorage". Это происходит потому, что система не знает, как визуализировать объект хранилища в текстовой ячейке.
Первым делом нам нужно подготовить сам макет. Вывод картинки в 1С осуществляется не в саму ячейку, а в специальный объект, который "плавает" над сеткой таблицы. Этот объект называется Рисунок.
Footer).КартаМаршрута. Это имя мы будем использовать в коде.Пропорционально, чтобы карта не искажалась при изменении размеров области.Теперь перейдем к модификации процедуры печати. Нам нужно "перехватить" область макета перед тем, как она будет выведена в итоговый табличный документ, найти в ней наш рисунок по имени и вставить туда данные из базы.
Проанализируем обновленный код процедуры печати:
Procedure Печать(Spreadsheet, Ref) Export
Template = Documents.Shipment.GetTemplate("Печать");
// ... получение данных запросом ...
Selection = Query.Execute().Select();
While Selection.Next() Do
// Получаем область подвала из макета
AreaFooter = Template.GetArea("Footer");
// Извлекаем картинку из ХранилищаЗначения реквизита ссылки
// Обратите внимание: метод Get() возвращает объект Картинка
ValueFromStorage = Selection.Picture.Get();
If ValueFromStorage <> Неопределено Тогда
// Ищем наш рисунок в коллекции Рисунки текущей области
// Имя "КартаМаршрута" должно совпадать с именем в макете
AreaFooter.Drawings.КартаМаршрута.Picture = ValueFromStorage;
Else
// Если картинки нет, можно скрыть рамку, чтобы не было пустого места
AreaFooter.Drawings.КартаМаршрута.Visible = False;
EndIf;
// Заполняем остальные параметры области (текстовые поля)
AreaFooter.Parameters.Fill(Selection);
// Выводим готовую область в итоговый документ
Spreadsheet.Put(AreaFooter);
EndDo;
EndProcedure
Рассмотрим подробнее, что происходит в коде. Основная работа выполняется через коллекцию Drawings (Рисунки). Каждый табличный документ (или его область) содержит эту коллекцию.
Метод Get() объекта ValueStorage: Этот метод извлекает содержимое из хранилища. Так как мы записывали туда объект Picture (Картинка), то и Get() вернет нам именно Picture. Если в хранилище пусто, метод вернет Undefined (Неопределено), поэтому проверка на пустое значение обязательна для избежания ошибок.
Прямое обращение через точку: В примере выше мы использовали Selection.Picture. Однако помните, что в языке запросов 1С напрямую прочитать данные из ХранилищеЗначения нельзя. Запрос вернет сам объект хранилища. Если вы работаете не через запрос, а напрямую с объектом или ссылкой, код будет выглядеть так: Ref.Picture.Get().
При работе с изображениями в 1С важно учитывать производительность. Рассмотрим несколько советов, которые помогут сделать ваш код более профессиональным:
Selection.Picture.Get() в каждом цикле может существенно замедлить процесс, так как бинарные данные картинки считываются из базы каждый раз. Если картинка статична (например, логотип компании), лучше получить ее один раз перед циклом.SizeMode (РазмерКартинки). Для карт идеально подходит PictureSizeMode.Proportional. Если же вы выводите штрих-код или QR-код, лучше использовать PictureSizeMode.RealSize, чтобы избежать проблем со сканированием.C:\Users\Admin\.... Рассмотрим, как сделать это правильнее с использованием временных файлов системы:
// Правильный способ работы с временными файлами
TempFileName = GetTempFileName("png");
Result.GetBodyAsBinaryData().Write(TempFileName);
Picture = New Picture(TempFileName);
// ... дальнейшая работа ...
// После завершения желательно удалить файл
DeleteFiles(TempFileName);
Иногда возникает вопрос: можно ли вывести картинку в макет, не сохраняя ее в базу, а имея только навигационную ссылку во временном хранилище? Да, это возможно. Для этого в процедуре печати (если она выполняется на сервере) можно использовать функцию GetFromTempStorage().
// Пример вывода из временного хранилища (например, при предпросмотре)
If IsTempStorageURL(AddressInStorage) Then
BinaryData = GetFromTempStorage(AddressInStorage);
AreaFooter.Drawings.КартаМаршрута.Picture = New Picture(BinaryData);
EndIf;
Подведем итог. Для успешного вывода картинки из хранилища значений в макет 1С нужно выполнить три условия: создать объект Рисунок в макете, присвоить ему уникальное Имя и программно передать в свойство Picture этого рисунка данные, извлеченные методом Get() из реквизита. Этот метод является стандартным и наиболее надежным для платформы 1С:Предприятие 8.3.