使用Pycairo创建PDF并缩放PNG图像 - 表面缩放问题
我有一些PNG图片链接,想用Python和Cairo下载这些图片,"转换成缩略图",然后保存为PDF。
现在我已经有了可以运行的代码,但我不知道怎么控制纸上的图片大小。有没有办法调整PyCairo表面的尺寸到我想要的大小(其实是比原图小)?我希望把原来的像素“缩小”到更高的分辨率(在纸上)。
另外,我试过用PIL的Image.rescale()
函数,但它给我的输出是20x20像素(原图是200x200像素,这不是代码中的横幅示例)。我想要的是把一个200x200像素的图片放在纸上一个20x20毫米的方框里(而不是现在得到的200x200毫米的方框)。
我现在的代码是:
#!/usr/bin/python
import cairo, urllib, StringIO, Image # could I do it without Image module?
paper_width = 210
paper_height = 297
margin = 20
point_to_milimeter = 72/25.4
pdfname = "out.pdf"
pdf = cairo.PDFSurface(pdfname , paper_width*point_to_milimeter, paper_height*point_to_milimeter)
cr = cairo.Context(pdf)
cr.scale(point_to_milimeter, point_to_milimeter)
f=urllib.urlopen("http://cairographics.org/cairo-banner.png")
i=StringIO.StringIO(f.read())
im=Image.open(i)
# are these StringIO operations really necessary?
imagebuffer = StringIO.StringIO()
im.save(imagebuffer, format="PNG")
imagebuffer.seek(0)
imagesurface = cairo.ImageSurface.create_from_png(imagebuffer)
### EDIT: best answer from Jeremy, and an alternate answer from mine:
best_answer = True # put false to use my own alternate answer
if best_answer:
cr.save()
cr.scale(0.5, 0.5)
cr.set_source_surface(imagesurface, margin, margin)
cr.paint()
cr.restore()
else:
cr.set_source_surface(imagesurface, margin, margin)
pattern = cr.get_source()
scalematrix = cairo.Matrix() # this can also be used to shear, rotate, etc.
scalematrix.scale(2,2) # matrix numbers seem to be the opposite - the greater the number, the smaller the source
scalematrix.translate(-margin,-margin) # this is necessary, don't ask me why - negative values!!
pattern.set_matrix(scalematrix)
cr.paint()
pdf.show_page()
注意,这个漂亮的Cairo横幅甚至没有适合页面……理想的结果是我可以控制这个图片在用户空间单位(在这个例子中是毫米)的宽度和高度,比如说用来创建一个漂亮的头图。
谢谢你的阅读和任何帮助或评论!!
3 个回答
0
Jeremy Flores 很好地解决了我的问题,他在设置图像表面为源之前,先对目标表面进行了缩放。虽然也许有一天你真的需要调整一个表面(或者以其他方式变换它),所以我会简单描述一下我在另一个答案中使用的思路(已经包含在问题里),这是我在仔细阅读文档后得出的:
- 把你的表面设置为上下文的源,这样会自动创建一个
cairo.Pattern
! - 使用
Context.get_source()
来获取这个图案; - 创建一个
cairo.Matrix
; - 把这个矩阵(包括它的所有变换)应用到图案上;
- 开始绘制!
唯一的问题似乎是变换总是围绕原点进行,所以缩放和旋转必须在前后加上相应的平移到原点(真是麻烦)。
1
这段话并没有回答问题,我只是想分享一下heltonbiker目前的代码,已经修改为可以在Python 3.2上运行的版本:
import cairo, urllib.request, io
from PIL import Image
paper_width = 210
paper_height = 297
margin = 20
point_to_millimeter = 72/25.4
pdfname = "out.pdf"
pdf = cairo.PDFSurface( pdfname,
paper_width*point_to_millimeter,
paper_height*point_to_millimeter
)
cr = cairo.Context(pdf)
cr.scale(point_to_millimeter, point_to_millimeter)
# load image
f = urllib.request.urlopen("http://cairographics.org/cairo-banner.png")
i = io.BytesIO(f.read())
im = Image.open(i)
imagebuffer = io.BytesIO()
im.save(imagebuffer, format="PNG")
imagebuffer.seek(0)
imagesurface = cairo.ImageSurface.create_from_png(imagebuffer)
cr.save()
cr.scale(0.5, 0.5)
cr.set_source_surface(imagesurface, margin, margin)
cr.paint()
cr.restore()
pdf.show_page()
3
试着在绘制图像时调整一下上下文的比例。
比如:
cr.save() # push a new context onto the stack
cr.scale(0.5, 0.5) # scale the context by (x, y)
cr.set_source_surface(imagesurface, margin, margin)
cr.paint()
cr.restore() # pop the context
更多细节请查看:http://cairographics.org/documentation/pycairo/2/reference/context.html