Я разрабатываю эмулятор принтера (частично) в PostScript. Система команд, которую я хочу эмулировать, предназначена для термопринтеров на рулонной бумаге, которые в основном используются для печати чеков в точках продаж. Я бы предпочел выполнять операции в том же порядке, что и реальный принтер, а это означает, что моя программа не знает размер страницы, пока не встретит команду «вырезать». Я хочу, чтобы программа работала с принтерами CUPS переменного размера бумаги ¹.
Могу ли я изменить высоту страницы после выполнения команд рисования/отображения без исчезновения заполненных частей документа?
Я попытался изменить словарь устройства страницы в конце документа, но если я изменю массив PageSize, все в документе исчезнет.
Например, если я запускаю следующую программу:
<< /PageSize [ 100 30 ] >> setpagedevice
0 0 moveto
(Text) show
showpage
Я получаю вывод:
Но когда я изменяю код, чтобы настроить размер страницы прямо перед командой showpage:
<< /PageSize [ 100 30 ] >> setpagedevice
0 0 moveto
(Text) show
<< /PageSize [ 100 100 ] >> setpagedevice
showpage
Я получаю только пустое изображение:
Я знаю, что могу отложить выполнение операторов рисования/отображения, поэтому моя программа вычисляет размер документа перед рисованием и выполняет операции только тогда, когда встречает команду вырезания. Я мог бы реализовать это сам, в настоящее время мне не нужна помощь с таким решением. Мне скорее интересно, возможно ли более простое решение для обрезки уже нарисованного документа до рассчитанного размера страницы.





Вы не можете использовать операции маркировки, а тогда выбрать размер страницы в PostScript. Установка размера носителя в PostScript выполняет неявное стирание, которое очищает все отметки на странице.
См. примечание на стр. 408 3-го издания PLRM (Раздел 6.1.1 Словарь PageDevice):
Note: setpagedevice is a page-oriented operator used to control the output processing of one or more pages of a page description. Any call to setpagedevice implicitly invokes erasepage and initgraphics, and thus must precede the descriptions of the pages to be affected.
Благодаря KenS я понял, что не так с моим первоначальным подходом, поэтому я придумал альтернативное решение, откладывая выполнение операторов маркировки и заранее вычисляя высоту страницы. Ниже приведено неполное доказательство концепции моего метода реализации простого чекового принтера с переменным размером страницы:
%!
/feed {
0 % return to left margin
currentpoint exch pop % y coordinate
20 sub moveto % feed 20 points
} def
% deferred feed
/_feed {
/feed cvx % push executable name on stack
dup exec % execute procedure, to save position in current point
} def
% deferred show
/_show {
dup % duplicate string
stringwidth rmoveto % simulate position change
/show cvx % push show operator on stack
2 array
astore cvx % create procedure for showing the text
} def
Каждый раз, когда я запускаю процедуры подчеркивания, они помещают процедуру в стек операндов, но применяют все изменения позиции, которые произойдут во время окончательного выполнения.
% Set font
/DejaVuSansMono findfont
16 scalefont
setfont
% The receipt itself
0 0 moveto
(text) _show
_feed
(text) _show
_feed
% Save coordinates
currentpoint
/y exch def
/x exch def
% Calculate and set document height based on position
/pageheight y neg def
<< /PageSize [ 100 pageheight ] >> setpagedevice
% Translate the negative y coordinates
0 pageheight 16 sub translate
% reset position
0 0 moveto
% Execute all procedures on the operand stack
count array astore { exec } forall
showpage
Вывод этого скрипта: слово "текст" появляется дважды, изображение автоматически обрезается до нужной высоты
Конечно, это неполно, но я хотел продемонстрировать это как можно проще. Надеюсь, кому-то будет интересно/полезно.
Большое спасибо, что указали на это. Похоже, мой единственный выбор - вычислить высоту страницы, прежде чем я поставлю отметки на странице. Я мог бы отредактировать сообщение позже, чтобы включить обходной путь после того, как я реализую его в своей собственной программе.