tdf#139778 Switch to ZXing for generating QR code

Change-Id: Ief944266d5183bb862afe99ec6b0bdaca4956938
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112534
Tested-by: Jenkins
Tested-by: René Engelhard <rene@debian.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index ff221a9..f2df06c 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -73,7 +73,7 @@ $(eval $(call gb_Library_use_externals,cui,\
    libxml2 \
    orcus-parser \
    orcus \
    qrcodegen \
    zxing \
))
ifeq ($(DISABLE_GUI),)
$(eval $(call gb_Library_use_externals,cui,\
diff --git a/cui/source/dialogs/QrCodeGenDialog.cxx b/cui/source/dialogs/QrCodeGenDialog.cxx
index 3de87ab..3a82a11 100644
--- a/cui/source/dialogs/QrCodeGenDialog.cxx
+++ b/cui/source/dialogs/QrCodeGenDialog.cxx
@@ -17,14 +17,26 @@
#include <utility>
#include <vcl/svapp.hxx>

#if ENABLE_QRCODEGEN
#if defined(SYSTEM_QRCODEGEN)
#include <qrcodegen/QrCode.hpp>
#else
#include <QrCode.hpp>
#if ENABLE_ZXING
#include <rtl/ustrbuf.hxx>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif

#include <BarcodeFormat.h>
#include <BitArray.h>
#include <BitMatrix.h>
#include <MultiFormatWriter.h>
#include <TextUtfEncoding.h>

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#endif // ENABLE_ZXING

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/XShape.hpp>
@@ -56,9 +68,37 @@ using namespace css::sheet;
using namespace css::text;
using namespace css::drawing;
using namespace css::graphic;
#if ENABLE_QRCODEGEN
using namespace qrcodegen;
namespace
{
#if ENABLE_ZXING
// Implementation adapted from the answer: https://stackoverflow.com/questions/10789059/create-qr-code-in-vector-image/60638350#60638350
OUString ConvertToSVGFormat(const ZXing::BitMatrix& bitmatrix)
{
    OUStringBuffer sb;
    const int width = bitmatrix.width();
    const int height = bitmatrix.height();
    ZXing::BitArray row(width);
    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
              "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 "
              + OUString::number(width) + " " + OUString::number(height)
              + "\" stroke=\"none\">\n"
                "<path d=\"");
    for (int i = 0; i < height; ++i)
    {
        bitmatrix.getRow(i, row);
        for (int j = 0; j < width; ++j)
        {
            if (row.get(j))
            {
                sb.append("M" + OUString::number(j) + "," + OUString::number(i) + "h1v1h-1z");
            }
        }
    }
    sb.append("\"/>\n</svg>");
    return sb.toString();
}
#endif
}

QrCodeGenDialog::QrCodeGenDialog(weld::Widget* pParent, Reference<XModel> xModel,
                                 bool bEditExisting)
@@ -70,7 +110,7 @@ QrCodeGenDialog::QrCodeGenDialog(weld::Widget* pParent, Reference<XModel> xModel
              m_xBuilder->weld_radio_button("button_quartile"),
              m_xBuilder->weld_radio_button("button_high") }
    , m_xSpinBorder(m_xBuilder->weld_spin_button("edit_border"))
#if ENABLE_QRCODEGEN
#if ENABLE_ZXING
    , mpParent(pParent)
#endif
{
@@ -108,7 +148,7 @@ QrCodeGenDialog::QrCodeGenDialog(weld::Widget* pParent, Reference<XModel> xModel

short QrCodeGenDialog::run()
{
#if ENABLE_QRCODEGEN
#if ENABLE_ZXING
    short nRet;
    while (true)
    {
@@ -120,7 +160,7 @@ short QrCodeGenDialog::run()
                Apply();
                break;
            }
            catch (const qrcodegen::data_too_long&)
            catch (const std::exception&)
            {
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
                    mpParent, VclMessageType::Warning, VclButtonsType::Ok,
@@ -139,7 +179,7 @@ short QrCodeGenDialog::run()

void QrCodeGenDialog::Apply()
{
#if ENABLE_QRCODEGEN
#if ENABLE_ZXING
    css::drawing::QRCode aQRCode;
    aQRCode.Payload = m_xEdittext->get_text();

@@ -264,43 +304,41 @@ void QrCodeGenDialog::Apply()

OUString QrCodeGenDialog::GenerateQRCode(OUString aQRText, tools::Long aQRECC, int aQRBorder)
{
#if ENABLE_QRCODEGEN
    //Select ECC:: value from aQrECC
    qrcodegen::QrCode::Ecc bqrEcc = qrcodegen::QrCode::Ecc::LOW;
#if ENABLE_ZXING
    // Associated ZXing error correction levels (0-8) to our constants arbitrarily.
    int bqrEcc = 1;

    switch (aQRECC)
    {
        case 1:
        case css::drawing::QRCodeErrorCorrection::LOW:
        {
            bqrEcc = qrcodegen::QrCode::Ecc::LOW;
            bqrEcc = 1;
            break;
        }
        case 2:
        case css::drawing::QRCodeErrorCorrection::MEDIUM:
        {
            bqrEcc = qrcodegen::QrCode::Ecc::MEDIUM;
            bqrEcc = 3;
            break;
        }
        case 3:
        case css::drawing::QRCodeErrorCorrection::QUARTILE:
        {
            bqrEcc = qrcodegen::QrCode::Ecc::QUARTILE;
            bqrEcc = 5;
            break;
        }
        case 4:
        case css::drawing::QRCodeErrorCorrection::HIGH:
        {
            bqrEcc = qrcodegen::QrCode::Ecc::HIGH;
            bqrEcc = 7;
            break;
        }
    }

    //OuString to char* qrtext
    OString o = OUStringToOString(aQRText, RTL_TEXTENCODING_UTF8);
    const char* qrtext = o.pData->buffer;

    // From QR Code library
    qrcodegen::QrCode qr0 = qrcodegen::QrCode::encodeText(qrtext, bqrEcc);
    std::string svg = qr0.toSvgString(aQRBorder);
    //cstring to OUString
    return OUString::createFromAscii(svg.c_str());
    std::string QRText(o.getStr(), o.getLength());
    ZXing::BarcodeFormat format = ZXing::BarcodeFormatFromString("QR_CODE");
    auto writer = ZXing::MultiFormatWriter(format).setMargin(aQRBorder).setEccLevel(bqrEcc);
    writer.setEncoding(ZXing::CharacterSet::UTF8);
    ZXing::BitMatrix bitmatrix = writer.encode(ZXing::TextUtfEncoding::FromUtf8(QRText), 0, 0);
    return ConvertToSVGFormat(bitmatrix);
#else
    (void)aQRText;
    (void)aQRECC;
diff --git a/cui/source/inc/QrCodeGenDialog.hxx b/cui/source/inc/QrCodeGenDialog.hxx
index 7c39fe0..c3f7a9a 100644
--- a/cui/source/inc/QrCodeGenDialog.hxx
+++ b/cui/source/inc/QrCodeGenDialog.hxx
@@ -8,7 +8,7 @@
 */
#pragma once

#include <config_qrcodegen.h>
#include <config_zxing.h>

#include <vcl/weld.hxx>

@@ -33,7 +33,7 @@ private:
    std::unique_ptr<weld::Entry> m_xEdittext;
    std::unique_ptr<weld::RadioButton> m_xECC[4];
    std::unique_ptr<weld::SpinButton> m_xSpinBorder;
#if ENABLE_QRCODEGEN
#if ENABLE_ZXING
    weld::Widget* mpParent;
#endif