This sounds really simple, but I can't find a way to load a PDF into Cairo. I want to be able to do cairo.PDFSurface.create_from_pdf
in the same way I do cairo.ImageSurface.create_from_png
(yes I'm using the Python bindings but that's neither here nor there).
The documentation doesn't appear to give any hints.
No, cairo cannot read PDFs. However, poppler can load PDFs an paint them onto a cairo context - http://poppler.freedesktop.org/
(Oh and create_from_png() is part of cairo's toy API. It works, but you are recommended to use some "real" API which can do more things than just loading PNGs)
Example code to render a PDF get it into a pycairo ImageSurface
:
import io
from pathlib import Path
import cairo
import poppler
from PIL import Image
filepath = Path('test.pdf')
document = poppler.load_from_file(filepath)
renderer = poppler.PageRenderer()
# Render first page and convert to image buffer
page = document.create_page(0)
image = renderer.render_page(page, xres=72, yres=72)
buf = io.BytesIO(image.data).getbuffer()
if False: # for debugging
pil_img = Image.frombytes('RGBA', (image.width, image.height),
image.data, 'raw', str(image.format))
pil_img.save('test.png')
# Use page dimensions to create cairo surface
rect = page.page_rect()
width = int(rect.width)
height = int(rect.height)
#print(f'bytes used per pixel: {len(buf)/(width*height)}')
surface = cairo.ImageSurface.create_for_data(buf, cairo.FORMAT_ARGB32, width, height)
The resulting surface
can be used as input to Context.set_source_surface()
to paint onto an existing PDFSurface. If the resulting PDF shows a grainy image, increasing xres
or yres
by a factor of 72 can help, but this creates a need to scale down before painting.