|
|
|
// This library is distributed under the conditions of the GNU LGPL.
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqprinter.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "eps.h"
|
|
|
|
|
|
|
|
#define BUFLEN 200
|
|
|
|
|
|
|
|
#define BBOX "%%BoundingBox:"
|
|
|
|
#define BBOX_LEN strlen(BBOX)
|
|
|
|
|
|
|
|
static bool seekToCodeStart( TQIODevice * io, TQ_UINT32 & ps_offset, TQ_UINT32 & ps_size )
|
|
|
|
{
|
|
|
|
char buf[4]; // We at most need to read 4 bytes at a time
|
|
|
|
ps_offset=0L;
|
|
|
|
ps_size=0L;
|
|
|
|
|
|
|
|
if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: EPS file has less than 2 bytes." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic
|
|
|
|
{
|
|
|
|
kdDebug(399) << "kimgio EPS: normal EPS file" << endl;
|
|
|
|
}
|
|
|
|
else if ( buf[0]==char(0xc5) && buf[1]==char(0xd0) ) // Check start of MS-DOS EPS magic
|
|
|
|
{ // May be a MS-DOS EPS file
|
|
|
|
if ( io->readBlock(buf+2, 2)!=2 ) // Read further bytes of MS-DOS EPS magic
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: potential MS-DOS EPS file has less than 4 bytes." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( buf[2]==char(0xd3) && buf[3]==char(0xc6) ) // Check last bytes of MS-DOS EPS magic
|
|
|
|
{
|
|
|
|
if (io->readBlock(buf, 4)!=4) // Get offset of PostScript code in the MS-DOS EPS file.
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: cannot read offset of MS-DOS EPS file" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ps_offset // Offset is in little endian
|
|
|
|
= ((unsigned char) buf[0])
|
|
|
|
+ ((unsigned char) buf[1] << 8)
|
|
|
|
+ ((unsigned char) buf[2] << 16)
|
|
|
|
+ ((unsigned char) buf[3] << 24);
|
|
|
|
if (io->readBlock(buf, 4)!=4) // Get size of PostScript code in the MS-DOS EPS file.
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: cannot read size of MS-DOS EPS file" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ps_size // Size is in little endian
|
|
|
|
= ((unsigned char) buf[0])
|
|
|
|
+ ((unsigned char) buf[1] << 8)
|
|
|
|
+ ((unsigned char) buf[2] << 16)
|
|
|
|
+ ((unsigned char) buf[3] << 24);
|
|
|
|
kdDebug(399) << "kimgio EPS: Offset: " << ps_offset <<" Size: " << ps_size << endl;
|
|
|
|
if ( !io->tqat(ps_offset) ) // Get offset of PostScript code in the MS-DOS EPS file.
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: cannot seek in MS-DOS EPS file" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes of what should be the Postscript code
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: PostScript code has less than 2 bytes." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic
|
|
|
|
{
|
|
|
|
kdDebug(399) << "kimgio EPS: MS-DOS EPS file" << endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: supposed Postscript code of a MS-DOS EPS file doe not start with %!." << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: wrong magic for potential MS-DOS EPS file!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdError(399) << "kimgio EPS: not an EPS file!" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool bbox ( TQIODevice *io, int *x1, int *y1, int *x2, int *y2)
|
|
|
|
{
|
|
|
|
char buf[BUFLEN+1];
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
while (io->readLine(buf, BUFLEN) > 0)
|
|
|
|
{
|
|
|
|
if (strncmp (buf, BBOX, BBOX_LEN) == 0)
|
|
|
|
{
|
|
|
|
// Some EPS files have non-integer values for the bbox
|
|
|
|
// We don't support that currently, but at least we parse it
|
|
|
|
float _x1, _y1, _x2, _y2;
|
|
|
|
if ( sscanf (buf, "%*s %f %f %f %f",
|
|
|
|
&_x1, &_y1, &_x2, &_y2) == 4) {
|
|
|
|
kdDebug(399) << "kimgio EPS BBOX: " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl;
|
|
|
|
*x1=(int)_x1; *y1=(int)_y1; *x2=(int)_x2; *y2=(int)_y2;
|
|
|
|
ret = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDE_EXPORT void kimgio_eps_read (TQImageIO *image)
|
|
|
|
{
|
|
|
|
kdDebug(399) << "kimgio EPS: starting..." << endl;
|
|
|
|
|
|
|
|
FILE * ghostfd;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
//TQTime dt;
|
|
|
|
//dt.start();
|
|
|
|
|
|
|
|
TQString cmdBuf;
|
|
|
|
TQString tmp;
|
|
|
|
|
|
|
|
TQIODevice* io = image->ioDevice();
|
|
|
|
TQ_UINT32 ps_offset, ps_size;
|
|
|
|
|
|
|
|
// find start of PostScript code
|
|
|
|
if ( !seekToCodeStart(io, ps_offset, ps_size) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// find bounding box
|
|
|
|
if ( !bbox (io, &x1, &y1, &x2, &y2)) {
|
|
|
|
kdError(399) << "kimgio EPS: no bounding box found!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KTempFile tmpFile;
|
|
|
|
tmpFile.setAutoDelete(true);
|
|
|
|
|
|
|
|
if( tmpFile.status() != 0 ) {
|
|
|
|
kdError(399) << "kimgio EPS: no temp file!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tmpFile.close(); // Close the file, we just want the filename
|
|
|
|
|
|
|
|
// x1, y1 -> translation
|
|
|
|
// x2, y2 -> new size
|
|
|
|
|
|
|
|
x2 -= x1;
|
|
|
|
y2 -= y1;
|
|
|
|
//kdDebug(399) << "origin point: " << x1 << "," << y1 << " size:" << x2 << "," << y2 << endl;
|
|
|
|
double xScale = 1.0;
|
|
|
|
double yScale = 1.0;
|
|
|
|
bool needsScaling = false;
|
|
|
|
int wantedWidth = x2;
|
|
|
|
int wantedHeight = y2;
|
|
|
|
|
|
|
|
if (image->parameters())
|
|
|
|
{
|
|
|
|
// Size forced by the caller
|
|
|
|
TQStringList params = TQStringList::split(':', image->parameters());
|
|
|
|
if (params.count() >= 2 && x2 != 0.0 && y2 != 0.0)
|
|
|
|
{
|
|
|
|
wantedWidth = params[0].toInt();
|
|
|
|
xScale = (double)wantedWidth / (double)x2;
|
|
|
|
wantedHeight = params[1].toInt();
|
|
|
|
yScale = (double)wantedHeight / (double)y2;
|
|
|
|
//kdDebug(399) << "wanted size:" << wantedWidth << "x" << wantedHeight << endl;
|
|
|
|
//kdDebug(399) << "scaling:" << xScale << "," << yScale << endl;
|
|
|
|
needsScaling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create GS command line
|
|
|
|
|
|
|
|
cmdBuf = "gs -sOutputFile=";
|
|
|
|
cmdBuf += tmpFile.name();
|
|
|
|
cmdBuf += " -q -g";
|
|
|
|
tmp.setNum( wantedWidth );
|
|
|
|
cmdBuf += tmp;
|
|
|
|
tmp.setNum( wantedHeight );
|
|
|
|
cmdBuf += "x";
|
|
|
|
cmdBuf += tmp;
|
|
|
|
cmdBuf += " -dSAFER -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ppm -c "
|
|
|
|
"0 0 moveto "
|
|
|
|
"1000 0 lineto "
|
|
|
|
"1000 1000 lineto "
|
|
|
|
"0 1000 lineto "
|
|
|
|
"1 1 254 255 div setrgbcolor fill "
|
|
|
|
"0 0 0 setrgbcolor - -c showpage quit";
|
|
|
|
|
|
|
|
// run ghostview
|
|
|
|
|
|
|
|
ghostfd = popen (TQFile::encodeName(cmdBuf), "w");
|
|
|
|
|
|
|
|
if ( ghostfd == 0 ) {
|
|
|
|
kdError(399) << "kimgio EPS: no GhostScript?" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (ghostfd, "\n%d %d translate\n", -tqRound(x1*xScale), -tqRound(y1*yScale));
|
|
|
|
if ( needsScaling )
|
|
|
|
fprintf (ghostfd, "%g %g scale\n", xScale, yScale);
|
|
|
|
|
|
|
|
// write image to gs
|
|
|
|
|
|
|
|
io->reset(); // Go back to start of file to give all the file to GhostScript
|
|
|
|
if (ps_offset>0L) // We have an offset
|
|
|
|
io->tqat(ps_offset);
|
|
|
|
TQByteArray buffer ( io->readAll() );
|
|
|
|
|
|
|
|
// If we have no MS-DOS EPS file or if the size seems wrong, then choose the buffer size
|
|
|
|
if (ps_size<=0L || ps_size>buffer.size())
|
|
|
|
ps_size=buffer.size();
|
|
|
|
|
|
|
|
fwrite(buffer.data(), sizeof(char), ps_size, ghostfd);
|
|
|
|
buffer.resize(0);
|
|
|
|
|
|
|
|
pclose ( ghostfd );
|
|
|
|
|
|
|
|
// load image
|
|
|
|
TQImage myimage;
|
|
|
|
if( myimage.load (tmpFile.name()) ) {
|
|
|
|
image->setImage (myimage);
|
|
|
|
image->seStatus (0);
|
|
|
|
kdDebug(399) << "kimgio EPS: success!" << endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
kdError(399) << "kimgio EPS: no image!" << endl;
|
|
|
|
|
|
|
|
//kdDebug(399) << "Loading EPS took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sven Wiegand <SWiegand@tfh-berlin.de> -- eps output filter (from KSnapshot)
|
|
|
|
KDE_EXPORT void kimgio_eps_write( TQImageIO *imageio )
|
|
|
|
{
|
|
|
|
TQPrinter psOut(TQPrinter::PrinterResolution);
|
|
|
|
TQPainter p;
|
|
|
|
|
|
|
|
// making some definitions (papersize, output to file, filename):
|
|
|
|
psOut.setCreator( "KDE " KDE_VERSION_STRING );
|
|
|
|
psOut.setOutputToFile( true );
|
|
|
|
|
|
|
|
// Extension must be .eps so that Qt generates EPS file
|
|
|
|
KTempFile tmpFile(TQString::null, ".eps");
|
|
|
|
tmpFile.setAutoDelete(true);
|
|
|
|
if ( tmpFile.status() != 0)
|
|
|
|
return;
|
|
|
|
tmpFile.close(); // Close the file, we just want the filename
|
|
|
|
|
|
|
|
psOut.setOutputFileName(tmpFile.name());
|
|
|
|
psOut.setFullPage(true);
|
|
|
|
|
|
|
|
// painting the pixmap to the "printer" which is a file
|
|
|
|
p.begin( &psOut );
|
|
|
|
// Qt uses the clip rect for the bounding box
|
|
|
|
p.setClipRect( 0, 0, imageio->image().width(), imageio->image().height(), TQPainter::CoordPainter);
|
|
|
|
p.drawImage( TQPoint( 0, 0 ), imageio->image() );
|
|
|
|
p.end();
|
|
|
|
|
|
|
|
// Copy file to imageio struct
|
|
|
|
TQFile inFile(tmpFile.name());
|
|
|
|
inFile.open( IO_ReadOnly );
|
|
|
|
|
|
|
|
TQTextStream in( &inFile );
|
|
|
|
in.setEncoding( TQTextStream::Latin1 );
|
|
|
|
TQTextStream out( imageio->ioDevice() );
|
|
|
|
out.setEncoding( TQTextStream::Latin1 );
|
|
|
|
|
|
|
|
TQString szInLine = in.readLine();
|
|
|
|
out << szInLine << '\n';
|
|
|
|
|
|
|
|
while( !in.atEnd() ){
|
|
|
|
szInLine = in.readLine();
|
|
|
|
out << szInLine << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
inFile.close();
|
|
|
|
|
|
|
|
imageio->seStatus(0);
|
|
|
|
}
|