File indexing completed on 2024-05-12 04:01:31
0001 /* 0002 SPDX-FileCopyrightText: 2011 Geoffry Song <goffrie@gmail.com> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "barcodeutil_p.h" 0008 #include "code39barcode_p.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 : AbstractBarcodePrivate(Barcode::OneDimension) 0109 { 0110 } 0111 Code39Barcode::~Code39Barcode() = default; 0112 0113 QImage Code39Barcode::paintImage() 0114 { 0115 QList<bool> barcode; 0116 // convert text into sequences of wide/narrow bars 0117 { 0118 // the guard sequence that goes on each end 0119 const QList<bool> endSequence = BarCodeUtil::barSequence("010010100"); 0120 barcode += endSequence; 0121 barcode += false; 0122 // translate the string 0123 const auto str = BarCodeUtil::asLatin1ByteArray(m_data); 0124 for (int i = 0; i < str.size(); i++) { 0125 QList<bool> b = sequenceForChar(str.at(i)); 0126 if (!b.empty()) { 0127 barcode += b; 0128 barcode += false; // add a narrow space between each character 0129 } 0130 } 0131 // ending guard 0132 barcode += endSequence; 0133 } 0134 0135 /* 0136 calculate integer bar widths that fit inside `size' 0137 each character has 6 narrow bars and 3 wide bars and there is a narrow bar between characters 0138 restrictions: 0139 *) smallWidth * 2 <= largeWidth <= smallWidth * 3 0140 - in other words, the ratio largeWidth:smallWidth is between 3:1 and 2:1 0141 *) wide * largeWidth + narrow * smallWidth <= size.width() 0142 - the barcode has to fit within the given size 0143 */ 0144 const int wide = barcode.count(true); 0145 const int narrow = barcode.count(false); 0146 // wide bar width 0147 const int largeWidth = 2; 0148 // narrow bar width 0149 const int smallWidth = 1; 0150 Q_ASSERT(largeWidth > smallWidth); 0151 0152 const int quietZoneWidth = 10 * smallWidth; 0153 0154 // one line of the result image 0155 QList<QRgb> line; 0156 line.reserve(wide * largeWidth + narrow * smallWidth + 2 * quietZoneWidth); 0157 line.insert(0, quietZoneWidth, m_background.rgba()); 0158 for (int i = 0; i < barcode.size(); i++) { 0159 const QRgb color = (((i & 1) == 0) ? m_foreground : m_background).rgba(); // alternate between foreground and background color 0160 const int width = barcode.at(i) ? largeWidth : smallWidth; 0161 for (int j = 0; j < width; j++) { 0162 line.append(color); 0163 } 0164 } 0165 line.insert(line.size(), quietZoneWidth, m_background.rgba()); 0166 0167 // build the complete barcode 0168 QImage ret(line.size(), 1, QImage::Format_ARGB32); 0169 memcpy(ret.scanLine(0), line.data(), line.size() * sizeof(QRgb)); 0170 return ret; 0171 }