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;