Сохраняем изображение из вложений 1С: вручную, кодом, через COM и HTTP

· 10 мин

Содержание

Получить картинку из присоединенных файлов 1С проще всего без кода: откройте карточку объекта, нажмите на скрепку «Присоединенные файлы», выделите изображение и выполните команду «Сохранить как». Программно то же самое делает одна строка на БСП: РаботаСФайлами.ДвоичныеДанныеФайла(Ссылка), а дальше ДвоичныеДанные.Записать(ПутьКФайлу).

Частое заблуждение — искать картинку в самом элементе справочника. Его там нет. В типовых конфигурациях 8.3 файл лежит отдельно: либо в служебной таблице информационной базы, либо на диске сервера в томах хранения. Элемент «Номенклатура» хранит только ссылку на запись присоединенного файла.

Где 1С хранит присоединенные файлы и картинки

Почти все типовые конфигурации на 8.3 (Бухгалтерия 3.0, ЗУП 3.1, УТ 11, КА, ERP) используют подсистему «Работа с файлами» из Библиотеки стандартных подсистем (БСП). Устроена она одинаково.

📁 Карточка файла. Для каждого владельца есть свой справочник присоединенных файлов. Имя строится по шаблону <Владелец>ПрисоединенныеФайлы: например, НоменклатураПрисоединенныеФайлы, КонтрагентыПрисоединенныеФайлы. В карточке — имя, расширение, размер, автор, ссылка на владельца (ВладелецФайла).

💾 Двоичные данные. Сами байты картинки лежат не в карточке. Где именно — решает настройка базы:

Способ храненияГде байтыЧто важно при извлечении
В информационной базеСлужебный регистр БСП внутри базыПопадает в выгрузку .dt, растёт размер базы
В томах на дискеКаталог на сервере или сетевой папкеНужен доступ к тому; файл может «потеряться», если том перенесли

Режим включают в разделе Администрирование → Общие настройки, блок про присоединенные файлы. Там же настраивают тома хранения.

🖼 Отдельные картинки в реквизитах. В старых и самописных конфигурациях изображение часто хранят прямо в реквизите типа ХранилищеЗначения. Это не присоединенный файл, и достают его иначе — об этом ниже.

Не читайте таблицы БСП напрямую запросом. Структура служебных регистров меняется между версиями библиотеки. Программный интерфейс РаботаСФайлами сам разберётся, где лежат байты — в базе или в томе.

Какой способ извлечения выбрать

СпособКогда подходитОграничения
Вручную «Сохранить как»1–10 картинокТолько руками
Код на БСПДоработка формы, кнопка «Выгрузить фото»Нужен доступ к конфигурации или расширение
Внешняя обработкаРазовая выгрузка всего каталогаПишет файлы на сервере 1С
COM-соединениеСкрипт на Windows забирает файлы по расписаниюЛицензия на сеанс, разрядность comcntr.dll
HTTP-сервисСайт, приложение, интеграцияНужен веб-сервер и публикация

Как сохранить картинку из вложений вручную

Если нужно одно-два изображения, программировать не нужно.

  1. Откройте карточку объекта: товара, контрагента, документа.
  2. В командной панели найдите кнопку со скрепкой — «Присоединенные файлы». У номенклатуры в БП и УТ к файлам ведёт и область картинки в карточке.
  3. В списке файлов выделите нужный — по расширению jpg, png, gif, bmp.
  4. Выполните «Сохранить как» (команда есть в контекстном меню и в меню Ещё).
  5. Укажите папку на своём компьютере.

Альтернатива — «Открыть». Файл откроется в программе просмотра Windows, оттуда его тоже можно сохранить. Но 1С сначала положит копию в рабочий каталог пользователя, и при повторных открытиях там копится мусор.

⚠️ Если команда неактивна, проверьте права. Для просмотра присоединенных файлов нужен доступ к владельцу: нет прав на документ — нет доступа и к его вложениям.

Получение картинки из присоединенного файла кодом: ДвоичныеДанные и БСП

