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 "code93barcode_p.h"
0009 #include <QChar>
0010 
0011 using namespace Prison;
0012 
0013 // returns a list of 9 bar colors, where `true' means foreground and `false' means background color
0014 static QList<bool> sequenceForID(int id)
0015 {
0016     switch (id) {
0017     case 0:
0018         return BarCodeUtil::barSequence("100010100"); // 0-9
0019     case 1:
0020         return BarCodeUtil::barSequence("101001000");
0021     case 2:
0022         return BarCodeUtil::barSequence("101000100");
0023     case 3:
0024         return BarCodeUtil::barSequence("101000010");
0025     case 4:
0026         return BarCodeUtil::barSequence("100101000");
0027     case 5:
0028         return BarCodeUtil::barSequence("100100100");
0029     case 6:
0030         return BarCodeUtil::barSequence("100100010");
0031     case 7:
0032         return BarCodeUtil::barSequence("101010000");
0033     case 8:
0034         return BarCodeUtil::barSequence("100010010");
0035     case 9:
0036         return BarCodeUtil::barSequence("100001010");
0037     case 10:
0038         return BarCodeUtil::barSequence("110101000"); // A-Z
0039     case 11:
0040         return BarCodeUtil::barSequence("110100100");
0041     case 12:
0042         return BarCodeUtil::barSequence("110100010");
0043     case 13:
0044         return BarCodeUtil::barSequence("110010100");
0045     case 14:
0046         return BarCodeUtil::barSequence("110010010");
0047     case 15:
0048         return BarCodeUtil::barSequence("110001010");
0049     case 16:
0050         return BarCodeUtil::barSequence("101101000");
0051     case 17:
0052         return BarCodeUtil::barSequence("101100100");
0053     case 18:
0054         return BarCodeUtil::barSequence("101100010");
0055     case 19:
0056         return BarCodeUtil::barSequence("100110100");
0057     case 20:
0058         return BarCodeUtil::barSequence("100011010");
0059     case 21:
0060         return BarCodeUtil::barSequence("101011000");
0061     case 22:
0062         return BarCodeUtil::barSequence("101001100");
0063     case 23:
0064         return BarCodeUtil::barSequence("101000110");
0065     case 24:
0066         return BarCodeUtil::barSequence("100101100");
0067     case 25:
0068         return BarCodeUtil::barSequence("100010110");
0069     case 26:
0070         return BarCodeUtil::barSequence("110110100");
0071     case 27:
0072         return BarCodeUtil::barSequence("110110010");
0073     case 28:
0074         return BarCodeUtil::barSequence("110101100");
0075     case 29:
0076         return BarCodeUtil::barSequence("110100110");
0077     case 30:
0078         return BarCodeUtil::barSequence("110010110");
0079     case 31:
0080         return BarCodeUtil::barSequence("110011010");
0081     case 32:
0082         return BarCodeUtil::barSequence("101101100");
0083     case 33:
0084         return BarCodeUtil::barSequence("101100110");
0085     case 34:
0086         return BarCodeUtil::barSequence("100110110");
0087     case 35:
0088         return BarCodeUtil::barSequence("100111010");
0089     case 36:
0090         return BarCodeUtil::barSequence("100101110"); // -
0091     case 37:
0092         return BarCodeUtil::barSequence("111010100"); // .
0093     case 38:
0094         return BarCodeUtil::barSequence("111010010"); // space
0095     case 39:
0096         return BarCodeUtil::barSequence("111001010"); // $
0097     case 40:
0098         return BarCodeUtil::barSequence("101101110"); // /
0099     case 41:
0100         return BarCodeUtil::barSequence("101110110"); // +
0101     case 42:
0102         return BarCodeUtil::barSequence("110101110"); // $
0103     case 43:
0104         return BarCodeUtil::barSequence("100100110"); // ($)
0105     case 44:
0106         return BarCodeUtil::barSequence("111011010"); // (%)
0107     case 45:
0108         return BarCodeUtil::barSequence("111010110"); // (/)
0109     case 46:
0110         return BarCodeUtil::barSequence("100110010"); // (+)
0111     case 47:
0112         return BarCodeUtil::barSequence("101011110"); // stop sequence
0113     default:
0114         // unknown ID... shouldn't happen
0115         qWarning("Code93Barcode::sequenceForID called with unknown ID");
0116         return QList<bool>();
0117     }
0118 }
0119 
0120 // returns the list of IDs that represent a character
0121 static QList<int> codesForChar(uint c)
0122 {
0123     QList<int> ret;
0124     switch (c) {
0125     case 0:
0126         ret += 44;
0127         ret += 30;
0128         break;
0129     case 1:
0130         ret += 43;
0131         ret += 10;
0132         break;
0133     case 2:
0134         ret += 43;
0135         ret += 11;
0136         break;
0137     case 3:
0138         ret += 43;
0139         ret += 12;
0140         break;
0141     case 4:
0142         ret += 43;
0143         ret += 13;
0144         break;
0145     case 5:
0146         ret += 43;
0147         ret += 14;
0148         break;
0149     case 6:
0150         ret += 43;
0151         ret += 15;
0152         break;
0153     case 7:
0154         ret += 43;
0155         ret += 16;
0156         break;
0157     case 8:
0158         ret += 43;
0159         ret += 17;
0160         break;
0161     case 9:
0162         ret += 43;
0163         ret += 18;
0164         break;
0165     case 10:
0166         ret += 43;
0167         ret += 19;
0168         break;
0169     case 11:
0170         ret += 43;
0171         ret += 20;
0172         break;
0173     case 12:
0174         ret += 43;
0175         ret += 21;
0176         break;
0177     case 13:
0178         ret += 43;
0179         ret += 22;
0180         break;
0181     case 14:
0182         ret += 43;
0183         ret += 23;
0184         break;
0185     case 15:
0186         ret += 43;
0187         ret += 24;
0188         break;
0189     case 16:
0190         ret += 43;
0191         ret += 25;
0192         break;
0193     case 17:
0194         ret += 43;
0195         ret += 26;
0196         break;
0197     case 18:
0198         ret += 43;
0199         ret += 27;
0200         break;
0201     case 19:
0202         ret += 43;
0203         ret += 28;
0204         break;
0205     case 20:
0206         ret += 43;
0207         ret += 29;
0208         break;
0209     case 21:
0210         ret += 43;
0211         ret += 30;
0212         break;
0213     case 22:
0214         ret += 43;
0215         ret += 31;
0216         break;
0217     case 23:
0218         ret += 43;
0219         ret += 32;
0220         break;
0221     case 24:
0222         ret += 43;
0223         ret += 33;
0224         break;
0225     case 25:
0226         ret += 43;
0227         ret += 34;
0228         break;
0229     case 26:
0230         ret += 43;
0231         ret += 35;
0232         break;
0233     case 27:
0234         ret += 44;
0235         ret += 10;
0236         break;
0237     case 28:
0238         ret += 44;
0239         ret += 11;
0240         break;
0241     case 29:
0242         ret += 44;
0243         ret += 12;
0244         break;
0245     case 30:
0246         ret += 44;
0247         ret += 13;
0248         break;
0249     case 31:
0250         ret += 44;
0251         ret += 14;
0252         break;
0253     case 32:
0254         ret += 38;
0255         break;
0256     case 33:
0257         ret += 45;
0258         ret += 10;
0259         break;
0260     case 34:
0261         ret += 45;
0262         ret += 11;
0263         break;
0264     case 35:
0265         ret += 45;
0266         ret += 12;
0267         break;
0268     case 36:
0269         ret += 39;
0270         break;
0271     case 37:
0272         ret += 42;
0273         break;
0274     case 38:
0275         ret += 45;
0276         ret += 15;
0277         break;
0278     case 39:
0279         ret += 45;
0280         ret += 16;
0281         break;
0282     case 40:
0283         ret += 45;
0284         ret += 17;
0285         break;
0286     case 41:
0287         ret += 45;
0288         ret += 18;
0289         break;
0290     case 42:
0291         ret += 45;
0292         ret += 19;
0293         break;
0294     case 43:
0295         ret += 41;
0296         break;
0297     case 44:
0298         ret += 45;
0299         ret += 21;
0300         break;
0301     case 45:
0302         ret += 36;
0303         break;
0304     case 46:
0305         ret += 37;
0306         break;
0307     case 47:
0308         ret += 40;
0309         break;
0310     case 48:
0311         ret += 0;
0312         break;
0313     case 49:
0314         ret += 1;
0315         break;
0316     case 50:
0317         ret += 2;
0318         break;
0319     case 51:
0320         ret += 3;
0321         break;
0322     case 52:
0323         ret += 4;
0324         break;
0325     case 53:
0326         ret += 5;
0327         break;
0328     case 54:
0329         ret += 6;
0330         break;
0331     case 55:
0332         ret += 7;
0333         break;
0334     case 56:
0335         ret += 8;
0336         break;
0337     case 57:
0338         ret += 9;
0339         break;
0340     case 58:
0341         ret += 45;
0342         ret += 35;
0343         break;
0344     case 59:
0345         ret += 44;
0346         ret += 15;
0347         break;
0348     case 60:
0349         ret += 44;
0350         ret += 16;
0351         break;
0352     case 61:
0353         ret += 44;
0354         ret += 17;
0355         break;
0356     case 62:
0357         ret += 44;
0358         ret += 18;
0359         break;
0360     case 63:
0361         ret += 44;
0362         ret += 19;
0363         break;
0364     case 64:
0365         ret += 44;
0366         ret += 31;
0367         break;
0368     case 65:
0369         ret += 10;
0370         break;
0371     case 66:
0372         ret += 11;
0373         break;
0374     case 67:
0375         ret += 12;
0376         break;
0377     case 68:
0378         ret += 13;
0379         break;
0380     case 69:
0381         ret += 14;
0382         break;
0383     case 70:
0384         ret += 15;
0385         break;
0386     case 71:
0387         ret += 16;
0388         break;
0389     case 72:
0390         ret += 17;
0391         break;
0392     case 73:
0393         ret += 18;
0394         break;
0395     case 74:
0396         ret += 19;
0397         break;
0398     case 75:
0399         ret += 20;
0400         break;
0401     case 76:
0402         ret += 21;
0403         break;
0404     case 77:
0405         ret += 22;
0406         break;
0407     case 78:
0408         ret += 23;
0409         break;
0410     case 79:
0411         ret += 24;
0412         break;
0413     case 80:
0414         ret += 25;
0415         break;
0416     case 81:
0417         ret += 26;
0418         break;
0419     case 82:
0420         ret += 27;
0421         break;
0422     case 83:
0423         ret += 28;
0424         break;
0425     case 84:
0426         ret += 29;
0427         break;
0428     case 85:
0429         ret += 30;
0430         break;
0431     case 86:
0432         ret += 31;
0433         break;
0434     case 87:
0435         ret += 32;
0436         break;
0437     case 88:
0438         ret += 33;
0439         break;
0440     case 89:
0441         ret += 34;
0442         break;
0443     case 90:
0444         ret += 35;
0445         break;
0446     case 91:
0447         ret += 44;
0448         ret += 20;
0449         break;
0450     case 92:
0451         ret += 44;
0452         ret += 21;
0453         break;
0454     case 93:
0455         ret += 44;
0456         ret += 22;
0457         break;
0458     case 94:
0459         ret += 44;
0460         ret += 23;
0461         break;
0462     case 95:
0463         ret += 44;
0464         ret += 24;
0465         break;
0466     case 96:
0467         ret += 44;
0468         ret += 32;
0469         break;
0470     case 97:
0471         ret += 46;
0472         ret += 10;
0473         break;
0474     case 98:
0475         ret += 46;
0476         ret += 11;
0477         break;
0478     case 99:
0479         ret += 46;
0480         ret += 12;
0481         break;
0482     case 100:
0483         ret += 46;
0484         ret += 13;
0485         break;
0486     case 101:
0487         ret += 46;
0488         ret += 14;
0489         break;
0490     case 102:
0491         ret += 46;
0492         ret += 15;
0493         break;
0494     case 103:
0495         ret += 46;
0496         ret += 16;
0497         break;
0498     case 104:
0499         ret += 46;
0500         ret += 17;
0501         break;
0502     case 105:
0503         ret += 46;
0504         ret += 18;
0505         break;
0506     case 106:
0507         ret += 46;
0508         ret += 19;
0509         break;
0510     case 107:
0511         ret += 46;
0512         ret += 20;
0513         break;
0514     case 108:
0515         ret += 46;
0516         ret += 21;
0517         break;
0518     case 109:
0519         ret += 46;
0520         ret += 22;
0521         break;
0522     case 110:
0523         ret += 46;
0524         ret += 23;
0525         break;
0526     case 111:
0527         ret += 46;
0528         ret += 24;
0529         break;
0530     case 112:
0531         ret += 46;
0532         ret += 25;
0533         break;
0534     case 113:
0535         ret += 46;
0536         ret += 26;
0537         break;
0538     case 114:
0539         ret += 46;
0540         ret += 27;
0541         break;
0542     case 115:
0543         ret += 46;
0544         ret += 28;
0545         break;
0546     case 116:
0547         ret += 46;
0548         ret += 29;
0549         break;
0550     case 117:
0551         ret += 46;
0552         ret += 30;
0553         break;
0554     case 118:
0555         ret += 46;
0556         ret += 31;
0557         break;
0558     case 119:
0559         ret += 46;
0560         ret += 32;
0561         break;
0562     case 120:
0563         ret += 46;
0564         ret += 33;
0565         break;
0566     case 121:
0567         ret += 46;
0568         ret += 34;
0569         break;
0570     case 122:
0571         ret += 46;
0572         ret += 35;
0573         break;
0574     case 123:
0575         ret += 44;
0576         ret += 25;
0577         break;
0578     case 124:
0579         ret += 44;
0580         ret += 26;
0581         break;
0582     case 125:
0583         ret += 44;
0584         ret += 27;
0585         break;
0586     case 126:
0587         ret += 44;
0588         ret += 28;
0589         break;
0590     case 127:
0591         ret += 44;
0592         ret += 29;
0593         break;
0594     }
0595     return ret; // return an empty list for a non-ascii character code
0596 }
0597 
0598 // calculate a checksum
0599 static int checksum(const QList<int> &codes, int wrap)
0600 {
0601     int check = 0;
0602     for (int i = 0; i < codes.size(); i++) {
0603         // weight goes from 1 to wrap, right-to-left, then repeats
0604         const int weight = (codes.size() - i - 1) % wrap + 1;
0605         check += codes.at(i) * weight;
0606     }
0607     return check % 47;
0608 }
0609 
0610 Code93Barcode::Code93Barcode()
0611     : AbstractBarcodePrivate(Barcode::OneDimension)
0612 {
0613 }
0614 Code93Barcode::~Code93Barcode() = default;
0615 
0616 QImage Code93Barcode::paintImage()
0617 {
0618     QList<bool> barcode;
0619     // convert text into sequences of fg/bg bars
0620     {
0621         // translate the string into a code sequence
0622         QList<int> codes;
0623         const auto str = BarCodeUtil::asLatin1ByteArray(m_data);
0624         for (int i = 0; i < str.size(); i++) {
0625             codes += codesForChar(str.at(i));
0626         }
0627 
0628         // calculate checksums
0629         codes.append(checksum(codes, 20)); // "C" checksum
0630         codes.append(checksum(codes, 15)); // "K" checksum: includes previous checksum
0631 
0632         // now generate the barcode
0633         // the guard sequence that goes on each end
0634         const QList<bool> endSequence = sequenceForID(47);
0635         barcode += endSequence;
0636         // translate codes into bars
0637         for (int i = 0; i < codes.size(); i++) {
0638             barcode += sequenceForID(codes.at(i));
0639         }
0640         // ending guard
0641         barcode += endSequence;
0642         // termination bar
0643         barcode += true;
0644     }
0645 
0646     const int barWidth = 1;
0647     const int quietZoneWidth = 10 * barWidth;
0648 
0649     // build one line of the result image
0650     QList<QRgb> line;
0651     line.reserve(barWidth * barcode.size() + 2 * quietZoneWidth);
0652     line.insert(0, quietZoneWidth, m_background.rgba());
0653     for (int i = 0; i < barcode.size(); i++) {
0654         const QRgb color = (barcode.at(i) ? m_foreground : m_background).rgba();
0655         for (int j = 0; j < barWidth; j++) {
0656             line.append(color);
0657         }
0658     }
0659     line.insert(line.size(), quietZoneWidth, m_background.rgba());
0660 
0661     // build the complete barcode
0662     QImage ret(line.size(), 1, QImage::Format_ARGB32);
0663     memcpy(ret.scanLine(0), line.data(), line.size() * sizeof(QRgb));
0664     return ret;
0665 }