При работе в системе 1С:Предприятие (особенно на платформе 8.1 и 8.2 при использовании обычных форм) программисты часто сталкиваются со следующей проблемой: подготовленная печатная форма, содержащая логотипы, факсимиле, штрихкоды или другие картинки, при сохранении в файл Excel стандартным методом ТабДок.Записать(ПутьФайла, ТипФайлаТабличногоДокумента.XLS) отображается некорректно. Картинки смещаются, накладываются на текст, растягиваются или вовсе исчезают. При последующей отправке такого файла в качестве вложения через почтовый клиент MS Outlook получатель видит сломанную верстку.
В этой статье мы подробно разберем причины такого поведения платформы 1С и рассмотрим несколько эффективных способов решения проблемы: от настройки свойств картинок в самом макете до конвертации файлов с помощью COM-объектов MS Excel.
Почему же стандартный механизм экспорта в формат XLS так сильно искажает графические элементы? Дело в архитектурных особенностях старого движка экспорта 1С. Когда выполняется метод сохранения табличного документа в формат XLS (Excel 97-2003), платформа пытается сопоставить экранные координаты картинок с координатной сеткой ячеек Excel. Если в вашей печатной форме присутствуют объединенные ячейки разной высоты и ширины, алгоритм пересчета координат сбивается. Картинка теряет жесткую привязку к своей позиции и «уплывает».
Кроме того, при экспорте в старый формат XLS часто происходит сильное пересжатие графики, из-за чего изображение теряет четкость и детализацию. Чтобы обойти эти ограничения, мы можем использовать альтернативные подходы.
---
Прежде чем приступать к написанию сложного кода конвертации, попробуем решить проблему «малой кровью», правильно настроив свойства самого объекта Рисунок в макете табличного документа.
Рассмотрим ключевые правила позиционирования графики в макете:
Растянуть (в коде это соответствует свойству РазмерКартинки.Растянуть). Практика показывает, что именно этот режим наиболее стабильно транслирует исходное разрешение картинки в Excel, не ломая ее пропорций. Режимы «Авторазмер» и «Пропорционально» часто приводят к непредсказуемым результатам при экспорте.Расположить().Посмотрим на пример кода, который подготавливает картинку в печатной форме перед отправкой:
// Получаем область с картинкой из макета
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
Рисунок = ОбластьПодвал.Рисунки.Найти("Логотип");
Если Рисунок <> Неопределено Тогда
// Задаем режим вывода
Рисунок.ВыводитьНаПечать = Истина;
// Устанавливаем режим растягивания для сохранения качества
Рисунок.РазмерКартинки = РазмерКартинки.Растянуть;
// Альтернативно можно позиционировать рисунок по ячейкам области
// Рисунок.Расположить(ОбластьПодвал.Область("R1C1:R5C4"));
КонецЕсли;
---
Поскольку в бизнес-сценарии автора темы на компьютерах пользователей гарантированно установлен пакет MS Office (так как отправка писем идет через COM-объект Outlook.Application), мы можем использовать сам табличный процессор Microsoft Excel для сборки корректного файла.
Суть метода заключается в следующем: 1С великолепно выгружает табличные документы с картинками в формат HTML. При этом разметка остается идеально точной, а все изображения сохраняются во временный каталог. Мы можем программно открыть этот HTML в фоновом режиме MS Excel и пересохранить его как полноценный документ XLS. Excel сделает это без малейших искажений.
Разберем по шагам реализацию этого алгоритма:
// 1. Формируем уникальные имена для временных файлов
ИмяВременногоКаталога = КаталогВременныхФайлов();
ВременныйФайлHTML = ИмяВременногоКаталога + "temp_act_" + Формат(ТекущаяДата(), "ДФ=yyyyMMddHHmmss") + ".html";
ИтоговыйФайлXLS = ИмяВременногоКаталога + "Акт_Сверки.xls";
// 2. Записываем ТабличныйДокумент в формате HTML
ТабДок.Записать(ВременныйФайлHTML, ТипФайлаТабличногоДокумента.HTML);
// 3. Конвертируем HTML в XLS с помощью MS Excel через COM
Попытка
ExcelПриложение = Новый COMОбъект("Excel.Application");
ExcelПриложение.DisplayAlerts = Ложь; // Отключаем диалоговые окна
// Открываем сохраненный HTML-файл
Книга = ExcelПриложение.Workbooks.Open(ВременныйФайлHTML);
// Сохраняем книгу в формате Excel 97-2003 (код формата 56)
// Параметр 56 соответствует константе xlExcel8
Книга.SaveAs(ИтоговыйФайлXLS, 56);
// Закрываем книгу и приложение
Книга.Close(Ложь);
ExcelПриложение.Quit();
Сообщить("Конвертация файла успешно завершена.");
Исключение
Сообщить("Ошибка при работе с Excel: " + ОписаниеОшибки());
// В случае сбоя попытаемся высвободить COM-объект
Если ExcelПриложение <> Неопределено Тогда
ExcelПриложение.Quit();
КонецЕсли;
КонецПопытки;
Теперь полученный файл по пути ИтоговыйФайлXLS содержит в себе идеально сверстанную таблицу с картинками. Мы можем прикрепить его к письму Outlook и отправить адресату.
---
Если на клиентских компьютерах нет возможности использовать COM-соединение с Excel (например, из-за ограничений прав или использования альтернативных офисных пакетов), существует простой «костыль», который отлично работает на практике.
Мы можем записать табличный документ в формате HTML, но принудительно задать файлу расширение .xls. Современные версии Microsoft Excel при открытии такого файла автоматически распознают HTML-разметку и корректно отобразят документ вместе со всеми встроенными картинками.
Посмотрим на пример реализации данного трюка:
// Назначаем файлу расширение XLS, но записываем его как HTML
ФайлВложения = КаталогВременныхФайлов() + "акт.xls";
ТабДок.Записать(ФайлВложения, ТипФайлаТабличногоДокумента.HTML);
// Теперь этот файл можно прикреплять к письму Outlook.
// Единственный нюанс: при открытии файла Excel может выдать предупреждение
// о несоответствии расширения файла его реальному формату.
// Пользователю достаточно нажать "Да", чтобы открыть документ.
---
Иногда задача стоит иначе: необходимо вывести картинку не во вложенном файле XLS, а непосредственно в теле отправляемого электронного письма (например, логотип компании в подписи или графический отчет). Для этого используется механизм связывания картинок через идентификаторы CID (Content-ID).
Проанализируем пример кода, выполняющий такую отправку с использованием встроенного почтового клиента 1С:
// Создаем объект Интернет-почты и сообщение
ПочтовоеСообщение = Новый ИнтернетПочтовоеСообщение;
ПочтовоеСообщение.Тема = "Акт сверки взаиморасчетов";
ПочтовоеСообщение.Получатели.Добавить("client@email.com");
// Формируем уникальный идентификатор для картинки
УникальныйИдентификаторКартинки = Новый УникальныйИдентификатор;
ИдентификаторКартинкиСтрокой = Строка(УникальныйИдентификаторКартинки);
// Получаем картинку из макета (двоичные данные)
КартинкаЛоготип = ПолучитьМакет("ЛоготипИзображение"); // Двоичный макет с картинкой PNG/JPG
// Добавляем картинку во вложения письма и связываем через Идентификатор
Вложение = ПочтовоеСообщение.Вложения.Добавить(КартинкаЛоготип, "logo.png");
Вложение.Идентификатор = ИдентификаторКартинкиСтрокой;
// Формируем HTML-текст письма, ссылаясь на картинку через "cid:"
ТекстHTML = "<html>" +
"<body>" +
"<h3>Добрый день!</h3>" +
"<p>Высылаем вам акт сверки.</p>" +
"<p><img src=""cid:" + ИдентификаторКартинкиСтрокой + """ alt=""Логотип фирмы""></p>" +
"<p>С уважением, Администрация.</p>" +
"</body>" +
"</html>";
ПочтовоеСообщение.Тексты.Добавить(ТекстHTML, ТипТекстаПочтовогоСообщения.HTML);
// Отправка через ИнтернетПочту...
// ИнтернетПочта = Новый ИнтернетПочта;
// ИнтернетПочта.Подключиться(Профиль);
// ИнтернетПочта.Послать(ПочтовоеСообщение);
---
Теперь объединим полученные знания и напишем готовый блок кода для формирования печатной формы, конвертации ее через Excel COM и отправки готового вложения через почтовый клиент MS Outlook:
// 1. Формируем печатную форму (ТабличныйДокумент)
ТабДок = СформироватьПечатнуюФормуАкта(); // Ваша функция генерации документа
// 2. Определяем пути к файлам
ВременнаяПапка = КаталогВременныхФайлов();
ФайлHTML = ВременнаяПапка + "temp_print_form.html";
ФайлXLS = ВременнаяПапка + "Акт_Заказа_" + СокрЛП(ЭтотОбъект.НомерЗаказа) + ".xls";
// Записываем временный HTML
ТабДок.Записать(ФайлHTML, ТипФайлаТабличногоДокумента.HTML);
// 3. Конвертируем в честный XLS через Excel Application
Попытка
ExcelApp = Новый COMОбъект("Excel.Application");
ExcelApp.DisplayAlerts = Ложь;
КнигаExcel = ExcelApp.Workbooks.Open(ФайлHTML);
КнигаExcel.SaveAs(ФайлXLS, 56); // Формат Excel 97-2003
КнигаExcel.Close(Ложь);
ExcelApp.Quit();
Исключение
Сообщить("Не удалось выполнить точную конвертацию в XLS. Отправляем исходную копию.", СтатусСообщения.Внимание);
// В случае сбоя используем более простой механизм записи (или переименования)
ТабДок.Записать(ФайлXLS, ТипФайлаТабличногоДокумента.XLS);
КонецПопытки;
// 4. Инициализируем Outlook и отправляем письмо
Попытка
Outlook = Новый COMОбъект("Outlook.Application");
Письмо = Outlook.CreateItem(0); // 0 = mailItem
Письмо.Subject = "Акт заказа № " + ЭтотОбъект.НомерЗаказа + " от " + Формат(ЭтотОбъект.Дата, "ДФ=dd.MM.yyyy");
// Заполняем получателей
Для Каждого СтрокаАдреса Из ТаблицаПолучателей Цикл
Если СтрокаАдреса.Использовать Тогда
Письмо.Recipients.Add(СтрокаАдреса.Email);
КонецЕсли;
КонецЦикла;
// Прикрепляем сконвертированный XLS-файл с красивыми картинками
Письмо.Attachments.Add(ФайлXLS);
// Текст письма
Письмо.Body = "Здравствуйте! Во вложении к письму находится сформированный акт заказа.";
// Выводим окно письма пользователю на экран для проверки перед отправкой
Письмо.Display();
// Или отправляем сразу программно
// Письмо.Send();
Исключение
Сообщить("Произошла ошибка при интеграции с Outlook: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;
// 5. Очищаем временные файлы
Попытка
УдалитьФайлы(ФайлHTML);
// Файл XLS удалять сразу нельзя, если используется метод Display(),
// так как Outlook должен успеть прочитать его с диска.
// Удаление лучше производить при закрытии формы или в фоновом режиме.
Исключение
// Игнорируем ошибки удаления временных файлов
КонецПопытки;
Применение любого из описанных выше методов позволит вам избавиться от проблем искажения верстки графических объектов в файлах Excel при экспорте из системы 1С:Предприятие.