From ddc805a534725b06a3e172014add5a0c68cb1b38 Mon Sep 17 00:00:00 2001
From: gitlost <burmartke@gmail.com>
Date: Mon, 19 Dec 2022 10:34:25 +0000
Subject: [PATCH 1/2] Guard against empty frames in `Model::w()` and
 `Model::h()` to avoid QList ASSERT being triggered in `TestModel::model()`.

---
 model/Model.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/model/Model.cpp b/model/Model.cpp
index 4bcf47fc..17be4d40 100644
--- a/model/Model.cpp
+++ b/model/Model.cpp
@@ -235,7 +235,7 @@ namespace glabels
 		///
 		Distance Model::w() const
 		{
-			if ( auto* frame = mTmplate.frames().constFirst() )
+			if ( auto* frame = !mTmplate.frames().isEmpty() ? mTmplate.frames().constFirst() : nullptr )
 			{
 				return mRotate ? frame->h() : frame->w();
 			}
@@ -251,7 +251,7 @@ namespace glabels
 		///
 		Distance Model::h() const
 		{
-			if ( auto* frame = mTmplate.frames().constFirst() )
+			if ( auto* frame = !mTmplate.frames().isEmpty() ? mTmplate.frames().constFirst() : nullptr )
 			{
 				return mRotate ? frame->w() : frame->h();
 			}

From 3b88071c6afee8b52598975f4f9eae1bf8cb42d1 Mon Sep 17 00:00:00 2001
From: gitlost <burmartke@gmail.com>
Date: Mon, 19 Dec 2022 11:02:27 +0000
Subject: [PATCH 2/2] Add handling of new Zint API >= 2.7.0 for Zint backend
 and use latest version (2.12.0) by default (issues #86 and #160, subsumes PR
 #164).

 - hack "FindLibZint.cmake" to use `zint -h` to get version;
   define `LIBZINT_VERSION`
 - add new API handling in `Zint` in LIBZINT_VERSION >= 20700 define,
   leaving 2.6.3 handling unchanged
 - add some new Zint barcodes and adjust style properties of various other
   Zint barcodes
 - enable check digit handling via Zint `option_2`
 - add horizontal alignment `halign` argument to `Barcode::addText()`,
   `QtRenderer::drawText()` and `DrawingPrimitiveText::DrawingPrimitiveText()`
   and use in `QtRenderer::drawText()` to cater for Zint EAN/UPC left/right
   text align of outside digits
 - guard against QT infinite loop bug in `QFontMetricsF` when point size
   < ~0.4 (MIN_POINT_SIZE)
---
 .travis.yml                      |   2 +-
 CMakeLists.txt                   |   2 +-
 backends/barcode/Backends.cpp    | 172 +++++++++---
 backends/barcode/CMakeLists.txt  |   1 +
 backends/barcode/Zint.cpp        | 458 ++++++++++++++++++++++++++++++-
 backends/barcode/Zint.h          | 240 +++++++++++++++-
 cmake/Modules/FindLibZint.cmake  |  24 +-
 docs/BUILD-INSTRUCTIONS-LINUX.md |   6 +-
 glbarcode/Barcode.cpp            |   4 +-
 glbarcode/Barcode.h              |  11 +-
 glbarcode/DrawingPrimitives.cpp  |  10 +-
 glbarcode/DrawingPrimitives.h    |  17 +-
 glbarcode/QtRenderer.cpp         |  17 +-
 glbarcode/QtRenderer.h           |   2 +-
 glbarcode/Renderer.cpp           |   2 +-
 glbarcode/Renderer.h             |   2 +-
 model/ModelBarcodeObject.cpp     |   3 +-
 translations/glabels_C.ts        | 146 +++++++---
 18 files changed, 1000 insertions(+), 119 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index d85e76d2..17f41725 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,7 +31,7 @@ matrix:
       - sudo apt-get -y install pkgconf libqrencode-dev
       - sudo apt-get -y install barcode
       # Install zint from source
-      - wget https://downloads.sourceforge.net/project/zint/zint/2.6.5/zint-2.6.5.tar.gz && tar xzf zint-2.6.5.tar.gz && ( cd zint-2.6.5 && mkdir build && cd build && cmake .. && make && sudo make install )
+      - wget https://downloads.sourceforge.net/project/zint/zint/2.12.0/zint-2.12.0-src.tar.gz && tar xzf zint-2.12.0-src.tar.gz && ( cd zint-2.12.0-src && mkdir build && cd build && cmake .. && make && sudo make install )
       - export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
 
     before_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c70fcc9d..7247d006 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -126,7 +126,7 @@ endif ()
 find_package (ZLIB 1.2 QUIET)
 find_package (GnuBarcode 0.98 QUIET)
 find_package (LibQrencode 3.4 QUIET)
-find_package (LibZint 2.6 EXACT QUIET)
+find_package (LibZint 2.6 QUIET)
 # Unit testing support
 find_package (Qt5Test 5.6 QUIET)
 
diff --git a/backends/barcode/Backends.cpp b/backends/barcode/Backends.cpp
index 2e4307a9..d9bad6a4 100644
--- a/backends/barcode/Backends.cpp
+++ b/backends/barcode/Backends.cpp
@@ -184,12 +184,19 @@ namespace glabels
 			glbarcode::Factory::registerType( "zint::ausrd",     Zint::AusRD::create );
 			glbarcode::Factory::registerType( "zint::aztec",     Zint::Aztec::create );
 			glbarcode::Factory::registerType( "zint::azrun",     Zint::Azrun::create );
+			#if LIBZINT_VERSION >= 21101
+			glbarcode::Factory::registerType( "zint::bc412",     Zint::Bc412::create );
+			glbarcode::Factory::registerType( "zint::cepnet",    Zint::Cepnet::create );
+			#endif
 			glbarcode::Factory::registerType( "zint::cbr",       Zint::Cbr::create );
+			glbarcode::Factory::registerType( "zint::cblockf",   Zint::Cblockf::create );
+			glbarcode::Factory::registerType( "zint::channel",   Zint::Channel::create );
 			glbarcode::Factory::registerType( "zint::code1",     Zint::Code1::create );
 			glbarcode::Factory::registerType( "zint::code11",    Zint::Code11::create );
 			glbarcode::Factory::registerType( "zint::c16k",      Zint::C16k::create );
 			glbarcode::Factory::registerType( "zint::c25m",      Zint::C25m::create );
 			glbarcode::Factory::registerType( "zint::c25i",      Zint::C25i::create );
+			glbarcode::Factory::registerType( "zint::c25ind",    Zint::C25ind::create );
 			glbarcode::Factory::registerType( "zint::c25dl",     Zint::C25dl::create );
 			glbarcode::Factory::registerType( "zint::code32",    Zint::Code32::create );
 			glbarcode::Factory::registerType( "zint::code39",    Zint::Code39::create );
@@ -202,10 +209,18 @@ namespace glabels
 			glbarcode::Factory::registerType( "zint::dmtx",      Zint::Dmtx::create );
 			glbarcode::Factory::registerType( "zint::dpl",       Zint::Dpl::create );
 			glbarcode::Factory::registerType( "zint::dpi",       Zint::Dpi::create );
+			glbarcode::Factory::registerType( "zint::dotcode",   Zint::Dotcode::create );
+			#if LIBZINT_VERSION >= 20901
+			glbarcode::Factory::registerType( "zint::dpd",       Zint::Dpd::create );
+			#endif
 			glbarcode::Factory::registerType( "zint::kix",       Zint::Kix::create );
 			glbarcode::Factory::registerType( "zint::ean",       Zint::Ean::create );
+			glbarcode::Factory::registerType( "zint::ean14",     Zint::Ean14::create );
+			glbarcode::Factory::registerType( "zint::fim",       Zint::Fim::create );
+			glbarcode::Factory::registerType( "zint::flat",      Zint::Flat::create );
 			glbarcode::Factory::registerType( "zint::gmtx",      Zint::Gmtx::create );
 			glbarcode::Factory::registerType( "zint::gs1-128",   Zint::Gs1128::create );
+			glbarcode::Factory::registerType( "zint::hanxin",    Zint::Hanxin::create );
 			glbarcode::Factory::registerType( "zint::rss14",     Zint::Rss14::create );
 			glbarcode::Factory::registerType( "zint::rssltd",    Zint::Rssltd::create );
 			glbarcode::Factory::registerType( "zint::rssexp",    Zint::Rssexp::create );
@@ -218,6 +233,7 @@ namespace glabels
 			glbarcode::Factory::registerType( "zint::hibcqr",    Zint::Hibcqr::create );
 			glbarcode::Factory::registerType( "zint::hibcpdf",   Zint::Hibcpdf::create );
 			glbarcode::Factory::registerType( "zint::hibcmpdf",  Zint::Hibcmpdf::create );
+			glbarcode::Factory::registerType( "zint::hibcblkf",  Zint::Hibcblkf::create );
 			glbarcode::Factory::registerType( "zint::hibcaz",    Zint::Hibcaz::create );
 			glbarcode::Factory::registerType( "zint::i25",       Zint::I25::create );
 			glbarcode::Factory::registerType( "zint::isbn",      Zint::Isbn::create );
@@ -238,13 +254,24 @@ namespace glabels
 			glbarcode::Factory::registerType( "zint::pharma2",   Zint::Pharma2::create );
 			glbarcode::Factory::registerType( "zint::pzn",       Zint::Pzn::create );
 			glbarcode::Factory::registerType( "zint::qr",        Zint::Qr::create );
+			#if LIBZINT_VERSION >= 20700
+			glbarcode::Factory::registerType( "zint::rmqr",      Zint::Rmqr::create );
+			#endif
 			glbarcode::Factory::registerType( "zint::rm4",       Zint::Rm4::create );
+			glbarcode::Factory::registerType( "zint::rm4sm",     Zint::Rm4sm::create );
+			#if LIBZINT_VERSION >= 21200
+			glbarcode::Factory::registerType( "zint::rm2dm",     Zint::Rm2dm::create );
+			#endif
 			glbarcode::Factory::registerType( "zint::tele",      Zint::Tele::create );
 			glbarcode::Factory::registerType( "zint::telex",     Zint::Telex::create );
 			glbarcode::Factory::registerType( "zint::upc-a",     Zint::UpcA::create );
 			glbarcode::Factory::registerType( "zint::upc-e",     Zint::UpcE::create );
+			#if LIBZINT_VERSION >= 21200
+			glbarcode::Factory::registerType( "zint::upus10",    Zint::UpuS10::create );
+			#endif
 			glbarcode::Factory::registerType( "zint::usps",      Zint::Usps::create );
 			glbarcode::Factory::registerType( "zint::pls",       Zint::Pls::create );
+			glbarcode::Factory::registerType( "zint::vin",       Zint::Vin::create );
 
 			registerStyle( "ausp", "zint", tr("Australia Post Standard"),
 			               false, false, true, false, "12345678901234567890123", true, 23 );
@@ -261,38 +288,55 @@ namespace glabels
 			registerStyle( "aztec", "zint", tr("Aztec Code"),
 			               false, false, true, false, "1234567890", true, 10 );
           
-			registerStyle( "azrun", "zint", tr("Aztec Rune"),
+			registerStyle( "azrun", "zint", tr("Aztec Runes"),
 			               false, false, true, false, "255", true, 3 );
 
+			#if LIBZINT_VERSION >= 21101
+			registerStyle( "bc412", "zint", tr("BC412 (SEMI TI-95)"),
+			               true, true, true, false, "12345678", true, 8 );
+
+			registerStyle( "cepnet", "zint", tr("CEPNet (Brazilian Post)"),
+			               false, false, true, false, "12345678", true, 8 );
+			#endif
+
+			registerStyle( "channel", "zint", tr("Channel Code"),
+			               true, true, false, false, "00", true, 2 );
+
 			registerStyle( "cbr", "zint", tr("Codabar"),
-			               true, true, true, false, "ABCDABCDAB", true, 10 );
+			               true, true, true, true, "A00000000B", true, 10 );
+
+			registerStyle( "cblockf", "zint", tr("Codablock-F"),
+			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "code1", "zint", tr("Code One"), 
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "code11", "zint", tr("Code 11"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
           
 			registerStyle( "c16k", "zint", tr("Code 16K"),
 			               false, false, true, false, "0000000000", true, 10 );
           
-			registerStyle( "c25m", "zint", tr("Code 2 of 5 Matrix"), 
-			               true, true, true, false, "0000000000", true, 10 );
+			registerStyle( "c25m", "zint", tr("Code 2 of 5 Standard"),
+			               true, true, true, true, "0000000000", true, 10 );
           
 			registerStyle( "c25i", "zint", tr("Code 2 of 5 IATA"), 
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
+
+			registerStyle( "c25ind", "zint", tr("Code 2 of 5 Industrial"),
+			               true, true, true, true, "0000000000", true, 10 );
           
 			registerStyle( "c25dl", "zint", tr("Code 2 of 5 Data Logic"), 
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
 
 			registerStyle( "code32", "zint", tr("Code 32 (Italian Pharmacode)"), 
 			               true, true, true, false, "12345678", true, 8 );
 
 			registerStyle( "code39", "zint", tr("Code 39"),
-			               true, true, false, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
           
 			registerStyle( "code39e", "zint", tr("Code 39 Extended"), 
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
 
 			registerStyle( "code49", "zint", tr("Code 49"),
 			               false, false, true, false, "0000000000", true, 10 );
@@ -317,36 +361,56 @@ namespace glabels
           
 			registerStyle( "dpi", "zint", tr("Deutsche Post Identcode"),
 			               true, true, true, false, "12345678901", true, 11 );
-          
-			registerStyle( "kix", "zint", tr("Dutch Post KIX Code"),
+
+			registerStyle( "dotcode", "zint", tr("DotCode"),
 			               false, false, true, false, "0000000000", true, 10 );
 
+			#if LIBZINT_VERSION >= 20901
+			registerStyle( "dpd", "zint", tr("DPD Code"),
+			               true, true, true, false, "000000000000000000000000000", true, 27 );
+			#endif
+
+			registerStyle( "kix", "zint", tr("Dutch Post KIX Code"),
+			               false, false, false, false, "0000000000", true, 10 );
+
 			registerStyle( "ean", "zint", tr("EAN"),
+			               true, true, true, false, "123456789012", false, 12 );
+
+			registerStyle( "ean14", "zint", tr("EAN-14"),
 			               true, true, true, false, "1234567890123", false, 13 );
 
+			registerStyle( "fim", "zint", tr("FIM (Facing ID Mark)"),
+			               false, false, false, false, "A", false, 1 );
+
+			registerStyle( "flat", "zint", tr("Flattermarken"),
+			               false, false, false, false, "11111111", false, 8 );
+
 			registerStyle( "gmtx", "zint", tr("Grid Matrix"), 
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "gs1-128", "zint", tr("GS1-128"),
-			               true, true, true, false, "[01]12345678901234", false, 18 );
+			               true, true, true, false, "[01]12345678901231", false, 18 );
 
-			registerStyle( "rss14", "zint", tr("GS1 DataBar-14"),
+			registerStyle( "rss14", "zint", tr("GS1 DataBar Omnidirectional"),
 			               true, true, true, false, "1234567890123", true, 13 );
           
-			registerStyle( "rssltd", "zint", "GS1 DataBar-14 Limited", 
+			registerStyle( "rssltd", "zint", "GS1 DataBar Limited",
 			               true, true, true, false, "1234567890123", true, 13 );
           
-			registerStyle( "rssexp", "zint", "GS1 DataBar Extended", 
-			               true, true, true, false, "[01]12345678901234", false, 18 );
+			registerStyle( "rssexp", "zint", "GS1 DataBar Expanded",
+			               true, true, true, false, "[01]12345678901231", false, 18 );
           
-			registerStyle( "rsss", "zint", tr("GS1 DataBar-14 Stacked"),
+			registerStyle( "rsss", "zint", tr("GS1 DataBar Stacked"),
 			               false, false, true, false, "0000000000", true, 10 );
 
-			registerStyle( "rssso", "zint", tr("GS1 DataBar-14 Stacked Omni."),
+			registerStyle( "rssso", "zint", tr("GS1 DataBar Stacked Omni."),
 			               false, false, true, false, "0000000000", true, 10 );
 
-			registerStyle( "rssse", "zint", tr("GS1 DataBar Extended Stacked"),
-			               false, false, true, false, "[01]12345678901234", false, 18 );
+			registerStyle( "rssse", "zint", tr("GS1 DataBar Expanded Stacked"),
+			               false, false, true, false, "[01]12345678901231", false, 18 );
+
+			registerStyle( "hanxin", "zint", tr("Han Xin"),
+			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "hibc128", "zint", tr("HIBC Code 128"),
 			               true, true, true, false, "0000000000", true, 10 );
@@ -363,14 +427,17 @@ namespace glabels
 			registerStyle( "hibcpdf", "zint", tr("HIBC PDF417"),
 			               false, false, true, false, "0000000000", true, 10 );
 
-			registerStyle( "hibcmpdf", "zint", tr("HIBC Micro PDF417"),
+			registerStyle( "hibcmpdf", "zint", tr("HIBC MicroPDF417"),
+			               false, false, true, false, "0000000000", true, 10 );
+
+			registerStyle( "hibcblkf", "zint", tr("HIBC Codablock-F"),
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "hibcaz", "zint", tr("HIBC Aztec Code"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "i25", "zint", tr("Interleaved 2 of 5"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
 
 			registerStyle( "isbn", "zint", tr("ISBN"),
 			               true, true, true, false, "123456789", false, 9 );
@@ -385,67 +452,88 @@ namespace glabels
 			               true, true, true, false, "123456", false, 6 );
 
 			registerStyle( "logm", "zint", tr("LOGMARS"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
 
 			registerStyle( "maxi", "zint", tr("Maxicode"),
-			               false, false, false, false, "0000000000", true, 10 );
+			               false, false, true, false, "0000000000", true, 10 );
 
-			registerStyle( "mpdf", "zint", tr("Micro PDF417"),
+			registerStyle( "mpdf", "zint", tr("MicroPDF417"),
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "mqr", "zint", tr("Micro QR Code"),
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "msi", "zint", tr("MSI Plessey"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               true, true, true, true, "0000000000", true, 10 );
 
-			registerStyle( "nve", "zint", tr("NVE-18"),
+			registerStyle( "nve", "zint", tr("NVE-18 (SSCC-18)"),
 			               true, true, true, false, "12345678901234567", false, 17 );
 
 			registerStyle( "pdf", "zint", tr("PDF417"),
 			               false, false, true, false, "0000000000", true, 10 );
 
-			registerStyle( "pdft", "zint", tr("PDF417 Truncated"),
+			registerStyle( "pdft", "zint", tr("PDF417 Compact"),
 			               false, false, true, false, "0000000000", true, 10 );
 
 			registerStyle( "plan", "zint", tr("PLANET"),
-			               false, false, true, false, "0000000000", true, 10 );
+			               false, false, true, false, "00000000000", true, 11 );
 
-			registerStyle( "postnet", "zint", tr("PostNet"),
-			               true, true, true, false, "0000000000", true, 10 );
+			registerStyle( "postnet", "zint", tr("POSTNET"),
+			               false, false, true, false, "00000000000", true, 11 );
 
 			registerStyle( "pharma", "zint", tr("Pharmacode"),
-			               false, false, true, false, "123456", false, 6 );
+			               false, false, false, false, "123456", false, 6 );
 
 			registerStyle( "pharma2", "zint", tr("Pharmacode 2-track"),
-			               false, false, true, false, "12345678", false, 8 );
+			               false, false, false, false, "12345678", false, 8 );
 
-			registerStyle( "pzn", "zint", tr("Pharmazentral Nummer (PZN)"),
-			               true, true, true, false, "123456", false, 6 );
+			registerStyle( "pzn", "zint", tr("Pharmazentralnummer (PZN)"),
+			               true, true, true, false, "1234567", false, 7 );
 
 			registerStyle( "qr", "zint", tr("QR Code"),
-			               true, true, true, false, "0000000000", true, 10 );
+			               false, false, true, false, "0000000000", true, 10 );
+
+			#if LIBZINT_VERSION >= 20700
+			registerStyle( "rmqr", "zint", tr("rMQR (Rectangular Micro QR)"),
+			               false, false, true, false, "0000000000", true, 10 );
+			#endif
 
-			registerStyle( "rm4", "zint", tr("Royal Mail 4-State"),
+			registerStyle( "rm4", "zint", tr("Royal Mail 4-State Customer"),
 			               false, false, true, false, "0000000000", true, 10 );
 
+			registerStyle( "rm4sm", "zint", tr("Royal Mail 4-State Mailmark"),
+			               false, false, true, false, "01000000000000000AA00AA0A", true, 25 );
+
+			#if LIBZINT_VERSION >= 21200
+			registerStyle( "rm2dm", "zint", tr("Royal Mail 2-D Mailmark"),
+			               false, false, true, false, "012100123412345678AB19XY1A 0", true, 28 );
+			#endif
+
 			registerStyle( "tele", "zint", tr("Telepen"),
 			               true, true, true, false, "0000000000", true, 10 );
 
 			registerStyle( "telex", "zint", tr("Telepen Numeric"),
 			               true, true, true, false, "0000000000", true, 10 );
 
+			registerStyle( "pls", "zint", tr("UK Plessey"),
+			               true, true, true, false, "0000000000", true, 10 );
+
 			registerStyle( "upc-a", "zint", tr("UPC-A"), 
 			               true, true, true, false, "12345678901", false, 11 );
           
 			registerStyle( "upc-e", "zint", tr("UPC-E"), 
 			               true, true, true, false, "1234567", false, 7 );
-          
-			registerStyle( "usps", "zint", tr("USPS One Code"),
+
+			#if LIBZINT_VERSION >= 21200
+			registerStyle( "upus10", "zint", tr("UPU S10"),
+			               true, true, true, false, "EE876543216CA", false, 13 );
+			#endif
+
+			registerStyle( "usps", "zint", tr("USPS Intelligent Mail"),
 			               false, false, true, false, "12345678901234567890", true, 20 );
 
-			registerStyle( "pls", "zint", tr("UK Plessey"),
-			               true, true, true, false, "0000000000", true, 10 );
+			registerStyle( "vin", "zint", tr("VIN (Vehicle ID Number)"),
+			               true, true, true, false, "12345678701234567", false, 27 );
 #endif // HAVE_ZINT
 
 		}
diff --git a/backends/barcode/CMakeLists.txt b/backends/barcode/CMakeLists.txt
index a4b1e34b..026c0922 100644
--- a/backends/barcode/CMakeLists.txt
+++ b/backends/barcode/CMakeLists.txt
@@ -19,6 +19,7 @@ endif ()
 
 if (${LIBZINT_FOUND})
   add_definitions (-DHAVE_ZINT=1)
+  add_definitions (-DHAVE_ZINT=1 -DLIBZINT_VERSION=${LIBZINT_VERSION})
   set (OPTIONAL_ZINT ZINT::ZINT)
 else ()
   set (OPTIONAL_ZINT "")
diff --git a/backends/barcode/Zint.cpp b/backends/barcode/Zint.cpp
index e0785e6a..f0b60164 100644
--- a/backends/barcode/Zint.cpp
+++ b/backends/barcode/Zint.cpp
@@ -31,6 +31,7 @@ namespace
 	const double FONT_SCALE = 0.9;
 	const int W_PTS_DEFAULT = 144;
 	const int H_PTS_DEFAULT = 72;
+	const double TWO_DIVIDED_BY_SQRT3 = 1.15470053837925152902;
 }
 
 
@@ -42,6 +43,14 @@ namespace glabels
 		{
 
 
+			//
+			// Base constructor
+			//
+			Base::Base() : symbology(0), option_2(0)
+			{
+			}
+
+
 			//
 			// Zint barcode data validation method
 			//
@@ -60,6 +69,123 @@ namespace glabels
 			                      double&            w,
 			                      double&            h )
 			{
+				#if LIBZINT_VERSION >= 20700
+
+				/*
+				 * First encode using Zint barcode library.
+				 */
+				zint_symbol* symbol = ZBarcode_Create();
+
+				symbol->symbology = symbology;
+				symbol->input_mode = UNICODE_MODE;
+				symbol->scale = 0.5f; // Pixels
+				symbol->option_2 = option_2; // Currently just check digit
+				symbol->show_hrt = showText();
+
+				if ( ZBarcode_Encode( symbol, (unsigned char*)(cookedData.c_str()), 0 ) >= 5 /*ZINT_ERROR*/ )
+				{
+					qDebug() << "Zint::ZBarcode_Encode: " << QString(symbol->errtxt);
+					setIsDataValid( false );
+					return;
+				}
+
+				if ( ZBarcode_Buffer_Vector( symbol, 0 ) >= 5 /*ZINT_ERROR*/ )
+				{
+					qDebug() << "Zint::ZBarcode_Buffer_Vector: " << QString(symbol->errtxt);
+					setIsDataValid( false );
+					return;
+				}
+
+
+				/*
+				 * Now do the actual vectorization.
+				 */
+				zint_vector *vector = symbol->vector;
+
+				w = std::max( w, 5.0 ); // TODO: proper minimum
+				h = std::max( h, 5.0 ); // TODO: proper minimum
+
+				#if LIBZINT_VERSION >= 20902
+				if ( ZBarcode_Cap( symbol->symbology, ZINT_CAP_FIXED_RATIO ) & ZINT_CAP_FIXED_RATIO )
+				{
+					if ( vector->width == vector->height )
+					{
+						w = h = std::min(w, h);
+					}
+					else
+					{
+						// Keep aspect ratio
+						if ( h < w )
+						{
+							w = h * vector->width / vector->height;
+						}
+						else
+						{
+							h = w * vector->height / vector->width;
+						}
+					}
+				}
+				#endif
+
+				double xscale = w / vector->width;
+				double yscale = h / vector->height;
+
+				setWidth( vector->width*xscale );
+				setHeight( vector->height*yscale );
+
+				for ( zint_vector_rect *zrect = vector->rectangles; zrect != nullptr; zrect = zrect->next )
+				{
+					addBox( zrect->x*xscale,
+					        zrect->y*yscale,
+					        zrect->width*xscale,
+					        zrect->height*yscale );
+				}
+
+				for ( zint_vector_circle *zcircle = vector->circles; zcircle != nullptr; zcircle = zcircle->next )
+				{
+					// Note will fail to properly draw MaxiCode bull's-eye rings for versions before 2.11.0
+					#if LIBZINT_VERSION >= 21100
+					double line_width = zcircle->width*xscale;
+					#else
+					double line_width = 0;
+					#endif
+					addRing( zcircle->x*xscale,
+					         zcircle->y*yscale,
+					         zcircle->diameter*xscale/2,
+					         line_width );
+				}
+
+				for ( zint_vector_hexagon *zhexagon = vector->hexagons; zhexagon != nullptr; zhexagon = zhexagon->next )
+				{
+					// Convert from Zint's horizontal short diameter (X) to vertical long diameter (V).
+					double h = TWO_DIVIDED_BY_SQRT3*zhexagon->diameter*yscale;
+					addHexagon( zhexagon->x*xscale, // Center x same as apex x
+					            zhexagon->y*yscale - h/2, // Subtract radius to convert from center y to apex y
+					            h );
+				}
+
+				if( showText() )
+				{
+					for ( zint_vector_string *zstring = vector->strings; zstring != nullptr; zstring = zstring->next )
+					{
+						// Zint's horizontal align used since 2.10.0 for EAN/UPC outside numbers, previously centered (0)
+						#if LIBZINT_VERSION >= 21000
+						int halign = zstring->halign; // 0 center, 1 left, 2 right
+						#else
+						int halign = 0;
+						#endif
+						addText( zstring->x*xscale,
+						         zstring->y*yscale,
+						         zstring->fsize*std::min( xscale, yscale ), // TODO: do something better here
+						         std::string((const char*)zstring->text),
+						         halign );
+					}
+				}
+
+				ZBarcode_Delete( symbol );
+
+				#else /* LIBZINT_VERSION >= 20700 */
+
 				/*
 				 * First encode using Zint barcode library.
 				 */
@@ -126,6 +252,8 @@ namespace glabels
 				}
 
 				ZBarcode_Delete( symbol );
+
+				#endif /* LIBZINT_VERSION >= 20700 */
 			}
 
 
@@ -223,6 +351,22 @@ namespace glabels
 				symbology = BARCODE_AZRUNE;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// Channel Code Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Channel::create()
+			{
+				return new Channel();
+			}
+
+
+			std::string Channel::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_CHANNEL;
+				return ""; // Actual encoding is done in vectorize
+			}
 		
 
 			//////////////////////////////////////////////////////
@@ -237,6 +381,26 @@ namespace glabels
 			std::string Cbr::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_CODABAR;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			//////////////////////////////////////////////////////
+			// Codablock-F Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Cblockf::create()
+			{
+				return new Cblockf();
+			}
+
+
+			std::string Cblockf::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_CODABLOCKF;
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -269,6 +433,10 @@ namespace glabels
 			std::string Code11::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_CODE11;
+				if (!checksum()) // Note default is 2 visible check digits
+				{
+					option_2 = 2;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -300,7 +468,11 @@ namespace glabels
 		
 			std::string C25m::encode( const std::string& cookedData )
 			{
-				symbology = BARCODE_C25MATRIX;
+				symbology = BARCODE_C25MATRIX; // BARCODE_C25STANDARD
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -317,6 +489,30 @@ namespace glabels
 			std::string C25i::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_C25IATA;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			//////////////////////////////////////////////////////
+			// Code 2 of 5 Industrial Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* C25ind::create()
+			{
+				return new C25ind();
+			}
+
+
+			std::string C25ind::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_C25IND;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -333,6 +529,10 @@ namespace glabels
 			std::string C25dl::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_C25LOGIC;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -365,6 +565,10 @@ namespace glabels
 			std::string Code39::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_CODE39;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -381,6 +585,10 @@ namespace glabels
 			std::string Code39e::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_EXCODE39;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -511,6 +719,40 @@ namespace glabels
 				symbology = BARCODE_DPIDENT;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// DotCode Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Dotcode::create()
+			{
+				return new Dotcode();
+			}
+
+
+			std::string Dotcode::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_DOTCODE;
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			#if LIBZINT_VERSION >= 20901
+			//////////////////////////////////////////////////////
+			// DPD Code Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Dpd::create()
+			{
+				return new Dpd();
+			}
+
+
+			std::string Dpd::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_DPD;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
 		
 
 			//////////////////////////////////////////////////////
@@ -543,6 +785,70 @@ namespace glabels
 				symbology = BARCODE_EANX;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// EAN-14 Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Ean14::create()
+			{
+				return new Ean14();
+			}
+
+
+			std::string Ean14::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_EAN14;
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			//////////////////////////////////////////////////////
+			// Facing Identification Mark Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Fim::create()
+			{
+				return new Fim();
+			}
+
+
+			std::string Fim::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_FIM;
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			//////////////////////////////////////////////////////
+			// Flattermarken Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Flat::create()
+			{
+				return new Flat();
+			}
+
+
+			std::string Flat::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_FLAT;
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			//////////////////////////////////////////////////////
+			// Han Xin Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Hanxin::create()
+			{
+				return new Hanxin();
+			}
+
+
+			std::string Hanxin::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_HANXIN;
+				return ""; // Actual encoding is done in vectorize
+			}
 		
 
 			//////////////////////////////////////////////////////
@@ -639,6 +945,22 @@ namespace glabels
 				symbology = BARCODE_HIBC_MICPDF;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// HIBC Codablock-F Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Hibcblkf::create()
+			{
+				return new Hibcblkf();
+			}
+
+
+			std::string Hibcblkf::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_HIBC_BLOCKF;
+				return ""; // Actual encoding is done in vectorize
+			}
 		
 
 			//////////////////////////////////////////////////////
@@ -669,6 +991,10 @@ namespace glabels
 			std::string I25::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_C25INTER;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -749,6 +1075,10 @@ namespace glabels
 			std::string Logm::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_LOGMARS;
+				if (checksum())
+				{
+					option_2 = 1;
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -1005,6 +1335,10 @@ namespace glabels
 			std::string Msi::encode( const std::string& cookedData )
 			{
 				symbology = BARCODE_MSI_PLESSEY;
+				if (checksum())
+				{
+					option_2 = 1; // 1 visible mod-10 check digit
+				}
 				return ""; // Actual encoding is done in vectorize
 			}
 		
@@ -1071,6 +1405,42 @@ namespace glabels
 				symbology = BARCODE_POSTNET;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			#if LIBZINT_VERSION >= 21101
+			//////////////////////////////////////////////////////
+			// BC412 (SEMI T1-95) Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Bc412::create()
+			{
+				return new Bc412();
+			}
+
+
+			std::string Bc412::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_BC412;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
+
+
+			#if LIBZINT_VERSION >= 21101
+			//////////////////////////////////////////////////////
+			// CEPNet Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Cepnet::create()
+			{
+				return new Cepnet();
+			}
+
+
+			std::string Cepnet::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_CEPNET;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
 		
 
 			//////////////////////////////////////////////////////
@@ -1119,6 +1489,24 @@ namespace glabels
 				symbology = BARCODE_QRCODE;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			#if LIBZINT_VERSION >= 20700
+			//////////////////////////////////////////////////////
+			// rMQR Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Rmqr::create()
+			{
+				return new Rmqr();
+			}
+
+
+			std::string Rmqr::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_RMQR;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
 		
 
 			//////////////////////////////////////////////////////
@@ -1135,6 +1523,40 @@ namespace glabels
 				symbology = BARCODE_RM4SCC;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// Royal Mail 4-State Mailmark Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Rm4sm::create()
+			{
+				return new Rm4sm();
+			}
+
+
+			std::string Rm4sm::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_MAILMARK; // BARCODE_MAILMARK_4S
+				return ""; // Actual encoding is done in vectorize
+			}
+
+
+			#if LIBZINT_VERSION >= 21200
+			//////////////////////////////////////////////////////
+			// Royal Mail 2-D Mailmark Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Rm2dm::create()
+			{
+				return new Rm2dm();
+			}
+
+
+			std::string Rm2dm::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_MAILMARK_2D;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
 		
 
 			//////////////////////////////////////////////////////
@@ -1167,6 +1589,24 @@ namespace glabels
 				symbology = BARCODE_UPCE;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			#if LIBZINT_VERSION >= 21200
+			//////////////////////////////////////////////////////
+			// UPU S10 Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* UpuS10::create()
+			{
+				return new UpuS10();
+			}
+
+
+			std::string UpuS10::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_UPU_S10;
+				return ""; // Actual encoding is done in vectorize
+			}
+			#endif
 		
 
 			//////////////////////////////////////////////////////
@@ -1199,6 +1639,22 @@ namespace glabels
 				symbology = BARCODE_PLESSEY;
 				return ""; // Actual encoding is done in vectorize
 			}
+
+
+			//////////////////////////////////////////////////////
+			// Vehicle Identification Number Barcode
+			//////////////////////////////////////////////////////
+			glbarcode::Barcode* Vin::create()
+			{
+				return new Vin();
+			}
+
+
+			std::string Vin::encode( const std::string& cookedData )
+			{
+				symbology = BARCODE_VIN;
+				return ""; // Actual encoding is done in vectorize
+			}
 		
 
 		}
diff --git a/backends/barcode/Zint.h b/backends/barcode/Zint.h
index c238b3cf..9f912db6 100644
--- a/backends/barcode/Zint.h
+++ b/backends/barcode/Zint.h
@@ -42,8 +42,11 @@ namespace glabels
 			{
 			protected:
 				int symbology;
-			
-			
+				int option_2;
+
+
+				Base();
+
 				bool validate( const std::string& rawData ) override;
 
 				void vectorize( const std::string& encodedData,
@@ -132,6 +135,19 @@ namespace glabels
 			};
 
 
+			/**
+			 * Channel Barcode
+			 */
+			class Channel : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 			/**
 			 * Cbr Barcode
 			 */
@@ -145,6 +161,19 @@ namespace glabels
 			};
 
 
+			/**
+			 * Codeblock-F Barcode
+			 */
+			class Cblockf : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 			/**
 			 * Code1 Barcode
 			 */
@@ -210,6 +239,19 @@ namespace glabels
 			};
 
 
+			/**
+			 * Code 2 of 5 Industrial Barcode
+			 */
+			class C25ind : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 			/**
 			 * C25dl Barcode
 			 */
@@ -366,6 +408,34 @@ namespace glabels
 			};
 
 
+			/**
+			 * DotCode Barcode
+			 */
+			class Dotcode : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
+			#if LIBZINT_VERSION >= 20901
+			/**
+			 * DPD Code Barcode
+			 */
+			class Dpd : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
 			/**
 			 * Kix Barcode
 			 */
@@ -392,6 +462,58 @@ namespace glabels
 			};
 
 
+			/**
+			 * EAN-14 Barcode
+			 */
+			class Ean14 : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
+			/**
+			 * Facing Identification Mark Barcode
+			 */
+			class Fim : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
+			/**
+			 * Flattermarken Barcode
+			 */
+			class Flat : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
+			/**
+			 * Han Xin Barcode
+			 */
+			class Hanxin : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 			/**
 			 * Hibc128 Barcode
 			 */
@@ -470,6 +592,19 @@ namespace glabels
 			};
 
 
+			/**
+			 * HIBC Codablock-F Barcode
+			 */
+			class Hibcblkf : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 			/**
 			 * Hibcaz Barcode
 			 */
@@ -821,6 +956,36 @@ namespace glabels
 			};
 
 
+			#if LIBZINT_VERSION >= 21101
+			/**
+			 * BC412 (SEMI T1-95) Barcode
+			 */
+			class Bc412 : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
+			#if LIBZINT_VERSION >= 21101
+			/**
+			 * CEPNet Barcode
+			 */
+			class Cepnet : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
 			/**
 			 * Pdf Barcode
 			 */
@@ -860,6 +1025,21 @@ namespace glabels
 			};
 
 
+			#if LIBZINT_VERSION >= 20700
+			/**
+			 * rMQR Barcode
+			 */
+			class Rmqr : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
 			/**
 			 * Rm4 Barcode
 			 */
@@ -873,6 +1053,34 @@ namespace glabels
 			};
 
 
+			/**
+			 * Royal Mail 4-State Mailmark Barcode
+			 */
+			class Rm4sm : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
+			#if LIBZINT_VERSION >= 21200
+			/**
+			 * Royal Mail 2-D Mailmark Barcode
+			 */
+			class Rm2dm : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
 			/**
 			 * UpcA Barcode
 			 */
@@ -899,6 +1107,21 @@ namespace glabels
 			};
 
 
+			#if LIBZINT_VERSION >= 21200
+			/**
+			 * UPU S10 Barcode
+			 */
+			class UpuS10 : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+			#endif
+
+
 			/**
 			 * Usps Barcode
 			 */
@@ -925,6 +1148,19 @@ namespace glabels
 			};
 
 
+			/**
+			 * Vehicle Identification Number Barcode
+			 */
+			class Vin : public Base
+			{
+			public:
+				static Barcode* create();
+
+			protected:
+				std::string encode( const std::string& cookedData ) override;
+			};
+
+
 		}
 	}
 }
