Python 使用Pycairo创建带有(调整大小的)PNG图像的PDF-重新缩放曲面问题

Python 使用Pycairo创建带有(调整大小的)PNG图像的PDF-重新缩放曲面问题,python,pdf,resize,cairo,geometry-surface,Python,Pdf,Resize,Cairo,Geometry Surface,我有一些要下载的som PNG图像链接,“转换为缩略图”并使用Python和Cairo保存为PDF 现在,我有一个工作代码,但我不知道如何控制纸张上的图像大小。有没有办法将PyCairo曲面调整到我想要的尺寸(正好比原始尺寸小)?我希望原始像素被“缩小”到更高的分辨率(在纸上) 另外,我尝试了PIL中的Image.rescale()函数,但它返回了20x20像素的输出(在200x200像素的原始图像中,这不是代码中的横幅示例)。我想要的是一个200x200像素的图像,在纸上一个20x20毫米的正

我有一些要下载的som 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()
请注意,美丽的开罗横幅甚至不适合页面。。。 理想的结果是,我可以用用户空间单位(本例中为毫米)控制此图像的宽度和高度,以创建一个漂亮的标题图像


感谢您的阅读和任何帮助或评论

在绘制图像时尝试缩放上下文

例如


请参阅:了解更多详细信息。

Jeremy Flores通过在将imagesurface设置为源之前缩放目标曲面,很好地解决了我的问题。尽管如此,也许有一天你真的需要调整曲面的大小(或以任何方式变换曲面),因此我将简要描述我的备选答案(已包含在问题中)中使用的基本原理,这是在仔细阅读文档后得出的:

  • 将您的曲面设置为上下文的源-它隐式创建一个
    cairo.Pattern
  • 使用
    Context.get_source()
    返回模式
  • 创建一个
    cairo.Matrix
  • 将该矩阵(及其所有变换)应用于模式
  • 油漆
    唯一的问题似乎是转换总是围绕着原点工作,因此缩放和旋转必须先进行,然后再进行到原点的补充转换(bleargh)。

    这并不是在回答问题,我只是想分享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()
    

    你说对了!我以前试过,但我将imagesurface设置为源,然后才进行缩放操作。因此,必须先缩放,然后再设置源。谢谢
    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()