/*************************************************************************** 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 #include #include #include #include #include #include #include #include #include #include #include /* 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(&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 TQDomElement* 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( TQDomElement* 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(&rhs); if( pix ) { m_pdf417_options = pix->m_pdf417_options; p = pix->p; } return *this; } const TQSize PixmapBarcode::size() const { return ( p.size().isNull() ? TQSize( 100, 80 ) : p.size() ); } void PixmapBarcode::update( const TQPaintDevice* device ) { p.resize( 0, 0 ); createBarcode( &p, device ); } void PixmapBarcode::drawBarcode( TQPainter & painter, int x, int y ) { if( p.isNull() ) createBarcode( &p, TQT_TQPAINTDEVICE(painter.device()) ); if( p.isNull() ) // still no barcode.... { barkode->drawInvalid( painter, x, y ); return; } painter.drawPixmap( x, y, p ); } bool PixmapBarcode::createPixmap( TQPixmap* target, int resx, int resy ) { char* postscript = NULL; long postscript_size = 0; TQString cmd; bool bMonocrome; bMonocrome = ( barkode->foreground() == TQt::black && barkode->background() == TQt::white && barkode->textColor() == TQt::black ); KTempFile* input = new KTempFile( TQString(), 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; } TQRect 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 = TQString("gs -g%1x%2").arg(int(sw*(double)barkode->scaling())).arg(int(sh*(double)barkode->scaling())); cmd += " -r" + TQString::number( resx*(double)barkode->scaling()) + "x" + TQString::number( resy*(double)barkode->scaling() ); cmd += TQString(" -sDEVICE=%1 -sOutputFile=").arg( bMonocrome ? "pbmraw" : "ppm" ); cmd += input->name(); cmd += " -sNOPAUSE -q - -c showpage quit"; tqDebug("cmd: %s", cmd.ascii() ); gs_pipe = popen( cmd.latin1(), "w" ); if( !gs_pipe ) { tqDebug("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 ) { TQString cmd; /* if( Barkode::engineForType( barkode->type() ) == TBARCODE ) { cmd = createTBarcodeCmd(); tqDebug("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; } TQRect PixmapBarcode::bbox( const char* data, long size ) { int x = 0, y = 0, w = 0, h = 0; const char* bbox = "%%BoundingBox:"; int len = strlen( bbox ); TQRect s(0,0,0,0); TQByteArray array; array.setRawData( data, size ); TQBuffer b( array ); if( !b.open( IO_ReadOnly ) ) return s; TQTextStream t( &b ); TQString 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 = TQRect( 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 ) { tqDebug("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( TQPixmap* target, const TQPaintDevice* device ) { TQPaintDeviceMetrics pdm( device ); int resx = pdm.logicalDpiX(); int resy = pdm.logicalDpiY(); TQPixmap* 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. TQPaintDeviceMetrics pdm( TDEApplication::desktop() ); int screenresx = pdm.logicalDpiX(); int screenresy = pdm.logicalDpiY(); TQWMatrix 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 TQWMatrix m; m.rotate( (double)barkode->rotation() ); *target = target->xForm( m ); //barcode.valid = true; } bool PixmapBarcode::createPdf417( KTempFile* output ) { const PDF417Options* options = (dynamic_cast(barkode->engine()->options())); if( !options ) { tqDebug("No PDF417Options available!"); return false; } KTempFile text( TQString(), ".txt" ); TQTextStream 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( TDEProcess::Block, TDEProcess::NoCommunication ); proc.resume(); if( proc.exitStatus() ) { text.unlink(); return false; } text.unlink(); return true; } #if 0 TQString PixmapBarcode::createTBarcodeCmd() { TQString cmd; // print text TQString 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( TQString( " h%1" ).arg( barkode->tbarcodeOptions()->height() ) ); // text above if( barkode->tbarcodeOptions()->above() ) flag.append( " a" ); cmd = "tbarcodeclient "; if( !Barkode::hasFeature( barkode->type(), BARCODE2D ) ) cmd += TQString( " m%1" ).arg( barkode->tbarcodeOptions()->moduleWidth() * 1000 ); if( Barkode::hasFeature( barkode->type(), DATAMATRIX ) ) cmd += TQString( " Ds%1" ).arg( barkode->datamatrixSize() ); if( Barkode::hasFeature( barkode->type(), PDF417BARCODE ) ) cmd += TQString( " Pr%1 Pc%2 Pe%3" ).arg( barkode->pdf417Options()->row() ) .arg( barkode->pdf417Options()->col() ) .arg( barkode->pdf417Options()->err() ); cmd += " " + barkode->type() + TQString(" tPS c%1").arg( barkode->tbarcodeOptions()->checksum() ); cmd += flag + " d" + KShellProcess::quote( barkode->parsedValue() ); return cmd; } #endif // 0 void PixmapBarcode::cleanUp( KTempFile* file, TQPixmap* target ) { target->resize( 0, 0 ); file->unlink(); delete file; } TQPixmap PixmapBarcode::cut( TQPixmap* pic, double cut) { if( cut == 1.0 ) return (*pic); TQPixmap pcut( pic->width(), int((double)pic->height() * cut) ); pcut.fill( TQt::white ); // barcode.bg TQWMatrix 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 ); TQPainter painter( &pcut ); painter.drawPixmap( 0, 0, pic->xForm( m ) ); return pcut.xForm( m ); } TQPixmap PixmapBarcode::addMargin( TQPixmap* pic ) { TQPixmap 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() ); TQPainter painter( &p ); painter.drawPixmap( barkode->quietZone(), barkode->quietZone(), *pic, (int)sx, (int)sy, (int)sw, (int)sh ); painter.end(); return p; }