SVN_SILENT made messages (.desktop file)
[kdegraphics.git] / okular / generators / dvi / psgs.cpp
blobc6d5fd0199ea26ce30686b0f7b7681d5459a046f
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
2 //
3 // ghostscript_interface
4 //
5 // Part of KDVI - A framework for multipage text/gfx viewers
6 //
7 // (C) 2004 Stefan Kebekus
8 // Distributed under the GPL
10 #include <config.h>
12 #include "psgs.h"
13 #include "psheader.cpp"
14 #include "dviFile.h"
15 #include "kvs_debug.h"
16 #include "pageNumber.h"
18 #include <klocale.h>
19 #include <kmessagebox.h>
20 #include <kprocess.h>
21 #include <ktemporaryfile.h>
22 #include <kurl.h>
24 #include <QDir>
25 #include <QPainter>
26 #include <QPixmap>
27 #include <QTextStream>
28 #include <QTimer>
30 //#define DEBUG_PSGS
32 //extern char psheader[];
34 pageInfo::pageInfo(const QString& _PostScriptString) {
35 PostScriptString = new QString(_PostScriptString);
36 background = Qt::white;
37 permanentBackground = Qt::white;
41 pageInfo::~pageInfo() {
42 if (PostScriptString != 0L)
43 delete PostScriptString;
47 // ======================================================
49 ghostscript_interface::ghostscript_interface() {
50 pageList.setAutoDelete(true);
52 PostScriptHeaderString = new QString();
54 knownDevices.append("png16m");
55 knownDevices.append("jpeg");
56 knownDevices.append("pnn");
57 knownDevices.append("pnnraw");
58 gsDevice = knownDevices.begin();
61 ghostscript_interface::~ghostscript_interface() {
62 if (PostScriptHeaderString != 0L)
63 delete PostScriptHeaderString;
67 void ghostscript_interface::setPostScript(const PageNumber& page, const QString& PostScript) {
68 #ifdef DEBUG_PSGS
69 kDebug(kvs::dvi) << "ghostscript_interface::setPostScript( " << page << ", ... )";
70 #endif
72 if (pageList.find(page) == 0) {
73 pageInfo *info = new pageInfo(PostScript);
74 // Check if dict is big enough
75 if (pageList.count() > pageList.size() -2)
76 pageList.resize(pageList.size()*2);
77 pageList.insert(page, info);
78 } else
79 *(pageList.find(page)->PostScriptString) = PostScript;
83 void ghostscript_interface::setIncludePath(const QString &_includePath) {
84 if (_includePath.isEmpty())
85 includePath = "*"; // Allow all files
86 else
87 includePath = _includePath+"/*";
91 void ghostscript_interface::setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent) {
92 #ifdef DEBUG_PSGS
93 kDebug(kvs::dvi) << "ghostscript_interface::setBackgroundColor( " << page << ", " << background_color << " )";
94 #endif
96 if (pageList.find(page) == 0) {
97 pageInfo *info = new pageInfo(QString::null); //krazy:exclude=nullstrassign for old broken gcc
98 info->background = background_color;
99 if (permanent)
100 info->permanentBackground = background_color;
101 // Check if dict is big enough
102 if (pageList.count() > pageList.size() -2)
103 pageList.resize(pageList.size()*2);
104 pageList.insert(page, info);
105 } else {
106 pageList.find(page)->background = background_color;
107 if (permanent)
108 pageList.find(page)->permanentBackground = background_color;
112 void ghostscript_interface::restoreBackgroundColor(const PageNumber& page)
114 #ifdef DEBUG_PSGS
115 kDebug(kvs::dvi) << "ghostscript_interface::restoreBackgroundColor( " << page << " )";
116 #endif
117 if (pageList.find(page) == 0)
118 return;
120 pageInfo *info = pageList.find(page);
121 info->background = info->permanentBackground;
124 // Returns the background color for a certain page. This color is
125 // always guaranteed to be valid
127 QColor ghostscript_interface::getBackgroundColor(const PageNumber& page) const {
128 #ifdef DEBUG_PSGS
129 kDebug(kvs::dvi) << "ghostscript_interface::getBackgroundColor( " << page << " )";
130 #endif
132 if (pageList.find(page) == 0)
133 return Qt::white;
134 else
135 return pageList.find(page)->background;
139 void ghostscript_interface::clear() {
140 PostScriptHeaderString->truncate(0);
142 // Deletes all items, removes temporary files, etc.
143 pageList.clear();
147 void ghostscript_interface::gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification) {
148 #ifdef DEBUG_PSGS
149 kDebug(kvs::dvi) << "ghostscript_interface::gs_generate_graphics_file( " << page << ", " << filename << " )";
150 #endif
152 if (knownDevices.isEmpty()) {
153 kError(kvs::dvi) << "No known devices found" << endl;
154 return;
157 pageInfo *info = pageList.find(page);
159 // Generate a PNG-file
160 // Step 1: Write the PostScriptString to a File
161 KTemporaryFile PSfile;
162 PSfile.setAutoRemove(false);
163 PSfile.setSuffix(".ps");
164 PSfile.open();
165 const QString PSfileName = PSfile.fileName();
167 QTextStream os(&PSfile);
168 os << "%!PS-Adobe-2.0\n"
169 << "%%Creator: kdvi\n"
170 << "%%Title: KDVI temporary PostScript\n"
171 << "%%Pages: 1\n"
172 << "%%PageOrder: Ascend\n"
173 // HSize and VSize in 1/72 inch
174 << "%%BoundingBox: 0 0 "
175 << (qint32)(72*(pixel_page_w/resolution)) << ' '
176 << (qint32)(72*(pixel_page_h/resolution)) << '\n'
177 << "%%EndComments\n"
178 << "%!\n"
179 << psheader
180 << "TeXDict begin "
181 // HSize in (1/(65781.76*72))inch
182 << (qint32)(72*65781*(pixel_page_w/resolution)) << ' '
183 // VSize in (1/(65781.76*72))inch
184 << (qint32)(72*65781*(pixel_page_h/resolution)) << ' '
185 // Magnification
186 << (qint32)(magnification)
187 // dpi and vdpi
188 << " 300 300"
189 // Name
190 << " (test.dvi)"
191 << " @start end\n"
192 << "TeXDict begin\n"
193 // Start page
194 << "1 0 bop 0 0 a \n";
196 if (!PostScriptHeaderString->toLatin1().isNull())
197 os << PostScriptHeaderString->toLatin1();
199 if (info->background != Qt::white) {
200 QString colorCommand = QString("gsave %1 %2 %3 setrgbcolor clippath fill grestore\n").
201 arg(info->background.red()/255.0).
202 arg(info->background.green()/255.0).
203 arg(info->background.blue()/255.0);
204 os << colorCommand.toLatin1();
207 if (!info->PostScriptString->toLatin1().isNull())
208 os << info->PostScriptString->toLatin1();
210 os << "end\n"
211 << "showpage \n";
213 PSfile.close();
215 // Step 2: Call GS with the File
216 QFile::remove(filename.toAscii());
217 KProcess proc;
218 QStringList argus;
219 argus << "gs";
220 argus << "-dSAFER" << "-dPARANOIDSAFER" << "-dDELAYSAFER" << "-dNOPAUSE" << "-dBATCH";
221 argus << QString("-sDEVICE=%1").arg(*gsDevice);
222 argus << QString("-sOutputFile=%1").arg(filename);
223 argus << QString("-sExtraIncludePath=%1").arg(includePath);
224 argus << QString("-g%1x%2").arg(pixel_page_w).arg(pixel_page_h); // page size in pixels
225 argus << QString("-r%1").arg(resolution); // resolution in dpi
226 argus << "-dTextAlphaBits=4 -dGraphicsAlphaBits=2"; // Antialiasing
227 argus << "-c" << "<< /PermitFileReading [ ExtraIncludePath ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe";
228 argus << "-f" << PSfileName;
230 #ifdef DEBUG_PSGS
231 kDebug(kvs::dvi) << argus.join(" ");
232 #endif
234 proc << argus;
235 int res = proc.execute();
237 if ( res ) {
238 // Starting ghostscript did not work.
239 // TODO: Issue error message, switch PS support off.
240 kError(kvs::dvi) << "ghostview could not be started" << endl;
243 PSfile.remove();
245 // Check if gs has indeed produced a file.
246 if (QFile::exists(filename) == false) {
247 kError(kvs::dvi) << "GS did not produce output." << endl;
249 // No. Check is the reason is that the device is not compiled into
250 // ghostscript. If so, try again with another device.
251 QString GSoutput;
252 proc.setReadChannel(QProcess::StandardOutput);
253 while(proc.canReadLine()) {
254 GSoutput = QString::fromLocal8Bit(proc.readLine());
255 if (GSoutput.contains("Unknown device")) {
256 kDebug(kvs::dvi) << QString("The version of ghostview installed on this computer does not support "
257 "the '%1' ghostview device driver.").arg(*gsDevice) << endl;
258 knownDevices.erase(gsDevice);
259 gsDevice = knownDevices.begin();
260 if (knownDevices.isEmpty())
261 // TODO: show a requestor of some sort.
262 KMessageBox::detailedError(0,
263 i18n("<qt>The version of Ghostview that is installed on this computer does not contain "
264 "any of the Ghostview device drivers that are known to Okular. PostScript "
265 "support has therefore been turned off in Okular.</qt>"),
266 i18n("<qt><p>The Ghostview program, which Okular uses internally to display the "
267 "PostScript graphics that is included in this DVI file, is generally able to "
268 "write its output in a variety of formats. The sub-programs that Ghostview uses "
269 "for these tasks are called 'device drivers'; there is one device driver for "
270 "each format that Ghostview is able to write. Different versions of Ghostview "
271 "often have different sets of device drivers available. It seems that the "
272 "version of Ghostview that is installed on this computer does not contain "
273 "<strong>any</strong> of the device drivers that are known to Okular.</p>"
274 "<p>It seems unlikely that a regular installation of Ghostview would not contain "
275 "these drivers. This error may therefore point to a serious misconfiguration of "
276 "the Ghostview installation on your computer.</p>"
277 "<p>If you want to fix the problems with Ghostview, you can use the command "
278 "<strong>gs --help</strong> to display the list of device drivers contained in "
279 "Ghostview. Among others, Okular can use the 'png256', 'jpeg' and 'pnm' "
280 "drivers. Note that Okular needs to be restarted to re-enable PostScript support."
281 "</p></qt>"));
282 else {
283 kDebug(kvs::dvi) << QString("Okular will now try to use the '%1' device driver.").arg(*gsDevice);
284 gs_generate_graphics_file(page, filename, magnification);
286 return;
293 void ghostscript_interface::graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint) {
294 #ifdef DEBUG_PSGS
295 kDebug(kvs::dvi) << "ghostscript_interface::graphics( " << page << ", " << dpi << ", ... ) called.";
296 #endif
298 if (paint == 0) {
299 kError(kvs::dvi) << "ghostscript_interface::graphics(PageNumber page, double dpi, long magnification, QPainter *paint) called with paint == 0" << endl;
300 return;
303 resolution = dpi;
305 pixel_page_w = paint->viewport().width();
306 pixel_page_h = paint->viewport().height();
308 pageInfo *info = pageList.find(page);
310 // No PostScript? Then return immediately.
311 if ((info == 0) || (info->PostScriptString->isEmpty())) {
312 #ifdef DEBUG_PSGS
313 kDebug(kvs::dvi) << "No PostScript found. Not drawing anything.";
314 #endif
315 return;
318 QTemporaryFile gfxFile;
319 gfxFile.open();
320 const QString gfxFileName = gfxFile.fileName();
321 // We are want the filename, not the file.
322 gfxFile.close();
324 gs_generate_graphics_file(page, gfxFileName, magnification);
326 QImage MemoryCopy(gfxFileName);
327 paint->drawImage(0, 0, MemoryCopy);
328 return;
332 QString ghostscript_interface::locateEPSfile(const QString &filename, const KUrl &base)
334 // If the base URL indicates that the DVI file is local, try to find
335 // the graphics file in the directory where the DVI file resides
336 if (base.isLocalFile()) {
337 QString path = base.path(); // -> "/bar/foo.dvi"
338 QFileInfo fi1(path);
339 QFileInfo fi2(fi1.dir(),filename);
340 if (fi2.exists())
341 return fi2.absoluteFilePath();
344 // Otherwise, use kpsewhich to find the eps file.
345 KProcess proc;
346 proc << "kpsewhich" << filename;
347 proc.execute();
348 return QString::fromLocal8Bit(proc.readLine().trimmed());
351 #include "psgs.moc"