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:


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:

This version uses the low-level layouting facility HexaPDF::Layout::TextLayouter.
This version uses the high-level HexaPDF::Composer to construct the document.

Language: Ruby
Version: 2.2.2

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.


Language: Python
Version: 3.5.6

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


Language: PHP
Version: 6.2.13

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).


These benchmark results are from 2018-12-31.

benchmark graphic

    Time Memory File size
hexapdf L 400 1.155ms 70.164KiB 361.689
hexapdf C 400 1.211ms 81.760KiB 361.691
prawn 400 6.021ms 42.504KiB 526.289
reportlab 400 2.544ms 57.700KiB 486.548
tcpdf 400 1.427ms 33.088KiB 513.421
hexapdf L 200 1.239ms 76.748KiB 408.712
hexapdf C 200 1.396ms 78.800KiB 408.706
prawn 200 7.750ms 41.764KiB 665.500
reportlab 200 2.711ms 58.064KiB 584.702
tcpdf 200 1.687ms 33.828KiB 668.200
hexapdf L 100 1.428ms 83.632KiB 464.258
hexapdf C 100 1.623ms 78.080KiB 464.256
prawn 100 10.301ms 52.336KiB 850.581
reportlab 100 2.879ms 58.204KiB 698.014
tcpdf 100 2.085ms 37.716KiB 918.140
hexapdf L 50 2.449ms 181.268KiB 569.800
hexapdf C 50 2.940ms 191.656KiB 569.809
prawn 50 17.102ms 56.096KiB 1.263.210
reportlab 50 3.418ms 59.124KiB 933.007
tcpdf 50 3.024ms 43.952KiB 1.465.529
hexapdf L 400 ttf 1.205ms 78.780KiB 445.397
hexapdf C 400 ttf 1.299ms 94.004KiB 445.419
prawn 400 ttf 4.764ms 38.516KiB 561.074
reportlab 400 ttf 2.574ms 60.632KiB 621.386
tcpdf 400 ttf 1.592ms 36.056KiB 631.318
hexapdf L 200 ttf 1.336ms 82.448KiB 508.010
hexapdf C 200 ttf 1.503ms 90.968KiB 508.035
prawn 200 ttf 6.352ms 45.776KiB 715.109
reportlab 200 ttf 2.722ms 61.172KiB 730.768
tcpdf 200 ttf 1.889ms 39.852KiB 817.990
hexapdf L 100 ttf 1.639ms 82.216KiB 611.454
hexapdf C 100 ttf 1.929ms 90.508KiB 611.473
prawn 100 ttf 9.948ms 57.288KiB 1.015.776
reportlab 100 ttf 3.019ms 61.316KiB 918.126
tcpdf 100 ttf 2.548ms 42.200KiB 1.200.386
hexapdf L 50 ttf 4.250ms 277.196KiB 772.064
hexapdf C 50 ttf 5.117ms 271.416KiB 772.079
prawn 50 ttf 16.722ms 49.588KiB 1.572.140
reportlab 50 ttf 3.592ms 61.964KiB 1.241.619
tcpdf 50 ttf 3.783ms 52.260KiB 1.940.696