diff options
Diffstat (limited to 'kdvi/psgs.cpp')
-rw-r--r-- | kdvi/psgs.cpp | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/kdvi/psgs.cpp b/kdvi/psgs.cpp new file mode 100644 index 00000000..9e23fcad --- /dev/null +++ b/kdvi/psgs.cpp @@ -0,0 +1,340 @@ +// +// ghostscript_interface +// +// Part of KDVI - A framework for multipage text/gfx viewers +// +// (C) 2004 Stefan Kebekus +// Distributed under the GPL + +#include <config.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocio.h> +#include <ktempfile.h> +#include <kurl.h> +#include <qdir.h> +#include <qpainter.h> + +#include "psgs.h" +#include "dviFile.h" +#include "pageNumber.h" + +extern const char psheader[]; + +//#define DEBUG_PSGS + + +pageInfo::pageInfo(const QString& _PostScriptString) { + PostScriptString = new QString(_PostScriptString); + background = Qt::white; + permanentBackground = Qt::white; +} + + +pageInfo::~pageInfo() { + if (PostScriptString != 0L) + delete PostScriptString; +} + + +// ====================================================== + +ghostscript_interface::ghostscript_interface() { + pageList.setAutoDelete(true); + + PostScriptHeaderString = new QString(); + + knownDevices.append("png256"); + knownDevices.append("jpeg"); + knownDevices.append("pnn"); + knownDevices.append("pnnraw"); + gsDevice = knownDevices.begin(); +} + +ghostscript_interface::~ghostscript_interface() { + if (PostScriptHeaderString != 0L) + delete PostScriptHeaderString; +} + + +void ghostscript_interface::setPostScript(const PageNumber& page, const QString& PostScript) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::setPostScript( " << page << ", ... )" << endl; +#endif + + if (pageList.find(page) == 0) { + pageInfo *info = new pageInfo(PostScript); + // Check if dict is big enough + if (pageList.count() > pageList.size() -2) + pageList.resize(pageList.size()*2); + pageList.insert(page, info); + } else + *(pageList.find(page)->PostScriptString) = PostScript; +} + + +void ghostscript_interface::setIncludePath(const QString &_includePath) { + if (_includePath.isEmpty()) + includePath = "*"; // Allow all files + else + includePath = _includePath+"/*"; +} + + +void ghostscript_interface::setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::setBackgroundColor( " << page << ", " << background_color << " )" << endl; +#endif + + if (pageList.find(page) == 0) { + pageInfo *info = new pageInfo(QString::null); + info->background = background_color; + if (permanent) + info->permanentBackground = background_color; + // Check if dict is big enough + if (pageList.count() > pageList.size() -2) + pageList.resize(pageList.size()*2); + pageList.insert(page, info); + } else { + pageList.find(page)->background = background_color; + if (permanent) + pageList.find(page)->permanentBackground = background_color; + } +} + +void ghostscript_interface::restoreBackgroundColor(const PageNumber& page) +{ +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::restoreBackgroundColor( " << page << " )" << endl; +#endif + if (pageList.find(page) == 0) + return; + + pageInfo *info = pageList.find(page); + info->background = info->permanentBackground; +} + +// Returns the background color for a certain page. This color is +// always guaranteed to be valid + +QColor ghostscript_interface::getBackgroundColor(const PageNumber& page) const { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::getBackgroundColor( " << page << " )" << endl; +#endif + + if (pageList.find(page) == 0) + return Qt::white; + else + return pageList.find(page)->background; +} + + +void ghostscript_interface::clear() { + PostScriptHeaderString->truncate(0); + + // Deletes all items, removes temporary files, etc. + pageList.clear(); +} + + +void ghostscript_interface::gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::gs_generate_graphics_file( " << page << ", " << filename << " )" << endl; +#endif + + if (knownDevices.isEmpty()) { + kdError(4300) << "No known devices found" << endl; + return; + } + + emit(setStatusBarText(i18n("Generating PostScript graphics..."))); + + pageInfo *info = pageList.find(page); + + // Generate a PNG-file + // Step 1: Write the PostScriptString to a File + KTempFile PSfile(QString::null,".ps"); + + QTextStream& os = *PSfile.textStream(); + os << "%!PS-Adobe-2.0\n" + << "%%Creator: kdvi\n" + << "%%Title: KDVI temporary PostScript\n" + << "%%Pages: 1\n" + << "%%PageOrder: Ascend\n" + // HSize and VSize in 1/72 inch + << "%%BoundingBox: 0 0 " + << (Q_INT32)(72*(pixel_page_w/resolution)) << ' ' + << (Q_INT32)(72*(pixel_page_h/resolution)) << '\n' + << "%%EndComments\n" + << "%!\n" + << psheader + << "TeXDict begin " + // HSize in (1/(65781.76*72))inch + << (Q_INT32)(72*65781*(pixel_page_w/resolution)) << ' ' + // VSize in (1/(65781.76*72))inch + << (Q_INT32)(72*65781*(pixel_page_h/resolution)) << ' ' + // Magnification + << (Q_INT32)(magnification) + // dpi and vdpi + << " 300 300" + // Name + << " (test.dvi)" + << " @start end\n" + << "TeXDict begin\n" + // Start page + << "1 0 bop 0 0 a \n"; + + if (PostScriptHeaderString->latin1() != NULL) + os << PostScriptHeaderString->latin1(); + + if (info->background != Qt::white) { + QString colorCommand = QString("gsave %1 %2 %3 setrgbcolor clippath fill grestore\n"). + arg(info->background.red()/255.0). + arg(info->background.green()/255.0). + arg(info->background.blue()/255.0); + os << colorCommand.latin1(); + } + + if (info->PostScriptString->latin1() != NULL) + os << info->PostScriptString->latin1(); + + os << "end\n" + << "showpage \n"; + + PSfile.close(); + + // Step 2: Call GS with the File + QFile::remove(filename.ascii()); + KProcIO proc; + QStringList argus; + argus << "gs"; + argus << "-dSAFER" << "-dPARANOIDSAFER" << "-dDELAYSAFER" << "-dNOPAUSE" << "-dBATCH"; + argus << QString("-sDEVICE=%1").arg(*gsDevice); + argus << QString("-sOutputFile=%1").arg(filename); + argus << QString("-sExtraIncludePath=%1").arg(includePath); + argus << QString("-g%1x%2").arg(pixel_page_w).arg(pixel_page_h); // page size in pixels + argus << QString("-r%1").arg(resolution); // resolution in dpi + argus << "-c" << "<< /PermitFileReading [ ExtraIncludePath ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe"; + argus << "-f" << PSfile.name(); + +#ifdef DEBUG_PSGS + kdDebug(4300) << argus.join(" ") << endl; +#endif + + proc << argus; + if (proc.start(KProcess::Block) == false) { + // Starting ghostscript did not work. + // TODO: Issue error message, switch PS support off. + kdError(4300) << "ghostview could not be started" << endl; + } + PSfile.unlink(); + + // Check if gs has indeed produced a file. + if (QFile::exists(filename) == false) { + kdError(4300) << "GS did not produce output." << endl; + + // No. Check is the reason is that the device is not compiled into + // ghostscript. If so, try again with another device. + QString GSoutput; + while(proc.readln(GSoutput) != -1) { + if (GSoutput.contains("Unknown device")) { + kdDebug(4300) << QString("The version of ghostview installed on this computer does not support " + "the '%1' ghostview device driver.").arg(*gsDevice) << endl; + knownDevices.remove(gsDevice); + gsDevice = knownDevices.begin(); + if (knownDevices.isEmpty()) + // TODO: show a requestor of some sort. + KMessageBox::detailedError(0, + i18n("<qt>The version of Ghostview that is installed on this computer does not contain " + "any of the Ghostview device drivers that are known to KDVI. PostScript " + "support has therefore been turned off in KDVI.</qt>"), + i18n("<qt><p>The Ghostview program, which KDVI uses internally to display the " + "PostScript graphics that is included in this DVI file, is generally able to " + "write its output in a variety of formats. The sub-programs that Ghostview uses " + "for these tasks are called 'device drivers'; there is one device driver for " + "each format that Ghostview is able to write. Different versions of Ghostview " + "often have different sets of device drivers available. It seems that the " + "version of Ghostview that is installed on this computer does not contain " + "<strong>any</strong> of the device drivers that are known to KDVI.</p>" + "<p>It seems unlikely that a regular installation of Ghostview would not contain " + "these drivers. This error may therefore point to a serious misconfiguration of " + "the Ghostview installation on your computer.</p>" + "<p>If you want to fix the problems with Ghostview, you can use the command " + "<strong>gs --help</strong> to display the list of device drivers contained in " + "Ghostview. Among others, KDVI can use the 'png256', 'jpeg' and 'pnm' " + "drivers. Note that KDVI needs to be restarted to re-enable PostScript support." + "</p></qt>")); + else { + kdDebug(4300) << QString("KDVI will now try to use the '%1' device driver.").arg(*gsDevice) << endl; + gs_generate_graphics_file(page, filename, magnification); + } + return; + } + } + } + emit(setStatusBarText(QString::null)); +} + + +void ghostscript_interface::graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "ghostscript_interface::graphics( " << page << ", " << dpi << ", ... ) called." << endl; +#endif + + if (paint == 0) { + kdError(4300) << "ghostscript_interface::graphics(PageNumber page, double dpi, long magnification, QPainter *paint) called with paint == 0" << endl; + return; + } + + resolution = dpi; + + pixel_page_w = paint->viewport().width(); + pixel_page_h = paint->viewport().height(); + + pageInfo *info = pageList.find(page); + + // No PostScript? Then return immediately. + if ((info == 0) || (info->PostScriptString->isEmpty())) { +#ifdef DEBUG_PSGS + kdDebug(4300) << "No PostScript found. Not drawing anything." << endl; +#endif + return; + } + + KTempFile gfxFile(QString::null, ".png"); + gfxFile.setAutoDelete(1); + gfxFile.close(); // we are want the filename, not the file + + gs_generate_graphics_file(page, gfxFile.name(), magnification); + + QPixmap MemoryCopy(gfxFile.name()); + paint->drawPixmap(0, 0, MemoryCopy); + return; +} + + +QString ghostscript_interface::locateEPSfile(const QString &filename, const KURL &base) +{ + // If the base URL indicates that the DVI file is local, try to find + // the graphics file in the directory where the DVI file resides + if (base.isLocalFile()) { + QString path = base.path(); // -> "/bar/foo.dvi" + QFileInfo fi1(path); + QFileInfo fi2(fi1.dir(),filename); + if (fi2.exists()) + return fi2.absFilePath(); + } + + // Otherwise, use kpsewhich to find the eps file. + QString EPSfilename; + KProcIO proc; + proc << "kpsewhich" << filename; + proc.start(KProcess::Block); + proc.readln(EPSfilename); + + return EPSfilename.stripWhiteSpace(); +} + +#include "psgs.moc" |