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 "code93barcode.h" 0008 #include "barcodeutil.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 : AbstractBarcode(AbstractBarcode::OneDimension) 0612 { 0613 } 0614 Code93Barcode::~Code93Barcode() = default; 0615 0616 QImage Code93Barcode::paintImage(const QSizeF &size) 0617 { 0618 Q_UNUSED(size); 0619 QList<bool> barcode; 0620 // convert text into sequences of fg/bg bars 0621 { 0622 // translate the string into a code sequence 0623 QList<int> codes; 0624 const QString str = data().isEmpty() ? QString::fromLatin1(byteArrayData().constData(), byteArrayData().size()) : data(); 0625 for (int i = 0; i < str.size(); i++) { 0626 codes += codesForChar(str.at(i).unicode()); 0627 } 0628 0629 // calculate checksums 0630 codes.append(checksum(codes, 20)); // "C" checksum 0631 codes.append(checksum(codes, 15)); // "K" checksum: includes previous checksum 0632 0633 // now generate the barcode 0634 // the guard sequence that goes on each end 0635 const QList<bool> endSequence = sequenceForID(47); 0636 barcode += endSequence; 0637 // translate codes into bars 0638 for (int i = 0; i < codes.size(); i++) { 0639 barcode += sequenceForID(codes.at(i)); 0640 } 0641 // ending guard 0642 barcode += endSequence; 0643 // termination bar 0644 barcode += true; 0645 } 0646 0647 const int barWidth = 1; 0648 const int quietZoneWidth = 10 * barWidth; 0649 0650 // build one line of the result image 0651 QVector<QRgb> line; 0652 line.reserve(barWidth * barcode.size() + 2 * quietZoneWidth); 0653 line.insert(0, quietZoneWidth, backgroundColor().rgba()); 0654 for (int i = 0; i < barcode.size(); i++) { 0655 const QRgb color = (barcode.at(i) ? foregroundColor() : backgroundColor()).rgba(); 0656 for (int j = 0; j < barWidth; j++) { 0657 line.append(color); 0658 } 0659 } 0660 line.insert(line.size(), quietZoneWidth, backgroundColor().rgba()); 0661 0662 // build the complete barcode 0663 QImage ret(line.size(), 1, QImage::Format_ARGB32); 0664 memcpy(ret.scanLine(0), line.data(), line.size() * sizeof(QRgb)); 0665 return ret; 0666 }