The highlight of this release is the support for optional content aka layers.
Optional content allows one to selectively show or hide content. It is most often used to
provide something akin to layers, think a building plan with separate layers for the walls,
electrical infrastructure, furniture and so on. However, it can also be used for something more
mundane, like hiding the answers of a quiz.
Apart from this larger change there is a new style property HexaPDF::Layout::Style#fill_horizontal
which allows a text fragment to fill the remaining space of a line. This is very useful when
creating table of content entries.
There is new documentation for the optional content feature and the document creation section got a
new how-tos section which will be expanded in the
future.
As always, have a look at the changelog for an overview of all changes.
This release contains many different changes and fixes. The highlight, however, is the support for
tables.
Table Implementation
The biggest change in this release is the addition of HexaPDF::Layout::TableBox which allows the
creation of fixed width tables:

With this addition creating a table becomes very easy:
require 'hexapdf'
HexaPDF::Composer.create('table.pdf') do |composer|
composer.table([['This', 'is'], ['a', 'table']], column_widths: [100, 100])
end
The table implementation supports
- one or more boxes of any type inside a table cell,
- header and footer rows,
- column and row spans, as well as
- easy styling of the whole table, rows, columns or individual cells.
There is also a new table benchmark which shows that HexaPDF is outperforming Prawn with the
prawn-table
gem.
Website Overhaul
The website got an overhaul and looks a bit (just a bit) different now. The changes were made to
make the website feel more coherent in terms of styling and colors. Here are before and after images
where this can be seen:

The documentation pages have also been enhanced with more sample PDFs. While the former version had
183 PDFs created with HexaPDF during the website generation, the current version has 237, so about
30% more!
Other Notable Changes
There was a bit of work making HexaPDF faster and use less memory. This can be seen in the line
wrapping benchmark where the low-level version and the HexaPDF::Composer version are now nearly
on par. Another change reduced the number of Fiber instances which greatly improves HexaPDF
performance on TruffleRuby.
The API documentation of many classes has also been updated and enhanced. This is an ongoing process
which will see all API documentation being updated.
As always, have a look at the changelog for an overview of all changes.
This release features major internal changes for the support of digital signatures. The whole code
was refactored and now HexaPDF itself creates the necessary CMS signed-data structures.
Due to this changes HexaPDF is now able to support PAdES-BES level B-B and B-T signatures!
Additionally, it is now very easy to create digital signatures via HSM calls:
require 'hexapdf'
# Set up client for HSM module
client = ...
doc = HexaPDF::Document.open(ARGV[0])
signing = lambda {|digest_method, data| client.sign_raw(digest_method, data) }
doc.sign("signed.pdf", external_signing: signing,
certificate: client.signing_certificate,
certificate_chain: client.certificate_chain)
As always, have a look at the changelog for an overview of all changes.