~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to libs/koreport/renderer/code128.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-21 15:36:35 UTC
  • mfrom: (1.4.1 upstream) (60.2.11 maverick)
  • Revision ID: james.westby@ubuntu.com-20100921153635-6tejqkiro2u21ydi
Tags: 1:2.2.2-0ubuntu3
Add kubuntu_03_fix-crash-on-closing-sqlite-connection-2.2.2.diff and
kubuntu_04_support-large-memo-values-for-msaccess-2.2.2.diff as
recommended by upstream http://kexi-
project.org/wiki/wikiview/index.php@Kexi2.2_Patches.html#sqlite_stab
ility

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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)
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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/>.
 
18
 */
 
19
 
 
20
/*
 
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.
 
23
 */
 
24
 
 
25
#include <QString>
 
26
#include <QVector>
 
27
#include <QRect>
 
28
#include <QPainter>
 
29
#include <QPen>
 
30
#include <QBrush>
 
31
 
 
32
#include "renderobjects.h"
 
33
 
 
34
static const int SETA = 0;
 
35
static const int SETB = 1;
 
36
static const int SETC = 2;
 
37
 
 
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;
 
49
 
 
50
 
 
51
struct code128 {
 
52
    char codea;
 
53
    char codeb;
 
54
    char codec;
 
55
 
 
56
    int values[6];
 
57
 
 
58
    bool _null;
 
59
};
 
60
 
 
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
 
169
 
 
170
    { '\0', '\0', '\0', { 0, 0, 0, 0, 0, 0 }, true } // null termininator of list
 
171
};
 
172
 
 
173
// STOP CHARACTER { 2 3 3 1 1 1 2 }
 
174
 
 
175
int code128Index(QChar code, int set)
 
176
{
 
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;
 
181
    }
 
182
    return -1;  // couldn't find it
 
183
}
 
184
 
 
185
 
 
186
 
 
187
void renderCode128(OROPage * page, const QRectF & r, const QString & _str, int align)
 
188
{
 
189
    QVector<int> str;
 
190
    int i = 0;
 
191
 
 
192
    // create the list.. if the list is empty then just set a start code and move on
 
193
    if (_str.isEmpty())
 
194
        str.push_back(104);
 
195
    else {
 
196
        int rank_a = 0;
 
197
        int rank_b = 0;
 
198
        int rank_c = 0;
 
199
 
 
200
        QChar c;
 
201
        for (i = 0; i < _str.length(); ++i) {
 
202
            c = _str.at(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);
 
206
        }
 
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
 
210
            i = 0;
 
211
            if ((rank_c % 2) == 1) {
 
212
                str.push_back(104); // START B
 
213
                c = _str.at(0);
 
214
                str.push_back(code128Index(c, SETB));
 
215
                str.push_back(99); // MODE C
 
216
                i = 1;
 
217
            } else
 
218
                str.push_back(105); // START C
 
219
 
 
220
            for (i = i; i < _str.length(); i += 2) {
 
221
                char a, b;
 
222
                c = _str.at(i);
 
223
                a = c.toAscii();
 
224
                a -= 48;
 
225
                c = _str.at(i + 1);
 
226
                b = c.toAscii();
 
227
                b -= 48;
 
228
                str.push_back(int((a * 10) + b));
 
229
            }
 
230
        } else {
 
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));
 
235
            int v = -1;
 
236
            for (i = 0; i < _str.length(); ++i) {
 
237
                c = _str.at(i);
 
238
                v = code128Index(c, set);
 
239
                if (v == -1) {
 
240
                    v = code128Index(c, (set == SETA ? SETB : SETA));
 
241
                    if (v != -1) {
 
242
                        str.push_back(98); // SHIFT
 
243
                        str.push_back(v);
 
244
                    }
 
245
                } else
 
246
                    str.push_back(v);
 
247
            }
 
248
        }
 
249
    }
 
250
 
 
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);
 
257
 
 
258
    // lets determine some core attributes about this barcode
 
259
    qreal bar_width = 1; // the width of the base unit bar 1/100 inch
 
260
 
 
261
    // this is are mandatory minimum quiet zone
 
262
    qreal quiet_zone = bar_width * 10;
 
263
    if (quiet_zone < 0.1)
 
264
        quiet_zone = 0.1;
 
265
 
 
266
    // what kind of area do we have to work with
 
267
    qreal draw_width = r.width();
 
268
    qreal draw_height = r.height();
 
269
 
 
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
 
273
 
 
274
    // L = (11C + 35)X
 
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)
 
278
    qreal L;
 
279
 
 
280
    qreal C = val_length;
 
281
    qreal X = bar_width;
 
282
 
 
283
    L = (((11.0 * C) + 35.0) * X);
 
284
 
 
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
 
290
    // to the right
 
291
    //
 
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)
 
297
            quiet_zone = nqz;
 
298
    } else if (align > 1) // right
 
299
        quiet_zone = draw_width - (L + quiet_zone);
 
300
    // else if(align < 1) {} // left : do nothing
 
301
 
 
302
    qreal pos = r.left() + quiet_zone;
 
303
    qreal top = r.top();
 
304
 
 
305
    QPen pen(Qt::NoPen);
 
306
    QBrush brush(QColor("black"));
 
307
 
 
308
    bool space = false;
 
309
    int idx = 0, b = 0;
 
310
    qreal w = 0.0;
 
311
    for (i = 0; i < str.size(); ++i) {
 
312
        // loop through each value and render the barcode
 
313
        idx = str.at(i);
 
314
        if (idx < 0 || idx > 105) {
 
315
            qDebug("Encountered a non-compliant element while rendering a 3of9 barcode -- skipping");
 
316
            continue;
 
317
        }
 
318
        space = false;
 
319
        for (b = 0; b < 6; ++b, space = !space) {
 
320
            w = _128codes[idx].values[b] * bar_width;
 
321
            if (!space) {
 
322
                ORORect * rect = new ORORect();
 
323
                rect->setPen(pen);
 
324
                rect->setBrush(brush);
 
325
                rect->setRect(QRectF(pos, top, w, draw_height));
 
326
                page->addPrimitive(rect);
 
327
            }
 
328
            pos += w;
 
329
        }
 
330
    }
 
331
 
 
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 };
 
335
    space = false;
 
336
    for (b = 0; b < 7; ++b, space = !space) {
 
337
        w = STOP_CHARACTER[b] * bar_width;
 
338
        if (!space) {
 
339
            ORORect * rect = new ORORect();
 
340
            rect->setPen(pen);
 
341
            rect->setBrush(brush);
 
342
            rect->setRect(QRectF(pos, top, w, draw_height));
 
343
            page->addPrimitive(rect);
 
344
        }
 
345
        pos += w;
 
346
    }
 
347
}