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


Language: Python
Version: 3.5.23

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


These benchmark results are from 2020-12-27.

benchmark graphic

    Time Memory File size
hexapdf L 400 1.307ms 101.320KiB 361.689
hexapdf C 400 1.419ms 108.700KiB 361.693
prawn 400 3.413ms 45.036KiB 513.329
reportlab 400 2.078ms 58.164KiB 486.548
tcpdf 400 1.611ms 30.408KiB 513.780
hexapdf L 200 1.364ms 93.356KiB 408.708
hexapdf C 200 1.654ms 100.828KiB 408.708
prawn 200 4.793ms 51.016KiB 642.172
reportlab 200 2.274ms 58.700KiB 584.702
tcpdf 200 1.851ms 32.204KiB 668.559
hexapdf L 100 1.584ms 90.128KiB 464.257
hexapdf C 100 1.951ms 97.032KiB 464.259
prawn 100 6.839ms 58.772KiB 811.701
reportlab 100 2.506ms 59.012KiB 698.014
tcpdf 100 2.347ms 35.052KiB 918.499
hexapdf L 50 2.682ms 231.976KiB 569.797
hexapdf C 50 3.204ms 219.276KiB 569.810
prawn 50 11.649ms 60.324KiB 1.188.322
reportlab 50 2.995ms 59.760KiB 933.007
tcpdf 50 3.382ms 42.684KiB 1.465.888
hexapdf L 400 ttf 1.361ms 91.588KiB 445.397
hexapdf C 400 ttf 1.531ms 108.304KiB 445.421
prawn 400 ttf 4.082ms 48.140KiB 547.152
reportlab 400 ttf 2.364ms 61.028KiB 621.386
tcpdf 400 ttf 1.866ms 35.704KiB 631.677
hexapdf L 200 ttf 1.544ms 85.652KiB 508.009
hexapdf C 200 ttf 1.777ms 98.704KiB 508.036
prawn 200 ttf 5.858ms 55.252KiB 689.475
reportlab 200 ttf 2.676ms 61.008KiB 730.768
tcpdf 200 ttf 2.199ms 37.748KiB 818.349
hexapdf L 100 ttf 1.861ms 86.696KiB 611.454
hexapdf C 100 ttf 2.490ms 96.508KiB 611.477
prawn 100 ttf 9.148ms 58.104KiB 964.126
reportlab 100 ttf 2.919ms 62.472KiB 918.126
tcpdf 100 ttf 2.869ms 41.160KiB 1.200.745
hexapdf L 50 ttf 4.675ms 254.304KiB 772.063
hexapdf C 50 ttf 5.727ms 290.032KiB 772.076
prawn 50 ttf 14.959ms 59.508KiB 1.469.834
reportlab 50 ttf 3.373ms 62.468KiB 1.241.619
tcpdf 50 ttf 4.346ms 50.516KiB 1.941.055