2
* OpenRPT report writer and rendering engine
3
* Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
4
* Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
21
* This file contains the implementation of the Code 128 barcode renderer.
22
* All this code assumes a 100dpi rendering surface for it's calculations.
32
#include "renderobjects.h"
34
static const int SETA = 0;
35
static const int SETB = 1;
36
static const int SETC = 2;
38
static const char FNC1 = (char)130;
39
static const char FNC2 = (char)131;
40
static const char FNC3 = (char)132;
41
static const char FNC4 = (char)133;
42
static const char SHIFT = (char)134;
43
static const char CODEA = (char)135;
44
static const char CODEB = (char)136;
45
static const char CODEC = (char)137;
46
static const char STARTA = (char)138;
47
static const char STARTB = (char)139;
48
static const char STARTC = (char)140;
61
static const struct code128 _128codes[] = {
62
// A , B , C , { B S B S B S }, NULL? },
63
{ ' ', ' ', 0, { 2, 1, 2, 2, 2, 2 }, false },
64
{ '!', '!', 1, { 2, 2, 2, 1, 2, 2 }, false },
65
{ '"', '"', 2, { 2, 2, 2, 2, 2, 1 }, false },
66
{ '#', '#', 3, { 1, 2, 1, 2, 2, 3 }, false },
67
{ '$', '$', 4, { 1, 2, 1, 3, 2, 2 }, false },
68
{ '%', '%', 5, { 1, 3, 1, 2, 2, 2 }, false },
69
{ '&', '&', 6, { 1, 2, 2, 2, 1, 3 }, false },
70
{ '\'', '\'', 7, { 1, 2, 2, 3, 1, 2 }, false },
71
{ '(', '(', 8, { 1, 3, 2, 2, 1, 2 }, false },
72
{ ')', ')', 9, { 2, 2, 1, 2, 1, 3 }, false },
73
{ '*', '*', 10, { 2, 2, 1, 3, 1, 2 }, false },
74
{ '+', '+', 11, { 2, 3, 1, 2, 1, 2 }, false },
75
{ ',', ',', 12, { 1, 1, 2, 2, 3, 2 }, false },
76
{ '-', '-', 13, { 1, 2, 2, 1, 3, 2 }, false },
77
{ '.', '.', 14, { 1, 2, 2, 2, 3, 1 }, false },
78
{ '/', '/', 15, { 1, 1, 3, 2, 2, 2 }, false },
79
{ '0', '0', 16, { 1, 2, 3, 1, 2, 2 }, false },
80
{ '1', '1', 17, { 1, 2, 3, 2, 2, 1 }, false },
81
{ '2', '2', 18, { 2, 2, 3, 2, 1, 1 }, false },
82
{ '3', '3', 19, { 2, 2, 1, 1, 3, 2 }, false },
83
{ '4', '4', 20, { 2, 2, 1, 2, 3, 1 }, false },
84
{ '5', '5', 21, { 2, 1, 3, 2, 1, 2 }, false },
85
{ '6', '6', 22, { 2, 2, 3, 1, 1, 2 }, false },
86
{ '7', '7', 23, { 3, 1, 2, 1, 3, 1 }, false },
87
{ '8', '8', 24, { 3, 1, 1, 2, 2, 2 }, false },
88
{ '9', '9', 25, { 3, 2, 1, 1, 2, 2 }, false },
89
{ ':', ':', 26, { 3, 2, 1, 2, 2, 1 }, false },
90
{ ';', ';', 27, { 3, 1, 2, 2, 1, 2 }, false },
91
{ '<', '<', 28, { 3, 2, 2, 1, 1, 2 }, false },
92
{ '=', '=', 29, { 3, 2, 2, 2, 1, 1 }, false },
93
{ '>', '>', 30, { 2, 1, 2, 1, 2, 3 }, false },
94
{ '?', '?', 31, { 2, 1, 2, 3, 2, 1 }, false },
95
{ '@', '@', 32, { 2, 3, 2, 1, 2, 1 }, false },
96
{ 'A', 'A', 33, { 1, 1, 1, 3, 2, 3 }, false },
97
{ 'B', 'B', 34, { 1, 3, 1, 1, 2, 3 }, false },
98
{ 'C', 'C', 35, { 1, 3, 1, 3, 2, 1 }, false },
99
{ 'D', 'D', 36, { 1, 1, 2, 3, 1, 3 }, false },
100
{ 'E', 'E', 37, { 1, 3, 2, 1, 1, 3 }, false },
101
{ 'F', 'F', 38, { 1, 3, 2, 3, 1, 1 }, false },
102
{ 'G', 'G', 39, { 2, 1, 1, 3, 1, 3 }, false },
103
{ 'H', 'H', 40, { 2, 3, 1, 1, 1, 3 }, false },
104
{ 'I', 'I', 41, { 2, 3, 1, 3, 1, 1 }, false },
105
{ 'J', 'J', 42, { 1, 1, 2, 1, 3, 3 }, false },
106
{ 'K', 'K', 43, { 1, 1, 2, 3, 3, 1 }, false },
107
{ 'L', 'L', 44, { 1, 3, 2, 1, 3, 1 }, false },
108
{ 'M', 'M', 45, { 1, 1, 3, 1, 2, 3 }, false },
109
{ 'N', 'N', 46, { 1, 1, 3, 3, 2, 1 }, false },
110
{ 'O', 'O', 47, { 1, 3, 3, 1, 2, 1 }, false },
111
{ 'P', 'P', 48, { 3, 1, 3, 1, 2, 1 }, false },
112
{ 'Q', 'Q', 49, { 2, 1, 1, 3, 3, 1 }, false },
113
{ 'R', 'R', 50, { 2, 3, 1, 1, 3, 1 }, false },
114
{ 'S', 'S', 51, { 2, 1, 3, 1, 1, 3 }, false },
115
{ 'T', 'T', 52, { 2, 1, 3, 3, 1, 1 }, false },
116
{ 'U', 'U', 53, { 2, 1, 3, 1, 3, 1 }, false },
117
{ 'V', 'V', 54, { 3, 1, 1, 1, 2, 3 }, false },
118
{ 'W', 'W', 55, { 3, 1, 1, 3, 2, 1 }, false },
119
{ 'X', 'X', 56, { 3, 3, 1, 1, 2, 1 }, false },
120
{ 'Y', 'Y', 57, { 3, 1, 2, 1, 1, 3 }, false },
121
{ 'Z', 'Z', 58, { 3, 1, 2, 3, 1, 1 }, false },
122
{ '[', '[', 59, { 3, 3, 2, 1, 1, 1 }, false },
123
{ '\\', '\\', 60, { 3, 1, 4, 1, 1, 1 }, false },
124
{ ']', ']', 61, { 2, 2, 1, 4, 1, 1 }, false },
125
{ '^', '^', 62, { 4, 3, 1, 1, 1, 1 }, false },
126
{ '_', '_', 63, { 1, 1, 1, 2, 2, 4 }, false },
127
{ 0x00, '`', 64, { 1, 1, 1, 4, 2, 2 }, false }, // NUL
128
{ 0x01, 'a', 65, { 1, 2, 1, 1, 2, 4 }, false }, // SOH
129
{ 0x02, 'b', 66, { 1, 2, 1, 4, 2, 1 }, false }, // STX
130
{ 0x03, 'c', 67, { 1, 4, 1, 1, 2, 2 }, false }, // ETX
131
{ 0x04, 'd', 68, { 1, 4, 1, 2, 2, 1 }, false }, // EOT
132
{ 0x05, 'e', 69, { 1, 1, 2, 2, 1, 4 }, false }, // ENQ
133
{ 0x06, 'f', 70, { 1, 1, 2, 4, 1, 2 }, false }, // ACK
134
{ 0x07, 'g', 71, { 1, 2, 2, 1, 1, 4 }, false }, // BEL
135
{ 0x08, 'h', 72, { 1, 2, 2, 4, 1, 1 }, false }, // BS
136
{ 0x09, 'i', 73, { 1, 4, 2, 1, 1, 2 }, false }, // HT
137
{ 0x0A, 'j', 74, { 1, 4, 2, 2, 1, 1 }, false }, // LF
138
{ 0x0B, 'k', 75, { 2, 4, 1, 2, 1, 1 }, false }, // VT
139
{ 0x0C, 'l', 76, { 2, 2, 1, 1, 1, 4 }, false }, // FF
140
{ 0x0D, 'm', 77, { 4, 1, 3, 1, 1, 1 }, false }, // CR
141
{ 0x0E, 'n', 78, { 2, 4, 1, 1, 1, 2 }, false }, // SO
142
{ 0x0F, 'o', 79, { 1, 3, 4, 1, 1, 1 }, false }, // SI
143
{ 0x10, 'p', 80, { 1, 1, 1, 2, 4, 2 }, false }, // DLE
144
{ 0x11, 'q', 81, { 1, 2, 1, 1, 4, 2 }, false }, // DC1
145
{ 0x12, 'r', 82, { 1, 2, 1, 2, 4, 1 }, false }, // DC2
146
{ 0x13, 's', 83, { 1, 1, 4, 2, 1, 2 }, false }, // DC3
147
{ 0x14, 't', 84, { 1, 2, 4, 1, 1, 2 }, false }, // DC4
148
{ 0x15, 'u', 85, { 1, 2, 4, 2, 1, 1 }, false }, // NAK
149
{ 0x16, 'v', 86, { 4, 1, 1, 2, 1, 2 }, false }, // SYN
150
{ 0x17, 'w', 87, { 4, 2, 1, 1, 1, 2 }, false }, // ETB
151
{ 0x18, 'x', 88, { 4, 2, 1, 2, 1, 1 }, false }, // CAN
152
{ 0x19, 'y', 89, { 2, 1, 2, 1, 4, 1 }, false }, // EM
153
{ 0x1A, 'z', 90, { 2, 1, 4, 1, 2, 1 }, false }, // SUB
154
{ 0x1B, '{', 91, { 4, 1, 2, 1, 2, 1 }, false }, // ESC
155
{ 0x1C, '|', 92, { 1, 1, 1, 1, 4, 3 }, false }, // FS
156
{ 0x1D, '}', 93, { 1, 1, 1, 3, 4, 1 }, false }, // GS
157
{ 0x1E, '~', 94, { 1, 3, 1, 1, 4, 1 }, false }, // RS
158
{ 0x1F, 0x7F, 95, { 1, 1, 4, 1, 1, 3 }, false }, // US DEL
159
{ FNC3, FNC3, 96, { 1, 1, 4, 3, 1, 1 }, false }, // FNC3 FNC3
160
{ FNC2, FNC2, 97, { 4, 1, 1, 1, 1, 3 }, false }, // FNC2 FNC2
161
{ SHIFT, SHIFT, 98, { 4, 1, 1, 3, 1, 1 }, false }, // SHIFT SHIFT
162
{ CODEC, CODEC, 99, { 1, 1, 3, 1, 4, 1 }, false }, // CODEC CODEC
163
{ CODEB, FNC4, CODEB, { 1, 1, 4, 1, 3, 1 }, false }, // CODEB FNC4 CODEB
164
{ FNC4, CODEA, CODEA, { 3, 1, 1, 1, 4, 1 }, false }, // FNC4 CODEA CODEA
165
{ FNC1, FNC1, FNC1, { 4, 1, 1, 1, 3, 1 }, false }, // FNC1 FNC1 FNC1
166
{ STARTA, STARTA, STARTA, { 2, 1, 1, 4, 1, 2 }, false }, // STARTA
167
{ STARTB, STARTB, STARTB, { 2, 1, 1, 2, 1, 4 }, false }, // STARTB
168
{ STARTC, STARTC, STARTC, { 2, 1, 1, 2, 3, 2 }, false }, // STARTC
170
{ '\0', '\0', '\0', { 0, 0, 0, 0, 0, 0 }, true } // null termininator of list
173
// STOP CHARACTER { 2 3 3 1 1 1 2 }
175
int code128Index(QChar code, int set)
177
for (int idx = 0; _128codes[idx]._null == false; ++idx) {
178
if (set == SETA && _128codes[idx].codea == code.toAscii()) return idx;
179
if (set == SETB && _128codes[idx].codeb == code.toAscii()) return idx;
180
if (set == SETC && _128codes[idx].codec == code.toAscii()) return idx;
182
return -1; // couldn't find it
187
void renderCode128(OROPage * page, const QRectF & r, const QString & _str, int align)
192
// create the list.. if the list is empty then just set a start code and move on
201
for (i = 0; i < _str.length(); ++i) {
203
rank_a += (code128Index(c, SETA) != -1 ? 1 : 0);
204
rank_b += (code128Index(c, SETB) != -1 ? 1 : 0);
205
rank_c += (c >= '0' && c <= '9' ? 1 : 0);
207
if (rank_c == _str.length() && ((rank_c % 2) == 0 || rank_c > 4)) {
208
// every value in the is a digit so we are going to go with mode C
209
// and we have an even number or we have more than 4 values
211
if ((rank_c % 2) == 1) {
212
str.push_back(104); // START B
214
str.push_back(code128Index(c, SETB));
215
str.push_back(99); // MODE C
218
str.push_back(105); // START C
220
for (i = i; i < _str.length(); i += 2) {
228
str.push_back(int((a * 10) + b));
231
// start in the mode that had the higher number of hits and then
232
// just shift into the opposite mode as needed
233
int set = (rank_a > rank_b ? SETA : SETB);
234
str.push_back((rank_a > rank_b ? 103 : 104));
236
for (i = 0; i < _str.length(); ++i) {
238
v = code128Index(c, set);
240
v = code128Index(c, (set == SETA ? SETB : SETA));
242
str.push_back(98); // SHIFT
251
// calculate and append the checksum value to the list
252
int checksum = str.at(0);
253
for (i = 1; i < str.size(); ++i)
254
checksum += (str.at(i) * i);
255
checksum = checksum % 103;
256
str.push_back(checksum);
258
// lets determine some core attributes about this barcode
259
qreal bar_width = 1; // the width of the base unit bar 1/100 inch
261
// this is are mandatory minimum quiet zone
262
qreal quiet_zone = bar_width * 10;
263
if (quiet_zone < 0.1)
266
// what kind of area do we have to work with
267
qreal draw_width = r.width();
268
qreal draw_height = r.height();
270
// how long is the value we need to encode?
271
int val_length = str.size() - 2; // we include start and checksum in are list so
272
// subtract them out for our calculations
275
// L length of barcode (excluding quite zone) in units same as X and I
276
// C the number of characters in the value excluding the start/stop and checksum characters
277
// X the width of a bar (pixels in our case)
280
qreal C = val_length;
283
L = (((11.0 * C) + 35.0) * X);
285
// now we have the actual width the barcode will be so can determine the actual
286
// size of the quiet zone (we assume we center the barcode in the given area
287
// what should we do if the area is too small????
288
// At the moment the way the code is written is we will always start at the minimum
289
// required quiet zone if we don't have enough space.... I guess we'll just have over-run
292
// calculate the starting position based on the alignment option
293
// for left align we don't need to do anything as the values are already setup for it
294
if (align == 1) { // center
295
qreal nqz = (draw_width - L) / 2.0;
296
if (nqz > quiet_zone)
298
} else if (align > 1) // right
299
quiet_zone = draw_width - (L + quiet_zone);
300
// else if(align < 1) {} // left : do nothing
302
qreal pos = r.left() + quiet_zone;
306
QBrush brush(QColor("black"));
311
for (i = 0; i < str.size(); ++i) {
312
// loop through each value and render the barcode
314
if (idx < 0 || idx > 105) {
315
qDebug("Encountered a non-compliant element while rendering a 3of9 barcode -- skipping");
319
for (b = 0; b < 6; ++b, space = !space) {
320
w = _128codes[idx].values[b] * bar_width;
322
ORORect * rect = new ORORect();
324
rect->setBrush(brush);
325
rect->setRect(QRectF(pos, top, w, draw_height));
326
page->addPrimitive(rect);
332
// we have to do the stop character separately like this because it has
333
// 7 elements in it's bar sequence rather than 6 like the others
334
int STOP_CHARACTER[] = { 2, 3, 3, 1, 1, 1, 2 };
336
for (b = 0; b < 7; ++b, space = !space) {
337
w = STOP_CHARACTER[b] * bar_width;
339
ORORect * rect = new ORORect();
341
rect->setBrush(brush);
342
rect->setRect(QRectF(pos, top, w, draw_height));
343
page->addPrimitive(rect);