00001
00007 #include "eps.h"
00008 #include <unistd.h>
00009 #include <stdio.h>
00010 #include <QtGui/QImage>
00011 #include <QtCore/QFile>
00012 #include <QtGui/QPainter>
00013 #include <QtGui/QPrinter>
00014 #include <QtCore/QTextStream>
00015 #include <QtCore/QTemporaryFile>
00016 #include <kapplication.h>
00017 #include <kdebug.h>
00018
00019 #define BUFLEN 200
00020
00021 #define BBOX "%%BoundingBox:"
00022 #define BBOX_LEN strlen(BBOX)
00023
00024 static bool seekToCodeStart( QIODevice * io, quint32 & ps_offset, quint32 & ps_size )
00025 {
00026 char buf[4];
00027 ps_offset=0L;
00028 ps_size=0L;
00029
00030 if ( io->read(buf, 2)!=2 )
00031 {
00032 kError(399) << "kimgio EPS: EPS file has less than 2 bytes." << endl;
00033 return false;
00034 }
00035
00036 if ( buf[0]=='%' && buf[1]=='!' )
00037 {
00038 kDebug(399) << "kimgio EPS: normal EPS file";
00039 }
00040 else if ( buf[0]==char(0xc5) && buf[1]==char(0xd0) )
00041 {
00042 if ( io->read(buf+2, 2)!=2 )
00043 {
00044 kError(399) << "kimgio EPS: potential MS-DOS EPS file has less than 4 bytes." << endl;
00045 return false;
00046 }
00047 if ( buf[2]==char(0xd3) && buf[3]==char(0xc6) )
00048 {
00049 if (io->read(buf, 4)!=4)
00050 {
00051 kError(399) << "kimgio EPS: cannot read offset of MS-DOS EPS file" << endl;
00052 return false;
00053 }
00054 ps_offset
00055 = ((unsigned char) buf[0])
00056 + ((unsigned char) buf[1] << 8)
00057 + ((unsigned char) buf[2] << 16)
00058 + ((unsigned char) buf[3] << 24);
00059 if (io->read(buf, 4)!=4)
00060 {
00061 kError(399) << "kimgio EPS: cannot read size of MS-DOS EPS file" << endl;
00062 return false;
00063 }
00064 ps_size
00065 = ((unsigned char) buf[0])
00066 + ((unsigned char) buf[1] << 8)
00067 + ((unsigned char) buf[2] << 16)
00068 + ((unsigned char) buf[3] << 24);
00069 kDebug(399) << "kimgio EPS: Offset: " << ps_offset <<" Size: " << ps_size;
00070 if ( !io->seek(ps_offset) )
00071 {
00072 kError(399) << "kimgio EPS: cannot seek in MS-DOS EPS file" << endl;
00073 return false;
00074 }
00075 if ( io->read(buf, 2)!=2 )
00076 {
00077 kError(399) << "kimgio EPS: PostScript code has less than 2 bytes." << endl;
00078 return false;
00079 }
00080 if ( buf[0]=='%' && buf[1]=='!' )
00081 {
00082 kDebug(399) << "kimgio EPS: MS-DOS EPS file";
00083 }
00084 else
00085 {
00086 kError(399) << "kimgio EPS: supposed Postscript code of a MS-DOS EPS file doe not start with %!." << endl;
00087 return false;
00088 }
00089 }
00090 else
00091 {
00092 kError(399) << "kimgio EPS: wrong magic for potential MS-DOS EPS file!" << endl;
00093 return false;
00094 }
00095 }
00096 else
00097 {
00098 kError(399) << "kimgio EPS: not an EPS file!" << endl;
00099 return false;
00100 }
00101 return true;
00102 }
00103
00104 static bool bbox ( QIODevice *io, int *x1, int *y1, int *x2, int *y2)
00105 {
00106 char buf[BUFLEN+1];
00107
00108 bool ret = false;
00109
00110 while (io->readLine(buf, BUFLEN) > 0)
00111 {
00112 if (strncmp (buf, BBOX, BBOX_LEN) == 0)
00113 {
00114
00115
00116 float _x1, _y1, _x2, _y2;
00117 if ( sscanf (buf, "%*s %f %f %f %f",
00118 &_x1, &_y1, &_x2, &_y2) == 4) {
00119 kDebug(399) << "kimgio EPS BBOX: " << _x1 << " " << _y1 << " " << _x2 << " " << _y2;
00120 *x1=(int)_x1; *y1=(int)_y1; *x2=(int)_x2; *y2=(int)_y2;
00121 ret = true;
00122 break;
00123 }
00124 }
00125 }
00126
00127 return ret;
00128 }
00129
00130 EPSHandler::EPSHandler()
00131 {
00132 }
00133
00134 bool EPSHandler::canRead() const
00135 {
00136 if (canRead(device())) {
00137 setFormat("eps");
00138 return true;
00139 }
00140 return false;
00141 }
00142
00143 bool EPSHandler::read(QImage *image)
00144 {
00145 kDebug(399) << "kimgio EPS: starting...";
00146
00147 FILE * ghostfd;
00148 int x1, y1, x2, y2;
00149
00150
00151
00152 QString cmdBuf;
00153 QString tmp;
00154
00155 QIODevice* io = device();
00156 quint32 ps_offset, ps_size;
00157
00158
00159 if ( !seekToCodeStart(io, ps_offset, ps_size) )
00160 return false;
00161
00162
00163 if ( !bbox (io, &x1, &y1, &x2, &y2)) {
00164 kError(399) << "kimgio EPS: no bounding box found!" << endl;
00165 return false;
00166 }
00167
00168 QTemporaryFile tmpFile;
00169 if( !tmpFile.open() ) {
00170 kError(399) << "kimgio EPS: no temp file!" << endl;
00171 return false;
00172 }
00173
00174
00175
00176
00177 x2 -= x1;
00178 y2 -= y1;
00179
00180 double xScale = 1.0;
00181 double yScale = 1.0;
00182 int wantedWidth = x2;
00183 int wantedHeight = y2;
00184
00185
00186
00187 cmdBuf = "gs -sOutputFile=";
00188 cmdBuf += tmpFile.fileName();
00189 cmdBuf += " -q -g";
00190 tmp.setNum( wantedWidth );
00191 cmdBuf += tmp;
00192 tmp.setNum( wantedHeight );
00193 cmdBuf += 'x';
00194 cmdBuf += tmp;
00195 cmdBuf += " -dSAFER -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ppm -c "
00196 "0 0 moveto "
00197 "1000 0 lineto "
00198 "1000 1000 lineto "
00199 "0 1000 lineto "
00200 "1 1 254 255 div setrgbcolor fill "
00201 "0 0 0 setrgbcolor - -c showpage quit";
00202
00203
00204
00205 ghostfd = popen (QFile::encodeName(cmdBuf), "w");
00206
00207 if ( ghostfd == 0 ) {
00208 kError(399) << "kimgio EPS: no GhostScript?" << endl;
00209 return false;
00210 }
00211
00212 fprintf (ghostfd, "\n%d %d translate\n", -qRound(x1*xScale), -qRound(y1*yScale));
00213
00214
00215
00216 io->reset();
00217 if (ps_offset>0L)
00218 io->seek(ps_offset);
00219 QByteArray buffer ( io->readAll() );
00220
00221
00222 if (ps_size<=0 || ps_size>(unsigned int)buffer.size())
00223 ps_size=buffer.size();
00224
00225 fwrite(buffer.data(), sizeof(char), ps_size, ghostfd);
00226 buffer.resize(0);
00227
00228 pclose ( ghostfd );
00229
00230
00231 if( image->load (tmpFile.fileName()) ) {
00232 kDebug(399) << "kimgio EPS: success!";
00233
00234 return true;
00235 }
00236
00237 kError(399) << "kimgio EPS: no image!" << endl;
00238 return false;
00239 }
00240
00241
00242
00243 bool EPSHandler::write(const QImage &image)
00244 {
00245 QPrinter psOut(QPrinter::PrinterResolution);
00246 QPainter p;
00247
00248
00249 psOut.setCreator( "KDE " KDE_VERSION_STRING );
00250 if ( psOut.outputFileName().isEmpty() )
00251 psOut.setOutputFileName( "untitled_printer_document" );
00252
00253
00254 QTemporaryFile tmpFile("XXXXXXXX.eps");
00255 if ( !tmpFile.open() )
00256 return false;
00257
00258 psOut.setOutputFileName(tmpFile.fileName());
00259 psOut.setFullPage(true);
00260
00261
00262 p.begin( &psOut );
00263
00264 p.setClipRect( 0, 0, image.width(), image.height());
00265 p.drawImage( QPoint( 0, 0 ), image );
00266 p.end();
00267
00268
00269 QFile inFile(tmpFile.fileName());
00270 inFile.open( QIODevice::ReadOnly );
00271
00272 QTextStream in( &inFile );
00273 in.setCodec( "ISO-8859-1" );
00274 QTextStream out( device() );
00275 out.setCodec( "ISO-8859-1" );
00276
00277 QString szInLine = in.readLine();
00278 out << szInLine << '\n';
00279
00280 while( !in.atEnd() ){
00281 szInLine = in.readLine();
00282 out << szInLine << '\n';
00283 }
00284
00285 inFile.close();
00286
00287 return true;
00288 }
00289
00290 QByteArray EPSHandler::name() const
00291 {
00292 return "eps";
00293 }
00294
00295 bool EPSHandler::canRead(QIODevice *device)
00296 {
00297 if (!device) {
00298 qWarning("EPSHandler::canRead() called with no device");
00299 return false;
00300 }
00301
00302 qint64 oldPos = device->pos();
00303
00304 QByteArray head = device->readLine(64);
00305 int readBytes = head.size();
00306 if (device->isSequential()) {
00307 while (readBytes > 0)
00308 device->ungetChar(head[readBytes-- - 1]);
00309 } else {
00310 device->seek(oldPos);
00311 }
00312
00313 return head.contains("%!PS-Adobe");
00314 }
00315
00316 class EPSPlugin : public QImageIOPlugin
00317 {
00318 public:
00319 QStringList keys() const;
00320 Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
00321 QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
00322 };
00323
00324 QStringList EPSPlugin::keys() const
00325 {
00326 return QStringList() << "eps" << "EPS" << "epsi" << "EPSI" << "epsf" << "EPSF";
00327 }
00328
00329 QImageIOPlugin::Capabilities EPSPlugin::capabilities(QIODevice *device, const QByteArray &format) const
00330 {
00331 if (format == "eps" || format == "epsi" || format == "EPS" || format == "EPSI" ||
00332 format == "epsf" || format == "EPSF")
00333 return Capabilities(CanRead | CanWrite);
00334 if (!format.isEmpty())
00335 return 0;
00336 if (!device->isOpen())
00337 return 0;
00338
00339 Capabilities cap;
00340 if (device->isReadable() && EPSHandler::canRead(device))
00341 cap |= CanRead;
00342 if (device->isWritable())
00343 cap |= CanWrite;
00344 return cap;
00345 }
00346
00347 QImageIOHandler *EPSPlugin::create(QIODevice *device, const QByteArray &format) const
00348 {
00349 QImageIOHandler *handler = new EPSHandler;
00350 handler->setDevice(device);
00351 handler->setFormat(format);
00352 return handler;
00353 }
00354
00355 Q_EXPORT_STATIC_PLUGIN(EPSPlugin)
00356 Q_EXPORT_PLUGIN2(eps, EPSPlugin)