При работе с графическими данными в 1С (например, при выгрузке номенклатуры на сайт, формировании печатных форм или создании превью) часто возникает задача изменения размера (ресайза) картинок. Стандартный подход с сохранением файла во временную папку вызовом ПолучитьИмяВременногоФайла(), обработкой внешними утилитами и последующим считыванием создает повышенную нагрузку на дисковую подсистему и замедляет работу при массовой обработке.
Рассмотри, как изменить размеры фото напрямую из оперативной памяти, используя объект ДвоичныеДанные или строку Base64, без применения промежуточных файлов на диске.
Выясним, какие штатные средства предлагает сама платформа. Начиная с версии 1С:Предприятие 8.3.14, в платформу был добавлен специальный объект ОбрабатываемаяКартинка. Он позволяет менять размеры, кадрировать, поворачивать и изменять формат изображений полностью в оперативной памяти.
Разберем по шагам алгоритм работы с этим объектом:
ХранилищаЗначений или реквизита в виде объекта ДвоичныеДанные.Картинка из байтового массива.ОбрабатываемаяКартинка.УстановитьРазмер() или Масштабировать().ДвоичныеДанные.Посмотрим на пример кода:
// 1. Получаем двоичные данные исходной картинки из базы
ДвоичныеДанныеИсходной = СсылкаНоменклатуры.ОсновноеИзображение.Хранилище.Получить();
Если ТипЗнч(ДвоичныеДанныеИсходной) = Тип("Картинка") Тогда
ДвоичныеДанныеИсходной = ДвоичныеДанныеИсходной.ПолучитьДвоичныеДанные();
КонецЕсли;
Если ЗначениеЗаполнено(ДвоичныеДанныеИсходной) Тогда
// 2. Создаем объект Картинка
ИсходнаяКартинка = Новый Картинка(ДвоичныеДанныеИсходной);
// 3. Создаем обрабатываемую картинку
ОбработкаКартинки = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// 4. Устанавливаем новые габариты (ширина, высота в пикселях)
ОбработкаКартинки.УстановитьРазмер(300, 300);
// 5. Извлекаем итоговый объект Картинка из обработки
НоваяКартинка = ОбработкаКартинки.ПолучитьКартинку();
// 6. Получаем двоичные данные нового изображения для сохранения в БД или передачи
ДвоичныеДанныеРезультат = НоваяКартинка.ПолучитьДвоичныеДанные();
КонецЕсли;
Этот способ является наиболее предпочтительным, так как он абсолютно кроссплатформенный (работает на Windows и Linux серверах) и не требует подключения сторонних библиотек или COM-объектов.
Проанализируем ситуацию, если обработка выполняется на более старых версиях платформы (до 8.3.14). В среде Windows можно задействовать классы .NET Framework через COM-обертку (например, NetObjectToIDispatch) или с помощью внешних компонент.
Ключевая идея заключается в создании потока в оперативной памяти System.IO.MemoryStream, куда передаются байты изображения, после чего выполняется ресайз средствами System.Drawing.Bitmap и System.Drawing.Graphics.
Рассмотрим пример реализации с конвертацией данных через Base64Строка:
// Преобразуем ДвоичныеДанные в строку Base64
Base64Изображения = Base64Строка(ДвоичныеДанныеИсходной);
// Подключаем обертку .NET (NetObjectToIDispatch)
Враппер = Новый COMОбъект("NetObjectToIDispatch45");
// Преобразуем Base64 в массив байт System.Byte[]
МассивБайт = Враппер.ВызватьСтатическийМетод("System.Convert", "FromBase64String", Base64Изображения);
// Создаем MemoryStream из массива байт
ПотокПамяти = Враппер.СоздатьОбъект("System.IO.MemoryStream", МассивБайт);
// Загружаем изображение из потока
ИсходныйBitmap = Враппер.ВызватьСтатическийМетод("System.Drawing.Image", "FromStream", ПотокПамяти);
// Создаем новый пустой Bitmap с нужными размерами
Ширина = 200;
Высота = 200;
НовыйBitmap = Враппер.СоздатьОбъект("System.Drawing.Bitmap", Ширина, Высота);
// Создаем объект Graphics для отрисовки
Графика = Враппер.ВызватьСтатическийМетод("System.Drawing.Graphics", "FromImage", НовыйBitmap);
// Настраиваем высокое качество масштабирования
Качество = Враппер.ПолучитьТип("System.Drawing.Drawing2D.InterpolationMode").HighQualityBicubic;
Графика.InterpolationMode = Качество;
// Отрисовываем исходное изображение на новом холсте с изменением размера
Прямоугольник = Враппер.СоздатьОбъект("System.Drawing.Rectangle", 0, 0, Ширина, Высота);
Графика.DrawImage(ИсходныйBitmap, Прямоугольник);
// Сохраняем результат в новый MemoryStream
ВыходнойПоток = Враппер.СоздатьОбъект("System.IO.MemoryStream");
ФорматJpeg = Враппер.ПолучитьТип("System.Drawing.Imaging.ImageFormat").Jpeg;
НовыйBitmap.Save(ВыходнойПоток, ФорматJpeg);
// Получаем массив байт и конвертируем обратно в Base64 или ДвоичныеДанные
ВыходнойМассивБайт = ВыходнойПоток.ToArray();
Base64Результат = Враппер.ВызватьСтатическийМетод("System.Convert", "ToBase64String", ВыходнойМассивБайт);
ДвоичныеДанныеРезультат = Base64Значение(Base64Результат);
Разберем причину ошибки при попытке использовать популярный COM-объект GFLAx.GFLAx (из пакета GFL SDK / XnView). Разработчики часто пытаются передать в метод ReceiveBinary строку Base64, из-за чего возникает сбой вызова метода. Метод ReceiveBinary ожидает на вход не тексты Base64, а бинарныйSafeArray (массив байт типа VT_UI1).
Чтобы выполнить ресайз через GFLAx без записи на диск, требуется сформировать COMSafeArray из байтов исходной картинки. Рассмотрим корректную последовательность действий:
GFLAx = Новый COMОбъект("GFLAx.GFLAx");
// Переводим ДвоичныеДанные в COMSafeArray
ДвоичныеДанные = СсылкаНоменклатуры.ОсновноеИзображение.Хранилище.Получить().ПолучитьДвоичныеДанные();
// Преобразуем данные в COMSafeArray типа VT_UI1
МассивБайт = Новый COMSafeArray("VT_UI1", ДвоичныеДанные.Размер());
// Передаем байтовый массив в GFLAx через COMSafeArray
GFLAx.ReceiveBinary(МассивБайт);
GFLAx.Resize(200, 200);
// Извлекаем результат обратно в байтовый массив без записи на диск
БайтыРезультата = GFLAx.SendBinary();
Посмотрим на ещё один гибкий вариант: интеграцию 1С с Python при помощи стандартных потоков ввода-вывода (stdin / stdout). Это позволяет передавать бинарный поток картинки напрямую в скрипт и получать сжатый результат обратно через вывод процесса без создания временных файлов.
В Python для обработки изображений в памяти используется библиотека Pillow:
import sys
import io
from PIL import Image
# Чтение байтов из стандартного ввода (stdin)
input_data = sys.stdin.buffer.read()
image = Image.open(io.BytesIO(input_data))
# Изменение размера с сохранением пропорций
image.thumbnail((300, 300))
# Сохранение результата в буфер оперативной памяти
output_buffer = io.BytesIO()
image.save(output_buffer, format='JPEG')
# Вывод результатов в stdout
sys.stdout.buffer.write(output_buffer.getvalue())
В 1С такой процесс запускается с помощью объекта ЗапускПриложения() с перенаправлением потоков ввода и вывода.
Подведем итоги проанализированных способов:
ОбрабатываемаяКартинка: Самый быстрый, надежный и кроссплатформенный вариант. Работает из коробки на серверах под управлением Windows и Linux.COMSafeArray. WIA штатно работает только через дисковые файлы, тогда как GFLAx умеет принимать и отдавать массивы байт.Таким образом, для современных версий 1С задачу изменения размера изображений в оперативной памяти проще всего решать штатными методами платформы, что исключит лишние операции ввода-вывода и сохранит высокую производительность сервера.