Line Wrapping Benchmark

This benchmark tests the performance of line wrapping and simple general layouting. The Project Gutenberg text of Homer’s Odyssey is used for this purposes.

Benchmark Setup

The text of the Odyssey is arranged on pages of the dimension WIDTHx1000 where WIDTH is set to different values (400, 200, 100 and 50 by default). Additionally, all widths are combined once with the standard PDF Type1 font Times-Roman and once with a TrueType font (DejaVu Sans by default).

In the case of pages with a width of 400 no line wrapping needs to be done because each line in the source text is shorter than 400 points. In the other cases lines need to be actually wrapped and the number of pages increases. With a width of 50 even words need sometimes to be broken.

Each benchmark script can be invoked standalone in the following way: script-executable TXT_FILE WIDTH OUTPUT_FILE [TTF_FILE].

The performance of the libraries hugely depends on how the input text is provided: Some are very fast when processing the whole input file at once, others only when processing the input line by line. The fastest method was always chosen.

The list of the benchmarked libraries:

HexaPDF

Homepage: http://hexapdf.gettalong.org
Language: Ruby
Version: Latest version

HexaPDF works faster if the whole input is given at once but still has acceptable runtimes for line by line input.

Two different ways of general layouting are benchmarked:

L
This version uses the low-level layouting facility HexaPDF::Layout::TextLayouter and processes the whole file at once.
C
This version uses the high-level HexaPDF::Composer to construct the document and processes chunks of 1000 lines at once to reduce peak memory usage.
Prawn

Homepage: https://prawnpdf.org
Language: Ruby
Version: 2.5.0

Prawn is much faster and uses much less memory if the input is provided line by line. However, it still works if the whole input is provided at once.

ReportLab

Homepage: https://www.reportlab.com/opensource/
Language: Python
Version: 4.2.2 + accel extension

ReportLab also needs its input line by line. Otherwise it is much, much slower (at least 60x, then the test run was aborted).

fpdf2

Homepage: https://pyfpdf.github.io/fpdf2/
Language: Python
Version: 2.7.9

As with HexaPDF itself, fpdf2 works equally fine when getting the input as one big string or line by line.

TCPDF

Homepage: https://tcpdf.org/
Language: PHP
Version: 6.7.5

As with Prawn and ReportLab, TCPDF needs its input line by line. Otherwise it is much, much slower when line wrapping needs to be done (the test run was aborted because it took too long).

Results

These benchmark results are from 2025-01-04.

benchmark graphic

    Time Memory File size
hexapdf L 400 844ms 87.864KiB 361.589
hexapdf C 400 781ms 46.288KiB 361.788
prawn 400 3.107ms 46.452KiB 526.289
reportlab/C 400 1.161ms 62.068KiB 486.548
fpdf2 400 3.057ms 88.608KiB 436.467
tcpdf 400 936ms 35.880KiB 513.780
hexapdf L 200 887ms 99.700KiB 408.493
hexapdf C 200 820ms 42.180KiB 408.675
prawn 200 4.091ms 51.792KiB 665.500
reportlab/C 200 1.206ms 62.872KiB 584.702
fpdf2 200 2.994ms 92.800KiB 545.185
tcpdf 200 1.102ms 37.776KiB 668.559
hexapdf L 100 955ms 98.972KiB 463.814
hexapdf C 100 891ms 43.576KiB 463.987
prawn 100 5.559ms 60.004KiB 850.581
reportlab/C 100 1.287ms 63.304KiB 698.375
fpdf2 100 3.207ms 98.916KiB 687.194
tcpdf 100 1.345ms 40.956KiB 918.499
hexapdf L 50 1.454ms 194.044KiB 569.340
hexapdf C 50 1.175ms 50.316KiB 569.514
prawn 50 9.080ms 70.316KiB 1.263.210
reportlab/C 50 1.510ms 65.068KiB 933.885
fpdf2 50 3.615ms 115.604KiB 1.006.761
tcpdf 50 1.940ms 48.376KiB 1.465.888
hexapdf L 400 ttf 957ms 94.892KiB 442.901
hexapdf C 400 ttf 878ms 44.860KiB 443.097
prawn 400 ttf 2.137ms 48.512KiB 559.485
reportlab/C 400 ttf 1.186ms 66.776KiB 620.385
fpdf2 400 ttf 3.952ms 92.380KiB 523.129
tcpdf 400 ttf 1.130ms 40.332KiB 631.674
hexapdf L 200 ttf 998ms 103.972KiB 504.937
hexapdf C 200 ttf 916ms 45.232KiB 505.113
prawn 200 ttf 3.005ms 54.908KiB 713.520
reportlab/C 200 ttf 1.241ms 67.648KiB 729.580
fpdf2 200 ttf 3.747ms 96.576KiB 649.907
tcpdf 200 ttf 1.267ms 41.880KiB 818.346
hexapdf L 100 ttf 1.077ms 98.428KiB 607.017
hexapdf C 100 ttf 1.036ms 46.364KiB 607.176
prawn 100 ttf 4.777ms 71.388KiB 1.014.187
reportlab/C 100 ttf 1.337ms 68.636KiB 918.498
fpdf2 100 ttf 3.889ms 106.536KiB 887.481
tcpdf 100 ttf 1.615ms 45.592KiB 1.200.742
hexapdf L 50 ttf 3.058ms 250.008KiB 768.318
hexapdf C 50 ttf 1.579ms 63.628KiB 768.482
prawn 50 ttf 7.878ms 73.248KiB 1.570.551
reportlab/C 50 ttf 1.602ms 70.448KiB 1.247.986
fpdf2 50 ttf 4.619ms 128.104KiB 1.319.784
tcpdf 50 ttf 2.431ms 54.728KiB 1.941.052