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 <QPen>
0028 #include <QBrush>
0029 
0030 #include "KReportRenderObjects.h"
0031 
0032 const char* _i2of5charmap[] = {
0033     "NNWWN",
0034     "WNNNW",
0035     "NWNNW",
0036     "WWNNN",
0037     "NNWNW",
0038     "WNWNN",
0039     "NWWNN",
0040     "NNNWW",
0041     "WNNWN",
0042     "NWNWN"
0043 };
0044 
0045 
0046 static QPointF addElement(OROPage * page, const QRectF &r, QPointF startPos, qreal width, bool isSpace)
0047 {
0048     QPen pen(Qt::NoPen);
0049     QBrush brush(QColor("black"));
0050 
0051     if (!isSpace) {
0052         ORORect * rect = new ORORect();
0053         rect->setPen(pen);
0054         rect->setBrush(brush);
0055         rect->setRect(QRectF(startPos.x(),startPos.y(), width, r.height()));
0056         //rect->setRotationAxis(bc->rect.topLeft()); //!< @todo check this
0057         page->insertPrimitive(rect);
0058     }
0059     return QPointF(startPos.x() + width, startPos.y());
0060 }
0061 
0062 static QPointF addBar(OROPage * page, const QRectF &r, QPointF startPos, qreal width)
0063 {
0064     return addElement(page, r, startPos, width, false);
0065 }
0066 static QPointF addSpace(OROPage * page, const QRectF &r, QPointF startPos, qreal width)
0067 {
0068     return addElement(page, r, startPos, width, true);
0069 }
0070 
0071 
0072 void renderI2of5(OROPage * page, const QRectF &r, const QString & _str, Qt::Alignment align)
0073 {
0074     QString str = _str;
0075     qreal narrow_bar = 1; // a narrow bar is 1/100th inch wide
0076     qreal bar_width_mult = 2.5; // the wide bar width multiple of the narrow bar
0077     qreal wide_bar = narrow_bar * bar_width_mult;
0078 
0079     if (str.length() % 2) {
0080         str = QLatin1Char('0') + str; // padding zero if number of characters is not even
0081     }
0082 
0083     // this is our mandatory minimum quiet zone
0084     qreal quiet_zone = narrow_bar * 10;
0085     if (quiet_zone < 0.1) {
0086         quiet_zone = 0.1;
0087     }
0088 
0089     // what kind of area do we have to work with
0090     qreal draw_width = r.width();
0091 
0092     // how long is the value we need to encode?
0093     int val_length = str.length();
0094 
0095     // L = (C(2N+3)+6+N)X
0096     // L length of barcode (excluding quite zone
0097     // C the number of characters in the value excluding the start/stop
0098     // N the bar width multiple for wide bars
0099     // X the width of a bar (pixels in our case)
0100     qreal L;
0101     qreal C = val_length;
0102     qreal N = bar_width_mult;
0103     qreal X = narrow_bar;
0104 
0105     L = (C * (2.0*N + 3.0) + 6.0 + N) * X;
0106 
0107     // now we have the actual width the barcode will be so can determine the actual
0108     // size of the quiet zone (we assume we center the barcode in the given area)
0109     // At the moment the way the code is written is we will always start at the minimum
0110     // required quiet zone if we don't have enough space.... I guess we'll just have over-run
0111     // to the right
0112     //
0113     // calculate the starting position based on the alignment option
0114     if (align == Qt::AlignHCenter) {
0115         qreal nqz = (draw_width - L) / 2.0;
0116         if (nqz > quiet_zone) {
0117             quiet_zone = nqz;
0118         }
0119     }
0120     else if (align == Qt::AlignRight) {
0121         quiet_zone = draw_width - (L + quiet_zone);
0122     }
0123     // left : do nothing
0124 
0125     QPointF pos(r.left() + quiet_zone, r.top());
0126 
0127     // start character
0128     pos = addBar(page, r, pos, narrow_bar);
0129     pos = addSpace(page, r, pos, narrow_bar);
0130     pos = addBar(page, r, pos, narrow_bar);
0131     pos = addSpace(page, r, pos, narrow_bar);
0132 
0133     for (int i = 0; i < str.length()-1; i+=2) {
0134         for (int iElt = 0; _i2of5charmap [0][iElt] != '\0'; iElt++) {
0135             for (int offset=0; offset<=1; offset++) {
0136                 QChar c = str.at(i+offset);
0137                 if (!c.isDigit()) {
0138                     break; // invalid character
0139                 }
0140 
0141                 int iChar = c.digitValue();
0142                 qreal width = _i2of5charmap[iChar][iElt] == 'W' ? wide_bar : narrow_bar;
0143                 pos = addElement(page, r, pos, width, offset==1);
0144             }
0145         }
0146     }
0147 
0148     // stop character
0149     pos = addBar(page, r, pos, wide_bar);
0150     pos = addSpace(page, r, pos, narrow_bar);
0151     pos = addBar(page, r, pos, narrow_bar);
0152 }