summaryrefslogtreecommitdiffstats
path: root/kbarcode/pixmapbarcode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kbarcode/pixmapbarcode.cpp')
-rw-r--r--kbarcode/pixmapbarcode.cpp492
1 files changed, 492 insertions, 0 deletions
diff --git a/kbarcode/pixmapbarcode.cpp b/kbarcode/pixmapbarcode.cpp
new file mode 100644
index 0000000..56a597e
--- /dev/null
+++ b/kbarcode/pixmapbarcode.cpp
@@ -0,0 +1,492 @@
+/***************************************************************************
+ pixmapbarcode.cpp - description
+ -------------------
+ begin : Mon Nov 22 2004
+ copyright : (C) 2004 by Dominik Seichter
+ email : domseichter@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ ***************************************************************************/
+
+#include "pixmapbarcode.h"
+#include "barkode.h"
+
+// patch from Ali Akcaagac says that this include is needed
+#include <stdlib.h>
+
+#include <kapplication.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+
+#include <qbuffer.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qpixmap.h>
+#include <qtextstream.h>
+
+/* Margin added by GNU Barcode to the barcodes */
+#define BARCODE_MARGIN 10
+
+/* Use a 5KB buffer for pipes */
+#define BUFFER_SIZE 1024 * 5
+
+PDF417Options::PDF417Options()
+{
+ defaults();
+}
+
+const PDF417Options& PDF417Options::operator=( const BarkodeEngineOptions& rhs )
+{
+ const PDF417Options* pdf = (dynamic_cast<const PDF417Options*>(&rhs));
+
+ this->m_row = pdf->m_row;
+ this->m_col = pdf->m_col;
+ this->m_err = pdf->m_err;
+
+ return *this;
+}
+
+void PDF417Options::defaults()
+{
+ m_row = 24;
+ m_col = 8;
+ m_err = 5;
+}
+
+void PDF417Options::load( const QDomElement* tag )
+{
+ m_row = tag->attribute( "pdf417.row", "24" ).toInt();
+ m_col = tag->attribute( "pdf417.col", "8" ).toInt();
+ m_err = tag->attribute( "pdf417.err", "5" ).toInt();
+}
+
+void PDF417Options::save( QDomElement* tag )
+{
+ tag->setAttribute( "pdf417.row", m_row );
+ tag->setAttribute( "pdf417.col", m_col );
+ tag->setAttribute( "pdf417.err", m_err );
+}
+
+PixmapBarcode::PixmapBarcode()
+ : BarkodeEngine()
+{
+}
+
+
+PixmapBarcode::~PixmapBarcode()
+{
+}
+
+const PixmapBarcode & PixmapBarcode::operator=( const BarkodeEngine & rhs )
+{
+ const PixmapBarcode* pix = dynamic_cast<const PixmapBarcode*>(&rhs);
+
+ if( pix )
+ {
+ m_pdf417_options = pix->m_pdf417_options;
+ p = pix->p;
+ }
+
+ return *this;
+}
+
+const QSize PixmapBarcode::size() const
+{
+ return ( p.size().isNull() ? QSize( 100, 80 ) : p.size() );
+}
+
+void PixmapBarcode::update( const QPaintDevice* device )
+{
+ p.resize( 0, 0 );
+ createBarcode( &p, device );
+}
+
+void PixmapBarcode::drawBarcode( QPainter & painter, int x, int y )
+{
+ if( p.isNull() )
+ createBarcode( &p, painter.device() );
+
+ if( p.isNull() ) // still no barcode....
+ {
+ barkode->drawInvalid( painter, x, y );
+ return;
+ }
+
+ painter.drawPixmap( x, y, p );
+}
+
+bool PixmapBarcode::createPixmap( QPixmap* target, int resx, int resy )
+{
+ char* postscript = NULL;
+ long postscript_size = 0;
+ QString cmd;
+ bool bMonocrome;
+
+ bMonocrome = ( barkode->foreground() == Qt::black &&
+ barkode->background() == Qt::white &&
+ barkode->textColor() == Qt::black );
+
+ KTempFile* input = new KTempFile( QString::null, bMonocrome ? ".pbm" : ".ppm" );
+ input->file()->close();
+
+ if( Barkode::engineForType( barkode->type() ) == PDF417 ) {
+ if(!createPdf417( input )) {
+ cleanUp( input, target );
+ return false;
+ }
+
+ target->load( input->name(), "GIF" );
+ } else {
+ if( !createPostscript( &postscript, &postscript_size ) )
+ {
+ cleanUp( input, target );
+ return false;
+ }
+
+ FILE* gs_pipe;
+
+ if( !postscript_size )
+ {
+ // GNU Barcode was not able to encode this barcode
+ cleanUp( input, target );
+ return false;
+ }
+
+ QRect size = bbox( postscript, postscript_size );
+ double sw = (double)(size.x() + size.width())/72 * resx;
+ double sh = (double)(size.y() + size.height())/72 * resy;
+
+ if( Barkode::engineForType( barkode->type() ) == TBARCODE )
+ {
+ sw = (double)(size.x() + size.width());
+ sh = (double)(size.y() + size.height());
+ }
+
+ cmd = QString("gs -g%1x%2").arg(int(sw*(double)barkode->scaling())).arg(int(sh*(double)barkode->scaling()));
+ cmd += " -r" + QString::number( resx*(double)barkode->scaling()) + "x" + QString::number( resy*(double)barkode->scaling() );
+ cmd += QString(" -sDEVICE=%1 -sOutputFile=").arg( bMonocrome ? "pbmraw" : "ppm" );
+ cmd += input->name();
+ cmd += " -sNOPAUSE -q - -c showpage quit";
+
+ qDebug("cmd: " + cmd );
+ gs_pipe = popen( cmd.latin1(), "w" );
+ if( !gs_pipe )
+ {
+ qDebug("ERROR: cannot open Ghostscript pipe!");
+ cleanUp( input, target );
+ return false;
+ }
+
+ fwrite( postscript, sizeof(char), postscript_size, gs_pipe );
+ pclose( gs_pipe );
+
+ target->load( input->name(), "PBM" );
+ }
+
+
+ free( postscript );
+
+ input->unlink();
+ delete input;
+
+ return true;
+}
+
+bool PixmapBarcode::createPostscript( char** postscript, long* postscript_size )
+{
+ QString cmd;
+
+ /*
+ if( Barkode::engineForType( barkode->type() ) == TBARCODE )
+ {
+ cmd = createTBarcodeCmd();
+ qDebug("tbarcodeclient commandline: %s", cmd.latin1() );
+ }
+ else // GNU_BARCODE
+ */
+ {
+ cmd = "barcode -E -b ";
+ cmd += KShellProcess::quote( barkode->parsedValue() ) + (barkode->textVisible() ? "" : " -n");
+ cmd += " -e " + barkode->type();
+ }
+
+ if( !readFromPipe( cmd.latin1(), postscript, postscript_size ) )
+ return false;
+
+ return true;
+}
+
+QRect PixmapBarcode::bbox( const char* data, long size )
+{
+ int x = 0, y = 0, w = 0, h = 0;
+ const char* bbox = "%%BoundingBox:";
+ int len = strlen( bbox );
+
+ QRect s(0,0,0,0);
+ QByteArray array;
+ array.setRawData( data, size );
+
+ QBuffer b( array );
+ if( !b.open( IO_ReadOnly ) )
+ return s;
+
+ QTextStream t( &b );
+
+ QString text = t.readLine();
+ while( !text.isNull() )
+ {
+ if( text.startsWith( bbox ) )
+ {
+ text = text.right( text.length() - len );
+ sscanf( (const char*)text, "%d %d %d %d", &x, &y, &w, &h );
+ s = QRect( x, y, w, h );
+ break;
+ }
+
+ text = t.readLine();
+ }
+
+ b.close();
+ array.resetRawData( data, size );
+
+ return s;
+}
+
+bool PixmapBarcode::readFromPipe( const char* command, char** buffer, long* buffer_size )
+{
+ FILE* pipe = popen( command, "r" );
+ if( !pipe )
+ {
+ qDebug("ERROR: cannot open pipe %s!", command );
+ return false;
+ }
+
+ char* buf = (char*)malloc( BUFFER_SIZE );
+ char* tmp = NULL;
+ int s = 0;
+
+ *buffer_size = 0;
+ do {
+ s = fread( buf, sizeof(char), BUFFER_SIZE, pipe );
+
+ // Special case:
+ // GNU Barcode Error
+ if( !s )
+ break;
+
+ // there won't be more data to read
+ tmp = (char*)malloc( *buffer_size + s );
+
+ if( *buffer )
+ {
+ memcpy( tmp, *buffer, *buffer_size );
+ free( *buffer );
+ }
+
+ memcpy( tmp+ *buffer_size, buf, s );
+ *buffer = tmp;
+ *buffer_size += s;
+ } while( s == BUFFER_SIZE );
+
+ pclose( pipe );
+ free( buf );
+
+ return true;
+}
+
+void PixmapBarcode::createBarcode( QPixmap* target, const QPaintDevice* device )
+{
+ QPaintDeviceMetrics pdm( device );
+ int resx = pdm.logicalDpiX();
+ int resy = pdm.logicalDpiY();
+
+ QPixmap* cached = 0;//BarcodeCache::instance()->read( barcode, resx, resy, value );
+
+ // no matching barcode found in cache
+ if( !cached ) {
+ if( !createPixmap( target, resx, resy ) )
+ return;
+ } else {
+ *target = *cached;
+ delete cached;
+ }
+
+ if( Barkode::hasFeature( barkode->type(), PDF417 ) ) {
+ // we have to scale to the correct resolution.
+ // we scale already here and not at the end,
+ // so that the addMargin function does not get a scaled margin.
+ QPaintDeviceMetrics pdm( KApplication::desktop() );
+ int screenresx = pdm.logicalDpiX();
+ int screenresy = pdm.logicalDpiY();
+
+ QWMatrix m;
+ double scalex = (resx/screenresx)*barkode->scaling();
+ double scaley = (resy/screenresy)*barkode->scaling();
+ m.scale( scalex, scaley );
+ *target = target->xForm( m );
+ }
+ *target = cut( target, barkode->cut() );
+ *target = addMargin( target );
+
+ // Rotate
+ QWMatrix m;
+ m.rotate( (double)barkode->rotation() );
+ *target = target->xForm( m );
+
+ //barcode.valid = true;
+}
+
+bool PixmapBarcode::createPdf417( KTempFile* output )
+{
+ const PDF417Options* options = (dynamic_cast<const PDF417Options*>(barkode->engine()->options()));
+
+ if( !options )
+ {
+ qDebug("No PDF417Options available!");
+ return false;
+ }
+
+ KTempFile text( QString::null, ".txt" );
+ QTextStream t( text.file() );
+ t << barkode->parsedValue();
+ text.file()->close();
+
+ // ps does not work because bounding box information is missing
+ // pbm cannot be loaded by KImgIO (works fine in GIMP)
+ // gif is the only other option
+ KShellProcess proc;
+ proc << "pdf417_enc" << "-tgif" << text.name() << output->name()
+ << options->row()
+ << options->col()
+ << options->err();
+
+ proc.start( KProcess::Block, KProcess::NoCommunication );
+ proc.resume();
+
+ if( proc.exitStatus() ) {
+ text.unlink();
+ return false;
+ }
+
+ text.unlink();
+ return true;
+}
+
+#if 0
+QString PixmapBarcode::createTBarcodeCmd()
+{
+ QString cmd;
+
+ // print text
+ QString flag = barkode->textVisible() ? " Ton" : " n Toff"; // we pass the old parameter Ton and the new one: n
+ // escape text
+ flag.append( barkode->tbarcodeOptions()->escape() ? " son" : " soff" );
+ // autocorrection
+ flag.append( barkode->tbarcodeOptions()->autocorrect() ? " Aon" : " Aoff" );
+ // barcode height
+ flag.append( QString( " h%1" ).arg( barkode->tbarcodeOptions()->height() ) );
+ // text above
+ if( barkode->tbarcodeOptions()->above() )
+ flag.append( " a" );
+
+ cmd = "tbarcodeclient ";
+ if( !Barkode::hasFeature( barkode->type(), BARCODE2D ) )
+ cmd += QString( " m%1" ).arg( barkode->tbarcodeOptions()->moduleWidth() * 1000 );
+
+ if( Barkode::hasFeature( barkode->type(), DATAMATRIX ) )
+ cmd += QString( " Ds%1" ).arg( barkode->datamatrixSize() );
+
+ if( Barkode::hasFeature( barkode->type(), PDF417BARCODE ) )
+ cmd += QString( " Pr%1 Pc%2 Pe%3" ).arg( barkode->pdf417Options()->row() )
+ .arg( barkode->pdf417Options()->col() )
+ .arg( barkode->pdf417Options()->err() );
+
+ cmd += " " + barkode->type() + QString(" tPS c%1").arg( barkode->tbarcodeOptions()->checksum() );
+ cmd += flag + " d" + KShellProcess::quote( barkode->parsedValue() );
+
+ return cmd;
+}
+#endif // 0
+
+void PixmapBarcode::cleanUp( KTempFile* file, QPixmap* target )
+{
+ target->resize( 0, 0 );
+
+ file->unlink();
+ delete file;
+}
+
+QPixmap PixmapBarcode::cut( QPixmap* pic, double cut)
+{
+ if( cut == 1.0 )
+ return (*pic);
+
+ QPixmap pcut( pic->width(), int((double)pic->height() * cut) );
+ pcut.fill( Qt::white ); // barcode.bg
+
+ QWMatrix m;
+ /*
+ * if text is above the barcode cut from
+ * below the barcode.
+ */
+
+ // TODO: put this into one if, I am to stupid today.....
+ if( Barkode::hasFeature( barkode->type(), TBARCODEADV ) ) {
+ //if( !barcode.tbarcode.above )
+ m.rotate( 180 );
+ } else
+ m.rotate( 180 );
+
+ QPainter painter( &pcut );
+ painter.drawPixmap( 0, 0, pic->xForm( m ) );
+
+ return pcut.xForm( m );
+}
+
+QPixmap PixmapBarcode::addMargin( QPixmap* pic )
+{
+ QPixmap p;
+
+ /* We have to handle UPC special because of the checksum character
+ * which is printed on the right margin.
+ * The samve goes for ISBN codes.
+ * Any other formats??
+ */
+
+ bool gnubarcode = (Barkode::engineForType( barkode->type() ) == GNU_BARCODE) ||
+ (Barkode::engineForType( barkode->type() ) == PURE_POSTSCRIPT);
+ double barm = gnubarcode ? BARCODE_MARGIN * barkode->scaling() : 0.0;
+
+ // Add margin
+ double sx = barm;
+ double sy = barm;
+ double sw = pic->width() - (barm * 2);
+ double sh = pic->height() - (barm * 2);
+ int margin = (int)(barkode->quietZone()*2 - barm*2);
+
+ if( gnubarcode && (barkode->type() == "upc" || barkode->type() == "isbn") )
+ {
+ sw = pic->width() - barm;
+
+ p.resize( pic->width() + int(barkode->quietZone()*2 - barm), pic->height() + margin );
+ }
+ else
+ p.resize( pic->width() + margin, pic->height() + margin );
+
+ p.fill( barkode->background() );
+ QPainter painter( &p );
+ painter.drawPixmap( barkode->quietZone(), barkode->quietZone(), *pic, (int)sx, (int)sy, (int)sw, (int)sh );
+ painter.end();
+
+ return p;
+}