PDF Hello World from Python
import time
PAGE_WIDTH = 612
PAGE_HEIGHT = 792
out_file = open("hello.pdf", "wb")
index_byte = 0
index_xref = 0
page_index = -1
content_index = -1
dictionary_object = {}
dictionary_info = {}
dictionary_outlines = {}
dictionary_procset = {}
dictionary_font = {}
dictionary_content = {}
dictionary_page = {}
dictionary_pages = {}
dictionary_root = {}
# rgb values for named html colors
color_table = {
"aliceblue": "0.94 0.97 1",
"antiquewhite": "0.98 0.92 0.84",
"aqua": "0 1 1",
"aquamarine": "0.5 1 0.83",
"azure": "0.94 1 1",
"beige": "0.96 0.96 0.86",
"bisque": "1 0.89 0.77",
"black": "0 0 0",
"blanchedalmond": "1 0.92 0.8",
"blue": "0 0 1",
"blueviolet": "0.54 0.17 0.88",
"brown": "0.64 0.16 0.16",
"burlywood": "0.87 0.72 0.53",
"cadetblue": "0.37 0.62 0.63",
"chartreuse": "0.5 1 0",
"chocolate": "0.82 0.41 0.12",
"coral": "1 0.5 0.31",
"cornflowerblue": "0.39 0.58 0.93",
"cornsilk": "1 0.97 0.86",
"crimson": "0.86 0.08 0.23",
"cyan": "0 1 1",
"darkblue": "0 0 0.54",
"darkcyan": "0 0.54 0.54",
"darkgoldenrod": "0.72 0.52 0.04",
"darkgray": "0.66 0.66 0.66",
"darkgreen": "0 0.39 0",
"darkkhaki": "0.74 0.71 0.42",
"darkmagenta": "0.54 0 0.54",
"darkolivegreen": "0.33 0.42 0.18",
"darkorange": "1 0.55 0",
"darkorchid": "0.6 0.2 0.8",
"darkred": "0.54 0 0",
"darksalmon": "0.91 0.59 0.48",
"darkseagreen": "0.56 0.73 0.56",
"darkslateblue": "0.28 0.24 0.54",
"darkslategray": "0.18 0.31 0.31",
"darkturquoise": "0 0.8 0.82",
"darkviolet": "0.58 0 0.82",
"deeppink": "1 0.08 0.57",
"deepskyblue": "0 0.75 1",
"dimgray": "0.41 0.41 0.41",
"dodgerblue": "0.12 0.56 1",
"firebrick": "0.7 0.13 0.13",
"floralwhite": "1 0.98 0.94",
"forestgreen": "0.13 0.54 0.13",
"fuchsia": "1 0 1",
"gainsboro": "0.86 0.86 0.86",
"ghostwhite": "0.97 0.97 1",
"gold": "1 0.84 0",
"goldenrod": "0.85 0.64 0.13",
"gray": "0.5 0.5 0.5",
"green": "0 0.5 0",
"greenyellow": "0.68 1 0.18",
"honeydew": "0.94 1 0.94",
"hotpink": "1 0.41 0.7",
"indianred": "0.8 0.36 0.36",
"indigo": "0.29 0 0.51",
"ivory": "1 1 0.94",
"khaki": "0.94 0.9 0.55",
"lavender": "0.9 0.9 0.98",
"lavenderblush": "1 0.94 0.96",
"lawngreen": "0.48 0.98 0",
"lemonchiffon": "1 0.98 0.8",
"lightblue": "0.68 0.84 0.9",
"lightcoral": "0.94 0.5 0.5",
"lightcyan": "0.88 1 1",
"lightgoldenrodyellow": "0.98 0.98 0.82",
"lightgreen": "0.56 0.93 0.56",
"lightgrey": "0.82 0.82 0.82",
"lightpink": "1 0.71 0.75",
"lightsalmon": "1 0.63 0.48",
"lightseagreen": "0.13 0.7 0.66",
"lightskyblue": "0.53 0.8 0.98",
"lightslategray": "0.46 0.53 0.6",
"lightsteelblue": "0.69 0.77 0.87",
"lightyellow": "1 1 0.88",
"lime": "0 1 0",
"limegreen": "0.2 0.8 0.2",
"linen": "0.98 0.94 0.9",
"magenta": "1 0 1",
"maroon": "0.5 0 0",
"mediumaquamarine": "0.4 0.8 0.66",
"mediumblue": "0 0 0.8",
"mediumorchid": "0.73 0.33 0.82",
"mediumpurple": "0.57 0.44 0.86",
"mediumseagreen": "0.23 0.7 0.44",
"mediumslateblue": "0.48 0.41 0.93",
"mediumspringgreen": "0 0.98 0.6",
"mediumturquoise": "0.28 0.82 0.8",
"mediumvioletred": "0.78 0.08 0.52",
"midnightblue": "0.1 0.1 0.44",
"mintcream": "0.96 1 0.98",
"mistyrose": "1 0.89 0.88",
"moccasin": "1 0.89 0.71",
"navajowhite": "1 0.87 0.68",
"navy": "0 0 0.5",
"navyblue": "0.62 0.68 0.87",
"oldlace": "0.99 0.96 0.9",
"olive": "0.5 0.5 0",
"olivedrab": "0.42 0.55 0.14",
"orange": "1 0.64 0",
"orangered": "1 0.27 0",
"orchid": "0.85 0.44 0.84",
"palegoldenrod": "0.93 0.91 0.66",
"palegreen": "0.59 0.98 0.59",
"paleturquoise": "0.68 0.93 0.93",
"palevioletred": "0.86 0.44 0.57",
"papayawhip": "1 0.93 0.83",
"peachpuff": "1 0.85 0.72",
"peru": "0.8 0.52 0.25",
"pink": "1 0.75 0.79",
"plum": "0.86 0.63 0.86",
"powderblue": "0.69 0.88 0.9",
"purple": "0.5 0 0.5",
"red": "1 0 0",
"rosybrown": "0.73 0.56 0.56",
"royalblue": "0.25 0.41 0.88",
"saddlebrown": "0.54 0.27 0.07",
"salmon": "0.98 0.5 0.45",
"sandybrown": "0.95 0.64 0.38",
"seagreen": "0.18 0.54 0.34",
"seashell": "1 0.96 0.93",
"sienna": "0.63 0.32 0.18",
"silver": "0.75 0.75 0.75",
"skyblue": "0.53 0.8 0.92",
"slateblue": "0.41 0.35 0.8",
"slategray": "0.44 0.5 0.56",
"snow": "1 0.98 0.98",
"springgreen": "0 1 0.5",
"steelblue": "0.27 0.51 0.7",
"tan": "0.82 0.7 0.55",
"teal": "0 0.5 0.5",
"thistle": "0.84 0.75 0.84",
"tomato": "1 0.39 0.28",
"turquoise": "0.25 0.88 0.81",
"violet": "0.93 0.51 0.93",
"wheat": "0.96 0.87 0.7",
"white": "1 1 1",
"whitesmoke": "0.96 0.96 0.96",
"yellow": "1 1 0",
"yellowgreen": "0.54 0.8 0.2"}
# these are the font-widths for the standard fonts
# useful for text alignment and text justify
# print font_width["Times-Roman"][ord("A")] * 12 / 1000.0
# font width values were borrowed from DelphiPDF by Stefan Menten
# (see http://www.torry.net/unitsconversion.htm)
font_width = {
"Times-Roman": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250, 333, 408, 500, 500, 833, 778, 333, 333, 333, 500, 564, 250, 333, 250, 278,
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444,
921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722,
556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500,
333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500,
500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 333, 500, 0, 167, 500, 500, 500, 500, 180, 444, 500, 333, 333, 556, 556,
0, 500, 500, 500, 250, 0, 453, 350, 333, 444, 444, 500, 100, 100, 0, 444,
0, 333, 333, 333, 333, 333, 333, 333, 333, 0, 333, 333, 333, 333, 333, 100,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
889, 0, 276, 0, 0, 0, 0, 611, 722, 889, 310, 0, 0, 0, 0, 0,
667, 0, 0, 0, 278, 0, 0, 278, 500, 722, 500, 0, 0, 0, 0, 0
],
"Times-Bold": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250, 333, 555, 500, 500, 100, 833, 333, 333, 333, 500, 570, 250, 333, 250, 278,
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778,
611, 778, 722, 556, 667, 722, 722, 100, 722, 722, 667, 333, 278, 333, 581, 500,
333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500,
556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 333, 500, 500, 167, 500, 500, 500, 500, 278, 500, 500, 333, 333, 556, 556,
0, 500, 500, 500, 250, 0, 540, 350, 333, 500, 500, 500, 100, 100, 0, 500,
0, 333, 333, 333, 333, 333, 333, 333, 333, 0, 333, 333, 0, 333, 333, 333,
100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 100, 0, 300, 0, 0, 0, 0, 667, 778, 100, 330, 0, 0, 0, 0,
0, 722, 0, 0, 0, 278, 0, 0, 278, 500, 722, 556, 0, 0, 0, 0
],
"Times-Italic": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250, 333, 420, 500, 500, 833, 778, 333, 333, 333, 500, 675, 250, 333, 250, 278,
500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500,
920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722,
611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500,
333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500,
500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 389, 500, 500, 167, 500, 500, 500, 500, 214, 556, 500, 333, 333, 500, 500,
0, 500, 500, 500, 250, 0, 523, 350, 333, 556, 556, 500, 889, 100, 0, 500,
0, 333, 333, 333, 333, 333, 333, 333, 333, 0, 333, 333, 0, 333, 333, 333,
889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 889, 0, 276, 0, 0, 0, 0, 556, 722, 944, 310, 0, 0, 0, 0,
0, 667, 0, 0, 0, 278, 0, 0, 278, 500, 667, 500, 0, 0, 0, 0
],
"Helvetica": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278, 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584, 278, 333, 278, 278,
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
102, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
222, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 333, 556, 556, 167, 556, 556, 556, 556, 191, 333, 556, 333, 333, 500, 500,
0, 556, 556, 556, 278, 0, 537, 350, 222, 333, 333, 556, 100, 100, 0, 611,
0, 333, 333, 333, 333, 333, 333, 333, 333, 0, 333, 333, 333, 333, 333, 100,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100, 0, 370, 0, 0, 0, 0, 0, 556, 778, 100, 365, 0, 0, 0, 0,
0, 889, 0, 0, 0, 278, 0, 0, 222, 611, 944, 611, 0, 0, 0, 0
],
"Helvetica-Bold": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278, 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584, 278, 333, 278, 278,
556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
278, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 228, 389, 584, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 333, 556, 556, 167, 556, 556, 556, 556, 238, 500, 556, 333, 333, 611, 611,
0, 556, 556, 556, 278, 0, 556, 350, 278, 500, 500, 556, 100, 100, 0, 611,
0, 333, 333, 333, 333, 333, 333, 333, 333, 0, 333, 333, 333, 333, 333, 100,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100, 0, 370, 0, 0, 0, 0, 0, 611, 778, 100, 365, 0, 0, 0, 0,
0, 889, 0, 0, 0, 278, 0, 0, 278, 611, 944, 611, 0, 0, 0, 0
]
}
# output a string to the pdf file
def pdf_write(output_string):
global index_byte
out_file.write(output_string)
index_byte += len(output_string)
# allocate a pdf object
def obj_allocate():
index_obj = len(dictionary_object) + 1
dictionary_object[index_obj] = index_byte
return index_obj
# escape out a pdf string
def escape_pdf(s):
return s.replace("\\","\\\\").replace("(","\\(").replace(")","\\)")
# find the length of a text string
def text_width(s, font_name, font_size):
rval = 0
for c in s:
rval = rval + font_width[font_name][ord(c)] * font_size / 1000.0
return rval
# pdf version identifier
pdf_write("%PDF-1.4\n")
# indicate binary content for viewer
pdf_write("%рсту\n")
# document information dictionary
dictionary_info[0] = obj_allocate()
pdf_write("%s 0 obj\n" % dictionary_info[0])
pdf_write("<<\n")
pdf_write("/Title (%s)\n" % escape_pdf("a titilating title"))
pdf_write("/Producer (%s)\n" % escape_pdf("Critter's Underground Software"))
pdf_write("/Creator (%s)\n" % escape_pdf("Chris Rathman"))
pdf_write("/Version (0.01)\n")
pdf_write("/Subject (%s)\n" % escape_pdf("Subject Matter"))
pdf_write("/Author (%s)\n" % escape_pdf("Chris Rathman"))
pdf_write("/Keywords (%s)\n" % escape_pdf("How to write PDF from Python"))
pdf_write("/CreationDate (%s)\n" % time.strftime("%Y%m%d%H%M%S-05'00'"))
pdf_write(">>\n")
pdf_write("endobj\n")
# outline dictionary
dictionary_outlines[0] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_outlines[0])
pdf_write("<<\n")
pdf_write("/Type /Outlines\n")
pdf_write("/Count 0\n")
pdf_write(">>\n")
pdf_write("endobj\n")
# procedure set - array of predefined procedure set names
dictionary_procset[0] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_procset[0])
pdf_write("[/PDF /Text]\n")
pdf_write("endobj\n")
# font dictionary
dictionary_font["Times-Roman"] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_font["Times-Roman"])
pdf_write("<<\n")
pdf_write("/Type /Font\n")
pdf_write("/Subtype /Type1\n")
pdf_write("/Name /Times-Roman\n")
pdf_write("/BaseFont /Times-Roman\n")
pdf_write("/Encoding /MacRomanEncoding\n")
pdf_write(">>\n")
pdf_write("endobj\n")
dictionary_font["Times-Bold"] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_font["Times-Bold"])
pdf_write("<<\n")
pdf_write("/Type /Font\n")
pdf_write("/Subtype /Type1\n")
pdf_write("/Name /Times-Bold\n")
pdf_write("/BaseFont /Times-Bold\n")
pdf_write("/Encoding /MacRomanEncoding\n")
pdf_write(">>\n")
pdf_write("endobj\n")
dictionary_font["Times-Italic"] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_font["Times-Italic"])
pdf_write("<<\n")
pdf_write("/Type /Font\n")
pdf_write("/Subtype /Type1\n")
pdf_write("/Name /Times-Italic\n")
pdf_write("/BaseFont /Times-Italic\n")
pdf_write("/Encoding /MacRomanEncoding\n")
pdf_write(">>\n")
pdf_write("endobj\n")
dictionary_font["Helvetica"] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_font["Helvetica"])
pdf_write("<<\n")
pdf_write("/Type /Font\n")
pdf_write("/Subtype /Type1\n")
pdf_write("/Name /Helvetica\n")
pdf_write("/BaseFont /Helvetica\n")
pdf_write("/Encoding /MacRomanEncoding\n")
pdf_write(">>\n")
pdf_write("endobj\n")
dictionary_font["Helvetica-Bold"] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_font["Helvetica-Bold"])
pdf_write("<<\n")
pdf_write("/Type /Font\n")
pdf_write("/Subtype /Type1\n")
pdf_write("/Name /Helvetica-Bold\n")
pdf_write("/BaseFont /Helvetica-Bold\n")
pdf_write("/Encoding /MacRomanEncoding\n")
pdf_write(">>\n")
pdf_write("endobj\n")
# hello world string (page #1)
page_index += 1
content_index += 1
dictionary_content[page_index] = {}
dictionary_content[page_index][content_index] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_content[page_index][content_index])
pdf_write("<< /Length %d 0 R >>\n" % (dictionary_content[page_index][content_index]+1))
pdf_write("stream\n")
first_byte = index_byte
pdf_write("BT\n")
pdf_write("%s rg\n" % color_table["black"])
pdf_write("/%s %d Tf\n" % ("Times-Roman", 12))
pdf_write("%d %d Td\n" % (100, PAGE_HEIGHT-100))
pdf_write("(%s) Tj\n" % escape_pdf("Hello World"))
pdf_write("ET\n")
last_byte = index_byte
pdf_write("endstream\n")
pdf_write("endobj\n")
pdf_write("%d 0 obj\n" % obj_allocate())
pdf_write("%d\n" % (last_byte-first_byte))
pdf_write("endobj\n")
# draw some lines & a rectangle (page #1)
content_index += 1
dictionary_content[page_index][content_index] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_content[page_index][content_index])
pdf_write("<< /Length %d 0 R >>\n" % (dictionary_content[page_index][content_index]+1))
pdf_write("stream\n")
first_byte = index_byte
pdf_write("%s rg\n" % color_table["red"])
pdf_write("%s RG\n" % color_table["blue"])
pdf_write("1 j\n")
pdf_write("2 w\n")
pdf_write("%d %d m\n" % (200, PAGE_HEIGHT-200))
pdf_write("%d %d l\n" % (250, PAGE_HEIGHT-200))
pdf_write("S\n")
pdf_write("%d %d %d %d re\n" % (300, PAGE_HEIGHT-300, 25, 50))
pdf_write("B\n")
last_byte = index_byte
pdf_write("endstream\n")
pdf_write("endobj\n")
pdf_write("%d 0 obj\n" % obj_allocate())
pdf_write("%d\n" % (last_byte-first_byte))
pdf_write("endobj\n")
# hello world string (page #2)
page_index += 1
content_index += 1
dictionary_content[page_index] = {}
dictionary_content[page_index][content_index] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_content[page_index][content_index])
pdf_write("<< /Length %d 0 R >>\n" % (dictionary_content[page_index][content_index]+1))
pdf_write("stream\n")
first_byte = index_byte
pdf_write("BT\n")
pdf_write("%s rg\n" % color_table["black"])
pdf_write("/%s %d Tf\n" % ("Times-Roman", 12))
pdf_write("%d %d Td\n" % ((PAGE_WIDTH - text_width("Center This Text", "Times-Roman", 12))/2, PAGE_HEIGHT-100))
pdf_write("(%s) Tj\n" % escape_pdf("Center This Text"))
pdf_write("ET\n")
last_byte = index_byte
pdf_write("endstream\n")
pdf_write("endobj\n")
pdf_write("%d 0 obj\n" % obj_allocate())
pdf_write("%d\n" % (last_byte-first_byte))
pdf_write("endobj\n")
# page objects
for key in dictionary_content.keys():
dictionary_page[key] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_page[key])
pdf_write("<<\n")
pdf_write("/Type /Page\n")
pdf_write("/Parent %d 0 R\n" % (dictionary_page[key] + len(dictionary_content) - key))
pdf_write("/MediaBox [0 0 %d %d]\n" % (PAGE_WIDTH, PAGE_HEIGHT))
pdf_write("/Contents [\n")
for item in dictionary_content[key].values():
pdf_write("%d 0 R\n" % item)
pdf_write("]\n")
pdf_write("/Resources\n")
pdf_write("<<\n")
pdf_write("/ProcSet %d 0 R\n" % dictionary_procset[0])
pdf_write("/Font << \n")
for key, val in dictionary_font.items():
pdf_write("/%s %d 0 R\n" % (key, val))
pdf_write(">>\n")
pdf_write(">>\n")
pdf_write(">>\n")
pdf_write("endobj\n")
# pages object
dictionary_pages[0] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_pages[0])
pdf_write("<<\n")
pdf_write("/Type /Pages\n")
pdf_write("/Parent null\n")
pdf_write("/Kids [\n")
for item in dictionary_page.values():
pdf_write("%d 0 R\n" % item)
pdf_write("]\n")
pdf_write("/Count %d\n" % len(dictionary_page))
pdf_write(">>\n")
pdf_write("endobj\n")
# root object
dictionary_root[0] = obj_allocate()
pdf_write("%d 0 obj\n" % dictionary_root[0])
pdf_write("<<\n")
pdf_write("/Type /Catalog\n")
pdf_write("/Outlines %d 0 R\n" % dictionary_outlines[0])
pdf_write("/Pages %d 0 R\n" % dictionary_pages[0])
pdf_write(">>\n")
pdf_write("endobj\n")
# cross reference tables
index_xref = index_byte
pdf_write("xref\n")
pdf_write("0 %d\n" % (len(dictionary_object)+1))
pdf_write("0000000000 65535 f \n")
for item in dictionary_object.values():
pdf_write("%s 00000 n \n" % str(item).zfill(10))
# trailer
pdf_write("trailer\n")
pdf_write("<<\n")
pdf_write("/Size " + str(len(dictionary_object)+1) + "\n")
pdf_write("/Root %d 0 R\n" % dictionary_root[0])
pdf_write("/Info %d 0 R\n" % dictionary_info[0])
pdf_write(">>\n")
pdf_write("startxref\n")
pdf_write("%d\n" % index_xref)
pdf_write("%%EOF\n")