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