Как уменьшить размер файла Excel с картинками при сохранении из 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

При этом наблюдается странный эффект: достаточно открыть этот «тяжелый» файл непосредственно в программе MS Excel и просто пересохранить его без каких-либо изменений, как его размер мгновенно уменьшается в несколько раз (иногда в 5–10 раз). В этой статье мы подробно разберем, почему так происходит, проанализируем внутренние механизмы работы платформы 1С с графикой и рассмотрим практические методы, позволяющие получить оптимизированный размер файла напрямую из кода 1С.

Выясняем причину: почему файлы Excel из 1С получаются такими большими?

Прежде чем переходить к написанию кода, давайте разберем физику процесса. Формат .xlsx представляет собой обычный ZIP-архив, внутри которого находится XML-структура документа и папка с медиафайлами (расположенная по пути xl/media). Именно в этой папке хранятся все картинки, выведенные в отчет.

Существует три основные технические причины, по которым файлы из 1С весят слишком много:

  1. Неэффективная конвертация форматов платформой 1С. Когда мы сохраняем табличный документ в формат Excel, платформа выполняет экспорт графических объектов. При этом исходные изображения (особенно в формате .jpg) 1С часто принудительно конвертирует в формат .png. Поскольку алгоритмы сжатия PNG ориентированы на графику с четкими границами и однородными цветами, для обычных фотографий товаров этот формат подходит плохо — размер одного и того же изображения в PNG может быть в разы больше, чем в JPG. В старых версиях платформы или при сохранении в формат .xls картинки и вовсе могли преобразовываться в тяжеловесные BMP-файлы.
  2. Экспорт оригинального разрешения картинок. Очень часто в базе данных 1С хранятся фотографии товаров в высоком разрешении (например, оригиналы 1920x1080 пикселей). В отчете эта картинка сжимается визуально и выводится в маленькую ячейку размером 100x100 пикселей. Однако платформа 1С при экспорте запишет в архив Excel картинку в её исходном, гигантском разрешении.
  3. Избыточное описание геометрии при динамическом позиционировании. Использование некоторых методов позиционирования картинок в коде заставляет 1С генерировать сложную и избыточную разметку для каждого графического объекта, что увеличивает объем XML-структуры внутри файла Excel.

Когда мы открываем файл в MS Excel и пересохраняем его, офисный пакет автоматически оптимизирует медиа-содержимое: сжимает картинки до стандартного экранного разрешения (96 или 150 DPI), удаляет избыточные метаданные и оптимизирует структуру ZIP-архива. Наша задача — добиться аналогичного результата программными методами в 1С.

---

Способ 1. Отказ от динамического позиционирования (метод Расположить)

Рассмотрим частую ошибку при формировании отчетов с картинками в коде. Разработчики часто используют метод Расположить() для динамического размещения картинок в ячейках на лету. При этом для каждой строки генерируется новый объект рисунка. Это не только замедляет формирование отчета, но и существенно увеличивает размер результирующего файла при экспорте в Excel.

Проанализируем альтернативный, более экономный подход. Вместо создания новых рисунков программно, мы можем заранее создать в макете область с пустым рисунком-шаблоном. При выводе каждой строки мы будем получать эту область, обращаться к уже созданному элементу по имени и просто заменять его свойство Картинка. Это исключает избыточное динамическое позиционирование.

Посмотрим на пример реализации этого метода:


// Получаем макет нашего отчета
Макет = ПолучитьМакет("МакетОтчета");
ТабДок = Новый ТабличныйДокумент;

// Выводим шапку отчета
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ТабДок.Вывести(ОбластьШапка);

// Получаем область строки, в которой заранее в конфигураторе добавлен 
// пустой рисунок с уникальным именем "ИзображениеТовара"
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");

Выборка = Справочники.Номенклатура.Выбрать();
Пока Выборка.Следующий() Цикл
    
    // Заполняем текстовые параметры строки
    ОбластьСтрока.Параметры.ТоварНаименование = Выборка.Наименование;
    ОбластьСтрока.Параметры.Артикул = Выборка.Артикул;
    
    // Получаем картинку из присоединенных файлов или реквизита ХранилищеЗначения
    ДвоичныеДанныеКартинки = Выборка.ФайлКартинки.Получить();
    
    Если ЗначениеЗаполнено(ДвоичныеДанныеКартинки) Тогда
        // Обращаемся к существующему рисунку-шаблону по имени и меняем картинку
        ОбластьСтрока.Рисунки.ИзображениеТовара.Картинка = Новый Картинка(ДвоичныеДанныеКартинки);
    Иначе
        // Если картинки нет, очищаем рисунок в шаблоне
        ОбластьСтрока.Рисунки.ИзображениеТовара.Картинка = Новый Картинка;
    КонецЕсли;
    
    // Выводим подготовленную область в итоговый табличный документ
    ТабДок.Вывести(ОбластьСтрока);
    
