File indexing completed on 2024-05-12 15:49:08
0001 /* 0002 SPDX-FileCopyrightText: 2011 Geoffry Song <goffrie@gmail.com> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "code39barcode.h" 0008 #include "barcodeutil.h" 0009 #include <QChar> 0010 0011 using namespace Prison; 0012 0013 static QList<bool> sequenceForChar(ushort c) 0014 { 0015 switch (QChar::toUpper(c)) { 0016 case '0': 0017 return BarCodeUtil::barSequence("000110100"); 0018 case '1': 0019 return BarCodeUtil::barSequence("100100001"); 0020 case '2': 0021 return BarCodeUtil::barSequence("001100001"); 0022 case '3': 0023 return BarCodeUtil::barSequence("101100000"); 0024 case '4': 0025 return BarCodeUtil::barSequence("000110001"); 0026 case '5': 0027 return BarCodeUtil::barSequence("100110000"); 0028 case '6': 0029 return BarCodeUtil::barSequence("001110000"); 0030 case '7': 0031 return BarCodeUtil::barSequence("000100101"); 0032 case '8': 0033 return BarCodeUtil::barSequence("100100100"); 0034 case '9': 0035 return BarCodeUtil::barSequence("001100100"); 0036 case 'A': 0037 return BarCodeUtil::barSequence("100001001"); 0038 case 'B': 0039 return BarCodeUtil::barSequence("001001001"); 0040 case 'C': 0041 return BarCodeUtil::barSequence("101001000"); 0042 case 'D': 0043 return BarCodeUtil::barSequence("000011001"); 0044 case 'E': 0045 return BarCodeUtil::barSequence("100011000"); 0046 case 'F': 0047 return BarCodeUtil::barSequence("001011000"); 0048 case 'G': 0049 return BarCodeUtil::barSequence("000001101"); 0050 case 'H': 0051 return BarCodeUtil::barSequence("100001100"); 0052 case 'I': 0053 return BarCodeUtil::barSequence("001001100"); 0054 case 'J': 0055 return BarCodeUtil::barSequence("000011100"); 0056 case 'K': 0057 return BarCodeUtil::barSequence("100000011"); 0058 case 'L': 0059 return BarCodeUtil::barSequence("001000011"); 0060 case 'M': 0061 return BarCodeUtil::barSequence("101000010"); 0062 case 'N': 0063 return BarCodeUtil::barSequence("000010011"); 0064 case 'O': 0065 return BarCodeUtil::barSequence("100010010"); 0066 case 'P': 0067 return BarCodeUtil::barSequence("001010010"); 0068 case 'Q': 0069 return BarCodeUtil::barSequence("000000111"); 0070 case 'R': 0071 return BarCodeUtil::barSequence("100000110"); 0072 case 'S': 0073 return BarCodeUtil::barSequence("001000110"); 0074 case 'T': 0075 return BarCodeUtil::barSequence("000010110"); 0076 case 'U': 0077 return BarCodeUtil::barSequence("110000001"); 0078 case 'V': 0079 return BarCodeUtil::barSequence("011000001"); 0080 case 'W': 0081 return BarCodeUtil::barSequence("111000000"); 0082 case 'X': 0083 return BarCodeUtil::barSequence("010010001"); 0084 case 'Y': 0085 return BarCodeUtil::barSequence("110010000"); 0086 case 'Z': 0087 return BarCodeUtil::barSequence("011010000"); 0088 case '-': 0089 return BarCodeUtil::barSequence("010000101"); 0090 case '.': 0091 return BarCodeUtil::barSequence("110000100"); 0092 case ' ': 0093 return BarCodeUtil::barSequence("011000100"); 0094 case '$': 0095 return BarCodeUtil::barSequence("010101000"); 0096 case '/': 0097 return BarCodeUtil::barSequence("010100010"); 0098 case '+': 0099 return BarCodeUtil::barSequence("010001010"); 0100 case '%': 0101 return BarCodeUtil::barSequence("000101010"); 0102 default: 0103 return QList<bool>(); // unknown character 0104 } 0105 } 0106 0107 Code39Barcode::Code39Barcode() 0108 : AbstractBarcode(AbstractBarcode::OneDimension) 0109 { 0110 } 0111 Code39Barcode::~Code39Barcode() = default; 0112 0113 QImage Code39Barcode::paintImage(const QSizeF &size) 0114 { 0115 Q_UNUSED(size); 0116 QList<bool> barcode; 0117 // convert text into sequences of wide/narrow bars 0118 { 0119 // the guard sequence that goes on each end 0120 const QList<bool> endSequence = BarCodeUtil::barSequence("010010100"); 0121 barcode += endSequence; 0122 barcode += false; 0123 // translate the string 0124 const QString str = data().isEmpty() ? QString::fromLatin1(byteArrayData().constData(), byteArrayData().size()) : data(); 0125 for (int i = 0; i < str.size(); i++) { 0126 QList<bool> b = sequenceForChar(str.at(i).unicode()); 0127 if (!b.empty()) { 0128 barcode += b; 0129 barcode += false; // add a narrow space between each character 0130 } 0131 } 0132 // ending guard 0133 barcode += endSequence; 0134 } 0135 0136 /* 0137 calculate integer bar widths that fit inside `size' 0138 each character has 6 narrow bars and 3 wide bars and there is a narrow bar between characters 0139 restrictions: 0140 *) smallWidth * 2 <= largeWidth <= smallWidth * 3 0141 - in other words, the ratio largeWidth:smallWidth is between 3:1 and 2:1 0142 *) wide * largeWidth + narrow * smallWidth <= size.width() 0143 - the barcode has to fit within the given size 0144 */ 0145 const int wide = barcode.count(true); 0146 const int narrow = barcode.count(false); 0147 // wide bar width 0148 const int largeWidth = 2; 0149 // narrow bar width 0150 const int smallWidth = 1; 0151 Q_ASSERT(largeWidth > smallWidth); 0152 0153 const int quietZoneWidth = 10 * smallWidth; 0154 0155 // one line of the result image 0156 QVector<QRgb> line; 0157 line.reserve(wide * largeWidth + narrow * smallWidth + 2 * quietZoneWidth); 0158 line.insert(0, quietZoneWidth, backgroundColor().rgba()); 0159 for (int i = 0; i < barcode.size(); i++) { 0160 const QRgb color = (((i & 1) == 0) ? foregroundColor() : backgroundColor()).rgba(); // alternate between foreground and background color 0161 const int width = barcode.at(i) ? largeWidth : smallWidth; 0162 for (int j = 0; j < width; j++) { 0163 line.append(color); 0164 } 0165 } 0166 line.insert(line.size(), quietZoneWidth, backgroundColor().rgba()); 0167 0168 // build the complete barcode 0169 QImage ret(line.size(), 1, QImage::Format_ARGB32); 0170 memcpy(ret.scanLine(0), line.data(), line.size() * sizeof(QRgb)); 0171 return ret; 0172 }