diff --git a/cmake/Modules/FindLibZint.cmake b/cmake/Modules/FindLibZint.cmake
index 9f1a7545..9cf532f5 100644
--- a/cmake/Modules/FindLibZint.cmake
+++ b/cmake/Modules/FindLibZint.cmake
@@ -37,17 +37,29 @@ if (LIBZINT_INCLUDE_DIR AND EXISTS "${LIBZINT_INCLUDE_DIR}/zint.h")
   file (STRINGS "${LIBZINT_INCLUDE_DIR}/zint.h" ZINT_MAJOR_H REGEX "^#define ZINT_VERSION_MAJOR *[0-9]*")
   file (STRINGS "${LIBZINT_INCLUDE_DIR}/zint.h" ZINT_MINOR_H REGEX "^#define ZINT_VERSION_MINOR *[0-9]*")
   file (STRINGS "${LIBZINT_INCLUDE_DIR}/zint.h" ZINT_MICRO_H REGEX "^#define ZINT_VERSION_RELEASE *[0-9]*")
-  string (REGEX REPLACE "^.*VERSION_MAJOR *([0-9]*)" "\\1" ZINT_MAJOR ${ZINT_MAJOR_H})
-  string (REGEX REPLACE "^.*VERSION_MINOR *([0-9]*)" "\\1" ZINT_MINOR ${ZINT_MINOR_H})
-  string (REGEX REPLACE "^.*VERSION_RELEASE *([0-9]*)" "\\1" ZINT_MICRO ${ZINT_MICRO_H})
-  set (LIBZINT_VERSION_STRING ${ZINT_MAJOR}.${ZINT_MINOR}.${ZINT_MICRO})
-endif()
+  if (ZINT_MAJOR_H) # ZINT_MINOR_H and ZINT_MICRO_H may be zero so don't test
+    string (REGEX REPLACE "^.*VERSION_MAJOR *([0-9]*)" "\\1" ZINT_MAJOR ${ZINT_MAJOR_H})
+    string (REGEX REPLACE "^.*VERSION_MINOR *([0-9]*)" "\\1" ZINT_MINOR "${ZINT_MINOR_H}")
+    string (REGEX REPLACE "^.*VERSION_RELEASE *([0-9]*)" "\\1" ZINT_MICRO "${ZINT_MICRO_H}")
+    set (LIBZINT_VERSION_STRING ${ZINT_MAJOR}.${ZINT_MINOR}.${ZINT_MICRO})
+    math (EXPR LIBZINT_VERSION "${ZINT_MAJOR} * 10000 + ${ZINT_MINOR} * 100 + ${ZINT_MICRO}")
+  else ()
+    execute_process(COMMAND "zint" "-h" OUTPUT_VARIABLE EXEC_ZINT_VERSION ERROR_QUIET)
+    if (EXEC_ZINT_VERSION)
+      string (REGEX REPLACE "^Zint version ([0-9.]+).*$" "\\1" LIBZINT_VERSION_STRING ${EXEC_ZINT_VERSION})
+      string (REGEX REPLACE "^([0-9]+).*$" "\\1" ZINT_MAJOR ${LIBZINT_VERSION_STRING})
+      string (REGEX REPLACE "^[0-9]+\.([0-9]+).*$" "\\1" ZINT_MINOR ${LIBZINT_VERSION_STRING})
+      string (REGEX REPLACE "^[0-9]+\.[0-9]+\.([0-9]+).*$" "\\1" ZINT_MICRO ${LIBZINT_VERSION_STRING})
+      math (EXPR LIBZINT_VERSION "${ZINT_MAJOR} * 10000 + ${ZINT_MINOR} * 100 + ${ZINT_MICRO}")
+    endif ()
+  endif ()
+endif ()
 
 # handle the QUIETLY and REQUIRED arguments and set LIBZINT_FOUND to TRUE if
 # all listed variables are TRUE
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(LibZint
-                                  REQUIRED_VARS LIBZINT_LIBRARY LIBZINT_INCLUDE_DIR
+                                  REQUIRED_VARS LIBZINT_LIBRARY LIBZINT_INCLUDE_DIR LIBZINT_VERSION
                                   VERSION_VAR LIBZINT_VERSION_STRING)
 
 mark_as_advanced(LIBZINT_INCLUDE_DIR LIBZINT_LIBRARY)