КонецЦикла;

Этот простой прием позволяет значительно разгрузить внутреннюю структуру табличного документа перед его экспортом в XLSX.

---

Способ 2. Предварительное сжатие и изменение разрешения картинок в 1С

Если в базе данных хранятся тяжелые изображения, отправлять их "как есть" в отчет — плохая практика. Мы должны программно уменьшить разрешение картинок до реального физического размера ячейки вывода перед тем, как поместить их в табличный документ.

Начиная с платформы 8.3, в 1С появились мощные штатные инструменты для работы с графикой — объект ОбрабатываемаяКартинка. С его помощью мы можем изменить размер (сделать ресайз) и сохранить изображение в оптимизированном формате.

Разберем по шагам, как реализовать предварительную подготовку изображений:


Функция ПодготовитьОптимизированнуюКартинку(ИсходныеДанныеКартинки, ТребуемаяШирина = 150, ТребуемаяВысота = 150)
    
    // Если картинка пустая, возвращаем пустой объект
    Если Не ЗначениеЗаполнено(ИсходныеДанныеКартинки) Тогда
        Возврат Новый Картинка;
    КонецЕсли;
    
    Попытка
        // Создаем объект Картинка из двоичных данных
        ИсходнаяКартинка = Новый Картинка(ИсходныеДанныеКартинки);
        
        // Инициализируем объект для обработки графики
        ОбработкаГрафики = Новый ОбрабатываемаяКартинка(ИсходнаяКартинка);
        
        // Изменяем размер картинки под параметры отображения в отчете
        ОбработкаГрафики.УстановитьРазмер(ТребуемаяШирина, ТребуемаяВысота);
        
        // Преобразуем картинку в формат PNG. 1С при экспорте в Excel все равно 
        // будет конвертировать графику, поэтому сделаем это заранее и под контролем платформы
        ОптимизированнаяКартинка = ОбработкаГрафики.ПолучитьКартинку(ФорматКартинки.PNG);
        
        Возврат ОптимизированнаяКартинка;
    Исключение
        // Если формат файла не поддерживается или произошла ошибка обработки
        Возврат Новый Картинка;
    КонецПопытки;
    
КонецФункции

Применяя эту функцию при обходе выборки данных, мы гарантируем, что в итоговый файл Excel попадут только легкие эскизы (preview) изображений вместо многомегабайтных оригиналов. Это дает колоссальное сокращение веса итогового документа.

---

Способ 3. Автоматическое фоновое пересохранение через COM-объект Excel

Если отчет формируется на рабочем месте пользователя, где гарантированно установлен 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.

---

Способ 4. Прямая оптимизация XLSX-архива (для Linux-серверов и веб-клиента)

Для крупных систем, где генерация отчетов происходит на сервере без участия интерфейса MS Excel (в том числе под Linux), отлично подходит метод прямой распаковки XLSX-файла как ZIP-архива.

Алгоритм действий выглядит следующим образом:

  1. Записываем табличный документ в .xlsx во временный каталог.
  2. С помощью встроенного объекта 1С ЧтениеZipФайла распаковываем его структуру.
  3. Находим в распакованном каталоге папку xl/media, в которой лежат файлы изображений.
  4. Используя внешние консольные утилиты оптимизации графики (например, optipng, pngquant или встроенные серверные скрипты на Python/PHP), производим пакетное сжатие картинок в этой папке.
  5. С помощью объекта 1С ЗаписьZipФайла упаковываем файлы обратно в архив и меняем расширение итогового файла на .xlsx.

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

Резюме и рекомендации

Мы проанализировали проблему раздувания размера файлов Excel при экспорте из 1С и изучили методы борьбы с этим явлением. Для достижения наилучшего результата мы рекомендуем придерживаться следующих правил:

← На главную