From f9d9a1d1cfd08096aa4f734e8d9134eac80e6e9b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 13 Dec 2021 05:56:44 +0000 Subject: [PATCH 1/3] Bugfix: GUI/QRImageWidget: Correctly calculate sizes - Margin of QRCode should be constant, not change based on complexity of QRCode - Text region should be sized based on height of actual text, not a constant guess - Width of image should not be adjusted based on vertical text size/margins - Adjusted constant QRCode and margin sizes to visually match what we had previously --- src/qt/qrimagewidget.cpp | 31 ++++++++++++++++++------------- src/qt/qrimagewidget.h | 6 +++--- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index 52f1e60957..ae2e77bbf1 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -54,33 +54,38 @@ bool QRImageWidget::setQR(const QString& data, const QString& text) return false; } - QImage qrImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); - qrImage.fill(0xffffff); + QImage qrImage = QImage(code->width, code->width, QImage::Format_RGB32); unsigned char *p = code->data; for (int y = 0; y < code->width; ++y) { for (int x = 0; x < code->width; ++x) { - qrImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff)); + qrImage.setPixel(x, y, ((*p & 1) ? 0x0 : 0xffffff)); ++p; } } QRcode_free(code); - const int qr_image_size = QR_IMAGE_SIZE + (text.isEmpty() ? 0 : 2 * QR_IMAGE_MARGIN); - QImage qrAddrImage(qr_image_size, qr_image_size, QImage::Format_RGB32); + const int qr_image_width = QR_IMAGE_SIZE + (2 * QR_IMAGE_MARGIN); + int qr_image_height = qr_image_width; + QFont font; + if (!text.isEmpty()) { + font = GUIUtil::fixedPitchFont(); + font.setStretch(QFont::SemiCondensed); + font.setLetterSpacing(QFont::AbsoluteSpacing, 1); + const qreal font_size = GUIUtil::calculateIdealFontSize(qr_image_width - 2 * QR_IMAGE_TEXT_MARGIN, text, font); + font.setPointSizeF(font_size); + + QFontMetrics fm(font); + qr_image_height += fm.height() + QR_IMAGE_TEXT_MARGIN; + } + QImage qrAddrImage(qr_image_width, qr_image_height, QImage::Format_RGB32); qrAddrImage.fill(0xffffff); { QPainter painter(&qrAddrImage); - painter.drawImage(QR_IMAGE_MARGIN, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); + painter.drawImage(QR_IMAGE_MARGIN, QR_IMAGE_MARGIN, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); if (!text.isEmpty()) { QRect paddedRect = qrAddrImage.rect(); - paddedRect.setHeight(QR_IMAGE_SIZE + QR_IMAGE_TEXT_MARGIN); - - QFont font = GUIUtil::fixedPitchFont(); - font.setStretch(QFont::SemiCondensed); - font.setLetterSpacing(QFont::AbsoluteSpacing, 1); - const qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 2 * QR_IMAGE_TEXT_MARGIN, text, font); - font.setPointSizeF(font_size); + paddedRect.setHeight(paddedRect.height() - QR_IMAGE_TEXT_MARGIN); painter.setFont(font); painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text); diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h index a031bd7632..55ae49e161 100644 --- a/src/qt/qrimagewidget.h +++ b/src/qt/qrimagewidget.h @@ -12,9 +12,9 @@ static const int MAX_URI_LENGTH = 255; /* Size of exported QR Code image */ -static constexpr int QR_IMAGE_SIZE = 300; -static constexpr int QR_IMAGE_TEXT_MARGIN = 10; -static constexpr int QR_IMAGE_MARGIN = 2 * QR_IMAGE_TEXT_MARGIN; +static constexpr int QR_IMAGE_SIZE = 252; +static constexpr int QR_IMAGE_TEXT_MARGIN = 8; +static constexpr int QR_IMAGE_MARGIN = 24; QT_BEGIN_NAMESPACE class QMenu; From 91d24c84ba4bc929df96ffd46c591ad3a92757bd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 13 Dec 2021 06:19:21 +0000 Subject: [PATCH 2/3] Bugfix: GUI/QRImageWidget: If text won't fit, split across multiple lines This ensures even with a font we can't scale down enough, the text doesn't get cut off --- src/qt/qrimagewidget.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index ae2e77bbf1..7f955700d5 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -64,31 +64,47 @@ bool QRImageWidget::setQR(const QString& data, const QString& text) } QRcode_free(code); - const int qr_image_width = QR_IMAGE_SIZE + (2 * QR_IMAGE_MARGIN); + int qr_image_width = QR_IMAGE_SIZE + (2 * QR_IMAGE_MARGIN); int qr_image_height = qr_image_width; + int qr_image_x_margin = QR_IMAGE_MARGIN; + int text_lines; QFont font; - if (!text.isEmpty()) { + if (text.isEmpty()) { + text_lines = 0; + } else { + // Determine font to use font = GUIUtil::fixedPitchFont(); font.setStretch(QFont::SemiCondensed); font.setLetterSpacing(QFont::AbsoluteSpacing, 1); - const qreal font_size = GUIUtil::calculateIdealFontSize(qr_image_width - 2 * QR_IMAGE_TEXT_MARGIN, text, font); + const int max_text_width = qr_image_width - (2 * QR_IMAGE_TEXT_MARGIN); + const qreal font_size = GUIUtil::calculateIdealFontSize(max_text_width, text, font); font.setPointSizeF(font_size); + // Plan how many lines are needed QFontMetrics fm(font); - qr_image_height += fm.height() + QR_IMAGE_TEXT_MARGIN; + const int text_width = GUIUtil::TextWidth(fm, text); + text_lines = (text_width + max_text_width - 1) / max_text_width; + qr_image_height += (fm.height() * text_lines) + QR_IMAGE_TEXT_MARGIN; } QImage qrAddrImage(qr_image_width, qr_image_height, QImage::Format_RGB32); qrAddrImage.fill(0xffffff); { QPainter painter(&qrAddrImage); - painter.drawImage(QR_IMAGE_MARGIN, QR_IMAGE_MARGIN, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); + painter.drawImage(qr_image_x_margin, QR_IMAGE_MARGIN, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); if (!text.isEmpty()) { QRect paddedRect = qrAddrImage.rect(); paddedRect.setHeight(paddedRect.height() - QR_IMAGE_TEXT_MARGIN); + QString text_wrapped = text; + const int char_per_line = (text.size() + text_lines - 1) / text_lines; + for (int line = 1, pos = 0; line < text_lines; ++line) { + pos += char_per_line; + text_wrapped.insert(pos, QChar{'\n'}); + } + painter.setFont(font); - painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text); + painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text_wrapped); } } From 4c5143d56c98d4f9f961059692f155bbe2248c44 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Mon, 13 Dec 2021 06:19:49 +0000 Subject: [PATCH 3/3] GUI/QRImageWidget: Allow image to grow up to 25% wider to accomidate single-line text Accomidates addresses that are just barely too long for the QRCode width --- src/qt/qrimagewidget.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index 7f955700d5..e8017cee54 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -83,7 +83,14 @@ bool QRImageWidget::setQR(const QString& data, const QString& text) // Plan how many lines are needed QFontMetrics fm(font); const int text_width = GUIUtil::TextWidth(fm, text); - text_lines = (text_width + max_text_width - 1) / max_text_width; + if (text_width > max_text_width && text_width < max_text_width * 5 / 4) { + // Allow the image to grow up to 25% wider + qr_image_width = text_width + (2 * QR_IMAGE_TEXT_MARGIN); + qr_image_x_margin = (qr_image_width - QR_IMAGE_SIZE) / 2; + text_lines = 1; + } else { + text_lines = (text_width + max_text_width - 1) / max_text_width; + } qr_image_height += (fm.height() * text_lines) + QR_IMAGE_TEXT_MARGIN; } QImage qrAddrImage(qr_image_width, qr_image_height, QImage::Format_RGB32);