Для программиста главный инструмент — общий модуль РаботаСФайлами. Он работает на сервере.

Получить двоичные данные и записать на диск

&НаСервере
Процедура СохранитьКартинкуНаСервере(ПрисоединенныйФайл, Каталог)

    ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(ПрисоединенныйФайл, Ложь);
    Если ДвоичныеДанные = Неопределено Тогда
        Сообщить("Нет данных файла: " + Строка(ПрисоединенныйФайл));
        Возврат;
    КонецЕсли;

    Реквизиты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ПрисоединенныйФайл,
        "Наименование, Расширение");
    ИмяФайла = Реквизиты.Наименование + "." + Реквизиты.Расширение;
    ДвоичныеДанные.Записать(Каталог + ПолучитьРазделительПути() + ИмяФайла);

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

Второй параметр Ложь говорит: не бросать исключение, если данных нет, а вернуть Неопределено. Для массовых обработок это удобнее — одна битая запись не остановит выгрузку.

Код выполняется на сервере, и путь Каталог — это путь на сервере 1С, а не на компьютере пользователя. В файловой базе это одно и то же. В клиент-серверной — нет.

Отдать картинку пользователю на клиент

Чтобы файл сохранился у пользователя, байты передают через временное хранилище. В БСП для этого есть готовая пара:

&НаСервере
Функция ДанныеФайлаНаСервере(ПрисоединенныйФайл)
    Возврат РаботаСФайлами.ДанныеФайла(ПрисоединенныйФайл, УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура СохранитьКартинку(Команда)
    ДанныеФайла = ДанныеФайлаНаСервере(Объект.ФайлКартинки);
    РаботаСФайламиКлиент.СохранитьФайлКак(ДанныеФайла);
КонецПроцедуры

ДанныеФайла возвращает структуру. В ней есть адрес двоичных данных во временном хранилище, имя и расширение. СохранитьФайлКак сам покажет диалог выбора папки.

Показать картинку на форме

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

АдресКартинки = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор);

Извлечение изображения из 1С через COM-соединение

COM нужен, когда картинки забирает внешняя программа на Windows: скрипт, сайт-синхронизатор, утилита склада. Внешняя программа подключается к базе как пользователь 1С и вызывает её код.

Что подготовить

  • 🔧 Зарегистрировать компоненту comcntr.dll той же разрядности, что и вызывающая программа. Команда от имени администратора:
regsvr32 "C:\Program Files\1cv8\8.3.25.1374\bin\comcntr.dll"

Номер версии в пути замените на свой.

  • 🔧 Создать в конфигурации (лучше в расширении) общий модуль с флагами «Сервер» и «Внешнее соединение».
  • 🔧 Завести отдельного пользователя 1С с правами только на чтение нужных справочников.

Функция в общем модуле

Двоичные данные через COM передавать неудобно. Надёжнее вернуть строку Base64 и раскодировать её на стороне программы:

Функция КартинкаBase64(ИдентификаторФайла) Экспорт

    Ссылка = Справочники.НоменклатураПрисоединенныеФайлы.ПолучитьСсылку(
        Новый УникальныйИдентификатор(ИдентификаторФайла));
    ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(Ссылка, Ложь);
    Если ДвоичныеДанные = Неопределено Тогда
        Возврат "";
    КонецЕсли;
    Возврат Base64Строка(ДвоичныеДанные);

КонецФункции

Вызов из Python

import base64
import win32com.client

connector = win32com.client.Dispatch("V83.COMConnector")
conn = connector.Connect('File="C:\\Bases\\Trade";Usr="Export";Pwd="secret"')

module = getattr(conn, "ВыгрузкаКартинок")
data = getattr(module, "КартинкаBase64")("8f3c2a1e-5b7d-11ee-9c1a-00155d012345")

if data:
    with open("C:\\Export\\item.jpg", "wb") as f:
        f.write(base64.b64decode(data))

