File indexing completed on 2024-05-12 15:49:07

0001 /*
0002     SPDX-FileCopyrightText: 2010-2016 Sune Vuorela <sune@vuorela.dk>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "abstractbarcode.h"
0008 #include "config-prison.h"
0009 #include "pdf417barcode.h"
0010 
0011 #include <QColor>
0012 #include <QPainter>
0013 #include <QVariant>
0014 
0015 using namespace Prison;
0016 /**
0017  * @cond private
0018  */
0019 class Prison::AbstractBarcodePrivate
0020 {
0021 public:
0022     QVariant m_data;
0023     QImage m_cache;
0024     QColor m_foreground = Qt::black;
0025     QColor m_background = Qt::white;
0026     AbstractBarcode::Dimensions m_dimension = AbstractBarcode::NoDimensions;
0027     AbstractBarcode *q;
0028 
0029     bool sizeTooSmall(const QSizeF &size) const
0030     {
0031         return m_cache.width() > size.width() || m_cache.height() > size.height();
0032     }
0033 
0034     bool isEmpty() const
0035     {
0036         switch (m_data.type()) {
0037         case QVariant::String:
0038             return m_data.toString().isEmpty();
0039         case QVariant::ByteArray:
0040             return m_data.toByteArray().isEmpty();
0041         default:
0042             break;
0043         }
0044         return true;
0045     }
0046 
0047     void recompute()
0048     {
0049         if (m_cache.isNull() && !isEmpty()) {
0050             m_cache = q->paintImage({});
0051         }
0052     }
0053 
0054     explicit AbstractBarcodePrivate(AbstractBarcode *barcode)
0055         : q(barcode)
0056     {
0057     }
0058 };
0059 /**
0060  * @endcond
0061  */
0062 
0063 #if PRISON_BUILD_DEPRECATED_SINCE(5, 69)
0064 AbstractBarcode::AbstractBarcode()
0065     : d(new AbstractBarcodePrivate(this))
0066 {
0067 }
0068 #endif
0069 
0070 AbstractBarcode::AbstractBarcode(AbstractBarcode::Dimensions dim)
0071     : d(new AbstractBarcodePrivate(this))
0072 {
0073     d->m_dimension = dim;
0074 }
0075 
0076 QString AbstractBarcode::data() const
0077 {
0078     return d->m_data.type() == QVariant::String ? d->m_data.toString() : QString();
0079 }
0080 
0081 QByteArray AbstractBarcode::byteArrayData() const
0082 {
0083     return d->m_data.type() == QVariant::ByteArray ? d->m_data.toByteArray() : QByteArray();
0084 }
0085 
0086 QImage AbstractBarcode::toImage(const QSizeF &size)
0087 {
0088     d->recompute();
0089     if (d->m_cache.isNull() || d->sizeTooSmall(size)) {
0090         return QImage();
0091     }
0092 
0093     // scale to the requested size, using only full integer factors to keep the code readable
0094     int scaleX = std::max<int>(1, size.width() / d->m_cache.width());
0095     int scaleY = std::max<int>(1, size.height() / d->m_cache.height());
0096     if (dimensions() == TwoDimensions) {
0097         scaleX = scaleY = std::min(scaleX, scaleY);
0098     }
0099 
0100     QImage out(d->m_cache.width() * scaleX, d->m_cache.height() * scaleY, d->m_cache.format());
0101     QPainter p(&out);
0102     p.setRenderHint(QPainter::SmoothPixmapTransform, false);
0103     p.drawImage(out.rect(), d->m_cache, d->m_cache.rect());
0104     return out;
0105 }
0106 
0107 void AbstractBarcode::setData(const QString &data)
0108 {
0109     d->m_data = data;
0110     d->m_cache = QImage();
0111 }
0112 
0113 void AbstractBarcode::setData(const QByteArray &data)
0114 {
0115     d->m_data = data;
0116     d->m_cache = QImage();
0117 }
0118 
0119 #if PRISON_BUILD_DEPRECATED_SINCE(5, 72)
0120 QSizeF AbstractBarcode::minimumSize() const
0121 {
0122     d->recompute();
0123 
0124     // ### backward compatibility: this is applying minimum size behavior that the specific
0125     // implementations were doing prior to 5.69. This is eventually to be dropped.
0126     if (d->m_cache.isNull()) {
0127         return {};
0128     }
0129     switch (d->m_dimension) {
0130     case NoDimensions:
0131         return {};
0132     case OneDimension:
0133         return QSizeF(d->m_cache.width(), std::max(d->m_cache.height(), 10));
0134     case TwoDimensions:
0135         return d->m_cache.size() * 4;
0136     }
0137 
0138     return d->m_cache.size();
0139 }
0140 #endif
0141 
0142 QSizeF AbstractBarcode::trueMinimumSize() const
0143 {
0144     d->recompute();
0145     return d->m_cache.size();
0146 }
0147 
0148 QSizeF AbstractBarcode::preferredSize(qreal devicePixelRatio) const
0149 {
0150     d->recompute();
0151     switch (d->m_dimension) {
0152     case NoDimensions:
0153         return {};
0154     case OneDimension:
0155         return QSizeF(d->m_cache.width() * (devicePixelRatio < 2 ? 2 : 1), std::max(d->m_cache.height(), 50));
0156     case TwoDimensions:
0157         // TODO KF6: clean this up once preferredSize is virtual
0158 #if HAVE_ZXING
0159         // the smallest element of a PDF417 code is 1x 3px, for Aztec/QR/DataMatrix it's just 1x1 px
0160         if (dynamic_cast<const Pdf417Barcode *>(this)) {
0161             return d->m_cache.size() * (devicePixelRatio < 2 ? 2 : 1);
0162         }
0163 #endif
0164         return d->m_cache.size() * (devicePixelRatio < 2 ? 4 : 2);
0165     }
0166     return {};
0167 }
0168 
0169 #if PRISON_BUILD_DEPRECATED_SINCE(5, 69)
0170 void AbstractBarcode::setMinimumSize(const QSizeF &minimumSize)
0171 {
0172     Q_UNUSED(minimumSize);
0173 }
0174 #endif
0175 
0176 const QColor &AbstractBarcode::backgroundColor() const
0177 {
0178     return d->m_background;
0179 }
0180 
0181 const QColor &AbstractBarcode::foregroundColor() const
0182 {
0183     return d->m_foreground;
0184 }
0185 
0186 void AbstractBarcode::setBackgroundColor(const QColor &backgroundcolor)
0187 {
0188     if (backgroundcolor != backgroundColor()) {
0189         d->m_background = backgroundcolor;
0190         d->m_cache = QImage();
0191     }
0192 }
0193 
0194 void AbstractBarcode::setForegroundColor(const QColor &foregroundcolor)
0195 {
0196     if (foregroundcolor != foregroundColor()) {
0197         d->m_foreground = foregroundcolor;
0198         d->m_cache = QImage();
0199     }
0200 }
0201 
0202 AbstractBarcode::Dimensions AbstractBarcode::dimensions() const
0203 {
0204     return d->m_dimension;
0205 }
0206 
0207 AbstractBarcode::~AbstractBarcode() = default;