0

I have searched on a variety of variation of "PIL tkinter canvas". The closest thing I have found is this: How to convert a Python tkinter canvas postscript file to an image file readable by the PIL?

turtle.py creates images on a scrollable tkinter canvas so I wrote a script based on the Answer above.

#! /usr/bin/python3

import sys
print(sys.argv[0])
sys.path.append('C:\\Program Files\\gs\\gs9.21\\bin\\') # Where Ghostscript lives
import turtle as t
from PIL import Image  
def line(nPlots=0,x0=0,y0=0,H=6000):
    t.penup()
    t.goto(x0,y0)
    #t.setheading(90)
    t.begin_fill()
    t.pendown()
    print('Forward:',H)
    t.forward(H)
t.screensize(12000,700)
t.color('red','light blue')
t.width(20)
t.tracer(10000)
line()

c=t.getcanvas()
t.update()
c.update()
import io
def savecanvas():
    screen=t.getscreen()
    canvas=screen.getcanvas()
    postscript=canvas.postscript().encode('utf-8')
    im=Image.open(io.BytesIO(postscript))
    im.save('canvas.png')
savecanvas()

This indeed results in a screencapture but not a complete canvascapture. The output file is the required 12000 pixels long but the long red bar is clipped by the screen size. The culprit seems to be the Ghostscript Bounding Box. Here is a snippet from the gs file:

infile: b"%!PS-Adobe-3.0 EPSF-3.0\n%%Creator: Tk Canvas Widget\n%%Title: Window .!canvas\n%%CreationDate: Sat Apr 29 10:36:40 2017\n%%BoundingBox: -197 188 811 605\ ...

Ghostscript is setup within the PIL EpsImagePlugin.py called from the PIL Image module.

Here is that code:

# Build ghostscript command
command = ["gs",
           "-q",                         # quiet mode
           "-g%dx%d" % (12000, 800),     # set output geometry (pixels)
           "-r%fx%f" % (96,96),          # set input DPI (dots per inch)
           "-dNOPAUSE",                  # don't pause between pages,
           "-dSAFER",                    # safe mode
           "-sDEVICE=ppmraw",            # ppm driver
           "-sOutputFile=%s" % outfile,  # output file
           "-c", "%d %d translate" % (-300,-375),
                                         # adjust for image origin
           "-f", infile,                 # input file

I have tried to force the bbox with no success. I suspect I am in need of some additional gs command line option.

Does anyone know how to coerce Ghostscript into accepting wide input images?

Community
  • 1
  • 1

2 Answers2

0

That's not the Ghostscript BoundingBox, its the Bounding Box declared by the PostScript program. Apparently produced by 'TK Canvas Widget', so if its wrong the culprit isn't Ghostscript.

Note that Ghostscript will totally ignore that, because its a comment (starts with a '%') unless you set -dEPSCrop, which you haven't. Since it claims to be an EPS file (this comment: "%!PS-Adobe-3.0 EPSF-3.0") try using -dEPSCrop.

I would also take the EPS file and try running Ghostscript directly from the command line on the EPS file. You've got a lot of switches in the command line, and I suspect these are only going to complicate things.

Firstly I would drop the -g switch, because that will set a fixed size media (in pixels), if you want a variable media size, you don't want to be fixing it, unless you also set -dPSFitPage, which will scale the requested media (given by the BoundingBox if you use -dEPSCrop) to the fixed page size given by -g. Initially at least I would drop that, its just getting in the way.

Then you probably also want to drop the -c "..." -f because that's shifting the content on the media.

If you do all of that I would expect Ghostscript to produce a ppmraw file for you at the requested resolution and containing the entire content. Of course that doesn't prove that its 'complete'. If it isn't then you will probably have to make an example available to look at.

KenS
  • 30,202
  • 3
  • 34
  • 51
0

I'm going to give a contradictory answer to @KenS and say the PostScript generated by the TK Canvas Widget looks fine. I used the following simplification of your code to dump the PostScript:

from turtle import Turtle, Screen

def line(turtle, H=6000):
    turtle.penup()
    turtle.begin_fill()
    turtle.pendown()
    turtle.forward(H)

def savecanvas(screen):
    canvas = screen.getcanvas()
    canvas.postscript(file="canvas.eps")

screen = Screen()
screen.setup(12000, 700)

yertle = Turtle()
yertle.pencolor('red')
yertle.width(20)

line(yertle)

savecanvas(screen)

screen.bye()

I then examined it via grep and Preview on my Mac:

> grep BoundingBox canvas.eps
%%BoundingBox: -5696 46 6309 746
> 

enter image description here

enter image description here

From this I was able to generate a very wide (12505 × 729) PNG file via Preview. So, I find it hard to fault he PostScript generated by the TK Canvas Widget, at least on my Apple system.

cdlane
  • 40,441
  • 5
  • 32
  • 81
  • Don't misunderstand me, I said **if** the BoundingBox is wrong.....I then went on to detail some of the myriad ways that using an EPS file for a purpose its not intended could result in unexpected results. By the way, the BoundingBox on your EPS appears to be quite different from that quoted in the question..... – KenS Apr 30 '17 at 08:57
  • I ran cdlane code. In my setup i still get the clipped result :( – Bob La Quey May 01 '17 at 08:04
  • I seem to making some progess. My code an that supplied by cdlane both generate %%BoundingBox: -197 188 811 605\ in my environment. If I simply replace with some big values in the canvas,eps code, eg, %%BoundingBox: -8197 188 *811 605\ and then invoke gswin64.exe -dEPSCrop canvas.eps I get a long bar that lives within a large scrollable window. I am having a devil of a time finding where Tk pulls its template from the build the infile (the one I cop and name as canvas.eps) but at least this suggest there is light at the end of the tunnel. – Bob La Quey May 01 '17 at 09:57