You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kbarcode/kbarcode/pixmapbarcode.cpp

493 lines
13 KiB

/***************************************************************************
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 <tdeapplication.h>
#include <kprocess.h>
#include <tdetempfile.h>
#include <tqbuffer.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqpainter.h>
#include <tqpaintdevicemetrics.h>
#include <tqpixmap.h>
#include <tqtextstream.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 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<const PixmapBarcode*>(&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( text.latin1(), "%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<const PDF417Options*>(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;
}