Для клиент-серверной базы строка подключения другая: Srvr="server1c";Ref="trade";. Base64 увеличивает объём примерно на треть. Для картинок каталога по 200–500 КБ это не критично. Для тысяч файлов по 10 МБ выгодней писать файлы на сервере и забирать папку.

Каждое COM-подключение занимает лицензию и стартует сеанс. Не открывайте соединение на каждую картинку — подключитесь один раз и обработайте весь список.

Картинки в хранилище значения и OLE-объектах

Сюда относятся два случая, которые с подсистемой файлов БСП не связаны.

Реквизит типа ХранилищеЗначения

В самописных базах и старых доработках картинку кладут в реквизит справочника. Извлекается она методом Получить(). Внутри может оказаться Картинка или ДвоичныеДанные — проверяйте тип:

Значение = СсылкаНаТовар.ФотоТовара.Получить();

Если ТипЗнч(Значение) = Тип("Картинка") Тогда
    ДвоичныеДанные = Значение.ПолучитьДвоичныеДанные();
ИначеЕсли ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
    ДвоичныеДанные = Значение;
Иначе
    ДвоичныеДанные = Неопределено;
КонецЕсли;

Если ДвоичныеДанные <> Неопределено Тогда
    ДвоичныеДанные.Записать("C:\Export\" + СсылкаНаТовар.Код + ".png");
КонецЕсли;

Имя реквизита ФотоТовара здесь условное — посмотрите своё в конфигураторе. Расширение у такой картинки неизвестно. Формат можно узнать через Картинка.Формат(), либо по первым байтам файла: PNG начинается с 89 50 4E 47, JPEG — с FF D8 FF.

Картинка внутри вложенного документа Word или Excel

Бывает, что изображение прикреплено не отдельным файлом, а вставлено в документ .docx или .xlsx. Тогда:

  1. Сохраните вложение на диск обычным способом.
  2. Смените расширение на .zip — современные форматы Office являются архивами.
  3. Откройте архив. Картинки лежат в папке word/media для Word и xl/media для Excel.

Так изображения выходят в исходном качестве, без пережатия, которое бывает при копировании из Word.

Старые форматы .doc и .xls архивами не являются. Их проще открыть в Office и сохранить в новом формате.

Массовая выгрузка изображений из 1С внешней обработкой

Типовая задача — выгрузить все фото номенклатуры для сайта или маркетплейса. Делается внешней обработкой с одной серверной процедурой.

Пример выгрузки фото всех товаров

&НаСервере
Процедура ВыгрузитьНаСервере(Каталог)

    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    Файлы.Ссылка КАК Ссылка,
    |    Файлы.Расширение КАК Расширение,
    |    Файлы.ВладелецФайла.Код КАК КодТовара
    |ИЗ
    |    Справочник.НоменклатураПрисоединенныеФайлы КАК Файлы
    |ГДЕ
    |    НЕ Файлы.ПометкаУдаления
    |    И Файлы.Расширение В (&Расширения)
    |УПОРЯДОЧИТЬ ПО
    |    КодТовара";

    Расширения = Новый Массив;
    Расширения.Добавить("jpg");
    Расширения.Добавить("jpeg");
    Расширения.Добавить("png");
    Запрос.УстановитьПараметр("Расширения", Расширения);

    Выборка = Запрос.Выполнить().Выбрать();
    ПредыдущийКод = "";
    Номер = 0;

    Пока Выборка.Следующий() Цикл
        КодТовара = СокрЛП(Выборка.КодТовара);
        Номер = ?(КодТовара = ПредыдущийКод, Номер + 1, 1);
        ПредыдущийКод = КодТовара;

        ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(Выборка.Ссылка, Ложь);
        Если ДвоичныеДанные = Неопределено Тогда
            Продолжить;
        КонецЕсли;

        ИмяФайла = СтрШаблон("%1_%2.%3", КодТовара,
            Формат(Номер, "ЧГ=0"), НРег(Выборка.Расширение));
        ДвоичныеДанные.Записать(Каталог + ПолучитьРазделительПути() + ИмяФайла);
    КонецЦикла;

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

У товара с кодом 00-00000123 и тремя фото получатся файлы 00-00000123_1.jpg, 00-00000123_2.jpg, 00-00000123_3.jpg.

Что учесть

  • 📌 Имя файла стройте из кода или артикула, а не из наименования. В наименованиях бывают /, ", *, на которых Записать() упадёт.
  • 📌 Регистр расширения в базе бывает разный: JPG и jpg. Если фильтр в запросе не сработал, приведите расширения к одному виду или добавьте оба варианта в массив.
  • 📌 Нужна только основная картинка товара? У номенклатуры в БП и УТ есть реквизит со ссылкой на основное изображение. Соберите запрос по нему, а не по всем файлам.
  • 📌 На 20–30 тысяч файлов выгрузка идёт долго. Запускайте её фоновым заданием, а не в форме — иначе клиент «повиснет» на всё время работы.

Доступ к картинкам 1С по ссылке через HTTP-сервис

HTTP-сервис нужен, когда изображения должен получать сайт, мобильное приложение или чужая система — без COM и без Windows на той стороне.

Как собрать сервис

  1. В конфигураторе в расширении добавьте объект «HTTP-сервис», корневой URL — images.
  2. Добавьте шаблон URL /file/{uid} и метод GET.
  3. Опубликуйте базу на веб-сервере (IIS или Apache) с флажком публикации HTTP-сервисов.
  4. Проверьте адрес вида http://server/trade/hs/images/file/<идентификатор>.

Обработчик метода GET

Функция ФайлGET(Запрос)

    Попытка
        Идентификатор = Новый УникальныйИдентификатор(Запрос.ПараметрыURL["uid"]);
    Исключение
        Возврат Новый HTTPСервисОтвет(400);
    КонецПопытки;

    Ссылка = Справочники.НоменклатураПрисоединенныеФайлы.ПолучитьСсылку(Идентификатор);
    ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(Ссылка, Ложь);
    Если ДвоичныеДанные = Неопределено Тогда
        Возврат Новый HTTPСервисОтвет(404);
    КонецЕсли;

    Расширение = НРег(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Расширение"));
    ТипКонтента = ?(Расширение = "png", "image/png", "image/jpeg");

    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.Заголовки.Вставить("Content-Type", ТипКонтента);
    Ответ.Заголовки.Вставить("Cache-Control", "max-age=86400");
    Ответ.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);
    Возврат Ответ;

КонецФункции

Сервис работает от имени пользователя 1С, который указан в публикации или передан в заголовке авторизации. Дайте ему минимальные права. Открывать доступ к базе без авторизации ради картинок не стоит: через тот же веб-сервер станут доступны и другие опубликованные сервисы.

Заголовок Cache-Control разгружает сервер 1С. Браузер и прокси не будут запрашивать одну и ту же картинку при каждом показе страницы.

Ошибки при извлечении картинок и что с ними делать

Диагностика: выберите симптом

Частые вопросы

Можно ли получить картинку из 1С без прав администратора?
Вручную — да, если у пользователя есть права на объект-владелец. Для COM и HTTP-сервиса нужна доработка конфигурации или расширения, а это уже задача администратора.
Сохранятся ли присоединенные файлы в выгрузке .dt?
Только те, что хранятся в информационной базе. Файлы из томов на диске в .dt не попадают — каталог тома копируют отдельно.
Почему картинка в 1С выглядит меньше оригинала?
Форма масштабирует изображение под размер поля. Присоединенный файл хранится в исходном размере, при сохранении вы получите оригинал.
Как узнать уникальный идентификатор файла для HTTP-запроса?
В коде — через Ссылка.УникальныйИдентификатор(). Внешняя система обычно получает его из той же выгрузки, где передаётся список товаров.
Можно ли вытащить картинки из базы, которая не запускается?
Если файлы лежат в томах — да, это обычные файлы в каталоге на диске, но имена у них служебные. Расширение придётся восстанавливать по первым байтам файла.