При формировании печатных форм заказов, прайс-листов или каталогов с выводом миниатюр товаров многие сталкиваются с серьезной проблемой: если в документе более 100–200 строк, результирующий файл в формате XLS или XLSX разрастается до огромных размеров (15–50 Мб и более). В результате такой файл невозможно отправить по электронной почте, а сам табличный редактор при открытии зависает или сообщает о повреждении структуры документа. Разберем, почему это происходит и какими техническими способами можно решить данную проблему.
Многие разработчики заранее оптимизируют графические файлы перед загрузкой в информационную базу, сжимая их до 20–30 КБ. Однако при выгрузке табличного документа в формат электронных таблиц размер файла все равно оказывается гигантским. Проанализируем внутренние механизмы платформы 1С, приводящие к такому поведению:
РисунокТабличногоДокумента параметр РазмерКартинки установлен в значение Пропорционально или Авторазмер, платформа 1С выполняет программный рендеринг изображения под точные границы ячейки. В процессе экспорта сжатый исходный JPEG декодируется и повторно сохраняется как несжатый или слабосжатый растр PNG. В итоге миниатюра весом 20 КБ превращается в 200–300 КБ внутри результирующего файла.xl/media/ внутри архива для каждой отдельной строки.Рассмотрим тонкость настройки свойств рисунка в макете табличного документа. Поведение механизма экспорта напрямую зависит от свойства РазмерКартинки:
РазмерКартинки с Пропорционально на Растянуть. В этом режиме платформа не запускает процедуру пересчета и растеризации, а помещает исходный поток данных изображения без принудительной переконвертации в тяжелый PNG.Посмотрим на пример программной установки размеров рисунка с сохранением пропорций перед выводом секции:
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Рисунок = ОбластьСтрока.Рисунки.ИзображениеТовара;
// Задаем режим, исключающий пережатие платформой
Рисунок.РазмерКартинки = ИзменениеРазмераКартинки.Растянуть;
// Загружаем данные
Рисунок.Картинка = Выборка.ФайлКартинки.Получить();
// Рассчитываем ширину и высоту рисунка исходя из пропорций оригинала
Коэффициент = Рисунок.Картинка.Ширина / Рисунок.Картинка.Высота;
БазоваяВысота = 25; // высота в миллиметрах
Рисунок.Высота = БазоваяВысота;
Рисунок.Ширина = БазоваяВысота * Коэффициент;
ТабДок.Вывести(ОбластьСтрока);
Если в базе хранятся оригиналы изображений с высоким разрешением, их вывод напрямую в печатную форму недопустим. Разберем, как подготовить компактные миниатюры перед помещением в табличный документ средствами платформы 1С:
ОбработкаКартинок для масштабирования геометрии (например, до 100х100 пикселей) и снижения разрешения.Посмотрим на пример функции подготовки миниатюры:
Функция СформироватьМиниатюру(ИсходнаяКартинка, ЦелевойРазмер) Экспорт
Обработка = Новый ОбработкаКартинок;
Обработка.Загрузить(ИсходнаяКартинка);
Обработка.Масштабировать(ЦелевойРазмер, ЦелевойРазмер);
// Возвращаем оптимизированную миниатюру
Возврат Обработка.ПолучитьКартинку();
КонецФункции
Если штатный экспорт 1С по-прежнему раздувает файл, применим подход постобработки готового документа. Поскольку файл формата XLSX является стандартным ZIP-архивом, разберем по шагам, как обработать его встроенными объектами платформы ЧтениеZipФайла и ЗаписьZipФайла без использования внешних библиотек:
ТабличныйДокумент.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX).ЧтениеZipФайла и распаковываем сформированный XLSX во временный каталог на диске.xl/media/, где лежат все сохраненные платформой графические файлы.ОбработкаКартинок.ЗаписьZipФайла упаковываем файлы из временного каталога обратно в исходный файл XLSX с максимальной степенью сжатия.Посмотрим на пример кода, распаковывающего и упаковывающего XLSX-документ:
// Сохраняем исходный XLSX
ТабДокумент.Записать(ИмяФайлаXLSX, ТипФайлаТабличногоДокумента.XLSX);
// Распаковываем документ как архив
АрхивЧтение = Новый ЧтениеZipФайла(ИмяФайлаXLSX);
АрхивЧтение.ИзвлечьВсе(КаталогРаспаковки, РежимВосстановленияПутейФайловZIP.Восстанавливать);
АрхивЧтение.Закрыть();
// ... выполняем пережатие файлов в подкаталоге КаталогРаспаковки + "/xl/media" ...
// Запаковываем обратно
АрхивЗапись = Новый ЗаписьZipФайла(ИмяФайлаXLSX, , , МетодСжатияZIP.Сжатие, УровеньСжатияZIP.Максимальный);
АрхивЗапись.Добавить(КаталогРаспаковки + "/*", РежимСохраненияПутейZIP.ОтносительноРасположенияФайла);
АрхивЗапись.Записать();
Если объем позиций превышает 500–1000 строк, даже оптимизированный файл с графикой будет создавать существенную нагрузку на почтовые сервисы и компьютер клиента. В таких ситуациях рассмотрим альтернативные варианты архитектуры обмена: