File indexing completed on 2024-05-12 04:43:18
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com) 0003 * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2.1 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Lesser General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Lesser General Public 0016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 /* 0020 * This file contains the implementation of the Code 128 barcode renderer. 0021 * All this code assumes a 100dpi rendering surface for it's calculations. 0022 */ 0023 0024 #include <QString> 0025 #include <QVector> 0026 #include <QRect> 0027 #include <QPainter> 0028 #include <QPen> 0029 #include <QBrush> 0030 0031 #include "KReportRenderObjects.h" 0032 #include "kreportplugin_debug.h" 0033 0034 static const int SETA = 0; 0035 static const int SETB = 1; 0036 static const int SETC = 2; 0037 0038 static const char FNC1 = (char)130; 0039 static const char FNC2 = (char)131; 0040 static const char FNC3 = (char)132; 0041 static const char FNC4 = (char)133; 0042 static const char SHIFT = (char)134; 0043 static const char CODEA = (char)135; 0044 static const char CODEB = (char)136; 0045 static const char CODEC = (char)137; 0046 static const char STARTA = (char)138; 0047 static const char STARTB = (char)139; 0048 static const char STARTC = (char)140; 0049 0050 0051 struct code128 { 0052 char codea; 0053 char codeb; 0054 char codec; 0055 0056 int values[6]; 0057 0058 bool _null; 0059 }; 0060 0061 static const struct code128 _128codes[] = { 0062 // A , B , C , { B S B S B S }, NULL? }, 0063 { ' ', ' ', 0, { 2, 1, 2, 2, 2, 2 }, false }, 0064 { '!', '!', 1, { 2, 2, 2, 1, 2, 2 }, false }, 0065 { '"', '"', 2, { 2, 2, 2, 2, 2, 1 }, false }, 0066 { '#', '#', 3, { 1, 2, 1, 2, 2, 3 }, false }, 0067 { '$', '$', 4, { 1, 2, 1, 3, 2, 2 }, false }, 0068 { '%', '%', 5, { 1, 3, 1, 2, 2, 2 }, false }, 0069 { '&', '&', 6, { 1, 2, 2, 2, 1, 3 }, false }, 0070 { '\'', '\'', 7, { 1, 2, 2, 3, 1, 2 }, false }, 0071 { '(', '(', 8, { 1, 3, 2, 2, 1, 2 }, false }, 0072 { ')', ')', 9, { 2, 2, 1, 2, 1, 3 }, false }, 0073 { '*', '*', 10, { 2, 2, 1, 3, 1, 2 }, false }, 0074 { '+', '+', 11, { 2, 3, 1, 2, 1, 2 }, false }, 0075 { ',', ',', 12, { 1, 1, 2, 2, 3, 2 }, false }, 0076 { '-', '-', 13, { 1, 2, 2, 1, 3, 2 }, false }, 0077 { '.', '.', 14, { 1, 2, 2, 2, 3, 1 }, false }, 0078 { '/', '/', 15, { 1, 1, 3, 2, 2, 2 }, false }, 0079 { '0', '0', 16, { 1, 2, 3, 1, 2, 2 }, false }, 0080 { '1', '1', 17, { 1, 2, 3, 2, 2, 1 }, false }, 0081 { '2', '2', 18, { 2, 2, 3, 2, 1, 1 }, false }, 0082 { '3', '3', 19, { 2, 2, 1, 1, 3, 2 }, false }, 0083 { '4', '4', 20, { 2, 2, 1, 2, 3, 1 }, false }, 0084 { '5', '5', 21, { 2, 1, 3, 2, 1, 2 }, false }, 0085 { '6', '6', 22, { 2, 2, 3, 1, 1, 2 }, false }, 0086 { '7', '7', 23, { 3, 1, 2, 1, 3, 1 }, false }, 0087 { '8', '8', 24, { 3, 1, 1, 2, 2, 2 }, false }, 0088 { '9', '9', 25, { 3, 2, 1, 1, 2, 2 }, false }, 0089 { ':', ':', 26, { 3, 2, 1, 2, 2, 1 }, false }, 0090 { ';', ';', 27, { 3, 1, 2, 2, 1, 2 }, false }, 0091 { '<', '<', 28, { 3, 2, 2, 1, 1, 2 }, false }, 0092 { '=', '=', 29, { 3, 2, 2, 2, 1, 1 }, false }, 0093 { '>', '>', 30, { 2, 1, 2, 1, 2, 3 }, false }, 0094 { '?', '?', 31, { 2, 1, 2, 3, 2, 1 }, false }, 0095 { '@', '@', 32, { 2, 3, 2, 1, 2, 1 }, false }, 0096 { 'A', 'A', 33, { 1, 1, 1, 3, 2, 3 }, false }, 0097 { 'B', 'B', 34, { 1, 3, 1, 1, 2, 3 }, false }, 0098 { 'C', 'C', 35, { 1, 3, 1, 3, 2, 1 }, false }, 0099 { 'D', 'D', 36, { 1, 1, 2, 3, 1, 3 }, false }, 0100 { 'E', 'E', 37, { 1, 3, 2, 1, 1, 3 }, false }, 0101 { 'F', 'F', 38, { 1, 3, 2, 3, 1, 1 }, false }, 0102 { 'G', 'G', 39, { 2, 1, 1, 3, 1, 3 }, false }, 0103 { 'H', 'H', 40, { 2, 3, 1, 1, 1, 3 }, false }, 0104 { 'I', 'I', 41, { 2, 3, 1, 3, 1, 1 }, false }, 0105 { 'J', 'J', 42, { 1, 1, 2, 1, 3, 3 }, false }, 0106 { 'K', 'K', 43, { 1, 1, 2, 3, 3, 1 }, false }, 0107 { 'L', 'L', 44, { 1, 3, 2, 1, 3, 1 }, false }, 0108 { 'M', 'M', 45, { 1, 1, 3, 1, 2, 3 }, false }, 0109 { 'N', 'N', 46, { 1, 1, 3, 3, 2, 1 }, false }, 0110 { 'O', 'O', 47, { 1, 3, 3, 1, 2, 1 }, false }, 0111 { 'P', 'P', 48, { 3, 1, 3, 1, 2, 1 }, false }, 0112 { 'Q', 'Q', 49, { 2, 1, 1, 3, 3, 1 }, false }, 0113 { 'R', 'R', 50, { 2, 3, 1, 1, 3, 1 }, false }, 0114 { 'S', 'S', 51, { 2, 1, 3, 1, 1, 3 }, false }, 0115 { 'T', 'T', 52, { 2, 1, 3, 3, 1, 1 }, false }, 0116 { 'U', 'U', 53, { 2, 1, 3, 1, 3, 1 }, false }, 0117 { 'V', 'V', 54, { 3, 1, 1, 1, 2, 3 }, false }, 0118 { 'W', 'W', 55, { 3, 1, 1, 3, 2, 1 }, false }, 0119 { 'X', 'X', 56, { 3, 3, 1, 1, 2, 1 }, false }, 0120 { 'Y', 'Y', 57, { 3, 1, 2, 1, 1, 3 }, false }, 0121 { 'Z', 'Z', 58, { 3, 1, 2, 3, 1, 1 }, false }, 0122 { '[', '[', 59, { 3, 3, 2, 1, 1, 1 }, false }, 0123 { '\\', '\\', 60, { 3, 1, 4, 1, 1, 1 }, false }, 0124 { ']', ']', 61, { 2, 2, 1, 4, 1, 1 }, false }, 0125 { '^', '^', 62, { 4, 3, 1, 1, 1, 1 }, false }, 0126 { '_', '_', 63, { 1, 1, 1, 2, 2, 4 }, false }, 0127 { 0x00, '`', 64, { 1, 1, 1, 4, 2, 2 }, false }, // NUL 0128 { 0x01, 'a', 65, { 1, 2, 1, 1, 2, 4 }, false }, // SOH 0129 { 0x02, 'b', 66, { 1, 2, 1, 4, 2, 1 }, false }, // STX 0130 { 0x03, 'c', 67, { 1, 4, 1, 1, 2, 2 }, false }, // ETX 0131 { 0x04, 'd', 68, { 1, 4, 1, 2, 2, 1 }, false }, // EOT 0132 { 0x05, 'e', 69, { 1, 1, 2, 2, 1, 4 }, false }, // ENQ 0133 { 0x06, 'f', 70, { 1, 1, 2, 4, 1, 2 }, false }, // ACK 0134 { 0x07, 'g', 71, { 1, 2, 2, 1, 1, 4 }, false }, // BEL 0135 { 0x08, 'h', 72, { 1, 2, 2, 4, 1, 1 }, false }, // BS 0136 { 0x09, 'i', 73, { 1, 4, 2, 1, 1, 2 }, false }, // HT 0137 { 0x0A, 'j', 74, { 1, 4, 2, 2, 1, 1 }, false }, // LF 0138 { 0x0B, 'k', 75, { 2, 4, 1, 2, 1, 1 }, false }, // VT 0139 { 0x0C, 'l', 76, { 2, 2, 1, 1, 1, 4 }, false }, // FF 0140 { 0x0D, 'm', 77, { 4, 1, 3, 1, 1, 1 }, false }, // CR 0141 { 0x0E, 'n', 78, { 2, 4, 1, 1, 1, 2 }, false }, // SO 0142 { 0x0F, 'o', 79, { 1, 3, 4, 1, 1, 1 }, false }, // SI 0143 { 0x10, 'p', 80, { 1, 1, 1, 2, 4, 2 }, false }, // DLE 0144 { 0x11, 'q', 81, { 1, 2, 1, 1, 4, 2 }, false }, // DC1 0145 { 0x12, 'r', 82, { 1, 2, 1, 2, 4, 1 }, false }, // DC2 0146 { 0x13, 's', 83, { 1, 1, 4, 2, 1, 2 }, false }, // DC3 0147 { 0x14, 't', 84, { 1, 2, 4, 1, 1, 2 }, false }, // DC4 0148 { 0x15, 'u', 85, { 1, 2, 4, 2, 1, 1 }, false }, // NAK 0149 { 0x16, 'v', 86, { 4, 1, 1, 2, 1, 2 }, false }, // SYN 0150 { 0x17, 'w', 87, { 4, 2, 1, 1, 1, 2 }, false }, // ETB 0151 { 0x18, 'x', 88, { 4, 2, 1, 2, 1, 1 }, false }, // CAN 0152 { 0x19, 'y', 89, { 2, 1, 2, 1, 4, 1 }, false }, // EM 0153 { 0x1A, 'z', 90, { 2, 1, 4, 1, 2, 1 }, false }, // SUB 0154 { 0x1B, '{', 91, { 4, 1, 2, 1, 2, 1 }, false }, // ESC 0155 { 0x1C, '|', 92, { 1, 1, 1, 1, 4, 3 }, false }, // FS 0156 { 0x1D, '}', 93, { 1, 1, 1, 3, 4, 1 }, false }, // GS 0157 { 0x1E, '~', 94, { 1, 3, 1, 1, 4, 1 }, false }, // RS 0158 { 0x1F, 0x7F, 95, { 1, 1, 4, 1, 1, 3 }, false }, // US DEL 0159 { FNC3, FNC3, 96, { 1, 1, 4, 3, 1, 1 }, false }, // FNC3 FNC3 0160 { FNC2, FNC2, 97, { 4, 1, 1, 1, 1, 3 }, false }, // FNC2 FNC2 0161 { SHIFT, SHIFT, 98, { 4, 1, 1, 3, 1, 1 }, false }, // SHIFT SHIFT 0162 { CODEC, CODEC, 99, { 1, 1, 3, 1, 4, 1 }, false }, // CODEC CODEC 0163 { CODEB, FNC4, CODEB, { 1, 1, 4, 1, 3, 1 }, false }, // CODEB FNC4 CODEB 0164 { FNC4, CODEA, CODEA, { 3, 1, 1, 1, 4, 1 }, false }, // FNC4 CODEA CODEA 0165 { FNC1, FNC1, FNC1, { 4, 1, 1, 1, 3, 1 }, false }, // FNC1 FNC1 FNC1 0166 { STARTA, STARTA, STARTA, { 2, 1, 1, 4, 1, 2 }, false }, // STARTA 0167 { STARTB, STARTB, STARTB, { 2, 1, 1, 2, 1, 4 }, false }, // STARTB 0168 { STARTC, STARTC, STARTC, { 2, 1, 1, 2, 3, 2 }, false }, // STARTC 0169 0170 { '\0', '\0', '\0', { 0, 0, 0, 0, 0, 0 }, true } // null termininator of list 0171 }; 0172 0173 // STOP CHARACTER { 2 3 3 1 1 1 2 } 0174 0175 int code128IndexP(QChar code, int set) 0176 { 0177 const char latin1Code = code.toLatin1(); 0178 for (int idx = 0; _128codes[idx]._null == false; idx++) { 0179 if (set == SETA && _128codes[idx].codea == latin1Code) return idx; 0180 if (set == SETB && _128codes[idx].codeb == latin1Code) return idx; 0181 if (set == SETC && _128codes[idx].codec == latin1Code) return idx; 0182 } 0183 return -1; // couldn't find it 0184 } 0185 0186 void renderCode128(const QRect & r, const QString & _str, Qt::Alignment align, QPainter * pPainter) 0187 { 0188 QVector<int> str; 0189 0190 // create the list.. if the list is empty then just set a start code and move on 0191 if (_str.isEmpty()) { 0192 str.push_back(104); 0193 } else { 0194 int rank_a = 0; 0195 int rank_b = 0; 0196 int rank_c = 0; 0197 0198 QChar c; 0199 for (int i = 0; i < _str.length(); ++i) { 0200 c = _str.at(i); 0201 rank_a += (code128IndexP(c, SETA) != -1 ? 1 : 0); 0202 rank_b += (code128IndexP(c, SETB) != -1 ? 1 : 0); 0203 rank_c += (c >= QLatin1Char('0') && c <= QLatin1Char('9') ? 1 : 0); 0204 } 0205 if (rank_c == _str.length() && ((rank_c % 2) == 0 || rank_c > 4)) { 0206 // every value in the is a digit so we are going to go with mode C 0207 // and we have an even number or we have more than 4 values 0208 int i; 0209 if ((rank_c % 2) == 1) { 0210 str.push_back(104); // START B 0211 c = _str.at(0); 0212 str.push_back(code128IndexP(c, SETB)); 0213 str.push_back(99); // MODE C 0214 i = 1; 0215 } else { 0216 str.push_back(105); // START C 0217 i = 0; 0218 } 0219 for (; i < _str.length(); i += 2) { 0220 char a, b; 0221 c = _str.at(i); 0222 a = c.toLatin1(); 0223 a -= 48; 0224 c = _str.at(i + 1); 0225 b = c.toLatin1(); 0226 b -= 48; 0227 str.push_back(int((a * 10) + b)); 0228 } 0229 } else { 0230 // start in the mode that had the higher number of hits and then 0231 // just shift into the opposite mode as needed 0232 int set = (rank_a > rank_b ? SETA : SETB); 0233 str.push_back((rank_a > rank_b ? 103 : 104)); 0234 for (int i = 0; i < _str.length(); ++i) { 0235 c = _str.at(i); 0236 int v = code128IndexP(c, set); 0237 if (v == -1) { 0238 v = code128IndexP(c, (set == SETA ? SETB : SETA)); 0239 if (v != -1) { 0240 str.push_back(98); // SHIFT 0241 str.push_back(v); 0242 } 0243 } else { 0244 str.push_back(v); 0245 } 0246 } 0247 } 0248 } 0249 0250 // calculate and append the checksum value to the list 0251 int checksum = str.at(0); 0252 for (int i = 1; i < str.size(); ++i) { 0253 checksum += (str.at(i) * i); 0254 } 0255 checksum = checksum % 103; 0256 str.push_back(checksum); 0257 0258 // lets determine some core attributes about this barcode 0259 int bar_width = 1; // the width of the base unit bar 0260 0261 // this is are mandatory minimum quiet zone 0262 int quiet_zone = bar_width * 10; 0263 //if (quiet_zone < 10) quiet_zone = 10; 0264 0265 // what kind of area do we have to work with 0266 int draw_width = r.width(); 0267 int draw_height = r.height(); 0268 0269 // how long is the value we need to encode? 0270 int val_length = str.size() - 2; // we include start and checksum in are list so 0271 // subtract them out for our calculations 0272 0273 // L = (11C + 35)X 0274 // L length of barcode (excluding quite zone) in units same as X and I 0275 // C the number of characters in the value excluding the start/stop and checksum characters 0276 // X the width of a bar (pixels in our case) 0277 int L; 0278 0279 int C = val_length; 0280 int X = bar_width; 0281 0282 L = (((11 * C) + 35) * X); 0283 0284 // now we have the actual width the barcode will be so can determine the actual 0285 // size of the quiet zone (we assume we center the barcode in the given area 0286 // what should we do if the area is too small???? 0287 // At the moment the way the code is written is we will always start at the minimum 0288 // required quiet zone if we don't have enough space.... I guess we'll just have over-run 0289 // to the right 0290 // 0291 // calculate the starting position based on the alignment option 0292 // for left align we don't need to do anything as the values are already setup for it 0293 if (align == Qt::AlignHCenter) { 0294 int nqz = (draw_width - L) / 2; 0295 if (nqz > quiet_zone) quiet_zone = nqz; 0296 } else if (align == Qt::AlignRight) { 0297 quiet_zone = draw_width - (L + quiet_zone); 0298 } 0299 // left : do nothing 0300 0301 int pos = r.left() + quiet_zone; 0302 int top = r.top(); 0303 0304 if (pPainter) { 0305 pPainter->save(); 0306 0307 QPen oneWide(pPainter->pen()); 0308 oneWide.setWidth(1); 0309 #ifndef Q_OS_WIN32 0310 oneWide.setJoinStyle(Qt::MiterJoin); 0311 #endif 0312 pPainter->setPen(oneWide); 0313 pPainter->setBrush(pPainter->pen().color()); 0314 } 0315 0316 0317 bool space = false; 0318 for (int i = 0; i < str.size(); ++i) { 0319 // loop through each value and render the barcode 0320 int idx = str.at(i); 0321 if (idx < 0 || idx > 105) { 0322 kreportpluginWarning() << "Encountered a non-compliant element while rendering a 3of9 barcode -- skipping"; 0323 continue; 0324 } 0325 space = false; 0326 for (int b = 0; b < 6; b++, space = !space) { 0327 int w = _128codes[idx].values[b] * bar_width; 0328 if (!space && pPainter) { 0329 pPainter->fillRect(pos, top, w, draw_height, pPainter->pen().color()); 0330 } 0331 pos += w; 0332 } 0333 } 0334 0335 // we have to do the stop character separately like this because it has 0336 // 7 elements in it's bar sequence rather than 6 like the others 0337 int STOP_CHARACTER[] = { 2, 3, 3, 1, 1, 1, 2 }; 0338 space = false; 0339 for (int b = 0; b < 7; b++, space = !space) { 0340 int w = STOP_CHARACTER[b] * bar_width; 0341 if (!space && pPainter) { 0342 pPainter->fillRect(pos, top, w, draw_height, pPainter->pen().color()); 0343 } 0344 pos += w; 0345 } 0346 0347 if (pPainter) { 0348 pPainter->restore(); 0349 } 0350 }