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 EAN and similar
22
* formats for rendering purposes. All this code assumes a 100dpi
23
* rendering surface for it's calculations.
33
#include "renderobjects.h"
35
static const int LEFTHAND_ODD = 0;
36
static const int LEFTHAND_EVEN = 1;
37
static const int RIGHTHAND = 2;
39
static int _encodings[10][3][7] = {
40
/* LEFTHAND_ODD */ /* LEFTHAND_EVEN */ /* RIGHTHAND */
41
{ { 0, 0, 0, 1, 1, 0, 1}, { 0, 1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0 } }, // 0
42
{ { 0, 0, 1, 1, 0, 0, 1}, { 0, 1, 1, 0, 0, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0 } }, // 1
43
{ { 0, 0, 1, 0, 0, 1, 1}, { 0, 0, 1, 1, 0, 1, 1 }, { 1, 1, 0, 1, 1, 0, 0 } }, // 2
44
{ { 0, 1, 1, 1, 1, 0, 1}, { 0, 1, 0, 0, 0, 0, 1 }, { 1, 0, 0, 0, 0, 1, 0 } }, // 3
45
{ { 0, 1, 0, 0, 0, 1, 1}, { 0, 0, 1, 1, 1, 0, 1 }, { 1, 0, 1, 1, 1, 0, 0 } }, // 4
46
{ { 0, 1, 1, 0, 0, 0, 1}, { 0, 1, 1, 1, 0, 0, 1 }, { 1, 0, 0, 1, 1, 1, 0 } }, // 5
47
{ { 0, 1, 0, 1, 1, 1, 1}, { 0, 0, 0, 0, 1, 0, 1 }, { 1, 0, 1, 0, 0, 0, 0 } }, // 6
48
{ { 0, 1, 1, 1, 0, 1, 1}, { 0, 0, 1, 0, 0, 0, 1 }, { 1, 0, 0, 0, 1, 0, 0 } }, // 7
49
{ { 0, 1, 1, 0, 1, 1, 1}, { 0, 0, 0, 1, 0, 0, 1 }, { 1, 0, 0, 1, 0, 0, 0 } }, // 8
50
{ { 0, 0, 0, 1, 0, 1, 1}, { 0, 0, 1, 0, 1, 1, 1 }, { 1, 1, 1, 0, 1, 0, 0 } } // 9
53
static const int odd = LEFTHAND_ODD;
54
static const int even = LEFTHAND_EVEN;
56
static int _parity[10][6] = {
57
{ odd, odd, odd, odd, odd, odd }, // 0
58
{ odd, odd, even, odd, even, even }, // 1
59
{ odd, odd, even, even, odd, even }, // 2
60
{ odd, odd, even, even, even, odd }, // 3
61
{ odd, even, odd, odd, even, even }, // 4
62
{ odd, even, even, odd, odd, even }, // 5
63
{ odd, even, even, even, odd, odd }, // 6
64
{ odd, even, odd, even, odd, even }, // 7
65
{ odd, even, odd, even, even, odd }, // 8
66
{ odd, even, even, odd, even, odd } // 9
69
static int _upcparenc[10][2][6] = {
70
/* PARITY 0 */ /* PARITY 1 */
71
{ { even, even, even, odd, odd, odd }, { odd, odd, odd, even, even, even } }, // 0
72
{ { even, even, odd, even, odd, odd }, { odd, odd, even, odd, even, even } }, // 1
73
{ { even, even, odd, odd, even, odd }, { odd, odd, even, even, odd, even } }, // 2
74
{ { even, even, odd, odd, odd, even }, { odd, odd, even, even, even, odd } }, // 3
75
{ { even, odd, even, even, odd, odd }, { odd, even, odd, odd, even, even } }, // 4
76
{ { even, odd, odd, even, even, odd }, { odd, even, even, odd, odd, even } }, // 5
77
{ { even, odd, odd, odd, even, even }, { odd, even, even, even, odd, odd } }, // 6
78
{ { even, odd, even, odd, even, odd }, { odd, even, odd, even, odd, even } }, // 7
79
{ { even, odd, even, odd, odd, even }, { odd, even, odd, even, even, odd } }, // 8
80
{ { even, odd, odd, even, odd, even }, { odd, even, even, odd, even, odd } } // 9
84
void renderCodeEAN13(const QRect & r, const QString & _str, int align, QPainter * pPainter)
89
// initialize all the values just so we can be predictable
90
for (i = 0; i < 13; ++i) {
94
// verify that the passed in string is valid
95
// if it's not either twelve or thirteen characters
96
// then it must be invalid to begin with
97
if (_str.length() != 12 && _str.length() != 13) return;
98
// loop through and convert each char to a digit.
99
// if we can't convert all characters then this is
101
for (i = 0; i < _str.length(); ++i) {
102
val[i] = ((QChar) _str.at(i)).digitValue();
103
if (val[i] == -1) return;
106
// calculate and append the checksum value
107
int old_sum = val[12]; // get the old check sum value (-1 if none was set)
109
for (i = 0; i < 12; ++i) {
110
checksum += val[i] * (i % 2 ? 3 : 1);
112
checksum = (checksum % 10);
113
if (checksum) checksum = 10 - checksum;
116
// if we had an old checksum value and if it doesn't match what we came
117
// up with then the string must be invalid so we will bail
118
if (old_sum != -1 && old_sum != checksum) return;
121
// lets determine some core attributes about this barcode
122
int bar_width = 1; // the width of the base unit bar
124
// this is are mandatory minimum quiet zone
125
int quiet_zone = bar_width * 10;
126
if (quiet_zone < 10) quiet_zone = 10;
128
// what kind of area do we have to work with
129
int draw_width = r.width();
130
int draw_height = r.height() - 2;
133
// L length of barcode (excluding quite zone) in units same as X and I
134
// X the width of a bar (pixels in our case)
141
// now we have the actual width the barcode will be so can determine the actual
142
// size of the quiet zone (we assume we center the barcode in the given area
143
// what should we do if the area is too small????
144
// At the moment the way the code is written is we will always start at the minimum
145
// required quiet zone if we don't have enough space.... I guess we'll just have over-run
148
// calculate the starting position based on the alignment option
149
// for left align we don't need to do anything as the values are already setup for it
150
if (align == 1) { // center
151
int nqz = (draw_width - L) / 2;
152
if (nqz > quiet_zone) quiet_zone = nqz;
153
} else if (align > 1) { // right
154
quiet_zone = draw_width - (L + quiet_zone);
155
} // else if(align < 1) {} // left : do nothing
157
int pos = r.left() + quiet_zone;
163
QPen oneWide(pPainter->pen());
166
oneWide.setJoinStyle(Qt::MiterJoin);
168
pPainter->setPen(oneWide);
169
pPainter->setBrush(pPainter->pen().color());
174
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
176
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
180
for (i = 0; i < 6; ++i) {
182
for (w = 0; w < 7; ++w) {
183
if (_encodings[b][_parity[val[0]][i]][w]) {
184
pPainter->fillRect(pos, top, 1, draw_height - 7, pPainter->pen().color());
190
// render center guard
192
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
194
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
198
for (i = 0; i < 6; ++i) {
200
for (w = 0; w < 7; ++w) {
201
if (_encodings[b][RIGHTHAND][w]) {
202
pPainter->fillRect(pos, top, 1, draw_height - 7, pPainter->pen().color());
208
// render close guard
209
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
211
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
213
QString parstr = QString("%1").arg(val[0]);
214
QString leftstr = QString().sprintf("%d%d%d%d%d%d",
215
val[1], val[2], val[3], val[4], val[5], val[6]);
216
QString rightstr = QString().sprintf("%d%d%d%d%d%d",
217
val[7], val[8], val[9], val[10], val[11], val[12]);
218
pPainter->setFont(QFont("Arial", 6));
219
pPainter->drawText(r.left(), r.top() + draw_height - 12,
220
quiet_zone - 2, 12, Qt::AlignRight | Qt::AlignTop,
222
pPainter->drawText(r.left() + quiet_zone + 3,
223
(r.top() + draw_height) - 7,
224
42, 10, Qt::AlignHCenter | Qt::AlignTop,
226
pPainter->drawText(r.left() + quiet_zone + 50,
227
(r.top() + draw_height) - 7,
228
42, 10, Qt::AlignHCenter | Qt::AlignTop,
235
void renderCodeUPCA(const QRect & r, const QString & _str, int align, QPainter * pPainter)
240
// initialize all the values just so we can be predictable
241
for (i = 0; i < 13; ++i) {
245
// verify that the passed in string is valid
246
// if it's not either twelve or thirteen characters
247
// then it must be invalid to begin with
248
if (_str.length() != 11 && _str.length() != 12) return;
249
// loop through and convert each char to a digit.
250
// if we can't convert all characters then this is
253
for (i = 0; i < _str.length(); ++i) {
254
val[i+1] = ((QChar) _str.at(i)).digitValue();
255
if (val[i+1] == -1) return;
258
// calculate and append the checksum value
259
int old_sum = val[12]; // get the old check sum value (-1 if none was set)
261
for (i = 0; i < 12; ++i) {
262
checksum += val[i] * (i % 2 ? 3 : 1);
264
checksum = (checksum % 10);
265
if (checksum) checksum = 10 - checksum;
268
// if we had an old checksum value and if it doesn't match what we came
269
// up with then the string must be invalid so we will bail
270
if (old_sum != -1 && old_sum != checksum) return;
273
// lets determine some core attributes about this barcode
274
int bar_width = 1; // the width of the base unit bar
276
// this is are mandatory minimum quiet zone
277
int quiet_zone = bar_width * 10;
278
if (quiet_zone < 10) quiet_zone = 10;
280
// what kind of area do we have to work with
281
int draw_width = r.width();
282
int draw_height = r.height() - 2;
285
// L length of barcode (excluding quite zone) in units same as X and I
286
// X the width of a bar (pixels in our case)
293
// now we have the actual width the barcode will be so can determine the actual
294
// size of the quiet zone (we assume we center the barcode in the given area
295
// what should we do if the area is too small????
296
// At the moment the way the code is written is we will always start at the minimum
297
// required quiet zone if we don't have enough space.... I guess we'll just have over-run
300
// calculate the starting position based on the alignment option
301
// for left align we don't need to do anything as the values are already setup for it
302
if (align == 1) { // center
303
int nqz = (draw_width - L) / 2;
304
if (nqz > quiet_zone) quiet_zone = nqz;
305
} else if (align > 1) { // right
306
quiet_zone = draw_width - (L + quiet_zone);
307
} // else if(align < 1) {} // left : do nothing
309
int pos = r.left() + quiet_zone;
315
QPen oneWide(pPainter->pen());
318
oneWide.setJoinStyle(Qt::MiterJoin);
320
pPainter->setPen(oneWide);
321
pPainter->setBrush(pPainter->pen().color());
326
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
328
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
332
for (i = 0; i < 6; ++i) {
334
for (w = 0; w < 7; ++w) {
335
if (_encodings[b][_parity[val[0]][i]][w]) {
336
pPainter->fillRect(pos, top, 1, draw_height - (i == 0 ? 0 : 7), pPainter->pen().color());
342
// render center guard
344
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
346
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
350
for (i = 0; i < 6; ++i) {
352
for (w = 0; w < 7; ++w) {
353
if (_encodings[b][RIGHTHAND][w]) {
354
pPainter->fillRect(pos, top, 1, draw_height - (i == 5 ? 0 : 7), pPainter->pen().color());
360
// render close guard
361
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
363
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
365
QString parstr = QString("%1").arg(val[1]);
366
QString chkstr = QString("%1").arg(val[12]);
367
QString leftstr = QString().sprintf("%d%d%d%d%d",
368
val[2], val[3], val[4], val[5], val[6]);
369
QString rightstr = QString().sprintf("%d%d%d%d%d",
370
val[7], val[8], val[9], val[10], val[11]);
371
pPainter->setFont(QFont("Arial", 6));
372
pPainter->drawText(r.left(), r.top() + draw_height - 12,
373
quiet_zone - 2, 12, Qt::AlignRight | Qt::AlignTop,
375
pPainter->drawText(r.left() + quiet_zone + 10,
376
(r.top() + draw_height) - 7,
377
35, 10, Qt::AlignHCenter | Qt::AlignTop,
379
pPainter->drawText(r.left() + quiet_zone + 50,
380
(r.top() + draw_height) - 7,
381
35, 10, Qt::AlignHCenter | Qt::AlignTop,
383
pPainter->drawText(r.left() + quiet_zone + L + 2, r.top() + draw_height - 12,
384
8, 12, Qt::AlignLeft | Qt::AlignTop,
391
void renderCodeEAN8(const QRect & r, const QString & _str, int align, QPainter * pPainter)
396
// initialize all the values just so we can be predictable
397
for (i = 0; i < 8; ++i) {
401
// verify that the passed in string is valid
402
// if it's not either twelve or thirteen characters
403
// then it must be invalid to begin with
404
if (_str.length() != 7 && _str.length() != 8) return;
405
// loop through and convert each char to a digit.
406
// if we can't convert all characters then this is
408
for (i = 0; i < _str.length(); ++i) {
409
val[i] = ((QChar) _str.at(i)).digitValue();
410
if (val[i] == -1) return;
413
// calculate and append the checksum value
414
int old_sum = val[7]; // get the old check sum value (-1 if none was set)
416
for (i = 0; i < 7; ++i) {
417
checksum += val[i] * (i % 2 ? 1 : 3);
419
checksum = (checksum % 10);
420
if (checksum) checksum = 10 - checksum;
423
// if we had an old checksum value and if it doesn't match what we came
424
// up with then the string must be invalid so we will bail
425
if (old_sum != -1 && old_sum != checksum) return;
428
// lets determine some core attributes about this barcode
429
int bar_width = 1; // the width of the base unit bar
431
// this is are mandatory minimum quiet zone
432
int quiet_zone = bar_width * 10;
433
if (quiet_zone < 10) quiet_zone = 10;
435
// what kind of area do we have to work with
436
int draw_width = r.width();
437
int draw_height = r.height() - 2;
440
// L length of barcode (excluding quite zone) in units same as X and I
441
// X the width of a bar (pixels in our case)
448
// now we have the actual width the barcode will be so can determine the actual
449
// size of the quiet zone (we assume we center the barcode in the given area
450
// what should we do if the area is too small????
451
// At the moment the way the code is written is we will always start at the minimum
452
// required quiet zone if we don't have enough space.... I guess we'll just have over-run
455
// calculate the starting position based on the alignment option
456
// for left align we don't need to do anything as the values are already setup for it
457
if (align == 1) { // center
458
int nqz = (draw_width - L) / 2;
459
if (nqz > quiet_zone) quiet_zone = nqz;
460
} else if (align > 1) { // right
461
quiet_zone = draw_width - (L + quiet_zone);
462
} // else if(align < 1) {} // left : do nothing
464
int pos = r.left() + quiet_zone;
470
QPen oneWide(pPainter->pen());
473
oneWide.setJoinStyle(Qt::MiterJoin);
475
pPainter->setPen(oneWide);
476
pPainter->setBrush(pPainter->pen().color());
481
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
483
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
487
for (i = 0; i < 4; ++i) {
489
for (w = 0; w < 7; ++w) {
490
if (_encodings[b][LEFTHAND_ODD][w]) {
491
pPainter->fillRect(pos, top, 1, draw_height - 6, pPainter->pen().color());
497
// render center guard
499
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
501
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
505
for (i = 0; i < 4; ++i) {
507
for (w = 0; w < 7; ++w) {
508
if (_encodings[b][RIGHTHAND][w]) {
509
pPainter->fillRect(pos, top, 1, draw_height - 6, pPainter->pen().color());
515
// render close guard
516
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
518
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
520
QString leftstr = QString().sprintf("%d%d%d%d",
521
val[0], val[1], val[2], val[3]);
522
QString rightstr = QString().sprintf("%d%d%d%d",
523
val[4], val[5], val[6], val[7]);
524
pPainter->setFont(QFont("Arial", 6));
525
pPainter->drawText(r.left() + quiet_zone + 3,
526
(r.top() + draw_height) - 6,
527
28, 10, Qt::AlignHCenter | Qt::AlignTop,
529
pPainter->drawText(r.left() + quiet_zone + 36,
530
(r.top() + draw_height) - 6,
531
28, 10, Qt::AlignHCenter | Qt::AlignTop,
538
void renderCodeUPCE(const QRect & r, const QString & _str, int align, QPainter * pPainter)
543
// initialize all the values just so we can be predictable
544
for (i = 0; i < 8; ++i) {
548
// verify that the passed in string is valid
549
// if it's not either twelve or thirteen characters
550
// then it must be invalid to begin with
551
if (_str.length() != 8) return;
552
// loop through and convert each char to a digit.
553
// if we can't convert all characters then this is
555
for (i = 0; i < _str.length(); ++i) {
556
val[i] = ((QChar) _str.at(i)).digitValue();
557
if (val[i] == -1) return;
560
// calculate and append the checksum value
561
// because everything is so messed up we don't calculate
562
// the checksum and require that it be passed in already
563
// however we do have to verify that the first digit is
564
// either 0 or 1 as that is our parity
565
if (val[0] != 0 && val[0] != 1) return;
567
// lets determine some core attributes about this barcode
568
int bar_width = 1; // the width of the base unit bar
570
// this is are mandatory minimum quiet zone
571
int quiet_zone = bar_width * 10;
572
if (quiet_zone < 10) quiet_zone = 10;
574
// what kind of area do we have to work with
575
int draw_width = r.width();
576
int draw_height = r.height() - 2;
579
// L length of barcode (excluding quite zone) in units same as X and I
580
// X the width of a bar (pixels in our case)
587
// now we have the actual width the barcode will be so can determine the actual
588
// size of the quiet zone (we assume we center the barcode in the given area
589
// what should we do if the area is too small????
590
// At the moment the way the code is written is we will always start at the minimum
591
// required quiet zone if we don't have enough space.... I guess we'll just have over-run
594
// calculate the starting position based on the alignment option
595
// for left align we don't need to do anything as the values are already setup for it
596
if (align == 1) { // center
597
int nqz = (draw_width - L) / 2;
598
if (nqz > quiet_zone) quiet_zone = nqz;
599
} else if (align > 1) { // right
600
quiet_zone = draw_width - (L + quiet_zone);
601
} // else if(align < 1) {} // left : do nothing
603
int pos = r.left() + quiet_zone;
609
QPen oneWide(pPainter->pen());
612
oneWide.setJoinStyle(Qt::MiterJoin);
614
pPainter->setPen(oneWide);
615
pPainter->setBrush(pPainter->pen().color());
620
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
622
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
626
for (i = 0; i < 6; ++i) {
628
for (w = 0; w < 7; ++w) {
629
if (_encodings[b][_upcparenc[val[7]][val[0]][i]][w]) {
630
pPainter->fillRect(pos, top, 1, draw_height - 7, pPainter->pen().color());
636
// render center guard
638
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
640
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
643
// render close guard
644
pPainter->fillRect(pos, top, 1, draw_height, pPainter->pen().color());
646
QString parstr = QString("%1").arg(val[0]);
647
QString chkstr = QString("%1").arg(val[7]);
648
QString leftstr = QString().sprintf("%d%d%d%d%d%d",
649
val[1], val[2], val[3], val[4], val[5], val[6]);
650
pPainter->setFont(QFont("Arial", 6));
651
pPainter->drawText(r.left(), r.top() + draw_height - 12,
652
quiet_zone - 2, 12, Qt::AlignRight | Qt::AlignTop,
654
pPainter->drawText(r.left() + quiet_zone + 3,
655
(r.top() + draw_height) - 7,
656
42, 10, Qt::AlignHCenter | Qt::AlignTop,
658
pPainter->drawText(r.left() + quiet_zone + L + 2, r.top() + draw_height - 12,
659
8, 12, Qt::AlignLeft | Qt::AlignTop,