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.
493 lines
13 KiB
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( (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<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;
|
|
}
|