KReport

3of9paint.cpp
1/* This file is part of the KDE project
2 * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
3 * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * This file contains the implementation of the 3of9 barcode renderer.
21 * All this code assumes a 100dpi rendering surface for it's calculations.
22 */
23
24#include <QString>
25#include <QPainter>
26#include <QPen>
27#include <QBrush>
28
29#include "kreportplugin_debug.h"
30
31struct code3of9 {
32 char code;
33 int values[9];
34};
35
36const struct code3of9 _3of9codes[] = {
37 { '0', { 0, 0, 0, 1, 1, 0, 1, 0, 0 } },
38 { '1', { 1, 0, 0, 1, 0, 0, 0, 0, 1 } },
39 { '2', { 0, 0, 1, 1, 0, 0, 0, 0, 1 } },
40 { '3', { 1, 0, 1, 1, 0, 0, 0, 0, 0 } },
41 { '4', { 0, 0, 0, 1, 1, 0, 0, 0, 1 } },
42 { '5', { 1, 0, 0, 1, 1, 0, 0, 0, 0 } },
43 { '6', { 0, 0, 1, 1, 1, 0, 0, 0, 0 } },
44 { '7', { 0, 0, 0, 1, 0, 0, 1, 0, 1 } },
45 { '8', { 1, 0, 0, 1, 0, 0, 1, 0, 0 } },
46 { '9', { 0, 0, 1, 1, 0, 0, 1, 0, 0 } },
47
48 { 'A', { 1, 0, 0, 0, 0, 1, 0, 0, 1 } },
49 { 'B', { 0, 0, 1, 0, 0, 1, 0, 0, 1 } },
50 { 'C', { 1, 0, 1, 0, 0, 1, 0, 0, 0 } },
51 { 'D', { 0, 0, 0, 0, 1, 1, 0, 0, 1 } },
52 { 'E', { 1, 0, 0, 0, 1, 1, 0, 0, 0 } },
53 { 'F', { 0, 0, 1, 0, 1, 1, 0, 0, 0 } },
54 { 'G', { 0, 0, 0, 0, 0, 1, 1, 0, 1 } },
55 { 'H', { 1, 0, 0, 0, 0, 1, 1, 0, 0 } },
56 { 'I', { 0, 0, 1, 0, 0, 1, 1, 0, 0 } },
57 { 'J', { 0, 0, 0, 0, 1, 1, 1, 0, 0 } },
58 { 'K', { 1, 0, 0, 0, 0, 0, 0, 1, 1 } },
59 { 'L', { 0, 0, 1, 0, 0, 0, 0, 1, 1 } },
60 { 'M', { 1, 0, 1, 0, 0, 0, 0, 1, 0 } },
61 { 'N', { 0, 0, 0, 0, 1, 0, 0, 1, 1 } },
62 { 'O', { 1, 0, 0, 0, 1, 0, 0, 1, 0 } },
63 { 'P', { 0, 0, 1, 0, 1, 0, 0, 1, 0 } },
64 { 'Q', { 0, 0, 0, 0, 0, 0, 1, 1, 1 } },
65 { 'R', { 1, 0, 0, 0, 0, 0, 1, 1, 0 } },
66 { 'S', { 0, 0, 1, 0, 0, 0, 1, 1, 0 } },
67 { 'T', { 0, 0, 0, 0, 1, 0, 1, 1, 0 } },
68 { 'U', { 1, 1, 0, 0, 0, 0, 0, 0, 1 } },
69 { 'V', { 0, 1, 1, 0, 0, 0, 0, 0, 1 } },
70 { 'W', { 1, 1, 1, 0, 0, 0, 0, 0, 0 } },
71 { 'X', { 0, 1, 0, 0, 1, 0, 0, 0, 1 } },
72 { 'Y', { 1, 1, 0, 0, 1, 0, 0, 0, 0 } },
73 { 'Z', { 0, 1, 1, 0, 1, 0, 0, 0, 0 } },
74
75 { '-', { 0, 1, 0, 0, 0, 0, 1, 0, 1 } },
76 { '.', { 1, 1, 0, 0, 0, 0, 1, 0, 0 } },
77 { ' ', { 0, 1, 1, 0, 0, 0, 1, 0, 0 } },
78 { '$', { 0, 1, 0, 1, 0, 1, 0, 0, 0 } },
79 { '/', { 0, 1, 0, 1, 0, 0, 0, 1, 0 } },
80 { '+', { 0, 1, 0, 0, 0, 1, 0, 1, 0 } },
81 { '%', { 0, 0, 0, 1, 0, 1, 0, 1, 0 } },
82
83 { '*', { 0, 1, 0, 0, 1, 0, 1, 0, 0 } }, // this is a special start/stop character
84
85 { '\0', { 0, 0, 0, 0, 0, 0, 0, 0, 0 } } // null termininator of list
86};
87
88int codeIndexP(QChar code)
89{
90 // we are a case insensitive search
91 const char latin1Code = code.toUpper().toLatin1();
92 for (int idx = 0; _3of9codes[idx].code != '\0'; idx++) {
93 if (_3of9codes[idx].code == latin1Code) return idx;
94 }
95 return -1; // couldn't find it
96}
97
98void render3of9(const QRect & r, const QString & _str, Qt::Alignment align, QPainter * pPainter)
99{
100 QString str = _str;
101 // lets determine some core attributes about this barcode
102 int narrow_bar = 1; // a narrow bar is 1px wide
103 int interchange_gap = narrow_bar; // the space between each 'set' of bars
104 int bar_width_mult = 2; // the wide bar width multiple of the narrow bar
105
106 // this is are mandatory minimum quiet zone
107 int quiet_zone = narrow_bar * 10;
108 //if (quiet_zone < 10) quiet_zone = 10;
109
110 // what kind of area do we have to work with
111 int draw_width = r.width();
112 int draw_height = r.height();
113
114 // how long is the value we need to encode?
115 int val_length = str.length();
116
117 // L = (C + 2)(3N + 6)X + (C + 1)I
118 // L length of barcode (excluding quite zone) in units same as X and I
119 // C the number of characters in the value excluding the start/stop
120 // N the bar width multiple for wide bars
121 // X the width of a bar (pixels in our case)
122 // I the interchange gap in the same units as X (value is same as X for our case)
123 int L;
124
125 int C = val_length;
126 int N = bar_width_mult;
127 int X = narrow_bar;
128 int I = interchange_gap;
129
130 L = ((C + 2) * (3 * N + 6) * X) + ((C + 1) * I);
131
132 // now we have the actual width the barcode will be so can determine the actual
133 // size of the quiet zone (we assume we center the barcode in the given area
134 // what should we do if the area is too small????
135 // At the moment the way the code is written is we will always start at the minimum
136 // required quiet zone if we don't have enough space.... I guess we'll just have over-run
137 // to the right
138 //
139 // calculate the starting position based on the alignment option
140 // for left align we don't need to do anything as the values are already setup for it
141 if (align == Qt::AlignHCenter) {
142 int nqz = (draw_width - L) / 2;
143 if (nqz > quiet_zone) quiet_zone = nqz;
144 } else if (align == Qt::AlignRight) {
145 quiet_zone = draw_width - (L + quiet_zone);
146 }
147 // left : do nothing
148
149 int pos = r.left() + quiet_zone;
150 int top = r.top();
151
152 // ok we need to prepend and append the str with a *
153 str = QLatin1Char('*') + str + QLatin1Char('*');
154
155 if (pPainter) {
156 pPainter->save();
157
158 QPen oneWide(pPainter->pen());
159 oneWide.setWidth(1);
160#ifndef Q_OS_WIN32
161 oneWide.setJoinStyle(Qt::MiterJoin);
162#endif
163 pPainter->setPen(oneWide);
164 pPainter->setBrush(pPainter->pen().color());
165 }
166 for (int i = 0; i < str.length(); i++) {
167 // loop through each char and render the barcode
168 QChar c = str.at(i);
169 int idx = codeIndexP(c);
170 if (idx == -1) {
171 kreportpluginWarning() << "Encountered a non-compliant character while rendering a 3of9 barcode -- skipping";
172 continue;
173 }
174
175 bool space = false;
176 for (int b = 0; b < 9; b++, space = !space) {
177 int w = (_3of9codes[idx].values[b] == 1 ? narrow_bar * bar_width_mult : narrow_bar);
178 if (!space && pPainter) {
179 pPainter->fillRect(pos, top, w, draw_height, pPainter->pen().color());
180 }
181 pos += w;
182 }
183 pos += interchange_gap;
184 }
185 if (pPainter) {
186 pPainter->restore();
187 }
188}
char32_t toUpper(char32_t ucs4)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QPen & pen() const const
void restore()
void save()
void setBrush(Qt::BrushStyle style)
void setPen(Qt::PenStyle style)
QColor color() const const
int height() const const
int left() const const
int top() const const
int width() const const
const QChar at(qsizetype position) const const
qsizetype length() const const
typedef Alignment
MiterJoin
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:06:04 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.