I'm developing a printer emulator (partly) in PostScript. The command system I want to emulate is designed for roll paper thermal printers, mostly used for printing Point of Sale receipts. I'd prefer to execute the operations in the same order as the real printer would do, which means my program doesn't know the page size until it encounters a "cut" command. I want the program to work with variable paper size CUPS printers¹.
Can I change the page height after I issued painting/show commands without the filled parts of the document disappearing?
I have tried modifying the page device dictionary at the end of the document, but if I change the PageSize array, everything on the document disappears.
For example if I run the following program:
<< /PageSize [ 100 30 ] >> setpagedevice
0 0 moveto
(Text) show
showpage
I get the output:
But when I modify the code to adjust the page size right before the showpage command:
<< /PageSize [ 100 30 ] >> setpagedevice
0 0 moveto
(Text) show
<< /PageSize [ 100 100 ] >> setpagedevice
showpage
I only get a blank image:
I'm aware I can defer the execution of the painting/show operators, so my program calculates the document size before painting, and only executes the operations when it encounters the cut command. I would be able to implement that by myself, I don't need help with such a solution currently. I'm rather wondering, whether a simpler solution is possible for cutting an already drawn document to a calculated page size.
You cannot use marking operations and then select the page size in PostScript. Setting the media size in PostScript executes an implicit erasepage which clears any marks on the page.
See the note on page 408 of the 3rd edition PLRM (Section 6.1.1 PageDevice Dictionary):
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.
Thanks to KenS I realized what was wrong with my original approach so I came up with an alternative solution, deferring the execution of the marking operators and calculating the page height beforehand. Below is an incomplete proof of concept of my method of implementing a simple receipt printer with variable page size:
%!
/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
Each time I run the underscore procedures, they will push a procedure on the operand stack, but apply all position changes that will happen during the final execution.
% 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
The output of this script: the word "text" appearing twice, the image is automatically cut to the right height
It is incomplete of course, but I wanted to demonstrate it the simplest possible way. I hope some will find it interesting/useful.
Related
I am a newbie with ghostscript. I am trying to add a an additional margin to pages in a PDF. My command line works for pages in portrait mode, but messes up pages in landscape mode. I want to add 30 points width and 42 points margin all round to portrait pages (to keep the same aspect ratio), so increase the A4 page size by double that. For landscape, I reverse the numbers.
When changing the command so that it works for landscape pages, it now messes up portrait pages.
Is there a way to conditionally change the pages so that it would work on both portrait and landscape pages?
My commands were (for Windows)
Works for for portrait mode:
gswin64 -o c:\temp\outport.pdf -sDEVICE=pdfwrite -g6550x9270 -c "<</Install {30 42 translate}>> setpagedevice" -f "mysource.pdf"
Works for landscape pages
gswin64 -o c:\temp\outland.pdf -sDEVICE=pdfwrite -g9270x6550 -c "<</Install {42 30 translate}>> setpagedevice" -f "mysource.pdf"
I am doing this as originally the PDF needed a 2cm margin around text. But now I need a (roughly) 3cm margin. This way, when I print it, it will print in A4 with a cm margin and the correct aspect ratio.
Reluctantly I'll have to post this as an answer because it's too big for a comment.
Create a text file with this content, call it something memorable like 'intelligent_resize.ps':
%!
userdict begin
/ResetPageSize true def
end
<<
/BeginPage
{
userdict /ResetPageSize known not
{
(Error: ResetPageSize undefined!\n) print flush
//true
}
{
userdict /ResetPageSize get
} ifelse
{
userdict /ResetPageSize //false put
currentpagedevice /PageSize get aload pop
2 copy gt
{
60 add exch 84 add exch
2 array astore /PageSize exch
1 dict dup 4 2 roll put
setpagedevice
42 30 translate
}
{
84 add exch 60 add exch
2 array astore /PageSize exch
1 dict dup 4 2 roll put
setpagedevice
30 42 translate
} ifelse
}
{
userdict /ResetPageSize //true put
} ifelse
}
>> setpagedevice
Then use this command line (or something similar):
gswin64 -o c:\temp\outport.pdf -sDEVICE=pdfwrite intelligent_resize.ps "mysource.pdf"
That installs a BeginPage routine which gets run at the start of every page, but with a control in userdict to determine what the routine does.
If the control is true then it sets it to false (prevents recursion in setpagedevice) checks to see if the media is portrait or landscape, adds 60, 84 or 84,60 points to the width and height, depending on the orientation, and translates the content by 30,42 or 42,30.
If the control is false it sets it to true.
So we get called when the first page is begun, The control is true so we reset the control, calculate the new media size, and call setpagedevice to set that new size. That means we call BeginPage again. This time the control is false so we set the control back to true and exit back to our original BeginPage routine, which then translates the CTM of the newly created page.
Then the content for the page gets executed. We move on to the next page and round we go again. So this 'ought' to work for PDF files containing a mixture of orientations. The code as it stands just expands all pages by the required amount and re-centers the content, it doesn't try to fit the content to a differently sized page or anything complicated.
I don't have time to spare today to comment the program, sorry, but it shouldn't be hard to work out and modify if required. It's also not as minimal as it could be there's repeated code that could be factored out but I don't have time for that today either.
I tried it on a Letter portrait file and a Letter landscape file and it seemed to do what you want.
Under Linux, I am writing a Ghostscript program to read a fairly long (1320 lines) data file of longitude and latitude co-ordinates (a file installed with Gnuplot) eventually to draw a map. I have written various test files and the latest is to read the data and display each line using show and showpage In order to check that the lines read match the input file. I would like to pause the program's execution after each showpage until a key is pressed. Please, how can I do this?
This is my test program for keyboard input. I expect it may need significant changes:
%!
% Testing Keyboard input
%
% Depictions of the stack have top on the right
%
/Courier findfont 16 scalefont setfont
% string needs a size and leaves the created string on the stack.
/s 15 string def % longer string stores /00 in extra places in outfile ..
/lcount 0 def
/vpos 750 def /nl 0 def
/newline {72 vpos moveto /vpos vpos 12 sub def} def
/inputfile (/dev/tty) (r) file def
%/inputfile (/home/Harry/Mercator/world.dat) (r) file def
/getdataline dataline into s ++> true, or false at end of file
{ /lcount 1 lcount add def
inputfile s readline % was readstring
} def
{ 0 1 14 { s exch 0 put }for % clears string s to nulls
getdataline
{newline s show} % got a line
{exit} % end of file
ifelse
showpage
% ******* I want to pause here *******
} loop
inputfile closefile
I missed the answer right before my nose, hidden in the terminal window behind my editor window. After each showpage in the preogram execution the message >>showpage, press <return> to continue<< appears in the terminal window, just what I wanted.
Being new to programming, AutoIt using Imagesearch
$result = _ImageSearch("flowr.png",1,$x1,$y1,100)
having saved the desired imagine, what does
the 1 after the image-name mean?
(1 click) $x1 and $y1 mean
(coordinates for that 1x click) the 100 the speed?
The line of code began with
#include <ImageSearch.au3>
$x1=0
$y1=0
what is the $x1=0 here?
I'd love to just use google and type in "what does $x1=0 mean" but the translation of it yields a completely different answer and has nothing to do with coding^^
Thank you very much for clarifying!
The 1 after the flowername seems to be the tolerance, a value from 0-255 according to this documentation I found here
; Description: Find the position of an image on the desktop
; Syntax: _ImageSearchArea, _ImageSearch
; Parameter(s):
; $findImage - the image to locate on the desktop
; $tolerance - 0 for no tolerance (0-255). Needed when colors of
; image differ from desktop. e.g GIF
; $resultPosition - Set where the returned x,y location of the image is.
; 1 for centre of image, 0 for top left of image
; $x $y - Return the x and y location of the image
;
; Return Value(s): On Success - Returns 1
; On Failure - Returns 0
The lines like $x1 = 0 are simple assignment operations. You are saving the value 0 in the variable $x1. You can later add, subtract, multiply, etc. using that value or store some other calculation which makes your program easy to alter.
You should try some examples to get the basics of programming down before diving in to an image search program. If all else fails though you can always check the Documentation.
I'm trying to put a stamp on the top right corner of a PDF file. I have a PS file created from Excel using driver for HP Color LaserJet 4500 printed to file.
I am using GhostScript to create a PDF.
GSWIN32C.EXE #S:\Temp\PS\Options.txt
Here is the contents of the Options.txt file:
-sDEVICE=pdfwrite -q -dSAFER -dNOPAUSE
-sOUTPUTFILE="S:\Temp\PS\Sample.pdf" -dBATCH
"S:\Temp\PS\Stamp.txt"
"S:\Temp\PS\Sample.ps"
Here is the contents of Stamp.txt modified from here:
<<
/EndPage
{
2 eq { pop false }
{
gsave
/Helvetica_Bold 15 selectfont
0 setgray
475 767 moveto
(STATE COPY) show
grestore
true
} ifelse
} bind
>> setpagedevice
The PDF is created just fine, but the stamp is causing me problems. The stamp shows very tiny on the upper left but flipped vertically.
Here is a section with the tiny stamp upper left:
Here is the stamp enlarged 800%
On a multi-page PDF I want the stamp on all pages. I understand that using the /EndPage should let me do that.
So how do I get my stamp on the upper right corner?
I assume the problem with the stamp resides in the previous transformations. So I used scale to flip the stamp upright and adjusted until I got it in the right place.
<<
/EndPage
{
2 eq { pop false }
{
gsave
/Helvetica_Bold 15 selectfont
0 setgray
10 10 scale
375 17 moveto
1 -1 scale
(STATE COPY) show
grestore
true
} ifelse
} bind
>> setpagedevice
I didn't test it but I assume using a different print driver to produce the PS file would give different results.
Guys,
I see ImageMagick is capable to generate image using Pango formatted text, which looks like quite a good approach.
Just want to know if there's anything else out there, what's the most recommended way of doing this.
imagemagick is probably the easiest, but ghostscript can also be used to render images with text.
Here's a little postscript program that displays some text.
%!
5 5 moveto
/Palatino-Roman 20 selectfont
(Some Text) show
showpage
Using ps2eps will calculate the Bounding-Box and add this information as a comment conforming to the Document Structuring Conventions.
%!PS-Adobe-2.0 EPSF-2.0
%%BoundingBox: 5 5 97 20
%%HiResBoundingBox: 5.500000 5.000000 97.000000 19.500000
%%EndComments
% EPSF created by ps2eps 1.64
%%BeginProlog
save
countdictstack
mark
newpath
/showpage {} def
/setpagedevice {pop} def
%%EndProlog
%%Page 1 1
5 5 moveto
/Palatino-Roman 20 selectfont
(Some Text) show
showpage
%%Trailer
cleartomark
countdictstack
exch sub { end } repeat
restore
%%EOF
Then imagemagick's convert utility can render this as an image.
The ps2eps is necessary so the final image is cropped to the interesting part, rather than at the bottom of a page-sized image.
Here's a typescript of the whole sequence. 0> is the command prompt.
0> cat > t.ps
%!
5 5 moveto
/Palatino-Roman 20 selectfont
(Some Text) show
showpage
0> ps2eps t.ps
Input files: t.ps
Processing: t.ps
Calculating Bounding Box...ready. %%BoundingBox: 5 5 97 20
Creating output file t.eps...** Warning **: Weird heading line -- %! -- ready.
0> convert t.eps t.png