Skip to content

Vector Image Support

Jorj X. McKie edited this page Sep 28, 2019 · 6 revisions

Via another supplement for version 1.12.1, vector images are now supported to the following extent.

Display

Page method showPDFpage places a vector image of a page from another PDF in a specified rectangle.

This method can for instance be used to create double-paged or "4-up" versions of existing PDFs. Here is a script that places 4 pages of the input on each output page:

from __future__ import print_function
import fitz, time

# choose appropriate timer for the Python version
mytime = time.clock if str is bytes else time.perf_counter

doc = fitz.open()
src = fitz.open(infile)

r = fitz.Rect(0, 0, 595, 842)          # A4 portrait output page format: adjust!

# define the 4 rectangles per page
r1 = fitz.Rect(0, 0, r.width/2, r.height/2)
r2 = r1 + (r1.width, 0, r1.width, 0)
r3 = r1 + (0, r1.height, 0, r1.height)
r4 = fitz.Rect(r1.br, r.br)

# put them in an array
r_tab = (r1,r2,r3,r4)

t0 = mytime()

# copy input to output
for spage in src:
    if spage.number % 4 == 0:
        page = doc.newPage(-1, width = r.width, height = r.height)
    # put input page in the correct rectangle of output page
    page.showPDFpage(r_tab[spage.number % 4], src, spage.number,
                     keep_proportion = True)

t1 = mytime()

# save new file using garbage collection and compression
doc.save("4up-" + infile, garbage = 4, deflate = True)

# log output
t2 = mytime()
print("processed %i pages of file '%s'" % (len(src), src.name))
print("showPDFpage time: %g" % (t1-t0))
print("save time: %g" % (t2-t1))

Another use may be displaying the same thumbnail (e.g. a company logo stored in a 1-pager PDF) on every page of a brochure. This has a similar effect like insertImage but maintains display precision across zooming.

Typical vector images come in SVG format. These can be coverted to PDF by a number of tools, like Apache Batik (Java) or the Python package svglib.

The following script makes use of svglib. It accepts filenames of a PDF and of an SVG and produces a new PDF with the SVG put on each page as a logo:

import fitz
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
import sys
doc_fn = sys.argv[1]                        # name of PDF file
svg_fn = sys.argv[2]                        # name of SVG image file

drawing = svg2rlg(svg_fn)                   # open the SVG
pdfbytes = renderPDF.drawToString(drawing)  # turn SVG to PDF image
src = fitz.open("pdf", pdfbytes)            # open SVG as a PDF
_, _, imgw, imgh = tuple(src[0])            # get width & height of image
factor = 50. / imgh                         # use to ensure 50 pix img height
rect = fitz.Rect(0, 0, imgw, imgh) * factor # logo rectangle on each page
doc = fitz.open(doc_fn)                     # open PDF to be modified
for page in doc:                            # scan through PDF pages
    xref = page.showPDFpage(rect, src, 0)   # put logo on page
  
doc.save("logo-" + doc_fn, garbage = 4)     # save PDF with a new name
#-------------------------------------------------
# usage: python svg-logo.py input.pdf image.svg
#-------------------------------------------------

SVG Output

Page method getSVGimage creates an SVG image of the page returned as a unicode string. This string can be save as an SVG-file. For example, turn one of the symbols from the example script into an SVG:

import fitz
import gzip

# import one of the symbols
from shapes_and_symbols import heart

# open empty output PDF
doc = fitz.open()

# make new page, square dimensions
page = doc.newPage(-1, width = 256, height = 256)

# start a Shape object
img = page.newShape()

# define some color
red = (1,0,0)

# create symbol on page
heart(img, page.rect, red)

# and commit it
img.commit()

# now turn page into SVG image
txt = page.getSVGimage()

# and compress it
txt_gzip = gzip.compress(txt.encode("utf-8"))
fout = open("heart.svgz", "wb")
fout.write(txt_gzip)
fout.close()
Clone this wiki locally