eps.cpp
00001 // This library is distributed under the conditions of the GNU LGPL. 00002 #include <unistd.h> 00003 #include <stdio.h> 00004 #include <tqimage.h> 00005 #include <tqfile.h> 00006 #include <tqpainter.h> 00007 #include <tqprinter.h> 00008 #include <tdeapplication.h> 00009 #include <tdetempfile.h> 00010 #include <kdebug.h> 00011 #include "eps.h" 00012 00013 #define BUFLEN 200 00014 00015 #define BBOX "%%BoundingBox:" 00016 #define BBOX_LEN strlen(BBOX) 00017 00018 static bool seekToCodeStart( TQIODevice * io, TQ_UINT32 & ps_offset, TQ_UINT32 & ps_size ) 00019 { 00020 char buf[4]; // We at most need to read 4 bytes at a time 00021 ps_offset=0L; 00022 ps_size=0L; 00023 00024 if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes 00025 { 00026 kdError(399) << "kimgio EPS: EPS file has less than 2 bytes." << endl; 00027 return false; 00028 } 00029 00030 if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic 00031 { 00032 kdDebug(399) << "kimgio EPS: normal EPS file" << endl; 00033 } 00034 else if ( buf[0]==char(0xc5) && buf[1]==char(0xd0) ) // Check start of MS-DOS EPS magic 00035 { // May be a MS-DOS EPS file 00036 if ( io->readBlock(buf+2, 2)!=2 ) // Read further bytes of MS-DOS EPS magic 00037 { 00038 kdError(399) << "kimgio EPS: potential MS-DOS EPS file has less than 4 bytes." << endl; 00039 return false; 00040 } 00041 if ( buf[2]==char(0xd3) && buf[3]==char(0xc6) ) // Check last bytes of MS-DOS EPS magic 00042 { 00043 if (io->readBlock(buf, 4)!=4) // Get offset of PostScript code in the MS-DOS EPS file. 00044 { 00045 kdError(399) << "kimgio EPS: cannot read offset of MS-DOS EPS file" << endl; 00046 return false; 00047 } 00048 ps_offset // Offset is in little endian 00049 = ((unsigned char) buf[0]) 00050 + ((unsigned char) buf[1] << 8) 00051 + ((unsigned char) buf[2] << 16) 00052 + ((unsigned char) buf[3] << 24); 00053 if (io->readBlock(buf, 4)!=4) // Get size of PostScript code in the MS-DOS EPS file. 00054 { 00055 kdError(399) << "kimgio EPS: cannot read size of MS-DOS EPS file" << endl; 00056 return false; 00057 } 00058 ps_size // Size is in little endian 00059 = ((unsigned char) buf[0]) 00060 + ((unsigned char) buf[1] << 8) 00061 + ((unsigned char) buf[2] << 16) 00062 + ((unsigned char) buf[3] << 24); 00063 kdDebug(399) << "kimgio EPS: Offset: " << ps_offset <<" Size: " << ps_size << endl; 00064 if ( !io->at(ps_offset) ) // Get offset of PostScript code in the MS-DOS EPS file. 00065 { 00066 kdError(399) << "kimgio EPS: cannot seek in MS-DOS EPS file" << endl; 00067 return false; 00068 } 00069 if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes of what should be the Postscript code 00070 { 00071 kdError(399) << "kimgio EPS: PostScript code has less than 2 bytes." << endl; 00072 return false; 00073 } 00074 if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic 00075 { 00076 kdDebug(399) << "kimgio EPS: MS-DOS EPS file" << endl; 00077 } 00078 else 00079 { 00080 kdError(399) << "kimgio EPS: supposed Postscript code of a MS-DOS EPS file doe not start with %!." << endl; 00081 return false; 00082 } 00083 } 00084 else 00085 { 00086 kdError(399) << "kimgio EPS: wrong magic for potential MS-DOS EPS file!" << endl; 00087 return false; 00088 } 00089 } 00090 else 00091 { 00092 kdError(399) << "kimgio EPS: not an EPS file!" << endl; 00093 return false; 00094 } 00095 return true; 00096 } 00097 00098 static bool bbox ( TQIODevice *io, int *x1, int *y1, int *x2, int *y2) 00099 { 00100 char buf[BUFLEN+1]; 00101 00102 bool ret = false; 00103 00104 while (io->readLine(buf, BUFLEN) > 0) 00105 { 00106 if (strncmp (buf, BBOX, BBOX_LEN) == 0) 00107 { 00108 // Some EPS files have non-integer values for the bbox 00109 // We don't support that currently, but at least we parse it 00110 float _x1, _y1, _x2, _y2; 00111 if ( sscanf (buf, "%*s %f %f %f %f", 00112 &_x1, &_y1, &_x2, &_y2) == 4) { 00113 kdDebug(399) << "kimgio EPS BBOX: " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl; 00114 *x1=(int)_x1; *y1=(int)_y1; *x2=(int)_x2; *y2=(int)_y2; 00115 ret = true; 00116 break; 00117 } 00118 } 00119 } 00120 00121 return ret; 00122 } 00123 00124 KDE_EXPORT void kimgio_eps_read (TQImageIO *image) 00125 { 00126 kdDebug(399) << "kimgio EPS: starting..." << endl; 00127 00128 FILE * ghostfd; 00129 int x1, y1, x2, y2; 00130 //TQTime dt; 00131 //dt.start(); 00132 00133 TQString cmdBuf; 00134 TQString tmp; 00135 00136 TQIODevice* io = image->ioDevice(); 00137 TQ_UINT32 ps_offset, ps_size; 00138 00139 // find start of PostScript code 00140 if ( !seekToCodeStart(io, ps_offset, ps_size) ) 00141 return; 00142 00143 // find bounding box 00144 if ( !bbox (io, &x1, &y1, &x2, &y2)) { 00145 kdError(399) << "kimgio EPS: no bounding box found!" << endl; 00146 return; 00147 } 00148 00149 KTempFile tmpFile; 00150 tmpFile.setAutoDelete(true); 00151 00152 if( tmpFile.status() != 0 ) { 00153 kdError(399) << "kimgio EPS: no temp file!" << endl; 00154 return; 00155 } 00156 tmpFile.close(); // Close the file, we just want the filename 00157 00158 // x1, y1 -> translation 00159 // x2, y2 -> new size 00160 00161 x2 -= x1; 00162 y2 -= y1; 00163 //kdDebug(399) << "origin point: " << x1 << "," << y1 << " size:" << x2 << "," << y2 << endl; 00164 double xScale = 1.0; 00165 double yScale = 1.0; 00166 bool needsScaling = false; 00167 int wantedWidth = x2; 00168 int wantedHeight = y2; 00169 00170 if (image->parameters()) 00171 { 00172 // Size forced by the caller 00173 TQStringList params = TQStringList::split(':', image->parameters()); 00174 if (params.count() >= 2 && x2 != 0.0 && y2 != 0.0) 00175 { 00176 wantedWidth = params[0].toInt(); 00177 xScale = (double)wantedWidth / (double)x2; 00178 wantedHeight = params[1].toInt(); 00179 yScale = (double)wantedHeight / (double)y2; 00180 //kdDebug(399) << "wanted size:" << wantedWidth << "x" << wantedHeight << endl; 00181 //kdDebug(399) << "scaling:" << xScale << "," << yScale << endl; 00182 needsScaling = true; 00183 } 00184 } 00185 00186 // create GS command line 00187 00188 cmdBuf = "gs -sOutputFile="; 00189 cmdBuf += tmpFile.name(); 00190 cmdBuf += " -q -g"; 00191 tmp.setNum( wantedWidth ); 00192 cmdBuf += tmp; 00193 tmp.setNum( wantedHeight ); 00194 cmdBuf += "x"; 00195 cmdBuf += tmp; 00196 cmdBuf += " -dSAFER -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ppm -c " 00197 "0 0 moveto " 00198 "1000 0 lineto " 00199 "1000 1000 lineto " 00200 "0 1000 lineto " 00201 "1 1 254 255 div setrgbcolor fill " 00202 "0 0 0 setrgbcolor - -c showpage quit"; 00203 00204 // run ghostview 00205 00206 ghostfd = popen (TQFile::encodeName(cmdBuf), "w"); 00207 00208 if ( ghostfd == 0 ) { 00209 kdError(399) << "kimgio EPS: no GhostScript?" << endl; 00210 return; 00211 } 00212 00213 fprintf (ghostfd, "\n%d %d translate\n", -tqRound(x1*xScale), -tqRound(y1*yScale)); 00214 if ( needsScaling ) 00215 fprintf (ghostfd, "%g %g scale\n", xScale, yScale); 00216 00217 // write image to gs 00218 00219 io->reset(); // Go back to start of file to give all the file to GhostScript 00220 if (ps_offset>0L) // We have an offset 00221 io->at(ps_offset); 00222 TQByteArray buffer ( io->readAll() ); 00223 00224 // If we have no MS-DOS EPS file or if the size seems wrong, then choose the buffer size 00225 if (ps_size<=0L || ps_size>buffer.size()) 00226 ps_size=buffer.size(); 00227 00228 fwrite(buffer.data(), sizeof(char), ps_size, ghostfd); 00229 buffer.resize(0); 00230 00231 pclose ( ghostfd ); 00232 00233 // load image 00234 TQImage myimage; 00235 if( myimage.load (tmpFile.name()) ) { 00236 image->setImage (myimage); 00237 image->setStatus (0); 00238 kdDebug(399) << "kimgio EPS: success!" << endl; 00239 } 00240 else 00241 kdError(399) << "kimgio EPS: no image!" << endl; 00242 00243 //kdDebug(399) << "Loading EPS took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl; 00244 return; 00245 } 00246 00247 // Sven Wiegand <SWiegand@tfh-berlin.de> -- eps output filter (from KSnapshot) 00248 KDE_EXPORT void kimgio_eps_write( TQImageIO *imageio ) 00249 { 00250 TQPrinter psOut(TQPrinter::PrinterResolution); 00251 TQPainter p; 00252 00253 // making some definitions (papersize, output to file, filename): 00254 psOut.setCreator( "KDE " TDE_VERSION_STRING ); 00255 psOut.setOutputToFile( true ); 00256 00257 // Extension must be .eps so that Qt generates EPS file 00258 KTempFile tmpFile(TQString::null, ".eps"); 00259 tmpFile.setAutoDelete(true); 00260 if ( tmpFile.status() != 0) 00261 return; 00262 tmpFile.close(); // Close the file, we just want the filename 00263 00264 psOut.setOutputFileName(tmpFile.name()); 00265 psOut.setFullPage(true); 00266 00267 // painting the pixmap to the "printer" which is a file 00268 p.begin( &psOut ); 00269 // Qt uses the clip rect for the bounding box 00270 p.setClipRect( 0, 0, imageio->image().width(), imageio->image().height(), TQPainter::CoordPainter); 00271 p.drawImage( TQPoint( 0, 0 ), imageio->image() ); 00272 p.end(); 00273 00274 // Copy file to imageio struct 00275 TQFile inFile(tmpFile.name()); 00276 inFile.open( IO_ReadOnly ); 00277 00278 TQTextStream in( &inFile ); 00279 in.setEncoding( TQTextStream::Latin1 ); 00280 TQTextStream out( imageio->ioDevice() ); 00281 out.setEncoding( TQTextStream::Latin1 ); 00282 00283 TQString szInLine = in.readLine(); 00284 out << szInLine << '\n'; 00285 00286 while( !in.atEnd() ){ 00287 szInLine = in.readLine(); 00288 out << szInLine << '\n'; 00289 } 00290 00291 inFile.close(); 00292 00293 imageio->setStatus(0); 00294 }