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 }