Уменьшить размер картинки в 1С можно без сторонних программ: с платформы 8.3.14 есть объект ОбрабатываемаяКартинка, который меняет размер и формат картинки на сервере. Если нужен контроль качества JPEG или платформа ниже 8.3.14, подойдут WIA и GFLAx через COM в Windows, PowerShell-скрипт или ImageMagick на Linux. Ниже — готовые функции для каждого варианта и пакетное сжатие картинок номенклатуры с замером «было/стало».
Менеджеры годами прикрепляют к карточкам товаров фото с телефона как есть — по несколько мегабайт и тысяч пикселей на снимок, хотя сайту и печатной форме нужна картинка в разы меньше. Растут база и резервные копии, обмен с сайтом и выгрузка на маркетплейсы гоняют мегабайты и падают по таймауту.
В УТ 11 и КА 2 это присоединённые файлы справочника НоменклатураПрисоединенныеФайлы, основная картинка — реквизит ФайлКартинки номенклатуры (сверено по выгрузкам УТ 11.4 и КА 2.5). Байты лежат в томах на диске или в базе: в УТ 11.4 — в регистре сведений ДвоичныеДанныеФайлов, в КА 2.5 (более новая БСП) — в справочнике ХранилищеДвоичныхДанных. БСП пишет их со сжатием Новый СжатиеДанных(9), но JPEG и PNG уже сжаты — подробнее в статье про хранилище значения. Поэтому уменьшить вес картинок в базе 1С можно только одним путём: уменьшить сами картинки.
| Способ | Где выполняется | Что установить | Качество JPEG |
|---|---|---|---|
ОбрабатываемаяКартинка | сервер, толстый клиент, внешнее соединение | ничего, платформа 8.3.14+ | не задаётся |
| WIA.ImageFile + WIA.ImageProcess | Windows: клиент или сервер 1С | ничего, компонент Windows | свойство Quality фильтра Convert |
| GFLAx | Windows: клиент или сервер 1С | GflAx, регистрация DLL 32 и 64 бит | по свойствам объекта GflAx |
| PowerShell + System.Drawing | Windows | скрипт .ps1 | параметр скрипта |
| ImageMagick | Linux, есть сборки под Windows | пакет из репозитория | ключ -quality |
| Облачный сервис с HTTP API (в заметке автора — optipic.io) | любой сервер с выходом в интернет | ничего; обычно платно, картинки уходят третьей стороне | в настройках сервиса |
Из объектов платформы изменить размер изображения в 1С программно умеет только ОбрабатываемаяКартинка. У объекта Картинка по синтакс-помощнику 8.3.27 есть Ширина(), Высота(), РазмерФайла() и КоличествоКадров() (8.3.14–8.3.15), но размер он не меняет. Преобразовать() с 8.3.14 не рекомендуется и, по примечанию в справке, переводит растровые картинки только в BMP и PNG — для фото это рост веса. Устаревший объект ОбработкаКартинок умеет лишь поворачивать и выделять значимую часть. ОбрабатываемаяКартинка доступна на сервере, в толстом клиенте и во внешнем соединении, поэтому функция живёт в серверном общем модуле.
// Общий модуль СжатиеКартинокСервер, флажок «Сервер».
// Платформа 8.3.15 и новее: ОбрабатываемаяКартинка и Картинка.КоличествоКадров().
// Уменьшает картинку так, чтобы длинная сторона была не больше МаксСторона.
// BMP и TIFF переводит в JPEG, PNG оставляет PNG: в нём бывает прозрачность.
// Возвращает структуру: Изменена (Булево), Данные (ДвоичныеДанные),
// Расширение (новое расширение без точки или "", если формат не менялся).
Функция УменьшитьКартинку(ДанныеКартинки, МаксСторона = 1200) Экспорт
Результат = Новый Структура("Изменена, Данные, Расширение", Ложь, ДанныеКартинки, "");
Исходная = Новый Картинка(ДанныеКартинки);
ИсходныйФормат = Исходная.Формат();
Ширина = Исходная.Ширина();
Высота = Исходная.Высота();
Растровые = Новый Массив;
Растровые.Добавить(ФорматКартинки.JPEG);
Растровые.Добавить(ФорматКартинки.PNG);
Растровые.Добавить(ФорматКартинки.BMP);
Растровые.Добавить(ФорматКартинки.TIFF);
Если Растровые.Найти(ИсходныйФормат) = Неопределено
Или Ширина = Неопределено Или Высота = Неопределено
Или Исходная.КоличествоКадров() > 1 Тогда
Возврат Результат; // вектор, GIF, иконки и многостраничный TIFF не трогаем
КонецЕсли;
НужноУменьшить = Макс(Ширина, Высота) > МаксСторона;
НовыйФормат = ?(ИсходныйФормат = ФорматКартинки.PNG, ФорматКартинки.PNG, ФорматКартинки.JPEG);
Если Не НужноУменьшить И НовыйФормат = ИсходныйФормат Тогда
Возврат Результат; // размер подходит: JPEG лишний раз не пересжимаем
КонецЕсли;
Преобразование = Новый ОбрабатываемаяКартинка(Исходная);
Если НужноУменьшить Тогда
Коэффициент = МаксСторона / Макс(Ширина, Высота);
Преобразование.УстановитьРазмер(Макс(1, Окр(Ширина * Коэффициент)), Макс(1, Окр(Высота * Коэффициент)));
КонецЕсли;
Преобразование.УстановитьФормат(НовыйФормат);
НовыеДанные = Преобразование.ПолучитьКартинку().ПолучитьДвоичныеДанные();
// Заменяем, только если файл стал легче хотя бы на 10%
Если НовыеДанные = Неопределено Или НовыеДанные.Размер() > ДанныеКартинки.Размер() * 0.9 Тогда
Возврат Результат;
КонецЕсли;
Результат.Изменена = Истина;
Результат.Данные = НовыеДанные;
Если НовыйФормат <> ИсходныйФормат Тогда
Результат.Расширение = "jpg";
КонецЕсли;
Возврат Результат;
КонецФункции
Сначала оцените масштаб — запрос можно выполнить в консоли запросов:
ВЫБРАТЬ
Файлы.Расширение КАК Расширение,
КОЛИЧЕСТВО(*) КАК Файлов,
СУММА(Файлы.Размер) / 1048576 КАК ВсегоМБ,
МАКСИМУМ(Файлы.Размер) / 1048576 КАК СамыйБольшойМБ
ИЗ
Справочник.НоменклатураПрисоединенныеФайлы КАК Файлы
ГДЕ
НЕ Файлы.ЭтоГруппа
И НЕ Файлы.ПометкаУдаления
СГРУППИРОВАТЬ ПО
Файлы.Расширение
УПОРЯДОЧИТЬ ПО
ВсегоМБ УБЫВ
Пакетная функция ужимает тяжёлые картинки функцией УменьшитьКартинку и записывает их через программный интерфейс БСП РаботаСФайлами — одинаково для файлов в базе и в томах. Итог «было/стало» возвращается строкой и пишется в журнал регистрации; ошибка по одному файлу не останавливает остальные.
// Там же, в общем модуле СжатиеКартинокСервер.
// Пакетное сжатие картинок номенклатуры через БСП «Работа с файлами».
// Первый запуск — на копии базы: СжатьКартинкиНоменклатуры(1200, 300, 20).
// Возвращает итог «было/стало» и пишет его в журнал регистрации.
Функция СжатьКартинкиНоменклатуры(МаксСторона = 1200, ПорогКБ = 300, МаксимумФайлов = 0) Экспорт
Расширения = Новый Массив;
Для Каждого Расширение Из СтрРазделить("jpg,jpeg,png,bmp,tif,tiff", ",") Цикл
Расширения.Добавить(Расширение);
Расширения.Добавить(ВРег(Расширение));
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Файлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.НоменклатураПрисоединенныеФайлы КАК Файлы
|ГДЕ
| НЕ Файлы.ЭтоГруппа
| И НЕ Файлы.ПометкаУдаления
| И НЕ Файлы.ХранитьВерсии
| И НЕ Файлы.Зашифрован
| И НЕ Файлы.ПодписанЭП
| И Файлы.Редактирует = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
| И Файлы.Размер > &Порог
| И Файлы.Расширение В (&Расширения)
|УПОРЯДОЧИТЬ ПО
| Файлы.Размер УБЫВ";
Если МаксимумФайлов > 0 Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "ВЫБРАТЬ", "ВЫБРАТЬ ПЕРВЫЕ " + Формат(МаксимумФайлов, "ЧГ=0"));
КонецЕсли;
Запрос.УстановитьПараметр("Порог", ПорогКБ * 1024);
Запрос.УстановитьПараметр("Расширения", Расширения);
Было = 0;
Стало = 0;
Сжато = 0;
БезИзменений = 0;
Ошибок = 0;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
Замер = СжатьФайлКартинки(Выборка.Ссылка, МаксСторона);
Если Замер = Неопределено Тогда
БезИзменений = БезИзменений + 1;
Иначе
Было = Было + Замер.Было;
Стало = Стало + Замер.Стало;
Сжато = Сжато + 1;
КонецЕсли;
Исключение
Ошибок = Ошибок + 1;
ЗаписьЖурналаРегистрации("СжатиеКартинок", УровеньЖурналаРегистрации.Ошибка,
Метаданные.Справочники.НоменклатураПрисоединенныеФайлы, Выборка.Ссылка,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
Итог = СтрШаблон("Сжато файлов: %1, без изменений: %2, ошибок: %3. Было %4 МБ, стало %5 МБ.",
Сжато, БезИзменений, Ошибок, Окр(Было / 1048576, 1), Окр(Стало / 1048576, 1));
ЗаписьЖурналаРегистрации("СжатиеКартинок", УровеньЖурналаРегистрации.Информация, , , Итог);
Возврат Итог;
КонецФункции
// Сжимает один присоединённый файл: Неопределено — файл не менялся,
// иначе структура Было, Стало (в байтах).
Функция СжатьФайлКартинки(ФайлСсылка, МаксСторона)
ДанныеФайла = РаботаСФайлами.ДвоичныеДанныеФайла(ФайлСсылка, Ложь);
Если ДанныеФайла = Неопределено Тогда
Возврат Неопределено; // данных нет ни в базе, ни в томе
КонецЕсли;
Сжатие = УменьшитьКартинку(ДанныеФайла, МаксСторона);
Если Не Сжатие.Изменена Тогда
Возврат Неопределено;
КонецЕсли;
ИнформацияОФайле = Новый Структура;
ИнформацияОФайле.Вставить("АдресФайлаВоВременномХранилище", ПоместитьВоВременноеХранилище(Сжатие.Данные));
ИнформацияОФайле.Вставить("АдресВременногоХранилищаТекста", ""); // нужен даже пустой
Если ЗначениеЗаполнено(Сжатие.Расширение) Тогда
ИнформацияОФайле.Вставить("Расширение", Сжатие.Расширение);
КонецЕсли;
РаботаСФайлами.ОбновитьФайл(ФайлСсылка, ИнформацияОФайле);
УдалитьИзВременногоХранилища(ИнформацияОФайле.АдресФайлаВоВременномХранилище);
// ОбновитьФайл в БСП (УТ 11.4, КА 2.5) не пересчитывает реквизит Размер
НовыйРазмер = Сжатие.Данные.Размер();
ФайлОбъект = ФайлСсылка.ПолучитьОбъект();
Если ФайлОбъект.Размер <> НовыйРазмер Тогда
ФайлОбъект.Размер = НовыйРазмер;
ФайлОбъект.Записать();
КонецЕсли;
РазблокироватьДанныеДляРедактирования(ФайлСсылка);
Возврат Новый Структура("Было, Стало", ДанныеФайла.Размер(), НовыйРазмер);
КонецФункции
ОбновитьФайл в БСП предназначен для файлов без версий.ДвоичныеДанныеФайла(Ссылка, Ложь) вернёт Неопределено вместо исключения, если данных нет.АдресВременногоХранилищаТекста нужен даже пустым: у справочника включён полнотекстовый поиск, и БСП читает это свойство без проверки.ОбновитьФайл не пересчитывает Размер ни у файлов в базе, ни у файлов в томах (видно по коду РаботаСФайламиСлужебный и РаботаСФайламиВТомахСлужебный). Функция дописывает его сама, иначе следующий запуск снова выберет те же файлы.Перед запуском сделайте резервную копию базы (и каталога томов, если файлы там) и прогоните функцию на копии с МаксимумФайлов = 20: сжатие необратимо. Тысячи файлов удобнее обрабатывать в фоне — см. длительные операции БСП. Если справочник файлов входит в план обмена — например, в РИБ (план «Полный» в УТ 11.4 и КА 2.5), — изменённые картинки зарегистрируются к выгрузке, и первый обмен будет дольше обычного.
Windows Image Acquisition — COM-библиотека Windows (WIA.ImageFile, WIA.ImageProcess), ставить её не нужно. Приём из практики автора — фильтр Scale со свойствами MaximumWidth и MaximumHeight; фильтр Convert для формата и качества JPEG добавлен по документации Microsoft. Функция ниже серверная, для сервера 1С под Windows; для веб-клиента и Linux вариант не подходит. Внутри WIA обрабатывает картинки через GDI+, поэтому оговорки про службы Windows и Server Core из раздела о PowerShell относятся и к ней.
// Сжатие через WIA (Windows Image Acquisition): COM-объекты есть в Windows,
// ставить ничего не нужно. Тот же общий модуль, сервер 1С под Windows.
Функция УменьшитьЧерезWIA(ДанныеКартинки, МаксСторона = 1200, Качество = 80) Экспорт
ИмяИсходного = ПолучитьИмяВременногоФайла("jpg");
ИмяРезультата = ПолучитьИмяВременногоФайла("jpg"); // файла с этим именем ещё нет
ДанныеКартинки.Записать(ИмяИсходного);
ТекстОшибки = "";
НовыеДанные = Неопределено;
Попытка
ПреобразоватьФайлWIA(ИмяИсходного, ИмяРезультата, МаксСторона, Качество);
НовыеДанные = Новый ДвоичныеДанные(ИмяРезультата);
Исключение
ТекстОшибки = ОписаниеОшибки();
КонецПопытки;
УдалитьФайлТихо(ИмяИсходного);
УдалитьФайлТихо(ИмяРезультата);
Если ЗначениеЗаполнено(ТекстОшибки) Тогда
ВызватьИсключение "WIA: " + ТекстОшибки;
КонецЕсли;
// Заменяем, только если файл стал легче хотя бы на 10%
Возврат ?(НовыеДанные.Размер() < ДанныеКартинки.Размер() * 0.9, НовыеДанные, ДанныеКартинки);
КонецФункции
// COM-объекты живут только внутри процедуры: после выхода файлы свободны.
Процедура ПреобразоватьФайлWIA(ИмяИсходного, ИмяРезультата, МаксСторона, Качество)
Изображение = Новый COMОбъект("WIA.ImageFile");
Изображение.LoadFile(ИмяИсходного);
Процессор = Новый COMОбъект("WIA.ImageProcess");
Длинная = Макс(Изображение.Width, Изображение.Height);
Если Длинная > МаксСторона Тогда
// Scale вписывает картинку в рамку; рамку считаем сами с одним коэффициентом
Коэффициент = МаксСторона / Длинная;
Процессор.Filters.Add(Процессор.FilterInfos.Item("Scale").FilterID);
Фильтр = Процессор.Filters.Item(Процессор.Filters.Count);
Фильтр.Properties.Item("MaximumWidth").Value = Макс(1, Окр(Изображение.Width * Коэффициент));
Фильтр.Properties.Item("MaximumHeight").Value = Макс(1, Окр(Изображение.Height * Коэффициент));
КонецЕсли;
// Convert — последним в цепочке: формат JPEG и качество
Процессор.Filters.Add(Процессор.FilterInfos.Item("Convert").FilterID);
Фильтр = Процессор.Filters.Item(Процессор.Filters.Count);
Фильтр.Properties.Item("FormatID").Value = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}"; // wiaFormatJPEG
Фильтр.Properties.Item("Quality").Value = Качество;
Результат = Процессор.Apply(Изображение);
Результат.SaveFile(ИмяРезультата);
КонецПроцедуры
Процедура УдалитьФайлТихо(ИмяФайла)
Попытка
УдалитьФайлы(ИмяФайла);
Исключение
// не удалось — временный файл платформа удалит сама позже
КонецПопытки;
КонецПроцедуры
Scale функция считает сама, поэтому пропорции не зависят от настроек фильтра.Convert ставится в цепочке последним — иначе WIA вернёт ошибку; Quality — от 1 до 100, по умолчанию 100. GUID — константа wiaFormatJPEG: при позднем связывании констант WIA в 1С нет.GFLAx — COM-обёртка GFL SDK от XnView, дистрибутив на сайте xnview.com. Её нужно зарегистрировать, и разрядность регистрации должна совпадать с процессом: 64-битный сервер 1С видит только 64-битную регистрацию, 32-битный клиент — только 32-битную. Порядок из практики автора для 64-битной Windows, пути полные:
rem cmd.exe от имени администратора. Архив GflAX-binaries-3.0.zip распакован в C:\Distr (путь условный)
rem 64-битная Windows: папка x64 - в System32, папка Win32 - в SysWOW64 (порядок из практики автора)
xcopy "C:\Distr\Unicode Release.x64" "C:\Windows\System32\Unicode Release.x64" /E /I
xcopy "C:\Distr\Unicode Release.Win32" "C:\Windows\SysWOW64\Unicode Release.Win32" /E /I
rem 64-битная регистрация - для 64-битного сервера 1С и 64-битного клиента
C:\Windows\System32\regsvr32.exe "C:\Windows\System32\Unicode Release.x64\GflAX.dll"
rem 32-битная - для 32-битного клиента 1С
C:\Windows\SysWOW64\regsvr32.exe "C:\Windows\SysWOW64\Unicode Release.Win32\GflAX.dll"
rem 32-битная Windows: только папка Win32 в System32 и regsvr32 оттуда же
rem Отменить регистрацию: тот же regsvr32 с ключом /u и тем же путём к DLL
Команды пишут в системные каталоги и реестр: до установки на рабочий сервер сделайте снимок или точку восстановления, ничего не заменяйте в System32 и проверьте лицензию GFL SDK. В заметке автора опечатка regsrv32 — правильно regsvr32. На 64-битной Windows System32\regsvr32.exe 64-битный, а SysWOW64\regsvr32.exe — 32-битный.
Функция автора ограничивала ширину 700 px и перезаписывала исходник. Ниже ограничена длинная сторона, маленькие картинки не растягиваются, результат пишется в новый файл. В первом варианте заметки была ошибка: внутри ?() стояли сравнения Делитель=Ширина/500, переменная получала тип Булево, и деление не работало.
// GFLAx из практики автора: длинная сторона не больше МаксСторона.
// Результат пишется в новый файл; исходник замените только после проверки.
Функция УменьшитьЧерезGFLAx(ИмяИсходного, ИмяРезультата, МаксСторона = 700) Экспорт
GFLAx = Новый COMОбъект("GFLAx.GFLAx");
GFLAx.LoadBitmap(ИмяИсходного);
Ширина = GFLAx.Width;
Высота = GFLAx.Height;
Длинная = Макс(Ширина, Высота);
Если Длинная <= МаксСторона Тогда
Возврат Ложь; // уже меньше предела: не растягиваем и не пересохраняем
КонецЕсли;
// Один коэффициент на обе стороны — пропорции сохраняются
Коэффициент = МаксСторона / Длинная;
GFLAx.Resize(Макс(1, Окр(Ширина * Коэффициент)), Макс(1, Окр(Высота * Коэффициент)));
GFLAx.SaveBitmap(ИмяРезультата);
Возврат Истина;
КонецФункции
Формат и качество сохранения задаются свойствами GflAx — их имена сверьте по справке из архива вашей версии.
Третий путь — внешняя программа через ФайловаяСистема.ЗапуститьПрограмму из БСП (есть в УТ 11.4 и КА 2.5): она сама берёт в кавычки аргументы с пробелами, ждёт завершения и возвращает код возврата и поток ошибок. На Windows — PowerShell-скрипт с System.Drawing. Положите его на сервер 1С, например в C:\Scripts\resize-image.ps1, с правом записи только для администраторов: сервер выполнит всё, что там окажется.
# resize-image.ps1: уменьшает JPEG до MaxSide по длинной стороне и сохраняет с качеством Quality
param(
[Parameter(Mandatory = $true)] [string] $InFile,
[Parameter(Mandatory = $true)] [string] $OutFile,
[int] $MaxSide = 1200,
[int] $Quality = 80
)
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
$src = [System.Drawing.Image]::FromFile($InFile)
try {
# Фото с телефона: применяем поворот из EXIF (тег 0x0112), иначе картинка ляжет набок
if ($src.PropertyIdList -contains 0x0112) {
switch ($src.GetPropertyItem(0x0112).Value[0]) {
3 { $src.RotateFlip([System.Drawing.RotateFlipType]::Rotate180FlipNone) }
6 { $src.RotateFlip([System.Drawing.RotateFlipType]::Rotate90FlipNone) }
8 { $src.RotateFlip([System.Drawing.RotateFlipType]::Rotate270FlipNone) }
}
}
# Маленькие картинки не растягиваем: коэффициент не больше 1
$k = [Math]::Min(1.0, $MaxSide / [Math]::Max($src.Width, $src.Height))
$w = [Math]::Max(1, [int][Math]::Round($src.Width * $k))
$h = [Math]::Max(1, [int][Math]::Round($src.Height * $k))
$dst = New-Object System.Drawing.Bitmap($w, $h)
try {
$g = [System.Drawing.Graphics]::FromImage($dst)
$g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
$g.Clear([System.Drawing.Color]::White)
$g.DrawImage($src, 0, 0, $w, $h)
$g.Dispose()
$jpeg = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() |
Where-Object { $_.MimeType -eq 'image/jpeg' }
$params = New-Object System.Drawing.Imaging.EncoderParameters(1)
$params.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, [long]$Quality)
$dst.Save($OutFile, $jpeg, $params)
}
finally {
$dst.Dispose()
}
}
finally {
$src.Dispose()
}
Ключ -ExecutionPolicy Bypass действует только на этот процесс и в реестр не пишет, но политику из групповой политики не перекрывает — тогда скрипт придётся подписать или согласовать исключение с администратором. Кроме того, по документации Microsoft GDI+, на котором стоит System.Drawing, не поддерживается в службах Windows, а сервер 1С работает службой; в Server Core GDI+ в составе ОС нет. Поэтому PowerShell — для разовой чистки с проверкой на копии, а регламентное задание стройте на платформенном способе или ImageMagick.
// Внешняя программа через БСП, выполняется на сервере 1С:
// Windows — скрипт resize-image.ps1, Linux — ImageMagick. Только для JPEG.
// Процедура УдалитьФайлТихо — из листинга с WIA.
Функция УменьшитьВнешнейПрограммой(ДанныеКартинки, МаксСторона = 1200, Качество = 80) Экспорт
Исходная = Новый Картинка(ДанныеКартинки);
Если Исходная.Формат() <> ФорматКартинки.JPEG Тогда
Возврат ДанныеКартинки; // PNG с прозрачностью и прочее — платформенным способом
КонецЕсли;
НужноУменьшить = Макс(Исходная.Ширина(), Исходная.Высота()) > МаксСторона;
ИмяИсходного = ПолучитьИмяВременногоФайла("jpg");
ИмяРезультата = ПолучитьИмяВременногоФайла("jpg");
ДанныеКартинки.Записать(ИмяИсходного);
// Числа в командную строку — через Формат: Строка(1200) даст "1 200"
Предел = Формат(МаксСторона, "ЧГ=0");
СтрокаКачества = Формат(Качество, "ЧГ=0");
Команда = Новый Массив;
Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
Команда.Добавить("powershell.exe");
Команда.Добавить("-NoProfile");
Команда.Добавить("-NonInteractive");
Команда.Добавить("-ExecutionPolicy");
Команда.Добавить("Bypass");
Команда.Добавить("-File");
Команда.Добавить("C:\Scripts\resize-image.ps1");
Команда.Добавить("-InFile");
Команда.Добавить(ИмяИсходного);
Команда.Добавить("-OutFile");
Команда.Добавить(ИмяРезультата);
Команда.Добавить("-MaxSide");
Команда.Добавить(Предел);
Команда.Добавить("-Quality");
Команда.Добавить(СтрокаКачества);
Иначе
Команда.Добавить("convert"); // ImageMagick 6; в версии 7 — "magick"
Команда.Добавить(ИмяИсходного);
Команда.Добавить("-auto-orient"); // повернуть по EXIF до удаления метаданных
Если НужноУменьшить Тогда
Команда.Добавить("-resize");
Команда.Добавить(Предел + "x" + Предел); // вписать в квадрат, пропорции сохраняются
КонецЕсли;
Команда.Добавить("-strip");
Команда.Добавить("-quality");
Команда.Добавить(СтрокаКачества);
Команда.Добавить(ИмяРезультата);
КонецЕсли;
ПараметрыЗапуска = ФайловаяСистема.ПараметрыЗапускаПрограммы();
ПараметрыЗапуска.ДождатьсяЗавершения = Истина;
ПараметрыЗапуска.ПолучитьПотокОшибок = Истина;
Результат = ФайловаяСистема.ЗапуститьПрограмму(Команда, ПараметрыЗапуска);
НовыеДанные = Неопределено;
ФайлРезультата = Новый Файл(ИмяРезультата);
Если Результат.КодВозврата = 0 И ФайлРезультата.Существует() Тогда
НовыеДанные = Новый ДвоичныеДанные(ИмяРезультата);
КонецЕсли;
УдалитьФайлТихо(ИмяИсходного);
УдалитьФайлТихо(ИмяРезультата);
Если НовыеДанные = Неопределено Тогда
ВызватьИсключение СтрШаблон("Программа завершилась с кодом %1: %2",
Результат.КодВозврата, Результат.ПотокОшибок);
КонецЕсли;
// Заменяем, только если файл стал легче хотя бы на 10%
Возврат ?(НовыеДанные.Размер() < ДанныеКартинки.Размер() * 0.9, НовыеДанные, ДанныеКартинки);
КонецФункции
Формат(Число, "ЧГ=0"): Строка(1200) даст «1 200» с неразрывным пробелом, и программа не разберёт такое число.-resize добавляется, только если картинка больше предела, иначе ImageMagick её растянет; -auto-orient поворачивает фото по EXIF до того, как -strip удалит метаданные.ЗапуститьПриложение на сервере, хотя БСП делает именно так, — проверьте функцию на своём релизе.Сервер на Linux. COM там нет, поэтому WIA и GFLAx отпадают. Остаются ОбрабатываемаяКартинка (ограничений по ОС в синтакс-помощнике нет — проверьте на своём релизе) и ImageMagick из репозитория: команда convert в версии 6 и magick в версии 7. При включённых профилях безопасности кластера программу нужно добавить в разрешённые приложения профиля.
&НаКлиенте. В тонком клиенте этого типа нет: уменьшайте картинку на сервере.Новый COMОбъект("GFLAx.GFLAx") — библиотека не зарегистрирована или зарегистрирована не той разрядности.ОбновитьФайл не добавили адрес текста.-auto-orient и скрипт выше его учитывают; платформенный вариант и WIA проверьте на своих фото.SaveFile в WIA поверх существующего файла писать не стоит: по практике метод его не перезаписывает, а завершается ошибкой. Функция выше берёт новое имя из ПолучитьИмяВременногоФайла() — по справке этот метод файл не создаёт.В файловой базе место внутри 1Cv8.1CD освобождается, но сам файл не уменьшается: нужна процедура «Тестирование и исправление» в конфигураторе с флажком «Сжатие таблиц информационной базы» — в монопольном режиме и после резервной копии. В клиент-серверной базе место освобождается внутри файлов СУБД; сжимать сами файлы MS SQL или PostgreSQL — отдельная плановая операция.
Да, но на сервере: в тонком клиенте ОбрабатываемаяКартинка недоступна. Надёжнее всего регламентное задание раз в сутки с вызовом СжатьКартинкиНоменклатуры — новые тяжёлые файлы попадут под отбор сами. Подписка на запись файла хуже: ОбновитьФайл снова запишет файл, обработчик сработает повторно, а пользователь будет ждать сжатия.
Ориентируйтесь на самое крупное место показа: карточку товара на сайте и требования маркетплейса к фото. Разумная отправная точка — 1200–1600 px по длинной стороне и качество JPEG 75–85; проверьте на своих снимках. Уменьшенную картинку обратно не увеличить, поэтому предел берите с запасом.
Логотипы и картинки с прозрачностью оставляйте в PNG — УменьшитьКартинку их только уменьшит. Фото, сохранённые в PNG по ошибке, выгоднее перевести в JPEG отдельным отбором: прозрачность при этом пропадёт.
Если картинок десятки тысяч, база распределённая или обмен с сайтом уже падает, проще поручить работу программисту: он подберёт способ под вашу платформу и ОС, настроит регламентное задание и проверит обмен после сжатия. Такая задача относится к доработке отчётов и обработок — разместите задачу, оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.