diff options
Diffstat (limited to 'kbarcode/pixmapbarcode.cpp')
-rw-r--r-- | kbarcode/pixmapbarcode.cpp | 492 |
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; +} |