diff --git a/docs/BUILD-INSTRUCTIONS-LINUX.md b/docs/BUILD-INSTRUCTIONS-LINUX.md
index dbc40a0d..435c2ffe 100644
--- a/docs/BUILD-INSTRUCTIONS-LINUX.md
+++ b/docs/BUILD-INSTRUCTIONS-LINUX.md
@@ -41,9 +41,9 @@ _Zint (Optional)_
 
 Install zint from source:
 ```
-wget https://downloads.sourceforge.net/project/zint/zint/2.6.3/zint-2.6.3_final.tar.gz
-tar xzf zint-2.6.3_final.tar.gz
-cd zint-2.6.3.src/
+wget https://downloads.sourceforge.net/project/zint/zint/2.12.0/zint-2.12.0-src.tar.gz
+tar xzf zint-2.12.0-src.tar.gz
+cd zint-2.12.0-src/
 mkdir build && cd build && cmake .. && make
 sudo make install
 ```
diff --git a/glbarcode/Barcode.cpp b/glbarcode/Barcode.cpp
index 039cf2f2..c24717bd 100644
--- a/glbarcode/Barcode.cpp
+++ b/glbarcode/Barcode.cpp
@@ -174,9 +174,9 @@ namespace glbarcode
 	}
 
 
-	void Barcode::addText( double x, double y, double size, const std::string& text )
+	void Barcode::addText( double x, double y, double size, const std::string& text, int halign )
 	{
-		d->mPrimitives.push_back( new DrawingPrimitiveText( x, y, size, text ) );
+		d->mPrimitives.push_back( new DrawingPrimitiveText( x, y, size, text, halign ) );
 	}
 
 
