Create PDF with (resized) PNG images using Pycairo - rescaling Surface issue
Question: I have som PNG image links that I want to download, "convert to thumbnails"
and save to PDF using Python and Cairo.

Now, I have a working code, but I don't know how to control image size on
paper. Is there a way to resize a PyCairo Surface to the dimensions I want
(which happens to be smaller than the original)? I want the original pixels to
be "shrinked" to a higher resolution (on paper).

Also, I tried `Image.rescale()` function from PIL, but it gives me back a
20x20 pixel output (out of a 200x200 pixel original image, which is not the
banner example on the code). What I want is a 200x200 pixel image plotted
inside a 20x20 mm square on paper (instead of a 200x200 mm square as I am
getting now)

My current code is:

    
    
    #!/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()
    

Note that the beautiful Cairo banner does not even fit the page... The ideal
result would be that I could control the width and height of this image in
user space units (milimeters, in this case), to create a nice header image,
for example.

Thanks for reading and for any help or comment!!


Answer: Try scaling the context when you draw the image.

E.g.

    
    
    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
    

See: <http://cairographics.org/documentation/pycairo/2/reference/context.html>
for more details.

