При разработке прикладных решений на платформе 1С:Предприятие часто возникает задача обработки графических файлов. Например, при загрузке изображений номенклатуры, сканов документов или аватаров пользователей необходимо проверить их разрешение (ширину и высоту в пикселях), оценить размер в байтах и, при необходимости, оптимизировать их — уменьшить разрешение, обрезать пустые поля или конвертировать в более легкий формат (например, из BMP в JPEG). Разберем, как решать эти задачи наиболее эффективно.
Долгое время в платформе 1С отсутствовали встроенные инструменты для полноценного анализа и трансформации графических данных в оперативной памяти. Разработчикам приходилось прибегать к различным ухищрениям, которые существенно усложняли код и снижали производительность системы. В этой статье мы подробно проанализируем, как развивались механизмы работы с графикой в 1С, и рассмотрим современные кроссплатформенные методы, доступные в актуальных версиях платформы.
В старых версиях платформы встроенный объект Картинка представлял собой по сути простой контейнер для двоичных данных. У него отсутствовали методы для чтения метаданных изображения, таких как ширина или высота. Выяснить параметры картинки напрямую из оперативной памяти (например, из полученных из временного хранилища двоичных данных) было невозможно.
Для решения этой задачи разработчики использовали внешние библиотеки и COM-объекты операционной системы Windows. Самым популярным решением было использование библиотеки WIA (Windows Image Acquisition). Рассмотрим пример кода, который использовался для этой цели:
// Пример получения параметров файла через COM-объект WIA
ПутьКФайлуКартинки = "C:\Temp\temp_image.png";
// Двоичные данные предварительно обязательно нужно было записать на диск
ДвоичныеДанныеКартинки.Записать(ПутьКФайлуКартинки);
ImageFile = Новый COMОбъект("WIA.ImageFile");
ImageFile.LoadFile(ПутьКФайлуКартинки);
Высота = ImageFile.Height;
Ширина = ImageFile.Width;
Размер = Окр(ImageFile.FileData.Count / 1024, 2); // Размер в Кб
// Удаление временного файла после анализа
УдалитьФайлы(ПутьКФайлуКартинки);
Этот подход имел множество критических недостатков:
Начиная с версии платформы 8.3.14, разработчики 1С получили долгожданные встроенные кроссплатформенные инструменты, которые позволяют выполнять все эти операции непосредственно в оперативной памяти без использования сторонних библиотек и сохранения файлов на диск.
Если у нас есть двоичные данные файла изображения (например, полученные из реквизита базы данных с типом ХранилищеЗначения или из временного хранилища по адресу), мы можем мгновенно инициализировать объект Картинка и прочитать все его характеристики.
Рассмотрим подробнее ключевые методы объекта Картинка, предназначенные для чтения свойств изображения:
Ширина() — возвращает ширину изображения в пикселях (тип Число).Высота() — возвращает высоту изображения в пикселях (тип Число).РазмерФайла() — возвращает точный размер исходного файла картинки на диске в байтах (тип Число).ФорматКартинки() — возвращает системное перечисление ФорматКартинки (например, ФорматКартинки.JPEG, ФорматКартинки.PNG, ФорматКартинки.GIF и т.д.).ГлубинаЦвета() — возвращает значение системного перечисления ГлубинаЦвета, отражающее количество бит на пиксель.ПлотностьПоВертикали() и ПлотностьПоГоризонтали() — возвращают разрешение изображения в DPI (точек на дюйм).КоличествоКадров() — возвращает количество страниц для многостраничных TIFF или количество кадров для анимированных GIF.Ниже представлен пример кода, который демонстрирует, как извлечь двоичные данные из временного хранилища и получить все необходимые параметры изображения:
// 1. Получаем двоичные данные из временного хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХранилище);
// 2. Инициализируем объект Картинка напрямую из двоичных данных
Картинка = Новый Картинка(ДвоичныеДанные);
// 3. Считываем параметры без записи файла на диск
ШиринаИзображения = Картинка.Ширина();
ВысотаИзображения = Картинка.Высота();
РазмерВБайтах = Картинка.РазмерФайла();
ФорматФайла = Картинка.ФорматКартинки();
// Выводим информацию для пользователя или логирования
Сообщить(СтрШаблон("Параметры картинки: %1x%2 пикс., Размер: %3 Кб, Формат: %4",
ШиринаИзображения,
ВысотаИзображения,
Окр(РазмерВБайтах / 1024, 2),
ФорматФайла));
Важное примечание: Если объект Картинка является коллекцией (набором картинок для кнопок или списков), то методы Ширина() и Высота() вернут значение Неопределено. Также учтите, что если картинка содержит несколько вариантов разрешения (под разные DPI экрана), методы вернут параметры того варианта, который наиболее соответствует текущим настройкам клиентского сеанса.
Для того чтобы не просто прочитать параметры, но и изменить их (например, уменьшить слишком большую картинку перед сохранением в базу данных), платформа предоставляет специализированный объект ОбрабатываемаяКартинка. Этот объект работает по принципу графического редактора в оперативной памяти.
Проанализируем основные методы преобразования, которые предоставляет этот объект:
УстановитьРазмер(Ширина, Высота). Метод позволяет изменить разрешение изображения. Очень удобная особенность: если один из параметров (например, высоту) передать как Неопределено, платформа автоматически рассчитает его значение, сохранив исходные пропорции картинки. Это избавляет разработчика от необходимости писать собственные математические формулы расчета пропорций.Масштабировать(Процент). Пропорционально уменьшает или увеличивает картинку на заданную величину в процентах.Повернуть(УголПоворота). Позволяет развернуть изображение на 90, 180 или 270 градусов, а также отразить его зеркально по горизонтали или вертикали с помощью значений системного перечисления УголПоворота.ВыделитьОбласть(Лево, Верх, Ширина, Высота). Выполняет классическое кадрирование (обрезку) изображения по заданным координатам прямоугольной области.ВыделитьЗначимуюЧастьКартинки(). Интеллектуальный алгоритм платформы анализирует изображение, определяет границы основного объекта (например, товара на белом фоне) и автоматически обрезает лишние пустые поля по краям.УстановитьФормат(ФорматКартинки). Конвертирует изображение в другой формат (например, сжимает исходный тяжелый BMP-файл в компактный JPEG или PNG).ПреобразоватьВОттенкиСерого(). Полезный метод для оптимизации хранения документов — переводит картинку в черно-белый формат, что существенно уменьшает итоговый размер файла в байтах.После проведения всех необходимых манипуляций с объектом ОбрабатываемаяКартинка мы вызываем метод ПолучитьКартинку(), который возвращает нам готовый обновленный объект Картинка. Из него мы можем извлечь новые двоичные данные и записать их обратно в хранилище или базу данных.
Рассмотрим комплексный практический сценарий. Напишем готовую процедуру, которая принимает адрес временного хранилища с загруженной картинкой. Если ширина картинки превышает 1200 пикселей, процедура пропорционально уменьшает её до 1200 пикселей по ширине, конвертирует в формат JPEG для экономии места и перезаписывает данные во временном хранилище.
&НаСервере
Процедура ОптимизироватьКартинкуВХранилище(АдресВХранилище)
// 1. Извлекаем исходные данные
ДвоичныеДанныеИсходные = ПолучитьИзВременногоХранилища(АдресВХранилище);
КартинкаИсходная = Новый Картинка(ДвоичныеДанныеИсходные);
ШиринаИсходная = КартинкаИсходная.Ширина();
ВысотаИсходная = КартинкаИсходная.Высота();
МаксимальноДопустимаяШирина = 1200;
// Проверяем, нужно ли оптимизировать изображение
Если ШиринаИсходная > МаксимальноДопустимаяШирина Тогда
// 2. Инициализируем объект для редактирования
ОбрабатываемаяКартинка = Новый ОбрабатываемаяКартинка(КартинкаИсходная);
// Устанавливаем ширину в 1200 пикселей, высоту платформа рассчитает сама
ОбрабатываемаяКартинка.УстановитьРазмер(МаксимальноДопустимаяШирина, Неопределено);
// Переводим формат в JPEG (идеально для экономии дискового пространства)
ОбрабатываемаяКартинка.УстановитьФормат(ФорматКартинки.JPEG);
// 3. Получаем измененный объект Картинка
КартинкаРезультат = ОбрабатываемаяКартинка.ПолучитьКартинку();
// Извлекаем новые двоичные данные из оптимизированной картинки
ДвоичныеДанныеРезультат = КартинкаРезультат.ПолучитьДвоичныеДанные();
// 4. Перезаписываем данные по тому же адресу во временном хранилище
ПоместитьВоВременноеХранилище(ДвоичныеДанныеРезультат, АдресВХранилище);
Сообщить(СтрШаблон("Изображение успешно оптимизировано. Новый размер: %1х%2 пикс.",
КартинкаРезультат.Ширина(),
КартинкаРезультат.Высота()));
Иначе
Сообщить("Оптимизация не требуется, изображение соответствует стандартам.");
КонецЕсли;
КонецПроцедуры
Важнейшим аспектом использования встроенных объектов Картинка и ОбрабатываемаяКартинка является их полная кроссплатформенность. Это означает, что приведенный выше код будет абсолютно одинаково и стабильно работать:
Вам больше не требуется администрировать серверные операционные системы для установки консольных утилит обработки графики (таких как ImageMagick) или настраивать Wine для эмуляции работы COM-объектов Windows. Вся обработка графических данных теперь выполняется штатными средствами самой платформы 1С:Предприятие быстро, надежно и безопасно.