Как программно узнать количество страниц в ODT и вставить штрихкод в колонтитул из 1С

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

Работа с документами формата OpenDocument Text (ODT) из среды 1С часто вызывает затруднения у разработчиков, привыкших к объектной модели MS Word. Одной из типовых задач является определение количества страниц в готовом договоре или отчете, а также динамическое добавление элементов оформления, таких как штрихкоды, в колонтитулы документа. Разберем по шагам, как решить эти задачи с помощью COM-соединения с LibreOffice/OpenOffice и методом прямого редактирования XML-структуры файла.

Способ 1. Получение количества страниц через UNO API (COM-соединение)

Для взаимодействия с LibreOffice из 1С мы используем COMОбъект("com.sun.star.ServiceManager"). Основная сложность при получении количества страниц заключается в том, что текстовый процессор Writer вычисляет страницы динамически в процессе отрисовки (layout) документа. Рассмотрим, как правильно обратиться к этим данным.

Многие разработчики пытаются использовать методы типа GetSheets(), однако это методы табличного процессора Calc. Для текстового документа Writer необходимо обращаться к текущему контроллеру представления. Проанализируем пример кода:


// Инициализация сервисов LibreOffice
ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");

// Настройка параметров открытия (открываем скрыто)
Параметры = НайтиПараметрыОткрытия(ServiceManager); // Массив PropertyValue
ООДокумент = Desktop.loadComponentFromURL(ПреобразоватьВURL(ИмяФайла), "_blank", 0, Параметры);

// Попытка получить количество страниц напрямую
КоличествоСтраниц = ООДокумент.getCurrentController().PageCount;

Важный нюанс: Если вы открываете документ в скрытом режиме (параметр Hidden = True), свойство PageCount может вернуть 0 или неактуальное значение. Это происходит потому, что фоновая верстка еще не завершена. Чтобы гарантированно получить верное число, рассмотрим более надежный метод с использованием «видимого курсора» (ViewCursor):


// Создаем курсор, привязанный к экрану (контроллеру)
ViewCursor = ООДокумент.getCurrentController().getViewCursor();

// Перемещаем курсор в самый конец документа
ViewCursor.jumpToLastPage();

// Теперь свойство getPage() вернет номер последней страницы
КоличествоСтраниц = ViewCursor.getPage();

Этот метод заставляет LibreOffice выполнить расчет геометрии документа до конца, что дает нам точный результат.

Способ 2. Извлечение количества страниц из метаданных (без открытия офиса)

Если нам нужно только прочитать количество страниц, не запуская тяжелое приложение LibreOffice, мы можем рассмотреть ODT-файл как обычный ZIP-архив. Внутри него находится файл meta.xml, содержащий статистику документа.

Рассмотрим алгоритм действий:

  1. Распаковываем ODT-файл как ZIP.
  2. Находим в корне архива файл meta.xml.
  3. Ищем в XML-структуре тег <meta:document-statistic> и его атрибут meta:page-count.

Внимание: Этот метод имеет ограничение. Значение в meta.xml обновляется только в момент сохранения файла в самом редакторе. Если вы программно меняли содержимое текста через XML и не пересохраняли его в интерфейсе Writer, данные в статистике могут оказаться устаревшими.

Способ 3. Программная вставка штрихкода в колонтитул

Ситуация усложняется, когда на каждую страницу документа нужно добавить штрихкод. Рассмотрим ситуацию: у вас есть готовый ODT-файл, и нужно вставить изображение штрихкода в нижний колонтитул (footer). Если штрихкод одинаковый для всех страниц, проще всего вставить его в описание Стиля страницы.

Выясним причину, почему работа через XML здесь эффективнее. При работе через COM-объект позиционирование картинки в колонтитуле требует сложных манипуляций с объектами TextGraphicObject и TextFrame. Через XML мы можем действовать прямолинейно.

Разберем структуру колонтитулов в ODT:

  1. Колонтитулы хранятся в файле styles.xml (реже в content.xml).
  2. Они описываются внутри тега <style:master-page> в блоках <style:header> или <style:footer>.
  3. Само изображение штрихкода должно быть предварительно помещено в папку Pictures/ внутри архива.

Посмотрим на пример описания картинки в XML для колонтитула:


<style:footer>
    <text:p text:style-name="Footer">
        <draw:frame draw:name="BarcodeImage" svg:width="4cm" svg:height="1.5cm">
            <draw:image xlink:href="Pictures/barcode.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
        </draw:frame>
    </text:p>
</style:footer>

Критически важный шаг: Если вы добавляете новый файл изображения в архив, вы ОБЯЗАНЫ зарегистрировать его в файле META-INF/manifest.xml. Без этого при открытии документа LibreOffice выдаст ошибку о повреждении файла. Добавьте в манифест следующую строку:

<manifest:file-entry manifest:full-path="Pictures/barcode.png" manifest:media-type="image/png"/>

Практические рекомендации по реализации

Проанализируем ситуацию: что делать, если в исходном документе вообще нет колонтитула? В этом случае нам нужно программно создать блок <style:footer> внутри <style:master-page>. Мастер-страница по умолчанию обычно называется "Standard".

Алгоритм автоматизации из 1С выглядит так:

  1. Генерируем картинку штрихкода средствами 1С и сохраняем её во временный файл PNG.
  2. Используя объект ЗаписьZipФайла и ЧтениеZipФайла, работаем с ODT как с архивом.
  3. Добавляем картинку в папку Pictures.
  4. Модифицируем styles.xml, вставляя блок <draw:frame> с ссылкой на нашу картинку.
  5. Обновляем manifest.xml.
  6. Собираем архив обратно.

Такой подход позволяет обрабатывать документы массово и с высокой скоростью, так как нам не требуется визуальное открытие окна редактора на сервере или клиенте. Если же ваша задача требует сложной переверстки, лучше использовать первый способ с COM-объектом, вызывая метод ООДокумент.store() после всех манипуляций.

Таким образом, мы рассмотрели основные методы управления страницами и содержимым ODT. Выбор метода зависит от ваших требований к производительности и необходимости визуального контроля процесса.

← На главную