Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PSDraw.rectangle produces incorrect PostScript #6428

Closed
mrabarnett opened this issue Jul 10, 2022 · 10 comments · Fixed by #6429
Closed

PSDraw.rectangle produces incorrect PostScript #6428

mrabarnett opened this issue Jul 10, 2022 · 10 comments · Fixed by #6429
Labels
Bug Any unexpected behavior, until confirmed feature.

Comments

@mrabarnett
Copy link

mrabarnett commented Jul 10, 2022

This code should draw a rectangle, but it produces a blank page:

from PIL import PSDraw

with open('output.ps', 'wb') as file:
    ps = PSDraw.PSDraw(file)
    ps.begin_document('TEST')
    ps.rectangle((1 * 72, 4 * 72, 3 * 72, 2 * 72))
    ps.end_document()

I inspected the PostScript that it produced and it didn't make a whole lot of sense to me (I've worked with it in the past) until I realised that the parameters on the PostScript stack were in the wrong order.

The PostScript says "72 288 M 216 144 0 Vr" when it should say "72 288 M 0 216 144 Vr", i.e. it's "left top M width height 0 Vr" instead of "left top M 0 width height Vr".

When I edited the PostScript, I got the expected result.

@radarhere
Copy link
Member

Thanks for figuring out the solution. I've created PR #6429 to resolve this.

@radarhere radarhere added the Bug Any unexpected behavior, until confirmed feature. label Jul 10, 2022
@mrabarnett
Copy link
Author

There's some clarification that you could add to the docs and the docstring: it draws a solid black rectangle, and the box parameter is (left, top, width, height). Note that the height goes downwards even though the origin on the page is at the bottom-left.

Oh, and FTR: the Python code uses "%d", so it truncates to int points (1/72 inch), but PostScript is OK with decimal places.

@radarhere
Copy link
Member

the box parameter is (left, top, width, height). Note that the height goes downwards even though the origin on the page is at the bottom-left.

Would it be simpler then to think of the parameters as (left, bottom, width, height)? I've added that to the PR.

PostScript is OK with decimal places.

Is there any documentation that you know of that states that?

@mrabarnett
Copy link
Author

If you tried .rectangle((0, 0, 72, 72)), it would be drawing off the bottom of the page, so you can't just pretend that it's (left, bottom, width, height). On the other hand, it wasn't working before, so changing it probably won't break any code.

As for reals (as PostScript calls them, Python calls them floats), it's in PostScript's specification. Will anyone notice if snaps to 1/72 inch? That's not my decision! :-)

If you do want to have (left, bottom, width, height), alter this bit of PostScript from:

/Vr {   exch dup 0 rlineto
        exch dup neg 0 exch rlineto
        exch neg 0 rlineto
        0 exch rlineto
        100 div setgray fill 0 setgray } bind def

to:

/Vr {   exch dup 0 rlineto
        exch dup 0 exch rlineto
        exch neg 0 rlineto
        0 exch neg rlineto
        100 div setgray fill 0 setgray } bind def

@radarhere
Copy link
Member

Rather than changing the PostScript code, I've pushed a change to the PR to add the bottom and height parameters together internally.

@mrabarnett
Copy link
Author

You'd also need to negate the height because, currently, the height goes downwards (the PostScript code negates it to make it go downwards). IMHO, tweaking the PostScript makes more sense - it's a smaller change (moving a neg), and the directions in the PostScript work the way you'd expect.

@radarhere
Copy link
Member

I've updated the PR to match your suggestion.

As an aside, is there any reason that we couldn't also change

100 div setgray fill 0 setgray

to

setgray fill

?

@mrabarnett
Copy link
Author

I've realised that what I said about negating the height was wrong. However, my argument still stands. The fact that PostScript puts the origin at the bottom-left, and that the docs for PSDraw state that the origin is at the bottom-left, means that having the height go downwards can lead to confusion, as it did for me!

As for the code, the 0 that's passed to Vr is the grey level as a percentage (0=black). What it's doing is (with Python-style comments):

100 div # Convert the grey level from a percentage
setgray # Set the grey level
fill # Fill the rectangle
0 setgray # Set the grey level back to black

I'd probably leave it as it is for the time being, unless you're not happy about giving the grey level as a percentage (I'm thinking about future improvements where you might want to let the user set the fill colour - would a percentage be more friendly than a fraction?).

@radarhere
Copy link
Member

I was thinking that if it is always zero, then dividing it by 100 doesn't do anything. And there's no need to set it back to black if it is already black.

@mrabarnett
Copy link
Author

As I said, in the future you might want to let the user set the grey level for the fill. but if it's a case of YAGNI, then OK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Any unexpected behavior, until confirmed feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants