Работа с макетами офисных документов. Печать в DOCX методами БСП без COM объекта
Всё больше организаций выбирает для серверов под 1С операционные системы Linux. Одним из отличий систем Windows и Linux является отсутствие COM объектов, которые зачастую использовались для формирования печатных форм офисных документов (Word). Конечно, можно выполнять печать и на клиенте, но есть риск импортозамещения. В работе у меня случались проблемы с зависанием процесса Word, поэтому я не люблю его использовать.
В БСП (библиотека стандартных подсистем) существуют механизмы работы с офисными документами без использования COM объектов. Попробовал поработать с этим механизмом, сформировал заметку, где описал возможности и то, как с ним нужно работать. Описание механизма на версии БСП 3.1.9, механизм этот существовал и в более ранних версиях.
Примечание: механизм работает с документами формата docx.
Процедуры
Начнем с описания процедур. Описание скопировано из инструкции БСП чтобы было под рукой. Библиотека стандартных подсистем 3.1.9/Работа с макетами офисных документов
В некоторых процедурах присутствуют параметры с меткой «Удалить», они не используются в процедурах, но и не везде им задано значение по умолчанию, поэтому при вызове процедуры нужно их указывать, чтобы не поймать ошибку.
ИнициализироватьМакетОфисногоДокумента
Подготавливает макет для использования в процедурах формирования печатной формы.
Нужна чтобы из двоичных данных макета получить структуру с описанием областей
Принимает только документ с расширением docx
Пример вызова
Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, УдалитьТипМакета, УдалитьИмяМакета)
Параметры
ДвоичныеДанныеМакета — ДвоичныеДанные — двоичные данные макета;
УдалитьТипМакета — Строка — устаревший параметр, не используется;
УдалитьИмяМакета — Строка — устаревший параметр, не используется.
Возвращаемое значение
Структура:
* ИмяКаталога — Строка — путь, куда распаковывается контейнер DOCX шаблона для дальнейшего анализа;
* СтруктураДокумента — Структура — информация по областям, разделам и колонтитулам, входящих в шаблон.
ВставитьРазрывНаНовуюСтроку
Вставляет разрыв между строками в виде символа перевода строки.
Пример вызова
УправлениеПечатью.ВставитьРазрывНаНовуюСтроку(ПечатнаяФорма)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
ЗаполнитьПараметры
Заполняет параметры области печатной формы.
Работает со всеми типами областей
Пример вызова
УправлениеПечатью.ЗаполнитьПараметры(ПечатнаяФорма, Данные)
Параметры
ПечатнаяФорма — Структура — область печатной формы либо сама печатная форма.
Данные — Структура — данные заполнения.
ИнициализироватьПечатнуюФорму
Конструктор печатной формы в формате офисного документа.
Пример вызова
ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(УдалитьТипДокумента, УдалитьНастройкиСтраницыМакета, Макет)
Параметры
УдалитьТипДокумента — Строка — устаревший параметр, не используется;
УдалитьНастройкиСтраницыМакета — Соответствие — устаревший параметр, не используется;
Макет — см. ИнициализироватьМакетОфисногоДокумента
Возвращаемое значение
Структура — описание создаваемой печатной формы:
* ИмяКаталога — Строка — путь, куда помещается структура каталогов конечного документа для последующей сборки контейнера DOCX.
* СтруктураДокумента — см. УправлениеПечатьюСлужебный.ИнициализироватьДокумент
* Тип — Строка
* ПоследняяВыделеннаяОбласть — Структура
ОбластьМакета
Получает область из макета печатной формы.
Пример вызова
Результат = УправлениеПечатью.ОбластьМакета(СсылкаНаМакет, ОписаниеОбласти)
Параметры
СсылкаНаМакет — Структура — макет печатной формы.
ОписаниеОбласти — Структура:
* ИмяОбласти — Строка — имя области;
* ТипТипОбласти — Строка — тип области:
«ВерхнийКолонтитул», «НижнийКолонтитул»,
«ВерхнийТитульныйКолонтитул», «НижнийТитульныйКолонтитул»,
«ВерхнийЧетныйКолонтитул», «НижнийЧетныйКолонтитул»,
«Общая»,
«СтрокаТаблицы»,
«Список».
Возвращаемое значение
Структура — область макета.
ОчиститьСсылки
Удаляет временные файлы, образовавшиеся после раскрытия xml-структуры макета.
Необходимо вызывать каждый раз после завершения формирования макета и печатной формы, а также в случае аварийного завершения формирования.
Пример вызова
УправлениеПечатью.ОчиститьСсылки(ПечатнаяФорма, УдалитьЗакрытьПриложение)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
УдалитьЗакрытьПриложение — Булево — устаревший параметр, не используется.
ПрисоединитьИЗаполнитьКоллекцию
Добавляет область в печатную форму из макета, при этом заменяя параметры в области значениями из данных объекта.
Применяется при множественном выводе области выводе области. (В этом месте на ИТС опечатка)
Применяется этот метод только для областей с типом СтрокаТаблицы и Список
Пример вызова
УправлениеПечатью.ПрисоединитьИЗаполнитьКоллекцию(ПечатнаяФорма, ОбластьМакета, Данные, ПереходНаСледСтроку)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
ОбластьМакета — см. УправлениеПечатью.ОбластьМакета
Данные — Массив — коллекция элементов типа Структура — данные объекта.
ПереходНаСледСтроку — Булево — Истина, если требуется вставить разрыв после вывода области.
ПрисоединитьОбласть
Присоединяет область в печатную форму из макета.
Применяется при одиночном выводе области.
Пример вызова
УправлениеПечатью.ПрисоединитьОбласть(ПечатнаяФорма, ОбластьМакета, ПереходНаСледующуюСтроку)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
ОбластьМакета — см. УправлениеПечатью.ОбластьМакета
ПереходНаСледующуюСтроку — Булево — Истина, если требуется вставить разрыв после вывода области.
ПрисоединитьОбластьИЗаполнитьПараметры
Добавляет область в печатную форму из макета, при этом заменяя параметры в области значениями из данных объекта.
Применяется при одиночном выводе области.
Пример вызова
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, Данные, ПереходНаСледующуюСтроку)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
ОбластьМакета — см. УправлениеПечатью.ОбластьМакета
Данные — Структура — данные заполнения.
ПереходНаСледующуюСтроку — Булево — Истина, если требуется вставить разрыв после вывода области.
СформироватьДокумент
Формирует файл выходной печатной формы и помещает его в хранилище.
Необходимо вызывать после помещения в структуру печатной формы всех необходимых областей.
Пример вызова
Результат = УправлениеПечатью.СформироватьДокумент(ПечатнаяФорма)
Параметры
ПечатнаяФорма — см. УправлениеПечатью.ИнициализироватьПечатнуюФорму
Возвращаемое значение
Строка — адрес хранилища, куда помещается сформированный файл.
Макет
Принцип построения макета офисного документа похож на принцип построения макета 1С. В документе мы задаем области и указываем параметры, при выводе получаем области из макета и заполняем их.
Для указания параметра в макете мы пишем {v8 ИмяПараметра}.
При формировании печатной формы для заполнения областей мы передаем структуру, где ключ – это имя параметра. Всё, что мы передаем в качестве значения параметра будет преобразовано в строку методом Строка(). Если необходимо соблюдать определённое форматирование, то следует при заполнении структуры данных самостоятельно преобразовать значение в строку, отформатировать согласно требованиям. Параметр можно указать в качестве адреса гиперссылки и заполнить его.
При формировании макета мне пришлось перепроверять форматирование параметров, потому что копировал из другого документа. Стало интересно как определяется форматирование текста, выводимого в параметр. Опытным путем было установлено, что форматирование определяется по первому символу имени параметра.
Я проверял на выделении текста цветом, полагаю с остальным форматированием текста работает также.
Для указания области мы заключаем часть макета в «кавычки» такого вида:
Начало области — {v8 Область.НаименованиеОбласти}
Конец области — {/v8 Область.НаименованиеОбласти}
Начало и конец области должны быть в основной части документа, нельзя размещать область или одну из «кавычек» в таблице. Заметил, что текст внутри области и «кавычки», окружающие область, должны находиться на разных строках, иначе при получении области программа не видит текст внутри области. И не нужно помещать область в область при разборе макета, программа определит только область верхнего уровня, а внутреннюю не увидит.
Для вывода таблиц шапку таблицы и строку таблицы мы заключаем в отдельные области, также для вывода списка
Для вывода списка с разными уровнями нужно заранее подготовить области в макете, и реализовать их вывод соответствующим образом, тогда можно формировать списки с различными уровнями вложенности.
Для вывода разрыва страниц в макете нужно подготовить область с заключенным в неё разрывом страниц, и выводить его при необходимости.
Но не все области нужно обозначать «кавычками». Колонтитулы сами по себе являются областями. Их не нужно обозначать, к ним нужно обратиться по их имени, которое нельзя изменить. Есть 6 областей колонтитула. Они будут присутствовать в макете в зависимости от настроек документа.
ВерхнийЧетныйКолонтитул, НижнийЧетныйКолонтитул – эти области появляются, если установлена настройка «Разные колонтитулы для четных и не четных страниц», это колонтитул четных страниц.
ВерхнийТитульныйКолонтитул, НижнийТитульныйКолонтитул – эти области появляются, если установлена настройка «Особый колонтитул для первой страницы», и как видно из названия это колонтитул первой страницы.
ВерхнийКолонтитул, НижнийКолонтитул – эти области появляются без специальных настроек, если включен отдельный колонтитул для первой страницы, то область будет обозначать колонтитул для всех остальных страниц. Если включена настройка различных четных и нечетных колонтитулов, то будет отвечать за нечетные колонтитулы.
При получении области из макета необходимо передать и имя области, и тип области: СтрокаТаблицы — для вывода таблицы; Список — для вывода списка; ВерхнийКолонтитул, ВерхнийЧетныйКолонтитул, ВерхнийТитульныйКолонтитул, НижнийКолонтитул, НижнийЧетныйКолонтитул, НижнийТитульныйКолонтитул — для вывода колонтитулов; Общая — для всего остального.
Заметил, что при разборе макета даже из пустого документа читается область «Абзац», её можно использовать как общую область (там просто символ переноса строки).
Принцип построения процедуры формирования документа
Все процедуры формирования документа выполняются на сервере
//Получаем макет из двоичных данных файла
Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета,,);
//Нужно проверить что макет сформирован
Если Макет = Неопределено Тогда
ОбщегоНазначения.СообщитьПользователю("Неудалось получить макет документа");
Возврат;
КонецЕсли;
//Инициализируем печатную форму из макета
ПечатнаяФорма = УправлениеПечатью.ИнициализироватьПечатнуюФорму(,,Макет);
//На случай если при формировании возникнет ошибка выполняем заполнение в попытке. В случае если возникнет ошибка нужно очистить временные файлы печатной формы
Попытка
//Тут идет наполнение печатной формы
//О нем написано дальше
//Когда закончили заполнять печатную форму формируем документ и помещаем его во временное хранилище
АдресВХранилище = УправлениеПечатью.СформироватьДокумент(ПечатнаяФорма);
//Когда работа с печатной формой закончена нужно удалить её временные файлы
УправлениеПечатью.ОчиститьСсылки(ПечатнаяФорма);
Исключение
//В случае возникновения ошибки удаляем временные файлы макеета и сообщаем об ошибке
УправлениеПечатью.ОчиститьСсылки(ПечатнаяФорма);
ОбщегоНазначения.СообщитьПользователю(ОписаниеОшибки());
ЖурналРегистрации.ДобавитьСообщениеДляЖурналаРегистрации("Обработка формирования документов", УровеньЖурналаРегистрации.Ошибка, ,, ОписаниеОшибки());
КонецПопытки;
//Так же когда работа с макетом окончена нужно удалить его временные файлы
УправлениеПечатью.ОчиститьСсылки(Макет);
//По итогу если не возникло каких-либо ошибок мы имеем адрес файла во временном хранилище
//Адрес можем передать на клиента для дальнейшего сохранения файла
//Для сохранения готового документа я обычно использую процедуры:
//НачатьПолучениеФайлаССервера(<Адрес>, <ИмяФайла>, <ПараметрыДиалогаПолученияФайлов>)
//НачатьПолучениеФайловССервера(<ПолучаемыеФайлы>, <ПараметрыДиалогаПолученияФайлов>, <ПараметрыПолученияАрхиваФайлов>)
//Они асинхронные и варианты синтаксиса "с диалогом" в вэб клиенте не требуют расширения работы с файлами
Теперь посмотрим, как мы можем заполнить документ
В основном вывод областей выглядит следующим образом. Сначала получаем область. Затем выводим её в документ и параллельно заполняем параметры
ОбластьМакета = УправлениеПечатью.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти","ОбластьВМакете","Общая"));
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, СтруктураСДаннымиДляЗаполнения, ПереходНаСледСтроку);
Процесс заполнения параметров области и её вывод можно разделить, воспользовавшись процедурами. Это удобно, когда одну и туже область нужно заполнить параметрами из разных источников, чтобы не объединять их в одну структуру можно просто заполнить её из разных.
УправлениеПечатью.ЗаполнитьПараметры(ОбластьМакета, СтруктураСДаннымиДляЗаполнения);
УправлениеПечатью.ПрисоединитьОбласть(ПечатнаяФорма, ОбластьМакета, ПереходНаСледующуюСтроку);
Можно сначала сформировать документ и вывести в него все области, а уже после заполнить параметры в печатной форме. Отмечу, что области можно получить заранее в начале блока заполнения. Если вы используете одну область несколько раз, заполняете параметры в области методом ЗаполнитьПараметры, то заполнить её другими значениями уже не получится. Такой проблемы не возникнет, если использовать методы ПрисоединитьОбластьИЗаполнитьПараметры и ПрисоединитьИЗаполнитьКоллекцию, так как они сначала выводят область в печатную форму, а затем заполняют параметры. Либо сначала вывести область в макет, а затем заполнить параметры. Это аналогично методу ПрисоединитьОбластьИЗаполнитьПараметры.
Вывод таблицы или списка можно реализовать разными способами. Вариант 1: выполнить заполнение и вывод области в цикле.
Для Каждого СтруктураДанныхИзМассива Из МассивСтруктурСДанными Цикл
ОбластьМакета = УправлениеПечатью.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти","ОбластьВМакете","СтрокаТаблицы"));
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, СтруктураСДаннымиДляЗаполнения);
КонецЦикла;
Вариант 2: выполнить заполнение, используя метод ПрисоединитьИЗаполнитьКоллекцию, он работает также, просто не придется реализовывать цикл
ОбластьМакета = УправлениеПечатью.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти","ОбластьВМакете","Список"));
УправлениеПечатью.ПрисоединитьИЗаполнитьКоллекцию(ПечатнаяФорма, ОбластьМакета, МассивСтруктурСДанными, ПереходНаСледСтроку);
При необходимости можно вставить перенос строки, используя отдельную процедуру или, передав Истина в параметр процедуры заполнения «ПереходНаСледующуюСтроку»
УправлениеПечатью.ВставитьРазрывНаНовуюСтроку(ПечатнаяФорма);
Вывод картинок. Нашел два способа вывода картинок, точнее способы передачи параметра картинки. Первый рабочий второй нет. Второй метод не работает из-за ошибки в методе, разберем по порядку.
Можно выводить картинку также в параметр. Для этого создаем структуру со свойствами Ширина, Высота, АдресКартинки. АдресКартинки – это адрес двоичных данных во временном хранилище, что такое Высота и Ширина и так понятно. Задавать значения ширины и высоты не обязательно (он и без них её выведет), либо можно задать что-то одно, и программа рассчитает второй параметр пропорционально первому. Получившуюся структуру засовываем в другую структуру, в которой уже Ключ – это имя параметра в макете и выводим любым понравившимся методом.
СтруктураКартинки = Новый Структура;
СтруктураКартинки.Вставить("Ширина", 50);
СтруктураКартинки.Вставить("Высота", 50);
СтруктураКартинки.Вставить("АдресКартинки", АдресКартинки);
ОбластьМакета = УправлениеПечатью.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти","Область1","Общая"));
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, Новый Структура("Параметр", СтруктураКартинки));
Второй способ (напоминаю, что он не работает из-за ошибки в коде) не требует формировать структуру, можно в качестве параметра передать адрес двоичных данных во временном хранилище.
ОбластьМакета = УправлениеПечатью.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти","Область1","Общая"));
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьМакета, Новый Структура("Параметр", АдресКартинки));
Но в процедуре заполнения есть ошибка. Если мы передаем адрес, то программа понимает, что это картинка, но не определяет структуру с её размерами. Если мы передаем в качестве параметра структуру с адресом, даже, если там нет значений ширины и высоты, то структура для указания размеров будет определена дальше в коде. Для справки: ошибка находится в модуле УправлениеПечатьюСлужебный в процедуре ЗаполнитьПараметрыОбласти.
Comments
So empty here ... leave a comment!