diff --git a/glbarcode/Barcode.h b/glbarcode/Barcode.h
index 78ded8ad..577fd5eb 100644
--- a/glbarcode/Barcode.h
+++ b/glbarcode/Barcode.h
@@ -215,12 +215,13 @@ namespace glbarcode
 		 *
 		 * @image html figure-primitive-text.svg "Text primitive properties"
 		 *
-		 * @param[in] x     X coordinate of text's origin (points)
-		 * @param[in] y     Y coordinate of text's origin (points)
-		 * @param[in] size  Font size of text (points)
-		 * @param[in] text  Text
+		 * @param[in] x       X coordinate of text's origin (points)
+		 * @param[in] y       Y coordinate of text's origin (points)
+		 * @param[in] size    Font size of text (points)
+		 * @param[in] text    Text
+		 * @param[in] halign  Horizontal alignment (center 0, left 1, right 2)
 		 */
-		void addText( double x, double y, double size, const std::string& text );
+		void addText( double x, double y, double size, const std::string& text, int halign = 0 );
 
 
 		/**
diff --git a/glbarcode/DrawingPrimitives.cpp b/glbarcode/DrawingPrimitives.cpp
index fce6613a..b74e2656 100644
--- a/glbarcode/DrawingPrimitives.cpp
+++ b/glbarcode/DrawingPrimitives.cpp
@@ -81,8 +81,8 @@ namespace glbarcode
 
 
 
-	DrawingPrimitiveText::DrawingPrimitiveText( double x, double y, double size, const std::string& text )
-		: DrawingPrimitive( x, y ), mSize(size), mText(text)
+	DrawingPrimitiveText::DrawingPrimitiveText( double x, double y, double size, const std::string& text, int halign )
+		: DrawingPrimitive( x, y ), mSize(size), mText(text), mHalign(halign)
 	{
 	}
 
@@ -99,6 +99,12 @@ namespace glbarcode
 	}
 
 
+	int DrawingPrimitiveText::halign() const
+	{
+		return mHalign;
+	}
+
+
 
 	DrawingPrimitiveRing::DrawingPrimitiveRing( double x, double y, double r, double w )
 		: DrawingPrimitive( x, y ), mR(r), mW(w)
diff --git a/glbarcode/DrawingPrimitives.h b/glbarcode/DrawingPrimitives.h
index 466f1ceb..0ae2be9e 100644
--- a/glbarcode/DrawingPrimitives.h
+++ b/glbarcode/DrawingPrimitives.h
@@ -163,12 +163,13 @@ namespace glbarcode
 		/**
 		 * Text constructor
 		 *
-		 * @param[in] x    X coordinate of text's origin (points)
-		 * @param[in] y    Y coordinate of text's origin (points)
-		 * @param[in] size Font size of text (points)
-		 * @param[in] text Text
+		 * @param[in] x      X coordinate of text's origin (points)
+		 * @param[in] y      Y coordinate of text's origin (points)
+		 * @param[in] size   Font size of text (points)
+		 * @param[in] text   Text
+		 * @param[in] halign Horizontal alignment (center 0, left 1, right 2)
 		 */
