Картинки и файлы во встроенном языке 1С 8.3: загрузка, хранение, вывод в форму и отчёт
Содержание
Чтобы программно установить картинку в 1С 8.3, получите её двоичные данные, поместите их во временное хранилище через ПоместитьВоВременноеХранилище() и присвойте полученный адрес реквизиту формы, к которому привязано поле картинки. Для хранения в базе те же данные кладут в реквизит типа ХранилищеЗначения. Объект Картинка нужен для макетов, кнопок и проверки формата.
Частая ошибка новичков — записать в реквизит объекта сам объект Картинка или путь к файлу на диске пользователя. Первое платформа не позволит: тип Картинка нельзя выбрать для реквизита справочника или документа. Второе сломается на соседнем компьютере, где такого файла нет. Всё, что описано ниже, относится к управляемым формам платформы 8.3 и не зависит от конфигурации.
Какие типы данных отвечают за графику
Работа с изображением в 1С всегда идёт через несколько типов. Каждый решает свою задачу, и путаница между ними — главный источник ошибок.
| Тип | Где живёт | Для чего нужен |
|---|---|---|
ДвоичныеДанные | клиент и сервер | «сырые» байты файла: PNG, JPEG, PDF, что угодно |
Картинка | клиент и сервер | изображение, которое понимает платформа: макет, кнопка, рисунок |
ХранилищеЗначения | реквизит объекта в базе | упаковка двоичных данных для записи в справочник или документ |
| Строка — адрес во временном хранилище | реквизит формы | передача данных между клиентом и сервером, источник для поля картинки |
ФорматКартинки | перечисление | проверка формата: PNG, JPEG, GIF, BMP и другие |
Переходы между типами выглядят так:
- 📥 из файла получаем
ДвоичныеДанные; - 🖼
Новый Картинка(ДвоичныеДанные)— превращаем байты в картинку; - 📤
Картинка.ПолучитьДвоичныеДанные()— обратно в байты; - 💾
Новый ХранилищеЗначения(ДвоичныеДанные)— упаковка для записи,Хранилище.Получить()— распаковка; - 🔗
ПоместитьВоВременноеХранилище()иПолучитьИзВременногоХранилища()— передача через адрес.
Для картинок из конфигурации (общих картинок в дереве метаданных) двоичные данные не нужны. Их берут напрямую: БиблиотекаКартинок.ИмяКартинки.
Как загрузить картинку из файла программно
Источник файла определяет, где выполняется код. Файл с компьютера пользователя доступен только на клиенте. Файл из сетевой папки или по URL удобнее читать на сервере.
С компьютера пользователя через диалог
Клиент не может просто «открыть» локальный файл на сервере. Файл сначала передают во временное хранилище, а сервер забирает его оттуда по адресу.
&НаКлиенте
Процедура ЗагрузитьФото(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат; // пользователь закрыл диалог
КонецЕсли;
Расширение = НРег(Прав(ВыбранноеИмяФайла, 4));
Если СтрНайти(".png|.jpg|jpeg|.gif|.bmp", Расширение) = 0 Тогда
ПоказатьПредупреждение(, "Выберите файл изображения: PNG, JPG, GIF или BMP.");
Возврат;
КонецЕсли;
ЗагрузитьФотоНаСервере(Адрес);
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьФотоНаСервере(Адрес)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
Объект.Фото = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
АдресФото = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
Модифицированность = Истина;
КонецПроцедуры
Здесь Объект.Фото — реквизит справочника типа ХранилищеЗначения, а АдресФото — строковый реквизит формы, к которому привязано поле картинки. Четвёртый параметр Истина означает интерактивный выбор, а УникальныйИдентификатор формы привязывает время жизни данных к открытой форме.
С диска сервера
Если картинки лежат в общей папке, читайте их на сервере конструктором двоичных данных:
&НаСервере
Функция ПрочитатьКартинкуССервера(ПутьКФайлу)
Файл = Новый Файл(ПутьКФайлу);
Если Не Файл.Существует() Тогда
ВызватьИсключение СтрШаблон("Файл не найден: %1", ПутьКФайлу);
КонецЕсли;
Возврат Новый ДвоичныеДанные(ПутьКФайлу);
КонецФункции
В клиент-серверном варианте путь относится к компьютеру с сервером 1С, а не к рабочему месту. Права на папку нужны пользователю, от имени которого запущена служба сервера. Сетевую папку указывайте в формате UNC: \\fileserver\photo\001.jpg, подключённые диски службе не видны.
По ссылке из интернета
&НаСервере
Функция СкачатьКартинку(Сервер, ПутьНаСервере)
Соединение = Новый HTTPСоединение(Сервер, 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL);
Запрос = Новый HTTPЗапрос(ПутьНаСервере);
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния <> 200 Тогда
ВызватьИсключение СтрШаблон("Сервер вернул код %1", Формат(Ответ.КодСостояния, "ЧГ=0"));
КонецЕсли;
Возврат Ответ.ПолучитьТелоКакДвоичныеДанные();
КонецФункции
Вызов: СкачатьКартинку("example.com", "/images/logo.png"). Таймаут 30 секунд защищает от зависшего сеанса, если удалённый сайт не отвечает.
Где хранить изображение и как прикрепить файл к документу
Есть три рабочих способа сохранить картинку за объектом. Выбор зависит от того, сколько файлов будет и нужна ли история.
| Способ | Когда подходит | Риски |
|---|---|---|
Реквизит ХранилищеЗначения в самом объекте | одно фото на элемент: товар, сотрудник, логотип | объект становится тяжёлым, каждое чтение тянет картинку |
| Отдельный справочник «Изображения» с владельцем | несколько файлов на элемент, их надо добавлять и удалять | нужна своя форма и код удаления |
| Присоединённые файлы БСП | типовая конфигурация, нужны версии, тома, права | придётся разобраться с программным интерфейсом библиотеки |
Запись в реквизит объекта
Если реквизит заполняется не из формы, а, например, при загрузке справочника, код такой:
ТоварОбъект = Товар.ПолучитьОбъект();
ТоварОбъект.Фото = Новый ХранилищеЗначения(ДвоичныеДанные, Новый СжатиеДанных(9));
ТоварОбъект.Записать();
Прочитать обратно: ДвоичныеДанные = Товар.Фото.Получить();. Если картинку ни разу не записывали, Получить() вернёт Неопределено, и это надо проверять.
Присоединённый файл в типовой конфигурации
В конфигурациях на БСП 3.x (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) к документу файл прикрепляют через общий модуль РаботаСФайлами. Сначала данные кладут во временное хранилище, потом создают файл:
ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
ПараметрыФайла.ВладелецФайлов = ДокументСсылка;
ПараметрыФайла.ИмяБезРасширения = "Скан договора";
ПараметрыФайла.РасширениеБезТочки = "jpg";
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
ФайлСсылка = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, Адрес);
Плюс такого пути: файл появится в стандартной панели присоединённых файлов, попадёт в тома, если они настроены, и будет подчиняться правам. Состав полей структуры параметров зависит от версии БСП — откройте функцию ПараметрыДобавленияФайла в конфигураторе и посмотрите комментарий к ней.
Как показать картинку на форме программно
Поле картинки на управляемой форме не умеет показывать ХранилищеЗначения напрямую. Ему нужен строковый реквизит с адресом во временном хранилище или навигационной ссылкой.
Подготовка формы
- Добавьте реквизит формы
АдресФотос типомСтрокабез ограничения длины. - Перетащите его на форму. В свойстве элемента
ВидвыберитеПоле картинки. - В свойстве
Размер картинкипоставьтеПропорционально, чтобы фото не искажалось. - Заполните
Текст невыбранной картинки, например «Фото не загружено».
Заполнение при открытии
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ОбновитьКартинку();
КонецПроцедуры
&НаСервере
Процедура ОбновитьКартинку()
ДвоичныеДанные = Объект.Фото.Получить();
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
АдресФото = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);
Иначе
АдресФото = "";
КонецЕсли;
КонецПроцедуры
Для уже записанного объекта есть второй вариант без промежуточного хранилища:
АдресФото = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Фото");
Он экономит память сервера, но работает только для записанного элемента. В новом, ещё не записанном объекте ссылки нет — используйте временное хранилище.
Картинка на кнопке или декорации
Для элементов оформления данные из базы обычно не нужны:
Элементы.КнопкаПечать.Картинка = БиблиотекаКартинок.Печать;
Элементы.ДекорацияЛоготип.Картинка = Новый Картинка(ДвоичныеДанные);
Имя после БиблиотекаКартинок — это имя общей картинки в ветке Общие → Общие картинки. Код выполняется на сервере, например в ПриСозданииНаСервере, или на клиенте, если данные уже там.
Вывод изображения в отчёт и печатную форму
В табличном документе картинка выводится через рисунок в макете. Это основной способ для печатных форм: карточки товара, бейджа, акта с фото.
Через рисунок в макете
- В макете выделите область, например
Шапка. - Вставьте рисунок через меню
Таблица → Рисунки → Картинкаи задайте ему имя, скажемФото. - В коде заполните рисунок перед выводом области:
Макет = ПолучитьМакет("КарточкаТовара");
Область = Макет.ПолучитьОбласть("Шапка");
ДвоичныеДанные = Товар.Фото.Получить();
Если ДвоичныеДанные <> Неопределено Тогда
Область.Рисунки.Фото.Картинка = Новый Картинка(ДвоичныеДанные);
КонецЕсли;
ТабДок.Вывести(Область);
Если фото у элемента нет, рисунок останется пустым. Чтобы не было пустой рамки, задайте у рисунка в макете прозрачную линию или удалите его из области: Область.Рисунки.Удалить(Область.Рисунки.Фото).
Рисунок без макета
Можно добавить рисунок в готовый табличный документ напрямую:
Рисунок = ТабДок.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = Новый Картинка(ДвоичныеДанные);
Рисунок.Расположить(ТабДок.Область("R2C2:R10C5"));
Метод Расположить() вписывает рисунок в указанный диапазон ячеек. Для отчёта на СКД картинку обычно добавляют уже в полученный табличный документ, после вывода результата компоновки.
Для печати списка из сотен товаров с фото не читайте Фото.Получить() в цикле по ссылкам. Выберите хранилища одним запросом и получайте данные из выборки — это заметно быстрее.
Генерация картинки средствами встроенного языка
Иногда изображения нет в файле, его нужно создать: QR-код для чека, график для письма, картинку из строки Base64, пришедшей в JSON.
Из строки Base64
Внешние сервисы часто присылают изображение строкой. Превратить её в картинку можно одной строкой кода:
ДвоичныеДанные = Base64Значение(СтрокаBase64);
Картинка = Новый Картинка(ДвоичныеДанные);
Если строка начинается с префикса вида data:image/png;base64,, отрежьте всё до запятой включительно, иначе Base64Значение() вернёт пустые данные.
Из диаграммы
Объект Диаграмма можно заполнить на сервере и снять с него картинку заданного размера в пикселях:
Картинка = Диаграмма.ПолучитьКартинку(800, 400);
ДвоичныеДанные = Картинка.ПолучитьДвоичныеДанные();
Дальше такие данные можно вложить в письмо, сохранить в хранилище или вывести в макет.
QR-код и штрихкод
В конфигурациях на БСП 3.1 и новее есть общий модуль ГенерацияШтрихкода. Его функция ИзображениеШтрихкода() принимает структуру параметров и возвращает структуру с готовой картинкой и двоичными данными. Параметры получают функцией ГенерацияШтрихкода.ПараметрыГенерацииШтрихкода(), заполняют ширину, высоту, тип кода и сам текст. Набор полей и допустимые типы смотрите в комментарии к функции в своей версии библиотеки.
Размер изображений и как не раздуть базу
Каждое фото в ХранилищеЗначения хранится в той же таблице, что и объект. Тысяча товаров по 5 МБ — это 5 ГБ, которые попадут в каждую выгрузку .dt и каждый бэкап.
Что реально помогает:
- 📏 Ограничьте размер на входе. Проверка
ДвоичныеДанные.Размер() > 2 * 1024 * 1024отсекает файлы больше 2 МБ (2 097 152 байта). - 🗜
Новый СжатиеДанных(9)в конструкторе хранилища почти не уменьшает JPEG и PNG: эти форматы уже сжаты. Выигрыш есть для BMP и TIFF. - 🖼 Просите пользователей загружать JPEG вместо BMP и снимков с телефона в полном разрешении. Фото товара 1000×1000 точек в JPEG обычно занимает 100–300 КБ.
- 📦 Выносите картинки из основного объекта в отдельный справочник. Тогда открытие списка товаров не тянет за собой мегабайты данных.
- 💽 Для больших объёмов используйте хранение файлов в томах на диске — в типовых конфигурациях это настройка присоединённых файлов в разделе
Администрирование.
Временное хранилище тоже расходует память сервера. Когда адрес больше не нужен, освобождайте его: УдалитьИзВременногоХранилища(Адрес). Особенно это касается обработок, которые в цикле загружают сотни файлов.
Защитный код: проверки и обработка исключений
Битый файл, переименованный документ Word с расширением .jpg, пропавшая сетевая папка — всё это должно заканчиваться понятным сообщением, а не падением формы.
Проверка, что файл действительно изображение
&НаСервере
Функция ЭтоКартинка(ДвоичныеДанные)
Если ТипЗнч(ДвоичныеДанные) <> Тип("ДвоичныеДанные") Или ДвоичныеДанные.Размер() = 0 Тогда
Возврат Ложь;
КонецЕсли;
Попытка
Картинка = Новый Картинка(ДвоичныеДанные);
Возврат Картинка.Формат() <> ФорматКартинки.НеизвестныйФормат;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Проверка по расширению в имени файла — только первый фильтр. Окончательно формат определяет Картинка.Формат().
Запись ошибки в журнал регистрации
Попытка
ДвоичныеДанные = СкачатьКартинку(Сервер, Путь);
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаКартинок", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ОбщегоНазначения.СообщитьПользователю("Не удалось загрузить изображение. Подробности в журнале регистрации.");
Возврат;
КонецПопытки;
ОбщегоНазначения.СообщитьПользователю есть в конфигурациях на БСП. В самописной базе замените его на Сообщить() или объект СообщениеПользователю.