【问题标题】:Create PDF with (resized) PNG images using Pycairo - rescaling Surface issue使用 Pycairo 使用(调整大小的)PNG 图像创建 PDF - 重新缩放 Surface 问题
【发布时间】:2011-08-17 21:19:13
【问题描述】:

我有一些 PNG 图像链接,我想下​​载、“转换为缩略图”并使用 Python 和 Cairo 保存为 PDF。

现在,我有一个工作代码,但我不知道如何控制纸上的图像大小。有没有办法将 PyCairo Surface 的大小调整为我想要的尺寸(恰好比原来的小)?我希望将原始像素“缩小”到更高分辨率(在纸上)。

另外,我尝试了 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()

请注意,美丽的开罗横幅甚至不适合页面... 理想的结果是我可以以用户空间单位(在本例中为毫米)控制此图像的宽度和高度,以创建漂亮的标题图像。

感谢您的阅读以及任何帮助或评论!

【问题讨论】:

    标签: python pdf resize cairo geometry-surface


    【解决方案1】:

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

    例如

    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

    【讨论】:

    • 你明白了!我之前尝试过,但我将图像表面设置为源,然后才进行缩放操作。因此,有必要先缩放,然后才设置源。谢谢!
    【解决方案2】:

    这不是回答问题,我只是想分享 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】:

      Jeremy Flores 通过在将图像表面设置为源之前缩放目标表面很好地解决了我的问题。即使,也许有一天您实际上需要调整 Surface 的大小(或以任何方式对其进行转换),所以我将简要描述在我的替代答案中使用的基本原理(已包含在问题中),在彻底阅读文档后推断:

      1. 将您的表面设置为上下文的源 - 它隐式创建一个 cairo.Pattern!!
      2. 使用Context.get_source() 恢复模式;
      3. 创建cairo.Matrix
      4. 将此矩阵(及其所有变换)应用于模式;
      5. 油漆!

      唯一的问题似乎是始终围绕原点进行的转换,因此必须先进行缩放和旋转,然后再进行到原点的互补平移 (bleargh)。

      【讨论】:

        猜你喜欢
        • 2018-06-15
        • 2013-09-24
        • 1970-01-01
        • 1970-01-01
        • 2019-10-19
        • 2019-12-08
        • 1970-01-01
        • 1970-01-01
        • 2017-04-14
        相关资源
        最近更新 更多