TDE core libraries
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.

eps.cpp 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // This library is distributed under the conditions of the GNU LGPL.
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <tqimage.h>
  5. #include <tqfile.h>
  6. #include <tqpainter.h>
  7. #include <tqprinter.h>
  8. #include <tdeapplication.h>
  9. #include <tdetempfile.h>
  10. #include <kdebug.h>
  11. #include "eps.h"
  12. #define BUFLEN 200
  13. #define BBOX "%%BoundingBox:"
  14. #define BBOX_LEN strlen(BBOX)
  15. static bool seekToCodeStart( TQIODevice * io, TQ_UINT32 & ps_offset, TQ_UINT32 & ps_size )
  16. {
  17. char buf[4]; // We at most need to read 4 bytes at a time
  18. ps_offset=0L;
  19. ps_size=0L;
  20. if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes
  21. {
  22. kdError(399) << "kimgio EPS: EPS file has less than 2 bytes." << endl;
  23. return false;
  24. }
  25. if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic
  26. {
  27. kdDebug(399) << "kimgio EPS: normal EPS file" << endl;
  28. }
  29. else if ( buf[0]==char(0xc5) && buf[1]==char(0xd0) ) // Check start of MS-DOS EPS magic
  30. { // May be a MS-DOS EPS file
  31. if ( io->readBlock(buf+2, 2)!=2 ) // Read further bytes of MS-DOS EPS magic
  32. {
  33. kdError(399) << "kimgio EPS: potential MS-DOS EPS file has less than 4 bytes." << endl;
  34. return false;
  35. }
  36. if ( buf[2]==char(0xd3) && buf[3]==char(0xc6) ) // Check last bytes of MS-DOS EPS magic
  37. {
  38. if (io->readBlock(buf, 4)!=4) // Get offset of PostScript code in the MS-DOS EPS file.
  39. {
  40. kdError(399) << "kimgio EPS: cannot read offset of MS-DOS EPS file" << endl;
  41. return false;
  42. }
  43. ps_offset // Offset is in little endian
  44. = ((unsigned char) buf[0])
  45. + ((unsigned char) buf[1] << 8)
  46. + ((unsigned char) buf[2] << 16)
  47. + ((unsigned char) buf[3] << 24);
  48. if (io->readBlock(buf, 4)!=4) // Get size of PostScript code in the MS-DOS EPS file.
  49. {
  50. kdError(399) << "kimgio EPS: cannot read size of MS-DOS EPS file" << endl;
  51. return false;
  52. }
  53. ps_size // Size is in little endian
  54. = ((unsigned char) buf[0])
  55. + ((unsigned char) buf[1] << 8)
  56. + ((unsigned char) buf[2] << 16)
  57. + ((unsigned char) buf[3] << 24);
  58. kdDebug(399) << "kimgio EPS: Offset: " << ps_offset <<" Size: " << ps_size << endl;
  59. if ( !io->at(ps_offset) ) // Get offset of PostScript code in the MS-DOS EPS file.
  60. {
  61. kdError(399) << "kimgio EPS: cannot seek in MS-DOS EPS file" << endl;
  62. return false;
  63. }
  64. if ( io->readBlock(buf, 2)!=2 ) // Read first two bytes of what should be the Postscript code
  65. {
  66. kdError(399) << "kimgio EPS: PostScript code has less than 2 bytes." << endl;
  67. return false;
  68. }
  69. if ( buf[0]=='%' && buf[1]=='!' ) // Check %! magic
  70. {
  71. kdDebug(399) << "kimgio EPS: MS-DOS EPS file" << endl;
  72. }
  73. else
  74. {
  75. kdError(399) << "kimgio EPS: supposed Postscript code of a MS-DOS EPS file doe not start with %!." << endl;
  76. return false;
  77. }
  78. }
  79. else
  80. {
  81. kdError(399) << "kimgio EPS: wrong magic for potential MS-DOS EPS file!" << endl;
  82. return false;
  83. }
  84. }
  85. else
  86. {
  87. kdError(399) << "kimgio EPS: not an EPS file!" << endl;
  88. return false;
  89. }
  90. return true;
  91. }
  92. static bool bbox ( TQIODevice *io, int *x1, int *y1, int *x2, int *y2)
  93. {
  94. char buf[BUFLEN+1];
  95. bool ret = false;
  96. while (io->readLine(buf, BUFLEN) > 0)
  97. {
  98. if (strncmp (buf, BBOX, BBOX_LEN) == 0)
  99. {
  100. // Some EPS files have non-integer values for the bbox
  101. // We don't support that currently, but at least we parse it
  102. float _x1, _y1, _x2, _y2;
  103. if ( sscanf (buf, "%*s %f %f %f %f",
  104. &_x1, &_y1, &_x2, &_y2) == 4) {
  105. kdDebug(399) << "kimgio EPS BBOX: " << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl;
  106. *x1=(int)_x1; *y1=(int)_y1; *x2=(int)_x2; *y2=(int)_y2;
  107. ret = true;
  108. break;
  109. }
  110. }
  111. }
  112. return ret;
  113. }
  114. KDE_EXPORT void kimgio_eps_read (TQImageIO *image)
  115. {
  116. kdDebug(399) << "kimgio EPS: starting..." << endl;
  117. FILE * ghostfd;
  118. int x1, y1, x2, y2;
  119. //TQTime dt;
  120. //dt.start();
  121. TQString cmdBuf;
  122. TQString tmp;
  123. TQIODevice* io = image->ioDevice();
  124. TQ_UINT32 ps_offset, ps_size;
  125. // find start of PostScript code
  126. if ( !seekToCodeStart(io, ps_offset, ps_size) )
  127. return;
  128. // find bounding box
  129. if ( !bbox (io, &x1, &y1, &x2, &y2)) {
  130. kdError(399) << "kimgio EPS: no bounding box found!" << endl;
  131. return;
  132. }
  133. KTempFile tmpFile;
  134. tmpFile.setAutoDelete(true);
  135. if( tmpFile.status() != 0 ) {
  136. kdError(399) << "kimgio EPS: no temp file!" << endl;
  137. return;
  138. }
  139. tmpFile.close(); // Close the file, we just want the filename
  140. // x1, y1 -> translation
  141. // x2, y2 -> new size
  142. x2 -= x1;
  143. y2 -= y1;
  144. //kdDebug(399) << "origin point: " << x1 << "," << y1 << " size:" << x2 << "," << y2 << endl;
  145. double xScale = 1.0;
  146. double yScale = 1.0;
  147. bool needsScaling = false;
  148. int wantedWidth = x2;
  149. int wantedHeight = y2;
  150. if (image->parameters())
  151. {
  152. // Size forced by the caller
  153. TQStringList params = TQStringList::split(':', image->parameters());
  154. if (params.count() >= 2 && x2 != 0.0 && y2 != 0.0)
  155. {
  156. wantedWidth = params[0].toInt();
  157. xScale = (double)wantedWidth / (double)x2;
  158. wantedHeight = params[1].toInt();
  159. yScale = (double)wantedHeight / (double)y2;
  160. //kdDebug(399) << "wanted size:" << wantedWidth << "x" << wantedHeight << endl;
  161. //kdDebug(399) << "scaling:" << xScale << "," << yScale << endl;
  162. needsScaling = true;
  163. }
  164. }
  165. // create GS command line
  166. cmdBuf = "gs -sOutputFile=";
  167. cmdBuf += tmpFile.name();
  168. cmdBuf += " -q -g";
  169. tmp.setNum( wantedWidth );
  170. cmdBuf += tmp;
  171. tmp.setNum( wantedHeight );
  172. cmdBuf += "x";
  173. cmdBuf += tmp;
  174. cmdBuf += " -dSAFER -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ppm -c "
  175. "0 0 moveto "
  176. "1000 0 lineto "
  177. "1000 1000 lineto "
  178. "0 1000 lineto "
  179. "1 1 254 255 div setrgbcolor fill "
  180. "0 0 0 setrgbcolor - -c showpage quit";
  181. // run ghostview
  182. ghostfd = popen (TQFile::encodeName(cmdBuf), "w");
  183. if ( ghostfd == 0 ) {
  184. kdError(399) << "kimgio EPS: no GhostScript?" << endl;
  185. return;
  186. }
  187. fprintf (ghostfd, "\n%d %d translate\n", -tqRound(x1*xScale), -tqRound(y1*yScale));
  188. if ( needsScaling )
  189. fprintf (ghostfd, "%g %g scale\n", xScale, yScale);
  190. // write image to gs
  191. io->reset(); // Go back to start of file to give all the file to GhostScript
  192. if (ps_offset>0L) // We have an offset
  193. io->at(ps_offset);
  194. TQByteArray buffer ( io->readAll() );
  195. // If we have no MS-DOS EPS file or if the size seems wrong, then choose the buffer size
  196. if (ps_size<=0L || ps_size>buffer.size())
  197. ps_size=buffer.size();
  198. fwrite(buffer.data(), sizeof(char), ps_size, ghostfd);
  199. buffer.resize(0);
  200. pclose ( ghostfd );
  201. // load image
  202. TQImage myimage;
  203. if( myimage.load (tmpFile.name()) ) {
  204. image->setImage (myimage);
  205. image->setStatus (0);
  206. kdDebug(399) << "kimgio EPS: success!" << endl;
  207. }
  208. else
  209. kdError(399) << "kimgio EPS: no image!" << endl;
  210. //kdDebug(399) << "Loading EPS took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
  211. return;
  212. }
  213. // Sven Wiegand <SWiegand@tfh-berlin.de> -- eps output filter (from KSnapshot)
  214. KDE_EXPORT void kimgio_eps_write( TQImageIO *imageio )
  215. {
  216. TQPrinter psOut(TQPrinter::PrinterResolution);
  217. TQPainter p;
  218. // making some definitions (papersize, output to file, filename):
  219. psOut.setCreator( "KDE " TDE_VERSION_STRING );
  220. psOut.setOutputToFile( true );
  221. // Extension must be .eps so that Qt generates EPS file
  222. KTempFile tmpFile(TQString::null, ".eps");
  223. tmpFile.setAutoDelete(true);
  224. if ( tmpFile.status() != 0)
  225. return;
  226. tmpFile.close(); // Close the file, we just want the filename
  227. psOut.setOutputFileName(tmpFile.name());
  228. psOut.setFullPage(true);
  229. // painting the pixmap to the "printer" which is a file
  230. p.begin( &psOut );
  231. // Qt uses the clip rect for the bounding box
  232. p.setClipRect( 0, 0, imageio->image().width(), imageio->image().height(), TQPainter::CoordPainter);
  233. p.drawImage( TQPoint( 0, 0 ), imageio->image() );
  234. p.end();
  235. // Copy file to imageio struct
  236. TQFile inFile(tmpFile.name());
  237. inFile.open( IO_ReadOnly );
  238. TQTextStream in( &inFile );
  239. in.setEncoding( TQTextStream::Latin1 );
  240. TQTextStream out( imageio->ioDevice() );
  241. out.setEncoding( TQTextStream::Latin1 );
  242. TQString szInLine = in.readLine();
  243. out << szInLine << '\n';
  244. while( !in.atEnd() ){
  245. szInLine = in.readLine();
  246. out << szInLine << '\n';
  247. }
  248. inFile.close();
  249. imageio->setStatus(0);
  250. }