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 3of9 barcode renderer. 0021 * All this code assumes a 100dpi rendering surface for it's calculations. 0022 */ 0023 0024 #include <QString> 0025 #include <QPainter> 0026 #include <QPen> 0027 #include <QBrush> 0028 0029 #include "kreportplugin_debug.h" 0030 0031 struct code3of9 { 0032 char code; 0033 int values[9]; 0034 }; 0035 0036 const struct code3of9 _3of9codes[] = { 0037 { '0', { 0, 0, 0, 1, 1, 0, 1, 0, 0 } }, 0038 { '1', { 1, 0, 0, 1, 0, 0, 0, 0, 1 } }, 0039 { '2', { 0, 0, 1, 1, 0, 0, 0, 0, 1 } }, 0040 { '3', { 1, 0, 1, 1, 0, 0, 0, 0, 0 } }, 0041 { '4', { 0, 0, 0, 1, 1, 0, 0, 0, 1 } }, 0042 { '5', { 1, 0, 0, 1, 1, 0, 0, 0, 0 } }, 0043 { '6', { 0, 0, 1, 1, 1, 0, 0, 0, 0 } }, 0044 { '7', { 0, 0, 0, 1, 0, 0, 1, 0, 1 } }, 0045 { '8', { 1, 0, 0, 1, 0, 0, 1, 0, 0 } }, 0046 { '9', { 0, 0, 1, 1, 0, 0, 1, 0, 0 } }, 0047 0048 { 'A', { 1, 0, 0, 0, 0, 1, 0, 0, 1 } }, 0049 { 'B', { 0, 0, 1, 0, 0, 1, 0, 0, 1 } }, 0050 { 'C', { 1, 0, 1, 0, 0, 1, 0, 0, 0 } }, 0051 { 'D', { 0, 0, 0, 0, 1, 1, 0, 0, 1 } }, 0052 { 'E', { 1, 0, 0, 0, 1, 1, 0, 0, 0 } }, 0053 { 'F', { 0, 0, 1, 0, 1, 1, 0, 0, 0 } }, 0054 { 'G', { 0, 0, 0, 0, 0, 1, 1, 0, 1 } }, 0055 { 'H', { 1, 0, 0, 0, 0, 1, 1, 0, 0 } }, 0056 { 'I', { 0, 0, 1, 0, 0, 1, 1, 0, 0 } }, 0057 { 'J', { 0, 0, 0, 0, 1, 1, 1, 0, 0 } }, 0058 { 'K', { 1, 0, 0, 0, 0, 0, 0, 1, 1 } }, 0059 { 'L', { 0, 0, 1, 0, 0, 0, 0, 1, 1 } }, 0060 { 'M', { 1, 0, 1, 0, 0, 0, 0, 1, 0 } }, 0061 { 'N', { 0, 0, 0, 0, 1, 0, 0, 1, 1 } }, 0062 { 'O', { 1, 0, 0, 0, 1, 0, 0, 1, 0 } }, 0063 { 'P', { 0, 0, 1, 0, 1, 0, 0, 1, 0 } }, 0064 { 'Q', { 0, 0, 0, 0, 0, 0, 1, 1, 1 } }, 0065 { 'R', { 1, 0, 0, 0, 0, 0, 1, 1, 0 } }, 0066 { 'S', { 0, 0, 1, 0, 0, 0, 1, 1, 0 } }, 0067 { 'T', { 0, 0, 0, 0, 1, 0, 1, 1, 0 } }, 0068 { 'U', { 1, 1, 0, 0, 0, 0, 0, 0, 1 } }, 0069 { 'V', { 0, 1, 1, 0, 0, 0, 0, 0, 1 } }, 0070 { 'W', { 1, 1, 1, 0, 0, 0, 0, 0, 0 } }, 0071 { 'X', { 0, 1, 0, 0, 1, 0, 0, 0, 1 } }, 0072 { 'Y', { 1, 1, 0, 0, 1, 0, 0, 0, 0 } }, 0073 { 'Z', { 0, 1, 1, 0, 1, 0, 0, 0, 0 } }, 0074 0075 { '-', { 0, 1, 0, 0, 0, 0, 1, 0, 1 } }, 0076 { '.', { 1, 1, 0, 0, 0, 0, 1, 0, 0 } }, 0077 { ' ', { 0, 1, 1, 0, 0, 0, 1, 0, 0 } }, 0078 { '$', { 0, 1, 0, 1, 0, 1, 0, 0, 0 } }, 0079 { '/', { 0, 1, 0, 1, 0, 0, 0, 1, 0 } }, 0080 { '+', { 0, 1, 0, 0, 0, 1, 0, 1, 0 } }, 0081 { '%', { 0, 0, 0, 1, 0, 1, 0, 1, 0 } }, 0082 0083 { '*', { 0, 1, 0, 0, 1, 0, 1, 0, 0 } }, // this is a special start/stop character 0084 0085 { '\0', { 0, 0, 0, 0, 0, 0, 0, 0, 0 } } // null termininator of list 0086 }; 0087 0088 int codeIndexP(QChar code) 0089 { 0090 // we are a case insensitive search 0091 const char latin1Code = code.toUpper().toLatin1(); 0092 for (int idx = 0; _3of9codes[idx].code != '\0'; idx++) { 0093 if (_3of9codes[idx].code == latin1Code) return idx; 0094 } 0095 return -1; // couldn't find it 0096 } 0097 0098 void render3of9(const QRect & r, const QString & _str, Qt::Alignment align, QPainter * pPainter) 0099 { 0100 QString str = _str; 0101 // lets determine some core attributes about this barcode 0102 int narrow_bar = 1; // a narrow bar is 1px wide 0103 int interchange_gap = narrow_bar; // the space between each 'set' of bars 0104 int bar_width_mult = 2; // the wide bar width multiple of the narrow bar 0105 0106 // this is are mandatory minimum quiet zone 0107 int quiet_zone = narrow_bar * 10; 0108 //if (quiet_zone < 10) quiet_zone = 10; 0109 0110 // what kind of area do we have to work with 0111 int draw_width = r.width(); 0112 int draw_height = r.height(); 0113 0114 // how long is the value we need to encode? 0115 int val_length = str.length(); 0116 0117 // L = (C + 2)(3N + 6)X + (C + 1)I 0118 // L length of barcode (excluding quite zone) in units same as X and I 0119 // C the number of characters in the value excluding the start/stop 0120 // N the bar width multiple for wide bars 0121 // X the width of a bar (pixels in our case) 0122 // I the interchange gap in the same units as X (value is same as X for our case) 0123 int L; 0124 0125 int C = val_length; 0126 int N = bar_width_mult; 0127 int X = narrow_bar; 0128 int I = interchange_gap; 0129 0130 L = ((C + 2) * (3 * N + 6) * X) + ((C + 1) * I); 0131 0132 // now we have the actual width the barcode will be so can determine the actual 0133 // size of the quiet zone (we assume we center the barcode in the given area 0134 // what should we do if the area is too small???? 0135 // At the moment the way the code is written is we will always start at the minimum 0136 // required quiet zone if we don't have enough space.... I guess we'll just have over-run 0137 // to the right 0138 // 0139 // calculate the starting position based on the alignment option 0140 // for left align we don't need to do anything as the values are already setup for it 0141 if (align == Qt::AlignHCenter) { 0142 int nqz = (draw_width - L) / 2; 0143 if (nqz > quiet_zone) quiet_zone = nqz; 0144 } else if (align == Qt::AlignRight) { 0145 quiet_zone = draw_width - (L + quiet_zone); 0146 } 0147 // left : do nothing 0148 0149 int pos = r.left() + quiet_zone; 0150 int top = r.top(); 0151 0152 // ok we need to prepend and append the str with a * 0153 str = QLatin1Char('*') + str + QLatin1Char('*'); 0154 0155 if (pPainter) { 0156 pPainter->save(); 0157 0158 QPen oneWide(pPainter->pen()); 0159 oneWide.setWidth(1); 0160 #ifndef Q_OS_WIN32 0161 oneWide.setJoinStyle(Qt::MiterJoin); 0162 #endif 0163 pPainter->setPen(oneWide); 0164 pPainter->setBrush(pPainter->pen().color()); 0165 } 0166 for (int i = 0; i < str.length(); i++) { 0167 // loop through each char and render the barcode 0168 QChar c = str.at(i); 0169 int idx = codeIndexP(c); 0170 if (idx == -1) { 0171 kreportpluginWarning() << "Encountered a non-compliant character while rendering a 3of9 barcode -- skipping"; 0172 continue; 0173 } 0174 0175 bool space = false; 0176 for (int b = 0; b < 9; b++, space = !space) { 0177 int w = (_3of9codes[idx].values[b] == 1 ? narrow_bar * bar_width_mult : narrow_bar); 0178 if (!space && pPainter) { 0179 pPainter->fillRect(pos, top, w, draw_height, pPainter->pen().color()); 0180 } 0181 pos += w; 0182 } 0183 pos += interchange_gap; 0184 } 0185 if (pPainter) { 0186 pPainter->restore(); 0187 } 0188 }