赞
踩
turtle库画图的保存
项目场景:我们用turtle画的图,有时想保存成png或者jpg格式,该怎么处理呢?
使用postscript函数和PIL库所遇到的问题:
在网上很容易搜索到,turtle库中有postscript函数,可以将画图内容保存成eps文件,然后使用PIL中的Image.open()的方法,就可以打开该文件,并且save成想要的格式。但在使用过程中,我遇到了如下问题:
import turtle from PIL import Image Image.MAX_IMAGE_PIXELS = None # 设置参数 turtle.screensize(3000, 3000) turtle.color("red") turtle.pensize(1) turtle.speed(0) turtle.ht() # 画正方形,中心为原点 square = 1000 turtle.penup() turtle.goto(square, square) turtle.pendown() turtle.rt(90) for i in range(4): turtle.forward(square*2) turtle.rt(90) # 保存图片,并修改格式 turtle.getscreen().getcanvas().postscript(file="1.eps") im = Image.open("1.eps") im.save("1.jpg")
square参数是正方形边长的一半,当我把square写为100,会得到以下图片:
分辨率704x591,图形看起来正常的,但是设置的画布长宽均为3000,背景不符合要求。
接下来把正方形半边长调整为1000,会得到如下图像:
得到了一张704x593的白图,我的猜想是postscript()函数默认保存的是一定大小的图片,我们需要设置相应的参数来使得画布上的内容全部保存。打开postscript()函数的介绍:
def postscript(self, cnf={}, **kw):
"""Print the contents of the canvas to a postscript
file. Valid options: colormap, colormode, file, fontmap,
height, pageanchor, pageheight, pagewidth, pagex, pagey,
rotate, width, x, y."""
return self.tk.call((self._w, 'postscript') +
self._options(cnf, kw))
我们可以看到有width和height的参数,我修改代码后运行。
turtle.getscreen().getcanvas().postscript(file="1.eps", width=1000, height=1000)
得到的还是一张白图,分辨率为751x752,可知width和height的设置并没有起到想要的结果。
为了解决这个问题,接下来就开始走各种各样的弯路,turtle的setup函数,以及打开eps文件看到的0.7504这串神秘数字,具体过程就不再一一赘述,也是这个过程发现网上这个方面的资料几乎没有,才想着写下这篇博客。
最终还是转到了postscript()这个函数本身:
turtle.getscreen().getcanvas(),这个函数返回的是canvas对象,属于tk库中的内容,在经过科学上网后,找到了tk中canvas.postscrip()的相关文档(我只列了和本文相关的)。
height | Sets the height of the area to print. The default height is the Canvas height. |
---|---|
width | Sets the width of the Canvas area to be printed. Defaults to the width of the Canvas |
pageheight | Sets the height of the printed page. The Canvas image will be scaled to fit. height is any valid screen distance. |
pagewidth | Sets the width of the printed page. The Canvas image will be scaled to fit. |
pagex | Sets the coordinate for the x positioning point. Can be any valid screen distance. |
pagey | Sets the coordinate for the y positioning point. Can be any valid screen distance. |
经过百度查询后得知postscript是页面描述语言,用于打印机打印文件,我们可以将postscript()函数理解为将画布上的内容打印到一张纸上,想要将内容完整打印,就要设置好画布的大小,即width和height,还要设置好这张纸的大小,即pagewidth和pageheight,turtle画图默认从中心开始画图,打印机默认从左上角开始打印,我们就需要调整坐标系,即调整x和y。
这是了解postscript函数机理后重新写的代码。
import turtle from PIL import Image Image.MAX_IMAGE_PIXELS = None canvas_width = 1000 canvas_height = 1000 turtle.screensize(canvas_width, canvas_height) turtle.color("red") turtle.pensize(0) turtle.speed(0) turtle.ht() # 例1*************************************************************************************** # 画正方形 square = 500 turtle.penup() turtle.goto(square, square) turtle.pendown() turtle.rt(90) for i in range(4): turtle.forward(square*2+1) turtle.rt(90) turtle.getscreen().getcanvas().postscript(colormode="color", file="1.eps", pagewidth=canvas_width, pageheight=canvas_height, width=canvas_width, height=canvas_height, x=-canvas_width/2, y=-(canvas_height/2)) turtle.clear() im = Image.open("1.eps") print(im.size) print(im.getpixel((canvas_width/2-square, canvas_height/2-square+1))) for i in range(square*2): im.putpixel((canvas_width//2-square+i+1, canvas_height//2-square+i+1+1), (255, 0, 0)) # for i in range(1001): # if(im.getpixel((i, 500))!=(255,255,255)): # print(i) # break # print(im.getpixel((200, 501))) im.save('1.jpg') # 例2 画圆******************************************************************** turtle.clearscreen() turtle.color("red") turtle.pensize(0) turtle.speed(0) turtle.ht() center_x = 390 center_y = 0 circle = 100 turtle.penup() turtle.goto(center_x, center_y-circle) turtle.pendown() turtle.seth(0) turtle.circle(circle) turtle.getscreen().getcanvas().postscript(colormode="color", file="2.eps", pagewidth=canvas_width, pageheight=canvas_height, width=canvas_width, height=canvas_height, x=-canvas_width/2, y=-canvas_height/2) im = Image.open("2.eps") for i in range(circle*2): im.putpixel((center_x - circle + i + 1+canvas_width//2, center_y+canvas_height//2), (255, 0, 0)) im.putpixel((center_x+canvas_width//2, center_y - circle + i + 1+canvas_height//2), (255, 0, 0)) im.save('2.jpg')
得到的图片分辨率1001x1001,图形大小和位置均基本符合要求,但整张图长宽多了一个像素。
关于为什么会多一个像素:
我的猜想是turtle库的画图语法本身是一种比较艺术的语言,例如原点是(0,0),向右移动100个像素turtle.forward(100),然后海龟的位置就变成了(3,0),这样来看海龟本身是不占像素的,但是我们储存位图的时候是按照矩阵的形式储存的,每一个点都是矩阵中的一个元素,这两种描述有冲突的地方,所以turtle库没有提供直接把画布内容转换成位图的函数,而是提供了一种转换成矢量图的方法postscript,我们最后再把矢量图转换成位图,经过了两次转换,就可能在某个环节就会出现问题。
因为我的目的只是能够画出完整且不严重失真的图片,所以就没有细究太多。(细究也没弄懂放弃了)
如果有相关大佬弄懂了可以为大家解惑。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。