-		DrawingPrimitiveText( double x, double y, double size, const std::string& text );
+		DrawingPrimitiveText( double x, double y, double size, const std::string& text, int halign = 0 );
 
 		/**
 		 * Get font size (points).
@@ -180,9 +181,15 @@ namespace glbarcode
 		 */
 		const std::string& text() const;
 
+		/**
+		 * Get horizontal alignment.
+		 */
+		int halign() const;
+
 	private:
 		double       mSize;    /**< Font size of text (points). */
 		std::string  mText;    /**< Text. */
+		int          mHalign;  /**< Horizontal alignment. */
 	};
 
 
diff --git a/glbarcode/QtRenderer.cpp b/glbarcode/QtRenderer.cpp
index 0279bc95..1154e82b 100644
--- a/glbarcode/QtRenderer.cpp
+++ b/glbarcode/QtRenderer.cpp
@@ -30,6 +30,7 @@
 namespace
 {
 	const double FONT_SCALE = 0.75;
+	const double MIN_POINT_SIZE = 0.4; // Less than ~0.37 causes issues for QFontMetricsF
 }
 
 
@@ -122,7 +123,7 @@ namespace glbarcode
 	}
 
 
-	void QtRenderer::drawText( double x, double y, double size, const std::string& text )
+	void QtRenderer::drawText( double x, double y, double size, const std::string& text, int halign )
 	{
 		if ( d->painter )
 		{
@@ -131,10 +132,18 @@ namespace glbarcode
 			QFont font;
 			font.setStyleHint( QFont::Monospace );
 			font.setFamily( "monospace" );
-			font.setPointSizeF( FONT_SCALE*size );
+			font.setPointSizeF( std::max( FONT_SCALE*size, MIN_POINT_SIZE ) );
 
 			QFontMetricsF fm( font );
-			double xCorner = x - fm.width( QString::fromStdString(text) )/2.0;
+			double xCorner = x;
+			if ( halign == 0 ) // Center
+			{
+				xCorner -= fm.width( QString::fromStdString(text) )/2.0;
+			}
+			else if ( halign == 2 ) // Right
+			{
+				xCorner -= fm.width( QString::fromStdString(text) );
+			}
 			double yCorner = y - fm.ascent();
 		
 			QTextLayout layout( QString::fromStdString(text), font );
@@ -151,7 +160,7 @@ namespace glbarcode
 		if ( d->painter )
 		{
 			d->painter->setPen( QPen( d->color, w ) );
-			d->painter->setBrush( Qt::NoBrush );
+			d->painter->setBrush( w ? Qt::NoBrush : QBrush( d->color ) );
 		
 			d->painter->drawEllipse( QPointF(x, y), r, r );
 		}
diff --git a/glbarcode/QtRenderer.h b/glbarcode/QtRenderer.h
index 3b858cae..c7fecb55 100644
--- a/glbarcode/QtRenderer.h
+++ b/glbarcode/QtRenderer.h
@@ -76,7 +76,7 @@ namespace glbarcode
 		void drawEnd() override;
 		void drawLine( double x, double y, double w, double h ) override;
 		void drawBox( double x, double y, double w, double h ) override;
-		void drawText( double x, double y, double size, const std::string& text ) override;
+		void drawText( double x, double y, double size, const std::string& text, int halign = 0 ) override;
 		void drawRing( double x, double y, double r, double w ) override;
 		void drawHexagon( double x, double y, double h ) override;
 
diff --git a/glbarcode/Renderer.cpp b/glbarcode/Renderer.cpp
index 6a5b6d9d..fb54042e 100644
--- a/glbarcode/Renderer.cpp
+++ b/glbarcode/Renderer.cpp
@@ -41,7 +41,7 @@ void glbarcode::Renderer::render( double w, double h, const std::list<DrawingPri
 		}
 		else if ( auto* text = dynamic_cast<DrawingPrimitiveText*>(*primitive) )
 		{
-			drawText( text->x(), text->y(), text->size(), text->text() );
+			drawText( text->x(), text->y(), text->size(), text->text(), text->halign() );
 		}
 		else if ( auto* ring = dynamic_cast<DrawingPrimitiveRing*>(*primitive) )
 		{
diff --git a/glbarcode/Renderer.h b/glbarcode/Renderer.h
index 35874c92..81b10ce1 100644
--- a/glbarcode/Renderer.h
+++ b/glbarcode/Renderer.h
@@ -132,7 +132,7 @@ namespace glbarcode
 		 * @param[in] size Font size of text (points)
 		 * @param[in] text Text
 		 */
-		virtual void drawText( double x, double y, double size, const std::string& text ) = 0;
+		virtual void drawText( double x, double y, double size, const std::string& text, int halign = 0 ) = 0;
 
 
 		/**
diff --git a/model/ModelBarcodeObject.cpp b/model/ModelBarcodeObject.cpp
index ed4f1bf6..cd2530ee 100644
--- a/model/ModelBarcodeObject.cpp
+++ b/model/ModelBarcodeObject.cpp
@@ -49,6 +49,7 @@ namespace glabels
 			const Distance pad = Distance::pt(4);
 			const Distance minW = Distance::pt(18);
 			const Distance minH = Distance::pt(18);
+			const double MIN_POINT_SIZE = 0.4; // Less than ~0.37 causes issues for QFontMetricsF
 		}
 
 
@@ -508,7 +509,7 @@ namespace glabels
 			{
 				double scaleX = wPts / textRect.width();
 				double scaleY = hPts / textRect.height();
-				font.setPointSizeF( 6 * std::min( scaleX, scaleY ) );
+				font.setPointSizeF( std::max( 6 * std::min( scaleX, scaleY ), MIN_POINT_SIZE ) );
 			}
 
 			//
diff --git a/translations/glabels_C.ts b/translations/glabels_C.ts
index a0e3af47..f757ef88 100644
--- a/translations/glabels_C.ts
+++ b/translations/glabels_C.ts
@@ -2468,10 +2468,6 @@
         <source>Aztec Code</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>Aztec Rune</source>
-        <translation type="unfinished"></translation>
-    </message>
     <message>
         <source>Code One</source>
         <translation type="unfinished"></translation>
@@ -2484,10 +2480,6 @@
         <source>Code 16K</source>
         <translation type="unfinished"></translation>
     </message>
-    <message>
-        <source>Code 2 of 5 Matrix</source>
-        <translation type="unfinished"></translation>
-    </message>
     <message>
         <source>Code 2 of 5 IATA</source>
         <translation type="unfinished"></translation>
@@ -2541,135 +2533,207 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GS1 DataBar-14</source>
+        <source>HIBC Code 128</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GS1 DataBar-14 Stacked</source>
+        <source>HIBC Code 39</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GS1 DataBar-14 Stacked Omni.</source>
+        <source>HIBC Data Matrix</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>GS1 DataBar Extended Stacked</source>
+        <source>HIBC QR Code</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC Code 128</source>
+        <source>HIBC PDF417</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC Code 39</source>
+        <source>HIBC Aztec Code</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC Data Matrix</source>
+        <source>ITF-14</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC QR Code</source>
+        <source>Japanese Postal</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC PDF417</source>
+        <source>Korean Postal</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC Micro PDF417</source>
+        <source>LOGMARS</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>HIBC Aztec Code</source>
+        <source>Maxicode</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>ITF-14</source>
+        <source>Micro QR Code</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Japanese Postal</source>
+        <source>MSI Plessey</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Korean Postal</source>
+        <source>PDF417</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>LOGMARS</source>
+        <source>PLANET</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Maxicode</source>
+        <source>Pharmacode</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Micro PDF417</source>
+        <source>Pharmacode 2-track</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Micro QR Code</source>
+        <source>QR Code</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>MSI Plessey</source>
+        <source>Telepen</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>NVE-18</source>
+        <source>Telepen Numeric</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>PDF417</source>
+        <source>UK Plessey</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>PDF417 Truncated</source>
+        <source>Aztec Runes</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>PLANET</source>
+        <source>CEPNet (Brazilian Post)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>PostNet</source>
+        <source>Codablock-F</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Pharmacode</source>
+        <source>Code 2 of 5 Standard</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Pharmacode 2-track</source>
+        <source>GS1 DataBar Stacked</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Pharmazentral Nummer (PZN)</source>
+        <source>GS1 DataBar Stacked Omni.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>QR Code</source>
+        <source>GS1 DataBar Expanded Stacked</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Royal Mail 4-State</source>
+        <source>HIBC MicroPDF417</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Telepen</source>
+        <source>MicroPDF417</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>Telepen Numeric</source>
+        <source>NVE-18 (SSCC-18)</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>USPS One Code</source>
+        <source>PDF417 Compact</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <source>UK Plessey</source>
+        <source>Pharmazentralnummer (PZN)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Channel Code</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Code 2 of 5 Industrial</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>DotCode</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>EAN-14</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>GS1 DataBar Omnidirectional</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Han Xin</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Flattermarken</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>DPD Code</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>POSTNET</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Royal Mail 4-State Mailmark</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>UPU S10</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>FIM (Facing ID Mark)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>rMQR (Rectangular Micro QR)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Royal Mail 4-State Customer</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>VIN (Vehicle ID Number)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>HIBC Codablock-F</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>Royal Mail 2-D Mailmark</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>BC412 (SEMI TI-95)</source>
         <translation type="unfinished"></translation>
     </message>
 </context>