From 3d2b6db73e9a96706320a70b778d4644f3d8397f Mon Sep 17 00:00:00 2001 From: Stefan Kebekus Date: Fri, 16 Sep 2005 12:18:31 +0000 Subject: [PATCH] fixes issue #112446 svn path=/trunk/KDE/kdegraphics/kdvi/; revision=461082 --- dviFile.cpp | 71 ++++++++++++++++++++++++++++++++++++++++- dviFile.h | 36 ++++++++++++++++++++- dviRenderer_prescan.cpp | 28 ++++++++++++++-- 3 files changed, 131 insertions(+), 4 deletions(-) diff --git a/dviFile.cpp b/dviFile.cpp index ff0b9415d..94af0bf95 100644 --- a/dviFile.cpp +++ b/dviFile.cpp @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,7 @@ dvifile::dvifile(const dvifile *old, fontPool *fp) numberOfExternalPSFiles = 0; numberOfExternalNONPSFiles = 0; sourceSpecialMarker = old->sourceSpecialMarker; + have_complainedAboutMissingPDF2PS = false; dviData = old->dviData.copy(); @@ -278,7 +280,8 @@ dvifile::dvifile(QString fname, fontPool *pool) numberOfExternalNONPSFiles = 0; font_pool = pool; sourceSpecialMarker = true; - + have_complainedAboutMissingPDF2PS = false; + QFile file(fname); filename = file.name(); file.open( QIODevice::ReadOnly ); @@ -315,6 +318,13 @@ dvifile::~dvifile() kdDebug(4300) << "destroy dvi-file" << endl; #endif + // Delete converted PDF files + QMapIterator i(convertedFiles); + while (i.hasNext()) { + i.next(); + QFile::remove(i.value()); + } + if (suggestedPageSize != 0) delete suggestedPageSize; if (font_pool != 0) @@ -351,6 +361,65 @@ void dvifile::renumber() } +QString dvifile::convertPDFtoPS(const QString &PDFFilename, QString *converrorms) +{ + // Check if the PDFFile is known + QMap::Iterator it = convertedFiles.find(PDFFilename); + if (it != convertedFiles.end()) { + // PDF-File is known. Good. + return it.data(); + } + + // Get the name of a temporary file + KTempFile tmpfile(QString::null, ".ps"); + QString convertedFileName = tmpfile.name(); + tmpfile.close(); + tmpfile.unlink(); + + // Use pdf2ps to do the conversion + KProcIO proc; + proc << "pdf2ps" << PDFFilename << convertedFileName; + if (proc.start(KProcess::Block, true) == false) { + convertedFiles[PDFFilename] = QString::null; // Indicates that conversion failed, won't try again. + if ((converrorms != 0) && (have_complainedAboutMissingPDF2PS == false)) { + *converrorms = i18n("

The external program pdf2ps could not be started. As a result, " + "the PDF-file %1 could not be converted to PostScript. Some graphic elements in your " + "document will therefore not be displayed.

" + "

Possible reason: The program pdf2ps is perhaps not installed " + "on your system, or it cannot be found in the current search path.

" + "

What you can do: The program pdf2ps program is normally " + "contained in distributions of the ghostscript PostScript interpreter system. If " + "ghostscipt is not installed on your system, you could install it now. " + "If you are sure that ghostscript is installed, please try to use pdf2ps " + "from the command line to check if it really works.

PATH: %2

").arg(PDFFilename).arg(getenv("PATH")); + have_complainedAboutMissingPDF2PS = true; + } + return QString::null; + } + if ( !QFile::exists(convertedFileName) || !proc.normalExit() || (proc.exitStatus() != 0) ) { + convertedFiles[PDFFilename] = QString::null; // Indicates that conversion failed, won't try again. + if (converrorms != 0) { + QString outp, outl; + while(proc.readln(outl) != -1) + outp += outl; + + *converrorms = i18n("

The PDF-file %1 could not be converted to PostScript. Some graphic elements in your " + "document will therefore not be displayed.

" + "

Possible reason: The file %1 might be broken, or might not be a PDF-file at all. " + "This is the output of the pdf2ps program that KDVI used:

" + "

%2

