TDE graphics utilities
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.

865 lines
22KB

  1. /**
  2. * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #include <algorithm>
  19. #include <memory>
  20. #include <tqfileinfo.h>
  21. #include <kconfig.h>
  22. #include <kfiledialog.h>
  23. #include <kfilterdev.h>
  24. #include <kinstance.h>
  25. #include <kmessagebox.h>
  26. #include <kmimetype.h>
  27. #include <kprinter.h>
  28. #include <kprocess.h>
  29. #include <ktempfile.h>
  30. #include <kio/netaccess.h>
  31. #include <klocale.h>
  32. #include <kdebug.h>
  33. #include "configuration.h"
  34. #include "kdscerrordialog.h"
  35. #include "kgv_miniwidget.h"
  36. #include "marklist.h"
  37. #include "kgvfactory.h"
  38. extern "C" {
  39. #include "ps.h"
  40. }
  41. #include "kgvdocument.h"
  42. using namespace std;
  43. using namespace KGV;
  44. KGVDocument::KGVDocument( KGVPart* part, const char* name ) :
  45. TQObject( part, name ),
  46. _psFile( 0 ),
  47. _part( part ),
  48. _tmpUnzipped( 0 ),
  49. _tmpFromPDF( 0 ),
  50. _tmpDSC( 0 ),
  51. _isFileOpen( false ),
  52. _dsc( 0 )
  53. {
  54. readSettings();
  55. _pdf2dsc = new Pdf2dsc( _interpreterPath, this );
  56. connect( _pdf2dsc, TQT_SIGNAL( finished( bool ) ),
  57. TQT_SLOT( openPDFFileContinue( bool ) ) );
  58. }
  59. KGVDocument::~KGVDocument()
  60. {
  61. close();
  62. }
  63. void KGVDocument::readSettings()
  64. {
  65. _interpreterPath = Configuration::interpreter();
  66. }
  67. /*- OPENING and READING ---------------------------------------------------*/
  68. void KGVDocument::openFile( const TQString& name, const TQString& mimetype )
  69. {
  70. kdDebug(4500) << "KGVDocument::openFile" << endl;
  71. close();
  72. _fileName = name;
  73. _mimetype = mimetype;
  74. TQTimer::singleShot( 0, this, TQT_SLOT( doOpenFile() ) );
  75. }
  76. void KGVDocument::doOpenFile()
  77. {
  78. TQFileInfo fileInfo( _fileName );
  79. if( !fileInfo.exists() )
  80. {
  81. KMessageBox::sorry( _part->widget(),
  82. i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr>: "
  83. "File does not exist.</qt>" )
  84. .arg( _fileName ) );
  85. emit canceled( TQString() );
  86. return;
  87. }
  88. if( !fileInfo.isReadable() )
  89. {
  90. KMessageBox::sorry( _part->widget(),
  91. i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr>: "
  92. "Permission denied.</qt>" )
  93. .arg( _fileName ) );
  94. emit canceled( TQString() );
  95. return;
  96. }
  97. if( uncompressFile() )
  98. {
  99. kdDebug( 4500 ) << "FILENAME: " << _fileName << endl;
  100. KMimeType::Ptr mimetype = KMimeType::findByPath( _fileName );
  101. kdDebug(4500) << "KGVDocument::mimetype: " << mimetype->name()
  102. << endl;
  103. _mimetype = mimetype->name();
  104. }
  105. // If the file contains a PDF document, create a DSC description file
  106. // of the PDF document. This can be passed to Ghostscript just like
  107. // an ordinary PS file.
  108. if( _mimetype == "application/pdf"
  109. || _mimetype == "application/x-pdf" ) // see bug:67474
  110. {
  111. _tmpDSC = new KTempFile( TQString(), ".ps" );
  112. Q_CHECK_PTR( _tmpDSC );
  113. if( _tmpDSC->status() != 0 ) {
  114. KMessageBox::error( _part->widget(),
  115. i18n( "Could not create temporary file: %1" )
  116. .arg( strerror( _tmpDSC->status() ) ) );
  117. emit canceled( TQString() );
  118. return;
  119. }
  120. // When pdf2dsc has finished the program will continue with
  121. // openPDFFileContinue.
  122. _pdf2dsc->run( _fileName, _tmpDSC->name() );
  123. return;
  124. }
  125. else if( _mimetype == "application/postscript"
  126. || _mimetype == "application/x-postscript" // see bug:71546
  127. || _mimetype == "application/illustrator"
  128. || _mimetype == "image/x-eps"
  129. || _mimetype == "text/plain" )
  130. {
  131. _format = PS;
  132. openPSFile();
  133. return;
  134. }
  135. else
  136. {
  137. KMessageBox::sorry( _part->widget(),
  138. i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr> "
  139. "which has type <strong>%2</strong>. KGhostview can "
  140. "only load PostScript (.ps, .eps) and Portable "
  141. "Document Format (.pdf) files.</qt>" )
  142. .arg( _fileName )
  143. .arg( _mimetype ) );
  144. emit canceled( TQString() );
  145. return;
  146. }
  147. }
  148. bool KGVDocument::uncompressFile()
  149. {
  150. // If the file is gzipped, gunzip it to the temporary file _tmpUnzipped.
  151. kdDebug(4500) << "KGVDocument::uncompressFile()" << endl;
  152. auto_ptr<TQIODevice> filterDev( KFilterDev::deviceForFile( _fileName, _mimetype, true ) );
  153. if ( !filterDev.get() ) {
  154. KMimeType::Ptr mt = KMimeType::mimeType(_mimetype);
  155. if ( (_fileName.right( 3 ) == ".gz") || mt->is("application/x-gzip") ) {
  156. kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing gzip" << endl;
  157. filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-gzip", true ) );
  158. } else if ( (_fileName.right( 4 ) == ".bz2") || mt->is("application/x-bzip2") ) {
  159. kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing bzip2" << endl;
  160. filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-bzip2", true ) );
  161. } else {
  162. kdDebug( 4500 ) << "KGVDocument::uncompressFile(): Unable to guess " << _fileName << endl;
  163. }
  164. if ( !filterDev.get() )
  165. return false;
  166. }
  167. if( !filterDev->open( IO_ReadOnly ) )
  168. {
  169. KMessageBox::error( _part->widget(),
  170. i18n( "<qt>Could not uncompress <nobr><strong>%1</strong></nobr>.</qt>" )
  171. .arg( _fileName ) );
  172. emit canceled( TQString() );
  173. return false;
  174. }
  175. _tmpUnzipped = new KTempFile;
  176. Q_CHECK_PTR( _tmpUnzipped );
  177. if( _tmpUnzipped->status() != 0 )
  178. {
  179. KMessageBox::error( _part->widget(),
  180. i18n( "Could not create temporary file: %2" )
  181. .arg( strerror( _tmpUnzipped->status() ) ) );
  182. emit canceled( TQString() );
  183. return false;
  184. }
  185. TQByteArray buf( 8192 );
  186. int read = 0, wrtn = 0;
  187. while( ( read = filterDev->readBlock( buf.data(), buf.size() ) )
  188. > 0 )
  189. {
  190. wrtn = _tmpUnzipped->file()->writeBlock( buf.data(), read );
  191. if( read != wrtn )
  192. break;
  193. }
  194. if( read != 0 )
  195. {
  196. KMessageBox::error( _part->widget(),
  197. i18n( "<qt>Could not uncompress <nobr><strong>%1</strong></nobr>.</qt>" )
  198. .arg( _fileName ) );
  199. emit canceled( TQString() );
  200. return false;
  201. }
  202. _tmpUnzipped->close();
  203. _fileName = _tmpUnzipped->name();
  204. return true;
  205. }
  206. void KGVDocument::openPDFFileContinue( bool pdf2dscResult )
  207. {
  208. kdDebug(4500) << "KGVDocument::openPDFFileContinue" << endl;
  209. if( !pdf2dscResult )
  210. {
  211. KMessageBox::error( _part->widget(),
  212. i18n( "<qt>Could not open file <nobr><strong>%1</strong></nobr>.</qt>" )
  213. .arg( _part->url().url() ) );
  214. emit canceled( TQString() );
  215. return;
  216. }
  217. _tmpDSC->close();
  218. _format = PDF;
  219. openPSFile(_tmpDSC->name());
  220. }
  221. void KGVDocument::openPSFile(const TQString &file)
  222. {
  223. TQString fileName = file.isEmpty() ? _fileName : file;
  224. kdDebug(4500) << "KGVDocument::openPSFile (" << fileName << ")" << endl;
  225. FILE* fp = fopen( TQFile::encodeName( fileName ), "r");
  226. if( fp == 0 )
  227. {
  228. KMessageBox::error( _part->widget(),
  229. i18n( "<qt>Error opening file <nobr><strong>%1</strong></nobr>: %2</qt>" )
  230. .arg( _part->url().url() )
  231. .arg( strerror( errno ) ) );
  232. emit canceled( "" );
  233. return;
  234. }
  235. else
  236. {
  237. _psFile = fp;
  238. _isFileOpen = true;
  239. scanDSC();
  240. emit completed();
  241. }
  242. }
  243. void KGVDocument::fileChanged( const TQString& name )
  244. {
  245. kdDebug(4500) << "KGVDocument: fileChanged " << name << endl;
  246. if( !_psFile )
  247. return;
  248. // unsigned int savepage = _currentPage;
  249. /*
  250. if( openFile( name ) )
  251. goToPage( savepage );
  252. else
  253. emit fileChangeFailed();
  254. */
  255. }
  256. void KGVDocument::scanDSC()
  257. {
  258. _dsc = new KDSC();
  259. // Disable errorDialog for now while KDSCErrorDialog isn't fully
  260. // implemented
  261. // KDSCErrorDialog errorDialog;
  262. // KDSCErrorThreshold errorHandler( 3, &errorDialog );
  263. // _dsc->setErrorHandler( &errorHandler );
  264. char buf[4096];
  265. int count;
  266. /*
  267. TQTime clock;
  268. clock.start();
  269. */
  270. while( ( count = fread( buf, sizeof(char), sizeof( buf ), _psFile ) ) != 0 )
  271. {
  272. _dsc->scanData( buf, count );
  273. /*
  274. if( clock.elapsed() > 10 )
  275. {
  276. kapp->processEvents();
  277. clock.start();
  278. }
  279. */
  280. }
  281. _dsc->fixup();
  282. // _dsc->setErrorHandler( 0 );
  283. }
  284. void KGVDocument::close()
  285. {
  286. _pdf2dsc->kill();
  287. _isFileOpen = false;
  288. delete _dsc;
  289. _dsc = 0;
  290. if( _psFile )
  291. {
  292. fclose( _psFile );
  293. _psFile = 0;
  294. }
  295. clearTemporaryFiles();
  296. }
  297. bool KGVDocument::convertFromPDF( const TQString& saveFileName,
  298. unsigned int firstPage,
  299. unsigned int lastPage )
  300. {
  301. // TODO -- timeout/fail on this conversion (it can hang on a bad pdf)
  302. // TODO -- use output from gs (leave out -q) to drive a progress bar
  303. KProcess process;
  304. process << _interpreterPath
  305. << "-q"
  306. << "-dNOPAUSE"
  307. << "-dBATCH"
  308. << "-dSAFER"
  309. << "-dPARANOIDSAFER"
  310. << "-sDEVICE=pswrite"
  311. << ( TQCString("-sOutputFile=")+TQFile::encodeName(saveFileName).data() )
  312. << ( TQString("-dFirstPage=")+TQString::number( firstPage ) )
  313. << ( TQString("-dLastPage=")+TQString::number( lastPage ) )
  314. << "-c"
  315. << "save"
  316. << "pop"
  317. << "-f"
  318. << TQFile::encodeName(_fileName).data();
  319. /*TQValueList<TQCString> args = process.args();
  320. TQValueList<TQCString>::Iterator it = args.begin();
  321. for ( ; it != args.end() ; ++it )
  322. kdDebug(4500) << ( *it ) << endl;*/
  323. if( !process.start( KProcess::Block ) )
  324. {
  325. kdError() << "convertFromPDF: Couldn't start gs process" << endl;
  326. // TODO -- error message (gs not found?)
  327. return false;
  328. }
  329. if ( !process.normalExit() || process.exitStatus() != 0 )
  330. {
  331. kdError() << "convertFromPDF: normalExit=" << process.normalExit() << " exitStatus=" << process.exitStatus() << endl;
  332. // TODO -- error message (can't open, strerr())
  333. return false;
  334. }
  335. return true;
  336. }
  337. void KGVDocument::clearTemporaryFiles()
  338. {
  339. if( _tmpUnzipped ) {
  340. _tmpUnzipped->setAutoDelete( true );
  341. delete _tmpUnzipped;
  342. _tmpUnzipped = 0;
  343. }
  344. if( _tmpFromPDF ) {
  345. _tmpFromPDF->setAutoDelete( true );
  346. delete _tmpFromPDF;
  347. _tmpFromPDF = 0;
  348. }
  349. if( _tmpDSC ) {
  350. _tmpDSC->setAutoDelete( true );
  351. delete _tmpDSC;
  352. _tmpDSC = 0;
  353. }
  354. }
  355. /*- DOCUMENT --------------------------------------------------------------*/
  356. TQStringList KGVDocument::mediaNames() const
  357. {
  358. TQStringList names;
  359. const CDSCMEDIA* m = dsc_known_media;
  360. while( m->name ) {
  361. names << m->name;
  362. m++;
  363. }
  364. if( isOpen() && dsc()->media() ) {
  365. for( unsigned int i = 0; i < dsc()->media_count(); i++ ) {
  366. if( dsc()->media()[i] && dsc()->media()[i]->name )
  367. names << dsc()->media()[i]->name;
  368. }
  369. }
  370. return names;
  371. }
  372. const CDSCMEDIA* KGVDocument::findMediaByName( const TQString& mediaName ) const
  373. {
  374. if( !isOpen() )
  375. return 0;
  376. if( dsc()->media() ) {
  377. for( unsigned int i = 0; i < dsc()->media_count(); i++ ) {
  378. if( dsc()->media()[i] && dsc()->media()[i]->name
  379. && qstricmp( mediaName.local8Bit(),
  380. dsc()->media()[i]->name ) == 0 ) {
  381. return dsc()->media()[i];
  382. }
  383. }
  384. }
  385. /* It didn't match %%DocumentPaperSizes: */
  386. /* Try our known media */
  387. const CDSCMEDIA *m = dsc_known_media;
  388. while( m->name ) {
  389. if( qstricmp( mediaName.local8Bit(), m->name ) == 0 ) {
  390. return m;
  391. }
  392. m++;
  393. }
  394. return 0;
  395. }
  396. TQSize KGVDocument::computePageSize( const TQString& mediaName ) const
  397. {
  398. kdDebug(4500) << "KGVDocument::computePageSize( " << mediaName << " )" << endl;
  399. if( mediaName == "BoundingBox" ) {
  400. if( dsc()->bbox().get() != 0 )
  401. return dsc()->bbox()->size();
  402. else
  403. return TQSize( 0, 0 );
  404. }
  405. const CDSCMEDIA* m = findMediaByName( mediaName );
  406. Q_ASSERT( m );
  407. return TQSize( static_cast<int>( m->width ), static_cast<int>( m->height ) );
  408. }
  409. /*- PRINTING and SAVING ---------------------------------------------------*/
  410. TQString KGVDocument::pageListToRange( const PageList& pageList )
  411. {
  412. TQString range;
  413. // Iterators marking the begin and end of a successive sequence
  414. // of pages.
  415. PageList::const_iterator bss( pageList.begin() );
  416. PageList::const_iterator ess;
  417. PageList::const_iterator it ( pageList.begin() );
  418. while( it != pageList.end() )
  419. {
  420. ess = it++;
  421. // If ess points to the end of a successive sequence of pages,
  422. // add the stringrepresentation of the sequence to range and
  423. // update bss.
  424. if( it == pageList.end() || *it != (*ess) + 1 )
  425. {
  426. if( !range.isEmpty() )
  427. range += ",";
  428. if( bss == ess )
  429. range += TQString::number( *ess );
  430. else
  431. range += TQString( "%1-%2" ).arg( *bss ).arg( *ess );
  432. bss = it;
  433. }
  434. }
  435. return range;
  436. }
  437. void KGVDocument::print()
  438. {
  439. if( !dsc() ) return;
  440. KPrinter printer;
  441. if( dsc()->isStructured() )
  442. {
  443. printer.setPageSelection( KPrinter::ApplicationSide );
  444. printer.setCurrentPage( _part->miniWidget()->displayOptions().page() + 1 );
  445. printer.setMinMax( 1, dsc()->page_count() );
  446. printer.setOption( "kde-range",
  447. pageListToRange( _part->markList()->markList() ) );
  448. if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) )
  449. {
  450. KTempFile tf( TQString(), ".ps" );
  451. if( tf.status() == 0 )
  452. {
  453. if ( printer.pageList().empty() ) {
  454. KMessageBox::sorry( 0,
  455. i18n( "Printing failed because the list of "
  456. "pages to be printed was empty." ),
  457. i18n( "Error Printing" ) );
  458. } else if ( savePages( tf.name(), printer.pageList() ) ) {
  459. printer.printFiles( TQStringList( tf.name() ), true );
  460. } else {
  461. KMessageBox::error( 0, i18n( "<qt><strong>Printing failure:</strong><br>Could not convert to PostScript</qt>" ) );
  462. }
  463. }
  464. else
  465. {
  466. // TODO: Proper error handling
  467. ;
  468. }
  469. }
  470. }
  471. else
  472. {
  473. printer.setPageSelection( KPrinter::SystemSide );
  474. if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) )
  475. printer.printFiles( _fileName );
  476. }
  477. }
  478. void KGVDocument::saveAs()
  479. {
  480. if( !isOpen() )
  481. return;
  482. KURL saveURL = KFileDialog::getSaveURL(
  483. _part->url().isLocalFile()
  484. ? _part->url().url()
  485. : _part->url().fileName(),
  486. TQString(),
  487. _part->widget(),
  488. TQString() );
  489. if( !KIO::NetAccess::upload( _fileName,
  490. saveURL,
  491. static_cast<TQWidget*>( 0 ) ) ) {
  492. // TODO: Proper error dialog
  493. }
  494. }
  495. bool KGVDocument::savePages( const TQString& saveFileName,
  496. const PageList& pageList )
  497. {
  498. if( pageList.empty() )
  499. return true;
  500. if( _format == PDF )
  501. {
  502. KTempFile psSaveFile( TQString(), ".ps" );
  503. psSaveFile.setAutoDelete( true );
  504. if( psSaveFile.status() != 0 )
  505. return false;
  506. // Find the minimum and maximum pagenumber in pageList.
  507. int minPage = pageList.first(), maxPage = pageList.first();
  508. for( PageList::const_iterator ci = pageList.begin();
  509. ci != pageList.end(); ++ci )
  510. {
  511. minPage = TQMIN( *ci, minPage );
  512. maxPage = TQMAX( *ci, maxPage );
  513. }
  514. // TODO: Optimize "print whole document" case
  515. //
  516. // The convertion below from PDF to PS creates a temporary file which, in
  517. // the case where we are printing the whole document will then be
  518. // completelly copied to another temporary file.
  519. //
  520. // In very large files, the inefficiency is visible (measured in
  521. // seconds).
  522. //
  523. // luis_pedro 4 Jun 2003
  524. // Convert the pages in the range [minPage,maxPage] from PDF to
  525. // PostScript.
  526. if( !convertFromPDF( psSaveFile.name(),
  527. minPage, maxPage ) )
  528. return false;
  529. // The page minPage in the original file becomes page 1 in the
  530. // converted file. We still have to select the desired pages from
  531. // this file, so we need to take into account that difference.
  532. PageList normedPageList;
  533. transform( pageList.begin(), pageList.end(),
  534. back_inserter( normedPageList ),
  535. bind2nd( minus<int>(), minPage - 1 ) );
  536. // Finally select the desired pages from the converted file.
  537. psCopyDoc( psSaveFile.name(), saveFileName, normedPageList );
  538. }
  539. else
  540. {
  541. psCopyDoc( _fileName, saveFileName, pageList );
  542. }
  543. return true;
  544. }
  545. // length calculates string length at compile time
  546. // can only be used with character constants
  547. #define length( a ) ( sizeof( a ) - 1 )
  548. // Copy the headers, marked pages, and trailer to fp
  549. bool KGVDocument::psCopyDoc( const TQString& inputFile,
  550. const TQString& outputFile, const PageList& pageList )
  551. {
  552. FILE* from;
  553. FILE* to;
  554. char text[ PSLINELENGTH ];
  555. char* comment;
  556. bool pages_written = false;
  557. bool pages_atend = false;
  558. unsigned int i = 0;
  559. unsigned int pages = 0;
  560. long here;
  561. kdDebug(4500) << "KGVDocument: Copying pages from " << inputFile << " to "
  562. << outputFile << endl;
  563. pages = pageList.size();
  564. if( pages == 0 ) {
  565. KMessageBox::sorry( 0,
  566. i18n( "Printing failed because the list of "
  567. "pages to be printed was empty." ),
  568. i18n( "Error Printing" ) );
  569. return false;
  570. }
  571. from = fopen( TQFile::encodeName( inputFile ), "r" );
  572. to = fopen( TQFile::encodeName( outputFile ), "w" );
  573. // Hack in order to make printing of PDF files work. FIXME
  574. CDSC* dsc;
  575. if( _format == PS )
  576. dsc = _dsc->cdsc();
  577. else {
  578. FILE* fp = fopen( TQFile::encodeName( inputFile ), "r");
  579. char buf[256];
  580. int count;
  581. dsc = dsc_init( 0 );
  582. while( ( count = fread( buf, 1, sizeof( buf ), fp ) ) != 0 )
  583. dsc_scan_data( dsc, buf, count );
  584. fclose( fp );
  585. if( !dsc )
  586. return false;
  587. dsc_fixup( dsc );
  588. }
  589. here = dsc->begincomments;
  590. while( ( comment = pscopyuntil( from, to, here,
  591. dsc->endcomments, "%%Pages:" ) ) ) {
  592. here = ftell( from );
  593. if( pages_written || pages_atend ) {
  594. free( comment );
  595. continue;
  596. }
  597. sscanf( comment + length("%%Pages:" ), "%256s", text );
  598. text[256] = 0; // Just in case of an overflow
  599. if( strcmp( text, "(atend)" ) == 0 ) {
  600. fputs( comment, to );
  601. pages_atend = true;
  602. }
  603. else {
  604. switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) {
  605. case 1:
  606. fprintf( to, "%%%%Pages: %d %d\n", pages, i );
  607. break;
  608. default:
  609. fprintf( to, "%%%%Pages: %d\n", pages );
  610. break;
  611. }
  612. pages_written = true;
  613. }
  614. free(comment);
  615. }
  616. pscopy( from, to, dsc->beginpreview, dsc->endpreview );
  617. pscopy( from, to, dsc->begindefaults, dsc->enddefaults );
  618. pscopy( from, to, dsc->beginprolog, dsc->endprolog );
  619. pscopy( from, to, dsc->beginsetup, dsc->endsetup );
  620. //TODO -- Check that a all dsc attributes are copied
  621. unsigned int count = 1;
  622. PageList::const_iterator it;
  623. for( it = pageList.begin(); it != pageList.end(); ++it ) {
  624. i = (*it) - 1;
  625. comment = pscopyuntil( from, to, dsc->page[i].begin,
  626. dsc->page[i].end, "%%Page:" );
  627. if ( comment ) free( comment );
  628. fprintf( to, "%%%%Page: %s %d\n", dsc->page[i].label,
  629. count++ );
  630. pscopy( from, to, -1, dsc->page[i].end );
  631. }
  632. here = dsc->begintrailer;
  633. while( ( comment = pscopyuntil( from, to, here,
  634. dsc->endtrailer, "%%Pages:" ) ) ) {
  635. here = ftell( from );
  636. if ( pages_written ) {
  637. free( comment );
  638. continue;
  639. }
  640. switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) {
  641. case 1:
  642. fprintf( to, "%%%%Pages: %d %d\n", pages, i );
  643. break;
  644. default:
  645. fprintf( to, "%%%%Pages: %d\n", pages );
  646. break;
  647. }
  648. pages_written = true;
  649. free( comment );
  650. }
  651. fclose( from );
  652. fclose( to );
  653. if( _format == PDF )
  654. dsc_free( dsc );
  655. return true;
  656. }
  657. #undef length
  658. /*- Conversion stuff ------------------------------------------------------*/
  659. /*
  660. void KGVDocument::runPdf2ps( const TQString& pdfName,
  661. const TQString& dscName )
  662. {
  663. KProcess process;
  664. process << _interpreterPath
  665. << "-dNODISPLAY"
  666. << "-dTQUIET"
  667. << TQString( "-sPDFname=%1" ).arg( pdfName )
  668. << TQString( "-sDSCnamale locale( "kghostview" );
  669. _fallBackPageMedia = pageSizeToString(
  670. static_cast< TQPrinter::PageSize >( locale.pageSize() ) );
  671. _usePageLabels = false;
  672. e=%1" ).arg( dscName )
  673. << "pdf2dsc.ps"
  674. << "-c"
  675. << "quit";
  676. connect( &process, TQT_SIGNAL( processExited( KProcess* ) ),
  677. this, TQT_SLOT( pdf2psExited( KProcess* ) ) );
  678. kdDebug(4500) << "KGVDocument: pdf2ps started" << endl;
  679. process.start( KProcess::NotifyOnExit );
  680. }
  681. void KGVDocument::pdf2psExited( KProcess* process )
  682. {
  683. kdDebug(4500) << "KGVDocument: pdf2ps exited" << endl;
  684. emit pdf2psFinished( process.normalExit() && process.exitStatus() != 0 );
  685. }
  686. */
  687. Pdf2dsc::Pdf2dsc( const TQString& ghostscriptPath, TQObject* parent, const char* name ) :
  688. TQObject( parent, name ),
  689. _process( 0 ),
  690. _ghostscriptPath( ghostscriptPath )
  691. {}
  692. Pdf2dsc::~Pdf2dsc()
  693. {
  694. kill();
  695. }
  696. void Pdf2dsc::run( const TQString& pdfName, const TQString& dscName )
  697. {
  698. kill();
  699. _process = new KProcess;
  700. *_process << _ghostscriptPath
  701. << "-dSAFER"
  702. << "-dPARANOIDSAFER"
  703. << "-dDELAYSAFER"
  704. << "-dNODISPLAY"
  705. << "-dTQUIET"
  706. << TQString( "-sPDFname=%1" ).arg( pdfName )
  707. << TQString( "-sDSCname=%1" ).arg( dscName )
  708. << "-c"
  709. << "<< /PermitFileReading [ PDFname ] /PermitFileWriting [ DSCname ] /PermitFileControl [] >> setuserparams .locksafe"
  710. << "-f"
  711. << "pdf2dsc.ps"
  712. << "-c"
  713. << "quit";
  714. connect( _process, TQT_SIGNAL( processExited( KProcess* ) ),
  715. this, TQT_SLOT( processExited() ) );
  716. kdDebug(4500) << "Pdf2dsc: started" << endl;
  717. _process->start( KProcess::NotifyOnExit );
  718. }
  719. void Pdf2dsc::kill()
  720. {
  721. if( _process != 0 )
  722. {
  723. kdDebug(4500) << "Pdf2dsc: killing current process" << endl;
  724. delete _process;
  725. _process = 0;
  726. }
  727. }
  728. void Pdf2dsc::processExited()
  729. {
  730. kdDebug(4500) << "Pdf2dsc: process exited" << endl;
  731. emit finished( _process->normalExit() && _process->exitStatus() == 0 );
  732. delete _process;
  733. _process = 0;
  734. }
  735. #include "kgvdocument.moc"
  736. // vim:sw=4:sts=4:ts=8:sta:tw=78:noet