В современных конфигурациях на платформе 1С:Предприятие 8.3, таких как ERP Управление предприятием, Комплексная автоматизация или Управление торговлей 11, работа с присоединенными файлами реализована через стандартные механизмы Библиотеки стандартных подсистем (БСП). Часто у разработчиков возникает задача вывести изображение (например, логотип товара, фотографию спецификации или скан документа) в печатную форму (табличный документ). Разберем по шагам, как правильно извлечь данные и отобразить их в отчете.
Первая и самая частая ошибка начинающих разработчиков — попытка получить содержимое файла напрямую из реквизита справочника ПрисоединенныеФайлы. Проанализируем ситуацию: в справочнике действительно есть реквизит ФайлХранилище с типом ХранилищеЗначения. Однако в новых версиях систем бинарные данные файла (само «тело» картинки) там отсутствуют. Это сделано для оптимизации производительности базы данных.
Разберем, где на самом деле лежат данные:
ДвоичныеДанныеФайлов.Именно поэтому стандартный метод Выборка.ФайлХранилище.Получить() часто возвращает Неопределено. Для универсального получения данных мы должны использовать программный интерфейс БСП.
Сначала нам необходимо получить ссылку на сам элемент справочника присоединенных файлов, который связан с нашим владельцем (например, спецификацией или номенклатурой). Рассмотрим пример запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПрисоединенныеФайлы.Ссылка КАК СсылкаНаФайл,
| ПрисоединенныеФайлы.Наименование КАК ИмяФайла,
| ПрисоединенныеФайлы.Расширение КАК Расширение
|ИЗ
| Справочник.РесурсныеСпецификацииПрисоединенныеФайлы КАК ПрисоединенныеФайлы
|ГДЕ
| ПрисоединенныеФайлы.ВладелецФайла = &Владелец";
Запрос.УстановитьПараметр("Владелец", СсылкаНаСпецификацию);
Выборка = Запрос.Выполнить().Выбрать();
Обратите внимание, что мы получаем именно СсылкаНаФайл. Мы не пытаемся достать бинарные данные прямо в запросе, так как работа с ХранилищеЗначения в запросах ограничена, а обращение к регистру ДвоичныеДанныеФайлов лучше доверить специализированным функциям.
Для того чтобы наш код корректно работал как с файлами в базе, так и с файлами в томах, воспользуемся общим модулем РаботаСФайлами. Рассмотрим, как получить данные в цикле обхода результата запроса:
Пока Выборка.Следующий() Цикл
// Проверяем, является ли файл картинкой по расширению
Если СтрНайти("jpg,jpeg,png,bmp,gif", НРег(Выборка.Расширение)) = 0 Тогда
Продолжить; // Пропускаем PDF, DOCX и прочее
КонецЕсли;
// Получаем двоичные данные файла
// Функция РаботаСФайлами.ДвоичныеДанныеФайла возвращает объект ДвоичныеДанные
ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(Выборка.СсылкаНаФайл);
Если ДвоичныеДанные <> Неопределено Тогда
// Переходим к формированию картинки
Попытка
КартинкаОбъект = Новый Картинка(ДвоичныеДанные);
ВывестиКартинкуВТабличныйДокумент(КартинкаОбъект, ТабДок, Макет);
Исключение
Сообщить("Ошибка формирования картинки: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
Выясним, как правильно разместить полученный объект Картинка в ячейках печатной формы. В 1С ТабличныйДокумент содержит коллекцию Рисунки. Мы можем либо использовать заранее созданный рисунок в макете, либо создавать его программно. Рассмотрим вариант с использованием именованного рисунка в области макета.
Допустим, в макете у нас есть область Строка, и внутри этой области мы создали графический объект (Рисунок) с именем D2 (тип рисунка — Картинка).
// Получаем область из макета
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
// Обращаемся к коллекции Рисунки внутри области
// ВАЖНО: Рисунок должен существовать в макете с таким именем
Если ОбластьСтрока.Рисунки.Количество() > 0 Тогда
Попытка
РисунокМакета = ОбластьСтрока.Рисунки.D2;
РисунокМакета.Картинка = КартинкаОбъект;
// Настроим пропорции, чтобы изображение не растягивалось
РисунокМакета.РазмерКартинки = РазмерКартинки.Пропорционально;
Исключение
Сообщить("В области макета не найден рисунок с именем D2");
КонецПопытки;
КонецЕсли;
// Выводим готовую область в итоговый табличный документ
ТабличныйДокумент.Вывести(ОбластьСтрока);
Проанализируем ситуацию, когда количество картинок заранее неизвестно и нам нужно создавать области под них динамически. В этом случае мы используем метод Добавить коллекции Рисунки.
// Создаем новый рисунок в области
НовыйРисунок = ОбластьСтрока.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
// Устанавливаем координаты (в миллиметрах или через привязку к ячейкам)
НовыйРисунок.Верх = 2;
НовыйРисунок.Лево = 2;
НовыйРисунок.Ширина = 40;
НовыйРисунок.Высота = 40;
// Устанавливаем саму картинку
НовыйРисунок.Картинка = КартинкаОбъект;
НовыйРисунок.РазмерКартинки = РазмерКартинки.Авторазмер;
Рассмотрим несколько нюансов, которые помогут избежать ошибок при промышленной эксплуатации решения:
Получить() или ДвоичныеДанныеФайла(). Если файл был удален с диска или произошла ошибка доступа, система вернет Неопределено, что приведет к ошибке "Несоответствие типов" при попытке присвоить это значение свойству Картинка.РаботаСФайлами в цикле может быть медленным (каждое обращение — это отдельный вызов к БД или диску). В этом случае рассмотрите возможность пакетного извлечения данных из регистра ДвоичныеДанныеФайлов одним запросом, если файлы хранятся в базе.Новый Картинка(ДвоичныеДанные), где в данных лежит текстовый файл или архив, вызовет исключение.Таким образом, мы разобрали полный цикл вывода изображения: от понимания места его хранения в архитектуре БСП до программного манипулирования объектами Рисунок в табличном документе. Использование типовых функций РаботаСФайлами является наиболее надежным способом, гарантирующим работу печатной формы при любых настройках хранения томов.