").arg(PDFFilename).arg(outp); + } + return QString::null; + } + // Save name of converted file to buffer, so PDF file won't be + // converted again, and files can be deleted when *this is + // deconstructed. + convertedFiles[PDFFilename] = convertedFileName; + + return convertedFileName; +} + + bool dvifile::saveAs(const QString &filename) { if (dvi_Data() == 0) diff --git a/dviFile.h b/dviFile.h index f2494f64b..b13d2f247 100644 --- a/dviFile.h +++ b/dviFile.h @@ -5,7 +5,7 @@ // Class that represents a DVI file. Part of KDVI - A DVI previewing // plugin for kviewshell. // -// (C) 2004 Stefan Kebekus. Distributed under the GPL. +// (C) 2004-2005 Stefan Kebekus. Distributed under the GPL. // #ifndef _DVIFILE_H @@ -18,6 +18,7 @@ #include //Added by qt3to4: #include +#include #include "bigEndianByteReader.h" @@ -99,6 +100,26 @@ class dvifile : public bigEndianByteReader renumbers the pages. */ void renumber(); + /** PDF to PS file conversion + + This utility method takes the name of a PDF-file, and attempts to + convert it to a PS file. The dvifile internally keeps a list of + converted files, to do two thigs: + + - convert files only once. + + - delete all converted files on destruction + + @warning The internal buffer can lead to difficulties if filenames + of PDF-files are not unique: if the content of a PDF file is + changed and this method is called a second time with the same file + name, the method will then NOT convert the file, but simply return + the name from the buffer + + @returns The name of the PS file, or QString::null on failure. + */ + QString convertPDFtoPS(const QString &PDFFilename, QString *converrorms=0); + private: /** process_preamble reads the information in the preamble and stores it into global variables for later use. */ @@ -118,6 +139,19 @@ class dvifile : public bigEndianByteReader double cmPerDVIunit; Q3MemArray dviData; + + /** Map of filenames for converted PDF files + + This map contains names of PDF files that were converted to + PostScript. The key is the name of the PDF file, the data the name + of the associated PS file, or QString::null, if the file could not + be converted. The PS files are deleted when the DVI-file is + destructed. */ + QMap convertedFiles; + + /** Flag, used so that KDVI complains only once about a missing + "PDF2PS" utility. Set to "false" in the constructor. */ + bool have_complainedAboutMissingPDF2PS; }; #endif //ifndef _DVIFILE_H diff --git a/dviRenderer_prescan.cpp b/dviRenderer_prescan.cpp index e6a157ed9..1ff59eaad 100644 --- a/dviRenderer_prescan.cpp +++ b/dviRenderer_prescan.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -84,7 +85,11 @@ void dviRenderer::prescan_embedPS(char *cp, Q_UINT8 *beginningOfSpecialCommand) // Now locate the Gfx file on the hard disk... EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, dviFile); - + + // If the EPSfilename really points to a PDF file, convert that file now. + if (ending == "pdf") + EPSfilename = dviFile->convertPDFtoPS(EPSfilename); + if (!QFile::exists(EPSfilename)) { // Find the number of the page Q_UINT32 currentOffset = beginningOfSpecialCommand - dviFile->dvi_Data(); @@ -92,7 +97,10 @@ void dviRenderer::prescan_embedPS(char *cp, Q_UINT8 *beginningOfSpecialCommand) for(page=0; page < dviFile->total_pages; page++) if ((dviFile->page_offset[page] <= currentOffset) && (currentOffset <= dviFile->page_offset[page+1])) break; - errorMsg += i18n("Page %1: The PostScript file %2 could not be found.
").arg(page+1).arg(originalFName); + if (ending == "pdf") + errorMsg += i18n("Page %1: The PDF file %2 could not be converted to PostScript.
").arg(page+1).arg(originalFName); + else + errorMsg += i18n("Page %1: The PostScript file %2 could not be found.
").arg(page+1).arg(originalFName); embedPS_progress->progressBar()->advance(1); qApp->processEvents(); return; @@ -408,6 +416,22 @@ void dviRenderer::prescan_ParsePSFileSpecial(QString cp) // Now locate the Gfx file on the hard disk... EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, dviFile); + + // If the EPSfilename really points to a PDF file, convert that file now. + if (ending == "pdf") { + QString convErrorMsg; + QString oEPSfilename = EPSfilename; + emit setStatusBarText( i18n("Converting PDF-file %1...").arg(EPSfilename) ); + EPSfilename = dviFile->convertPDFtoPS(EPSfilename, &convErrorMsg); + emit setStatusBarText( QString::null ); + if (convErrorMsg.isEmpty() != true) { + KMessageBox::detailedError(parentWidget, + i18n("File conversion error! KDVI was not able to convert the external " + "PDF-file %1 into PostScript. Expect missing graphics or graphic errors.").arg(oEPSfilename), + convErrorMsg, i18n("PDF/PS conversion error")); + return; + } + } // Now parse the arguments. int llx = 0;