[PF] Векторная печать PDF на C# теория

в 7:28, , рубрики: .net, .net development, C#, pcl, PDF, pdf-принтер, vector magic, Алгоритмы, Блог компании Тинькофф Банк, печать документов, Программирование
[PF] Векторная печать PDF на C# теория - 1

Продолжаю тему печати PDF документов из под .NET.

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

Первое, что пришло в голову — рендерить страницы документа в растровые картинки и при помощи стандартных средств .NET выводить их на печать. Хорошо, что класс PrintDocument позволяет налету менять лоток принтера. О таком подходе я писал в предыдущей статье

[PF] Векторная печать PDF на C# теория - 2

Как только заработало первое приложение, обнаружился существенный недостаток этого решения. После преобразования PDF в картинку, файл раздувался до огромных размеров, поэтому печать шла очень долго. При этом объемы печати продолжали расти, и я решил найти найти другой способ.

Мне помог язык управления принтером PCL от Hewlett-Packard. В интернете информации по нему оказалось крайне мало, не говоря уже о рунете. Единственное внятное описание — официальная спецификация. Сказано — сделано. Запустил HEX редактор + утилитку от HP JetAsm и начал изучать PCL. Не так страшен черт, как его малюют. Язык хоть и бинарный, но довольно простой и логичный. В результате, через пару часов собрал тестовое приложение. И во благо всем, кому это может быть полезно и интересно, расскажу немного про PCL.

[PF] Векторная печать PDF на C# теория - 3

В Википедии написано:

“PCL (от англ. Printer Command Language) — язык управления принтером, разработанный компанией Hewlett-Packard. В первой версии это был просто набор команд для печати ASCII-символов, теперь же, в версиях PCL6 и PCL-X стало возможным печатать в цвете, а также печатать изображения, но вне Microsoft Windows и HP-UX этот язык редко используется”

От себя добавлю, что это язык бинарный и стековый — поступающие данные заносятся на стек, а при появлении оператора данные забираются со стека в качестве аргументов оператора.

Официальное описание PCL есть в интернете. Также понять и валидировать содержимое PCL файлов поможет бесплатная утилита от HP JetAsm. Ее и другие полезные файлы можно взять с официального сайта без регистрации. Для это нужно перейти по ссылке, нажать SDK->Public и найти интересующие файлы.

Старый добрый GhostScript

[PF] Векторная печать PDF на C# теория - 4

Для начала нам нужно где-то достать pcl файл. Известная по прошлой статье утилита GhostScript из коробки умеет конвертировать PDF в PCL. Сделать это можно командой:

gswin64c.exe   -o example.pcl   -sDEVICE=pxlmono   example.pdf

Таким образом, без лишних движений мы получили PCL файл, который можно отправлять на принтер в качестве RawData.

Однако, если нужно не только распечатать документ, но и распределить его по лоткам принтера (например, согласно какому-то шаблону), то придется соответствующим образом модифицировать сгенерированный PCL файл. Для этого нужно разобраться с его устройством.

Итак, откроем PCL файл в каком-либо HEX редакторе. Я использовал WinHex.

[PF] Векторная печать PDF на C# теория - 5

Язык имеет иерархичную структуру. Но вначале устройству надо понять что дальше будет передаваться поток данных PCL, для это служит строка инициализации.

Иерархия операторов PCL имеет следующий вид:

<сессия>
  <старница>элементы страницы</старница>
  <старница>элементы страницы</старница>
  <старница>элементы страницы</старница>
</сессия> 

При этом сессий может быть несколько, а элементы страницы могут быть вложенными в другие элементы.

Начнем по порядку

[PF] Векторная печать PDF на C# теория - 6

Я уже говорил, что вначале потока идет стандартная строка. Именно по ней устройство определяет, что дальше будут передаваться данные в формате PСLXL. Длина строки инициализации 99 байт.

[PF] Векторная печать PDF на C# теория - 7

Дальше начинается поток данных PCL. Чтобы начать описывать элементы документа, должна быть открыта сессия, для этого существует команда BeginSession с кодом 0x41. Этот и другие коды команд можно найти в мануале. В одном файле может быть одна или несколько сессий, но чаще одна.

[PF] Векторная печать PDF на C# теория - 8

Там же смотрим аргументы, которые необходимо передать в BeginSession.

Аргументы имеют следующую структуру: [тип данных][данные][тип атрибута][атрибут]

UnitsPerMeasure — разрешение рабочей области x и y, имеет тип данных uint16_xy — структура из двух двухбайтовых слов.

[PF] Векторная печать PDF на C# теория - 9

Measure — перечисление единиц измерения, в которых будем работать {eInch | eMillimeter | eTenthsOfAMillimeter}

[PF] Векторная печать PDF на C# теория - 10

ErrorReport — перечисление, определяющее, как устройство будет обрабатывать ошибки.

[PF] Векторная печать PDF на C# теория - 11

BeginPage

Аналогичным образом инициализируется страница. Именно оператор BeginPage позволяет задать режим дуплекса и указать лоток из которого будет производиться забор бумаги.

Разберем аргументы оператора BeginPage.

Orientation — ориентация страницы, может принимать значения {ePortraitOrientation | eLandscapeOrientation | eReversePortrait | eReverseLandscape}

[PF] Векторная печать PDF на C# теория - 12

MediaSize — размер страницы, перечисление, в нашем случае eA4Paper. Вместо типа MediaSize может быть CustomMediaSize, CustomMediaSizeUnits.

[PF] Векторная печать PDF на C# теория - 13

MediaSource — источник бумаги.
0 — eDefaultSource
1 — eAutoSelect
2 — eManualFeed
3 — eMultiPurposeTray
4 — eUpperCassette
5 — eLowerCassette
6 — eEnvelopeTray
7 — eThirdCassette
1-248 — External Trays

Вместо MediaSource может быть MediaType с именем источника.

[PF] Векторная печать PDF на C# теория - 14

SimplexPageMode — одностраничный режим печати, обязательно должно быть значение eSimplexFrontSide = 0

Вместо SimplexPageMode может быть DuplexPageMode или DuplexPageSide.

DuplexPageSide — печатает одну страницу на одном листе, но можно задать на какой стороне листа {eFrontMediaSide | eBackMediaSide}

DuplexPageMode — две последовательные страницы печатаются на двух сторонах одного листа, можно задавать значения eDuplexHorizontalBinding = 0 и eDuplexVerticalBinding = 1

[PF] Векторная печать PDF на C# теория - 15

И завершается все это командой BeginPage с кодом 0x43

[PF] Векторная печать PDF на C# теория - 16

Надеюсь, принцип понятен. Этого достаточно для разработки приложения и модификации PCL файла таким образом, чтобы можно было менять режим Duplex — Simplex и указывать, из какого лотка забирать бумагу. Для этого в файле нужно найти объявление очередной страницы и изменить ее нужным образом.

Про реализацию демоприложения печатающего PDF в векторе по шаблону расскажу в следующей статье.

Если есть неточности или нужно больше деталей, пожалуйста, напишите об этом в комментариях.

Автор: Тинькофф Банк

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js