Как масштабировать печатную форму в 1С, чтобы она всегда умещалась на одну страницу

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

В практике разработки на платформе «1С:Предприятие» часто возникает задача жесткого форматирования печатных документов. Бизнес-требования или жесткие регламенты корпоративных стандартов могут требовать, чтобы табличный документ (например, счет, расходная накладная или универсальный передаточный документ) при любых обстоятельствах выводился ровно на одну страницу. На первый взгляд решение кажется очевидным — использовать цикл с уменьшением масштаба или установить свойство автоматического масштабирования. Однако на практике разработчики сталкиваются с тем, что код масштабирования игнорируется, зависает или приводит к непредсказуемым результатам. В этой статье мы подробно разберем, почему возникают такие проблемы и как их гарантированно решить.

Почему стандартный цикл подбора масштаба перестает работать?

Рассмотрим классический алгоритм, который часто пытаются применить разработчики для принудительного сжатия табличного документа до одной страницы:


ТабДокумент.АвтоМасштаб = Ложь;
ТабДокумент.МасштабПечати = 100;

Пока ТабДокумент.КоличествоСтраниц() > 1 Цикл
    Если ТабДокумент.МасштабПечати <= 10 Тогда
        Прервать;
    КонецЕсли;
    ТабДокумент.МасштабПечати = ТабДокумент.МасштабПечати - 1;
КонецЦикла;

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

  1. Принудительные горизонтальные разделители страниц. Если в коде формирования документа (в цикле вывода строк табличной части) используется метод ПроверитьВывод() и принудительно вставляется разделитель с помощью метода ВывестиГоризонтальныйРазделительСтраниц(), то никакой масштаб не поможет сжать документ. Разделитель жестко указывает платформе перенести последующий текст на новый лист. В результате мы получаем документ, уменьшенный до микроскопического размера, но все равно размазанный по нескольким страницам.
  2. Выполнение кода на стороне сервера. Функции подсчета страниц КоличествоСтраниц() и проверки заполнения ПроверитьВывод() обращаются к подсистеме печати операционной системы и драйверу принтера по умолчанию. На сервере под управлением Windows или Linux часто отсутствуют установленные принтеры (или нет доступа к ним у пользователя, под которым запущен серверный процесс 1С). В этом случае методы могут возвращать некорректные данные или вызывать критические сбои. К тому же вызов этих методов в цикле на сервере создает огромную нагрузку на рабочий процесс rphost.
  3. Переопределение настроек через параметры печати. Свойство ИмяПараметровПечати (или КлючПараметровПечати) мгновенно затирает любые программно установленные свойства макета (поля, ориентацию, масштаб) теми значениями, которые сохранены в системном хранилище для текущего пользователя с прошлого сеанса печати.

Рассмотрим детально, как обойти каждое из этих ограничений.

Решение №1: Отключение разделителей страниц при формировании макета

Проанализируем типовой алгоритм вывода строк табличной части, который применяется в конфигурациях 1С. Платформа проверяет, умещается ли текущая строка вместе с шапкой и подвалом на текущую страницу, и если нет — принудительно создает новую страницу:


Для Каждого СтрокаТовары Из СсылкаНаОбъект.Товары Цикл
    // Заполнение параметров области строки...
    МассивПроверкиВывода = Новый Массив;
    МассивПроверкиВывода.Добавить(ОбластьСтрока);
    МассивПроверкиВывода.Добавить(ОбластьПодвал);
    
    Если Не ТабличныйДокумент.ПроверитьВывод(МассивПроверкиВывода) Тогда
        ТабличныйДокумент.ВывестиГоризонтальныйРазделительСтраниц();
        ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);
    КонецЕсли;
    
    ТабличныйДокумент.Вывести(ОбластьСтрока);
КонецЦикла;

Если перед нами стоит задача уместить документ на одну страницу, мы должны полностью исключить добавление горизонтальных разделителей. Для этого рекомендуется передавать в процедуру печати специальный параметр (например, структуру настроек) или флаг ПоместитьНаОднуСтраницу. Модернизируем алгоритм вывода строк следующим образом:


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

В таком сценарии документ будет сформирован одним сплошным полотном без единого жесткого разрыва. И только после этого к нему можно будет корректно применить алгоритм программного сжатия масштаба.

Решение №2: Правильное управление параметрами печати

Выясним причину, по которой настройки масштабирования могут сбрасываться. Если в коде вашей печатной формы сначала настраиваются свойства табличного документа, а затем присваивается имя параметров печати, то все настройки будут потеряны:


// НЕПРАВИЛЬНЫЙ ПОРЯДОК: Настройки сбросятся на сохраненные пользователем!
ТабДокумент.МасштабПечати = 85;
ТабДокумент.АвтоМасштаб = Ложь;
ТабДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_РеализацияТоваровУслуг";

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


// ПРАВИЛЬНЫЙ ПОРЯДОК:
ТабДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_РеализацияТоваровУслуг";
// Переопределяем параметры поверх загруженных системных настроек:
ТабДокумент.АвтоМасштаб = Ложь;
ТабДокумент.МасштабПечати = 100; // Стартовое значение для подбора

Решение №3: Безопасный подбор масштаба на стороне клиента

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

Рассмотрим оптимизированную клиентскую процедуру, которая выполняет сжатие документа:


&НаКлиенте
Процедура ПодогнатьТабличныйДокументПодСтраницу(ТабличныйДокумент)
    
    // Отключаем автомасшабирование, чтобы работал ручной подбор масштаба
    ТабличныйДокумент.АвтоМасштаб = Ложь;
    ТабличныйДокумент.МасштабПечати = 100;
    
    // Задаем предельное значение, ниже которого текст станет абсолютно нечитаемым
    МинимальныйМасштаб = 40; 
    
    // Цикл постепенного уменьшения масштаба
    Пока ТабличныйДокумент.КоличествоСтраниц() > 1 Цикл
        
        Если ТабличныйДокумент.МасштабПечати <= МинимальныйМасштаб Тогда
            // Достигнут предел читаемости, включаем АвтоМасштаб как резервный вариант
            ТабличныйДокумент.АвтоМасштаб = Истина;
            Прервать;
        КонецЕсли;
        
        // Уменьшаем масштаб с шагом в 2-3% для ускорения работы цикла
        ТабличныйДокумент.МасштабПечати = ТабличныйДокумент.МасштабПечати - 2;
        
    КонецЦикла;
    
КонецПроцедуры

Такой подход гарантирует, что расчет геометрии листа будет производиться локально на компьютере пользователя с использованием ресурсов его текущего принтера, установленного в операционной системе по умолчанию.

Решение №4: Оптимизация полей и колонтитулов печатной формы

Зачастую для того, чтобы документ поместился на одну страницу, не требуется сильно уменьшать масштаб и портить читаемость шрифтов. Достаточно минимизировать нерабочие зоны документа — поля и колонтитулы. По умолчанию платформа создает довольно большие отступы. Мы можем существенно увеличить полезную площадь листа программным путем:


ТабДокумент.ПолеСверху = 5;   // Размер в миллиметрах
ТабДокумент.ПолеСнизоу = 5;   // Минимизируем нижний отступ
ТабДокумент.ПолеСлева = 10;
ТабДокумент.ПолеСправа = 5;

// Полностью убираем колонтитулы, если они не несут важной информации
ТабДокумент.РазмерКолонтитулаСверху = 0;
ТабДокумент.РазмерКолонтитулаСнизу = 0;

Уменьшение верхнего и нижнего полей до 5 мм освобождает до 1.5–2 сантиметров вертикального пространства, что эквивалентно размещению еще 3–4 строк табличной части без изменения общего масштаба печатной формы.

Решение №5: Геометрический лайфхак с шириной колонок (АвтоМасштаб)

Стандартное свойство 1С АвтоМасштаб = Истина работает исключительно по ширине листа. Платформа уменьшает масштаб ровно настолько, чтобы все колонки поместились по горизонтали, при этом игнорируя высоту документа. Мы можем использовать эту особенность для обхода медленных циклов с расчетом КоличествоСтраниц().

Суть метода заключается в пропорциональном увеличении ширины колонок табличного документа. Если мы искусственно расширим документ по горизонтали, включенное свойство АвтоМасштаб будет вынуждено сжать весь документ, чтобы уместить его по ширине печатного листа. А поскольку масштабирование всегда происходит пропорционально (сохраняя соотношение сторон), документ автоматически уменьшится и по высоте, тем самым укладываясь на одну страницу.

Для реализации этого метода можно добавить в макет крайнюю правую сервисную колонку и динамически регулировать её ширину, либо пропорционально увеличивать ширину всех колонок макета при формировании документа на сервере.

Заключение

Для надежного масштабирования печатной формы на одну страницу рекомендуется придерживаться следующей стратегии:

  1. При формировании табличного документа полностью отказаться от вызова ВывестиГоризонтальныйРазделительСтраниц().
  2. Переопределять свойства полей, ориентации и масштаба строго после назначения ИмяПараметровПечати.
  3. Минимизировать поля документа до уровня 5 мм и обнулить высоту колонтитулов.
  4. Выполнять проверку количества страниц и уменьшение масштаба исключительно в клиентском контексте, чтобы избежать зависания сервера и гарантировать точность расчетов.
← На главную