File indexing completed on 2024-05-12 04:43:19

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2001-2012 by OpenMFG, LLC
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public
0015  * License along with this library; if not, write to the Free Software
0016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017  * Please contact info@openmfg.com with any questions on this license.
0018  */
0019 
0020 /*
0021  *     This file contains the implementation of the interleaved 2 of 5 barcode renderer.
0022  * All this code assumes a 100dpi rendering surface for it's calculations.
0023  */
0024 
0025 #include <QString>
0026 #include <QRectF>
0027 #include <QPainter>
0028 #include <QPen>
0029 #include <QBrush>
0030 
0031 const char* __i2of5charmap[] = {
0032     "NNWWN",
0033     "WNNNW",
0034     "NWNNW",
0035     "WWNNN",
0036     "NNWNW",
0037     "WNWNN",
0038     "NWWNN",
0039     "NNNWW",
0040     "WNNWN",
0041     "NWNWN"
0042 };
0043 
0044 
0045 static QPointF addElement(const QRectF &r, QPointF startPos, qreal width, bool isSpace, QPainter * pPainter)
0046 {
0047     if (!isSpace && pPainter) {
0048         pPainter->fillRect(startPos.x(),startPos.y(), width, r.height(), pPainter->pen().color());
0049     }
0050 
0051     return QPointF(startPos.x() + width, startPos.y());
0052 }
0053 
0054 static QPointF addBar(const QRectF &r, QPointF startPos, qreal width, QPainter * pPainter)
0055 {
0056     return addElement(r, startPos, width, false, pPainter);
0057 }
0058 static QPointF addSpace(const QRectF &r, QPointF startPos, qreal width, QPainter * pPainter)
0059 {
0060     return addElement(r, startPos, width, true, pPainter);
0061 }
0062 
0063 
0064 void renderI2of5(const QRectF &r, const QString & _str, Qt::Alignment align, QPainter * pPainter)
0065 {
0066     QString str = _str;
0067     qreal narrow_bar = 1; // a narrow bar is 1/100th inch wide
0068     qreal bar_width_mult = 2.5; // the wide bar width multiple of the narrow bar
0069     qreal wide_bar = narrow_bar * bar_width_mult;
0070 
0071     if (str.length() % 2) {
0072         str = QLatin1Char('0')+ str; // padding zero if number of characters is not even
0073     }
0074 
0075     // this is our mandatory minimum quiet zone
0076     qreal quiet_zone = narrow_bar * 10;
0077     if(quiet_zone < 0.1) {
0078         quiet_zone = 0.1;
0079     }
0080 
0081     // what kind of area do we have to work with
0082     int draw_width = r.width();
0083 
0084     // how long is the value we need to encode?
0085     int val_length = str.length();
0086 
0087     // L = (C(2N+3)+6+N)X
0088     // L length of barcode (excluding quite zone
0089     // C the number of characters in the value excluding the start/stop
0090     // N the bar width multiple for wide bars
0091     // X the width of a bar (pixels in our case)
0092     int L;
0093     int C = val_length;
0094     qreal N = bar_width_mult;
0095     qreal X = narrow_bar;
0096 
0097     L = (C * (2.0*N + 3.0) + 6.0 + N) * X;
0098 
0099     // now we have the actual width the barcode will be so can determine the actual
0100     // size of the quiet zone (we assume we center the barcode in the given area)
0101     // At the moment the way the code is written is we will always start at the minimum
0102     // required quiet zone if we don't have enough space.... I guess we'll just have over-run
0103     // to the right
0104     //
0105     // calculate the starting position based on the alignment option
0106     if (align == Qt::AlignHCenter) {
0107         int nqz = (draw_width - L) / 2.0;
0108         if (nqz > quiet_zone) {
0109             quiet_zone = nqz;
0110         }
0111     }
0112     else if (align == Qt::AlignRight) {
0113         quiet_zone = draw_width - (L + quiet_zone);
0114     }
0115     // left : do nothing
0116 
0117     if (pPainter) {
0118         pPainter->save();
0119 
0120         QPen oneWide(pPainter->pen());
0121         oneWide.setWidth(1);
0122 #ifndef Q_OS_WIN32
0123         oneWide.setJoinStyle(Qt::MiterJoin);
0124 #endif
0125         pPainter->setPen(oneWide);
0126         pPainter->setBrush(pPainter->pen().color());
0127     }
0128 
0129     QPointF pos(r.left() + quiet_zone, r.top());
0130 
0131     // start character
0132     pos = addBar(r, pos, narrow_bar,pPainter);
0133     pos = addSpace(r, pos, narrow_bar, pPainter);
0134     pos = addBar(r, pos, narrow_bar, pPainter);
0135     pos = addSpace(r, pos, narrow_bar, pPainter);
0136 
0137     for (int i = 0; i < str.length()-1; i+=2) {
0138         for (int iElt = 0; __i2of5charmap [0][iElt] != '\0'; iElt++) {
0139             for (int offset=0; offset<=1; offset++) {
0140                 QChar c = str.at(i+offset);
0141                 if (!c.isDigit()) {
0142                     break; // invalid character
0143                 }
0144 
0145                 int iChar = c.digitValue();
0146                 int width = __i2of5charmap[iChar][iElt] == 'W' ? wide_bar : narrow_bar;
0147                 pos = addElement(r, pos, width, offset==1, pPainter);
0148             }
0149         }
0150     }
0151 
0152     // stop character
0153     pos = addBar(r, pos, wide_bar, pPainter);
0154     pos = addSpace(r, pos, narrow_bar, pPainter);
0155     pos = addBar(r, pos, narrow_bar, pPainter);
0156 }