Каждый разработчик 1С рано или поздно сталкивается с задачей выгрузки отчетов в формат Excel. Если отчет содержит только текстовые и числовые данные, проблем обычно не возникает. Однако, как только в отчет добавляются изображения (например, фотографии номенклатуры в прайс-листе или изображения товаров в заказе), итоговый документ Excel начинает весить аномально много — десятки, а иногда и сотни мегабайт.
При этом наблюдается странный эффект: достаточно открыть этот «тяжелый» файл непосредственно в программе MS Excel и просто пересохранить его без каких-либо изменений, как его размер мгновенно уменьшается в несколько раз (иногда в 5–10 раз). В этой статье мы подробно разберем, почему так происходит, проанализируем внутренние механизмы работы платформы 1С с графикой и рассмотрим практические методы, позволяющие получить оптимизированный размер файла напрямую из кода 1С.
Прежде чем переходить к написанию кода, давайте разберем физику процесса. Формат .xlsx представляет собой обычный ZIP-архив, внутри которого находится XML-структура документа и папка с медиафайлами (расположенная по пути xl/media). Именно в этой папке хранятся все картинки, выведенные в отчет.
Существует три основные технические причины, по которым файлы из 1С весят слишком много:
.jpg) 1С часто принудительно конвертирует в формат .png. Поскольку алгоритмы сжатия PNG ориентированы на графику с четкими границами и однородными цветами, для обычных фотографий товаров этот формат подходит плохо — размер одного и того же изображения в PNG может быть в разы больше, чем в JPG. В старых версиях платформы или при сохранении в формат .xls картинки и вовсе могли преобразовываться в тяжеловесные BMP-файлы.Когда мы открываем файл в MS Excel и пересохраняем его, офисный пакет автоматически оптимизирует медиа-содержимое: сжимает картинки до стандартного экранного разрешения (96 или 150 DPI), удаляет избыточные метаданные и оптимизирует структуру ZIP-архива. Наша задача — добиться аналогичного результата программными методами в 1С.
---
Рассмотрим частую ошибку при формировании отчетов с картинками в коде. Разработчики часто используют метод Расположить() для динамического размещения картинок в ячейках на лету. При этом для каждой строки генерируется новый объект рисунка. Это не только замедляет формирование отчета, но и существенно увеличивает размер результирующего файла при экспорте в Excel.
Проанализируем альтернативный, более экономный подход. Вместо создания новых рисунков программно, мы можем заранее создать в макете область с пустым рисунком-шаблоном. При выводе каждой строки мы будем получать эту область, обращаться к уже созданному элементу по имени и просто заменять его свойство Картинка. Это исключает избыточное динамическое позиционирование.
Посмотрим на пример реализации этого метода:
// Получаем макет нашего отчета
Макет = ПолучитьМакет("МакетОтчета");
ТабДок = Новый ТабличныйДокумент;
// Выводим шапку отчета
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ТабДок.Вывести(ОбластьШапка);
// Получаем область строки, в которой заранее в конфигураторе добавлен
// пустой рисунок с уникальным именем "ИзображениеТовара"
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
// Заполняем текстовые параметры строки
ОбластьСтрока.Параметры.ТоварНаименование = Выборка.Наименование;
ОбластьСтрока.Параметры.Артикул = Выборка.Артикул;
// Получаем картинку из присоединенных файлов или реквизита ХранилищеЗначения
ДвоичныеДанныеКартинки = Выборка.ФайлКартинки.Получить();
Если ЗначениеЗаполнено(ДвоичныеДанныеКартинки) Тогда
// Обращаемся к существующему рисунку-шаблону по имени и меняем картинку
ОбластьСтрока.Рисунки.ИзображениеТовара.Картинка = Новый Картинка(ДвоичныеДанныеКартинки);
Иначе
// Если картинки нет, очищаем рисунок в шаблоне
ОбластьСтрока.Рисунки.ИзображениеТовара.Картинка = Новый Картинка;
КонецЕсли;
// Выводим подготовленную область в итоговый табличный документ
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Этот простой прием позволяет значительно разгрузить внутреннюю структуру табличного документа перед его экспортом в XLSX.
---
Если в базе данных хранятся тяжелые изображения, отправлять их "как есть" в отчет — плохая практика. Мы должны программно уменьшить разрешение картинок до реального физического размера ячейки вывода перед тем, как поместить их в табличный документ.
Начиная с платформы 8.3, в 1С появились мощные штатные инструменты для работы с графикой — объект ОбрабатываемаяКартинка. С его помощью мы можем изменить размер (сделать ресайз) и сохранить изображение в оптимизированном формате.
Разберем по шагам, как реализовать предварительную подготовку изображений:
Функция ПодготовитьОптимизированнуюКартинку(ИсходныеДанныеКартинки, ТребуемаяШирина = 150, ТребуемаяВысота = 150)
// Если картинка пустая, возвращаем пустой объект
Если Не ЗначениеЗаполнено(ИсходныеДанныеКартинки) Тогда
Возврат Новый Картинка;
КонецЕсли;
Попытка
// Создаем объект Картинка из двоичных данных
ИсходнаяКартинка = Новый Картинка(ИсходныеДанныеКартинки);
// Инициализируем объект для обработки графики
ОбработкаГрафики = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
// Изменяем размер картинки под параметры отображения в отчете
ОбработкаГрафики.УстановитьРазмер(ТребуемаяШирина, ТребуемаяВысота);
// Преобразуем картинку в формат PNG. 1С при экспорте в Excel все равно
// будет конвертировать графику, поэтому сделаем это заранее и под контролем платформы
ОптимизированнаяКартинка = ОбработкаГрафики.ПолучитьКартинку(ФорматКартинки.PNG);
Возврат ОптимизированнаяКартинка;
Исключение
// Если формат файла не поддерживается или произошла ошибка обработки
Возврат Новый Картинка;
КонецПопытки;
КонецФункции
Применяя эту функцию при обходе выборки данных, мы гарантируем, что в итоговый файл Excel попадут только легкие эскизы (preview) изображений вместо многомегабайтных оригиналов. Это дает колоссальное сокращение веса итогового документа.
---
Если отчет формируется на рабочем месте пользователя, где гарантированно установлен MS Excel, мы можем применить "чит-код" — автоматизировать процесс ручного пересохранения файла, который делает пользователь.
После того как табличный документ записан на диск стандартным методом 1С, мы можем программно, в фоновом режиме, открыть этот файл через COM-соединение и дать команду Excel пересохранить его. Сам движок Microsoft Excel оптимизирует структуру архива и пересчитает DPI картинок.
Рассмотрим подробнее программную реализацию этого сценария:
// Сначала сохраняем табличный документ стандартными средствами 1С
ПутьКФайлу = "C:\Temp\ПрайсЛист.xlsx";
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
// Запускаем процесс оптимизации через COM-объект Excel
Попытка
// Создаем экземпляр приложения MS Excel
ExcelПриложение = Новый COMОбъект("Excel.Application");
// Скрываем окно Excel от пользователя, чтобы процесс происходил незаметно
ExcelПриложение.Visible = Ложь;
ExcelПриложение.DisplayAlerts = Ложь; // Отключаем предупреждения системы
// Открываем только что сохраненный из 1С файл
РабочаяКнига = ExcelПриложение.Workbooks.Open(ПутьКФайлу);
// Выполняем сохранение средствами самого MS Excel
РабочаяКнига.Save();
// Закрываем книгу и завершаем работу процесса Excel
РабочаяКнига.Close();
ExcelПриложение.Quit();
Сообщить("Файл успешно оптимизирован!");
Исключение
// В случае возникновения ошибок (например, если Excel не установлен на ПК)
// корректно освобождаем занятые ресурсы
Если Найти(ОписаниеОшибки(), "Excel.Application") = 0 Тогда
Если ЗначениеЗаполнено(ExcelПриложение) Тогда
ExcelПриложение.Quit();
КонецЕсли;
КонецЕсли;
ВызватьИсключение "Не удалось оптимизировать файл Excel. Ошибка: " + ОписаниеОшибки();
КонецПопытки;
Важное примечание: Данный способ отлично работает на стороне клиента (в тонком или толстом клиенте Windows). Использовать его на стороне сервера 1С (особенно под управлением ОС Linux) крайне не рекомендуется из-за ограничений архитектуры COM и лицензионной политики Microsoft.
---
Для крупных систем, где генерация отчетов происходит на сервере без участия интерфейса MS Excel (в том числе под Linux), отлично подходит метод прямой распаковки XLSX-файла как ZIP-архива.
Алгоритм действий выглядит следующим образом:
.xlsx во временный каталог.ЧтениеZipФайла распаковываем его структуру.xl/media, в которой лежат файлы изображений.ЗаписьZipФайла упаковываем файлы обратно в архив и меняем расширение итогового файла на .xlsx.Этот способ является наиболее технологичным и производительным, так как работает в полностью автономном режиме, не требуя стороннего тяжелого софта на сервере.
Мы проанализировали проблему раздувания размера файлов Excel при экспорте из 1С и изучили методы борьбы с этим явлением. Для достижения наилучшего результата мы рекомендуем придерживаться следующих правил: