Subversion Repositories Scribus

Rev

Rev 23782 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4507 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
7
/***************************************************************************
8
                          gsutil.cpp  -  description
9
                             -------------------
10
    begin                : Fri Sep 14 2001
11
    copyright            : (C) 2001 by Franz Schmid
12
    copyright            : (C) 2006- Scribus Team (code moved from util.cpp)
13
    email                : Franz.Schmid@altmuehlnet.de
14
 ***************************************************************************/
15
 
16
/***************************************************************************
17
 *                                                                         *
18
 *   This program is free software; you can redistribute it and/or modify  *
19
 *   it under the terms of the GNU General Public License as published by  *
20
 *   the Free Software Foundation; either version 2 of the License, or     *
21
 *   (at your option) any later version.                                   *
22
 *                                                                         *
23
 ***************************************************************************/
24
 
10212 cbradney 25
#include "util_ghostscript.h"
4507 cbradney 26
 
10223 cbradney 27
#include <QDebug>
28
#include <QDir>
29
#include <QFile>
30
#include <QFileInfo>
31
#include <QPainter>
32
#include <QPixmap>
10006 cbradney 33
#include <QProcess>
4507 cbradney 34
 
35
#include "scconfig.h"
36
 
37
#ifdef HAVE_UNISTD_H
38
#include <unistd.h>
39
#endif
10223 cbradney 40
 
15706 jghali 41
#if defined(_WIN32)
42
#include <windows.h>
17762 jghali 43
#ifndef KEY_WOW64_32KEY
44
        #define KEY_WOW64_32KEY (0x0200)
15706 jghali 45
#endif
17762 jghali 46
#ifndef KEY_WOW64_64KEY
47
        #define KEY_WOW64_64KEY (0x0100)
48
#endif
49
#endif
15706 jghali 50
 
4507 cbradney 51
#include "prefsfile.h"
52
#include "prefsmanager.h"
53
#include "scpaths.h"
5243 cbradney 54
#include "scribuscore.h"
4507 cbradney 55
#include "scribus.h"
56
#include "util.h"
57
 
58
using namespace std;
59
 
60
 
61
int callGS(const QStringList& args_in, const QString device)
62
{
63
        QString cmd;
10006 cbradney 64
        QStringList args;
4507 cbradney 65
        PrefsManager* prefsManager = PrefsManager::instance();
66
        args.append( "-q" );
67
        args.append( "-dNOPAUSE" );
68
        args.append( "-dQUIET" );
69
        args.append( "-dPARANOIDSAFER" );
70
        args.append( "-dBATCH" );
71
        // Choose rendering device
72
        if (!device.isEmpty())
73
                args.append( QString("-sDEVICE=%1").arg(device) ); // user specified device
10866 fschmid 74
        else if (!ScCore->havePNGAlpha())
4507 cbradney 75
                args.append( "-sDEVICE=png16m" );
76
        else
77
                args.append( "-sDEVICE=pngalpha" );
78
        // and antialiasing
79
        if (prefsManager->appPrefs.gs_AntiAliasText)
80
                args.append( "-dTextAlphaBits=4" );
81
        if (prefsManager->appPrefs.gs_AntiAliasGraphics)
82
                args.append( "-dGraphicsAlphaBits=4" );
83
 
84
        // Add any extra font paths being used by Scribus to gs's font search path
85
        PrefsContext *pc = PrefsManager::instance()->prefsFile->getContext("Fonts");
86
        PrefsTable *extraFonts = pc->getTable("ExtraFontDirs");
87
        const char sep = ScPaths::envPathSeparator;
88
        if (extraFonts->getRowCount() >= 1)
16576 craig 89
                cmd = QString("-sFONTPATH=%1").arg(QDir::toNativeSeparators(extraFonts->get(0,0)));
4507 cbradney 90
        for (int i = 1; i < extraFonts->getRowCount(); ++i)
16576 craig 91
                cmd += QString("%1%2").arg(sep).arg(QDir::toNativeSeparators(extraFonts->get(i,0)));
4507 cbradney 92
        if( !cmd.isEmpty() )
93
                args.append( cmd );
94
 
95
        args += args_in;
96
        args.append("-c");
97
        args.append("showpage");
10866 fschmid 98
//      qDebug(args.join(" ").toAscii());
10006 cbradney 99
        return System( getShortPathName(prefsManager->ghostscriptExecutable()), args );
4507 cbradney 100
}
101
 
102
int callGS(const QString& args_in, const QString device)
103
{
104
        PrefsManager* prefsManager=PrefsManager::instance();
105
        QString cmd1 = getShortPathName(prefsManager->ghostscriptExecutable());
106
        cmd1 += " -q -dNOPAUSE -dQUIET -dPARANOIDSAFER -dBATCH";
107
        // Choose rendering device
108
        if (!device.isEmpty())
109
                // user specified device
110
                cmd1 += " -sDEVICE="+device;
10866 fschmid 111
        else if (!ScCore->havePNGAlpha())
4507 cbradney 112
                cmd1 += " -sDEVICE=png16m";
113
        else
114
                cmd1 += " -sDEVICE=pngalpha";
115
        // and antialiasing
116
        if (prefsManager->appPrefs.gs_AntiAliasText)
117
                cmd1 += " -dTextAlphaBits=4";
118
        if (prefsManager->appPrefs.gs_AntiAliasGraphics)
119
                cmd1 += " -dGraphicsAlphaBits=4";
120
 
121
        // Add any extra font paths being used by Scribus to gs's font search path
122
        PrefsContext *pc = PrefsManager::instance()->prefsFile->getContext("Fonts");
123
        PrefsTable *extraFonts = pc->getTable("ExtraFontDirs");
124
#ifndef _WIN32
125
        if (extraFonts->getRowCount() >= 1)
126
                cmd1 += QString(" -sFONTPATH='%1'").arg(extraFonts->get(0,0));
127
        for (int i = 1; i < extraFonts->getRowCount(); ++i)
128
                cmd1 += QString(":'%1'").arg(extraFonts->get(i,0));
129
#else
130
        if (extraFonts->getRowCount() >= 1)
131
                cmd1 += QString(" -sFONTPATH=\"%1\"").arg(extraFonts->get(0,0));
132
        for (int i = 1; i < extraFonts->getRowCount(); ++i)
133
                cmd1 += QString(";\"%1\"").arg(extraFonts->get(i,0));
134
#endif
135
 
136
        // then add any user specified args and run gs
137
        cmd1 += " " + args_in + " -c showpage";
138
//      qDebug("Calling gs as: %s", cmd1.ascii());
10398 cbradney 139
        return system(cmd1.toLocal8Bit().constData());
4507 cbradney 140
}
141
 
5771 jghali 142
int convertPS2PS(QString in, QString out, const QStringList& opts, int level)
4507 cbradney 143
{
144
        PrefsManager* prefsManager=PrefsManager::instance();
145
        QStringList args;
146
        args.append( "-q" );
147
        args.append( "-dQUIET" );
148
        args.append( "-dNOPAUSE" );
149
        args.append( "-dPARANOIDSAFER" );
150
        args.append( "-dBATCH" );
22624 jghali 151
        if (level == 2)
5627 jghali 152
        {
22624 jghali 153
                int gsVersion = 0;
5627 jghali 154
                // ps2write cannot be detected with testGSAvailability()
155
                // so determine availability according to gs version.
22624 jghali 156
                getNumericGSVersion(gsVersion);
157
                if (gsVersion >= 853)
5627 jghali 158
                        args.append( "-sDEVICE=ps2write" );
159
                else
160
                {
161
                        args.append( "-sDEVICE=pswrite" );
162
                        args.append( QString("-dLanguageLevel=%1").arg(level) );
22624 jghali 163
                }      
5627 jghali 164
        }
165
        else
166
        {
167
                args.append( "-sDEVICE=pswrite" );
22624 jghali 168
                if (level <= 3)
5627 jghali 169
                        args.append( QString("-dLanguageLevel=%1").arg(level) );
170
        }
4507 cbradney 171
        args += opts;
16576 craig 172
        args.append( QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(out)) );
173
        args.append( QDir::toNativeSeparators(in) );
10006 cbradney 174
        int ret = System( getShortPathName(prefsManager->ghostscriptExecutable()), args );
4507 cbradney 175
        return ret;
176
}
177
 
12520 fschmid 178
int convertPS2PDF(QString in, QString out, const QStringList& opts)
179
{
180
        PrefsManager* prefsManager=PrefsManager::instance();
181
        QStringList args;
182
        args.append( "-q" );
183
        args.append( "-dQUIET" );
184
        args.append( "-dNOPAUSE" );
185
        args.append( "-dPARANOIDSAFER" );
186
        args.append( "-dBATCH" );
187
        args.append( "-sDEVICE=pdfwrite" );
188
        args += opts;
16576 craig 189
        args.append( QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(out)) );
190
        args.append( QDir::toNativeSeparators(in) );
12520 fschmid 191
        int ret = System( getShortPathName(prefsManager->ghostscriptExecutable()), args );
192
        return ret;
193
}
194
 
10006 cbradney 195
bool testGSAvailability( void )
4507 cbradney 196
{
197
        QStringList args;
198
        PrefsManager* prefsManager = PrefsManager::instance();
10006 cbradney 199
        return testGSAvailability(prefsManager->ghostscriptExecutable());
5764 jghali 200
}
201
 
10006 cbradney 202
bool testGSAvailability( const QString& gsPath )
5764 jghali 203
{
204
        QStringList args;
4507 cbradney 205
        args.append( "-h" );
10006 cbradney 206
        QProcess proc;
207
        proc.start(getShortPathName(gsPath), args);
10032 jghali 208
        if (!proc.waitForStarted(5000))
209
                return false;
10006 cbradney 210
        proc.waitForFinished(5000);
211
        return (proc.exitCode()==0);
4507 cbradney 212
}
213
 
10006 cbradney 214
bool testGSDeviceAvailability( const QString& device )
4507 cbradney 215
{
216
        QStringList args;
217
        PrefsManager* prefsManager = PrefsManager::instance();
218
        args.append( QString("-sDEVICE=%1").arg( device ) );
219
        args.append( "-c" );
220
        args.append( "quit" );
10006 cbradney 221
        QProcess proc;
222
        proc.start(getShortPathName(prefsManager->ghostscriptExecutable()), args);
10032 jghali 223
        if (!proc.waitForStarted(5000))
224
                return false;
10006 cbradney 225
        proc.waitForFinished(5000);
226
        return (proc.exitCode()==0);
4507 cbradney 227
}
228
 
229
// Return the GhostScript version string, or QString::null if it couldn't be retrived.
230
QString getGSVersion()
231
{
232
        QStringList args;
10493 fschmid 233
        args.append(QString("--version").toLocal8Bit());
4507 cbradney 234
        QString gsExe = getShortPathName(PrefsManager::instance()->ghostscriptExecutable());
10006 cbradney 235
        QProcess proc;
10493 fschmid 236
        proc.start(gsExe.toLocal8Bit(), args);
10012 cbradney 237
        if (proc.waitForStarted(5000))
238
                while (!proc.waitForFinished(5000))
239
                        qApp->processEvents();
10006 cbradney 240
        QString gsVer;
241
        if (proc.exitStatus()==QProcess::NormalExit)
242
                gsVer = proc.readAllStandardOutput();
4507 cbradney 243
        return gsVer;
244
}
245
 
22624 jghali 246
bool getNumericGSVersion(int &version)
247
{
248
        int gsMajor(0), gsMinor(0);
249
        version = 0;
250
        if (getNumericGSVersion(gsMajor, gsMinor))
251
        {
252
                version = 100 * gsMajor + gsMinor;
253
                return true;
254
        }
255
        return false;
256
}
257
 
4507 cbradney 258
// Return the GhostScript major and minor version numbers.
259
bool getNumericGSVersion(int & major, int & minor)
260
{
261
        QString gs_ver_string(getGSVersion());
10032 jghali 262
        return getNumericGSVersion(gs_ver_string, major, minor);
263
}
264
 
265
bool getNumericGSVersion(const QString& ver, int& major, int& minor)
266
{
4507 cbradney 267
        // gs's version string is of the form MAJOR.MINOR, so look for the .
268
        // then convert to numbers. 7.07 will become (7,7) for example.
269
        bool success = false;
10032 jghali 270
        major = ver.section('.', 0, 0).toInt(&success);
4507 cbradney 271
        if (!success)
272
                return false;
10032 jghali 273
        minor = ver.section('.', 1, 1).toInt(&success);
4507 cbradney 274
        if (!success)
275
                return false;
276
        return true;
277
}
278
 
279
QString getGSDefaultExeName(void)
280
{
13052 cbradney 281
        QString gsName("gs");
4507 cbradney 282
#if defined _WIN32
283
        // Set gsName to its default value
284
        gsName = "gswin32c.exe";
285
 
17762 jghali 286
        // Test is we are running a 64bit version of WINDOWS
287
        bool isWindows64 = false;
288
        wchar_t* procArch = _wgetenv(L"PROCESSOR_ARCHITECTURE");
289
        if (procArch)
290
        {
291
                isWindows64 |= (wcscmp(procArch, L"AMD64") == 0);
292
                isWindows64 |= (wcscmp(procArch, L"IA64") == 0);
293
        }
294
        wchar_t* procArchWow64 = _wgetenv(L"PROCESSOR_ARCHITEW6432");
295
        if (procArchWow64) isWindows64 = true;
4507 cbradney 296
 
17762 jghali 297
        // Search for Ghostsscript executable in native registry
298
        QMap<int, QString> gsVersions;
299
        gsVersions.unite( getGSExePaths("SOFTWARE\\GPL Ghostscript") );
300
        gsVersions.unite( getGSExePaths("SOFTWARE\\AFPL Ghostscript") );
301
 
302
        // If running on Windows 64bit, search alternate registry view,
303
        // ie 32bit registry if process is 64bit, 64bit registry if process is 32bit
304
        if (isWindows64)
305
        {
306
                gsVersions.unite( getGSExePaths("SOFTWARE\\GPL Ghostscript", true) );
307
                gsVersions.unite( getGSExePaths("SOFTWARE\\AFPL Ghostscript", true) );
308
        }
309
 
10032 jghali 310
        if (gsVersions.isEmpty())
4507 cbradney 311
                return gsName;
312
 
10032 jghali 313
        int currentVer = 0;
314
        QString gsPath;
315
        QMap<int, QString>::ConstIterator it, itEnd = gsVersions.constEnd();
316
        for (it = gsVersions.constBegin(); it != itEnd; ++it)
317
        {
318
                int version = it.key();
319
                if (version > currentVer)
320
                {
10723 jghali 321
                        gsPath = it.value();
10032 jghali 322
                        QFileInfo fInfo(gsPath);
323
                        if (fInfo.exists())
324
                        {
325
                                gsName = gsPath;
326
                                currentVer = version;
327
                        }
328
                }
329
        }
4507 cbradney 330
#endif
13052 cbradney 331
#if defined Q_OS_MAC
332
        QStringList gsPaths;
13798 cbradney 333
        gsPaths << "/usr/bin/gs" << "/usr/local/bin/gs" << "/opt/local/bin/gs" << "/sw/bin/gs";
13052 cbradney 334
        for (int i = 0; i < gsPaths.size(); ++i)
335
        {
336
                QFileInfo fInfo(gsPaths.at(i));
337
                if (fInfo.exists())
338
                {
339
                        gsName = gsPaths.at(i);
340
                        break;
341
                }
342
        }
343
#endif
4507 cbradney 344
        return gsName;
345
}
346
 
17762 jghali 347
QMap<int, QString> SCRIBUS_API getGSExePaths(const QString& regKey, bool alternateView)
10032 jghali 348
{
349
        QMap<int, QString> gsVersions;
350
#if defined _WIN32
351
        // Try to locate GhostScript thanks to the registry
23782 jghali 352
        DWORD size, regVersionSize;
10032 jghali 353
        HKEY hKey1, hKey2;
354
        DWORD regType = REG_SZ;
17762 jghali 355
        REGSAM flags  = KEY_READ;
23782 jghali 356
        WCHAR regVersion[MAX_PATH] = {};
357
        WCHAR regPath[MAX_PATH] = {};
358
        WCHAR gsPath[MAX_PATH] = {};
17762 jghali 359
        QString gsVersion, gsExeName, gsName;
10032 jghali 360
 
17762 jghali 361
        bool isWin64Api = false;
362
#if defined(_WIN64)
363
        isWin64Api = true;
364
#endif
365
 
366
        gsExeName = isWin64Api ? "gswin64c.exe" : "gswin32c.exe";
367
        if (alternateView)
10032 jghali 368
        {
17762 jghali 369
                gsExeName = isWin64Api ? "gswin32c.exe" : "gswin64c.exe";
370
                flags |= (isWin64Api ? KEY_WOW64_32KEY : KEY_WOW64_64KEY);
371
        }
372
 
373
        if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR) regKey.utf16(), 0, flags, &hKey1) == ERROR_SUCCESS)
374
        {
24757 jghali 375
                regVersionSize = sizeof(regVersion) / sizeof(WCHAR);
10032 jghali 376
                DWORD keyIndex = 0;
23782 jghali 377
                while (RegEnumKeyExW(hKey1, keyIndex, regVersion, &regVersionSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
10032 jghali 378
                {
379
                        int gsNumericVer, gsMajor, gsMinor;
10304 jghali 380
                        wcscpy(regPath, (const wchar_t*) regKey.utf16());
381
                        wcscat(regPath, L"\\");
382
                        wcscat(regPath, regVersion);
17762 jghali 383
                        if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, regPath, 0, flags, &hKey2) == ERROR_SUCCESS)
10032 jghali 384
                        {
23782 jghali 385
                                size = sizeof(gsPath) - 2;
10304 jghali 386
                                if (RegQueryValueExW(hKey2, L"GS_DLL", 0, &regType, (LPBYTE) gsPath, &size) == ERROR_SUCCESS)
10032 jghali 387
                                {
388
                                        // We now have GhostScript dll path, but we want gswin32c.exe
389
                                        // Normally gswin32c.exe and gsdll.dll are in the same directory
22624 jghali 390
                                        if (getNumericGSVersion(QString::fromUtf16((const ushort*) regVersion), gsMajor, gsMinor))
10032 jghali 391
                                        {
22624 jghali 392
                                                gsNumericVer = gsMajor * 100 + gsMinor;
10304 jghali 393
                                                gsName = QString::fromUtf16((const ushort*) gsPath);
10427 cbradney 394
                                                size   = gsName.lastIndexOf("\\");
10032 jghali 395
                                                if (size > 0)
396
                                                {
397
                                                        gsName  = gsName.left(size + 1);
17762 jghali 398
                                                        gsName += gsExeName;
10032 jghali 399
                                                        gsName.replace("\\", "/");
400
                                                        gsVersions.insert(gsNumericVer, gsName);
401
                                                }      
402
                                        }      
403
                                }
404
                                RegCloseKey(hKey2);
405
                        }
24757 jghali 406
                        regVersionSize = sizeof(regVersion) / sizeof(WCHAR);
10032 jghali 407
                        keyIndex++;
408
                }
409
                RegCloseKey(hKey1);
410
        }
411
#else
412
        int gsNumericVer, gsMajor, gsMinor;
413
        PrefsManager* prefsManager=PrefsManager::instance();
414
        if (getNumericGSVersion(gsMajor, gsMinor))
415
        {
22624 jghali 416
                gsNumericVer = gsMajor * 100 + gsMinor;
10032 jghali 417
                gsVersions.insert(gsNumericVer, prefsManager->ghostscriptExecutable());
418
        }
419
#endif
420
        return gsVersions;
421
}
422
 
4507 cbradney 423
QPixmap LoadPDF(QString fn, int Page, int Size, int *w, int *h)
424
{
425
        QString tmp, cmd1, cmd2;
16576 craig 426
        QString pdfFile = QDir::toNativeSeparators(fn);
427
        QString tmpFile = QDir::toNativeSeparators(ScPaths::getTempFileDir() + "sc.png");
4507 cbradney 428
        QPixmap pm;
429
        int ret = -1;
430
        tmp.setNum(Page);
431
        QStringList args;
432
        args.append("-r72");
5230 fschmid 433
//      args.append("-sOutputFile=\""+tmpFile+"\"");
434
        args.append("-sOutputFile="+tmpFile);
4507 cbradney 435
        args.append("-dFirstPage="+tmp);
436
        args.append("-dLastPage="+tmp);
5230 fschmid 437
//      args.append("\""+pdfFile+"\"");
438
        args.append(pdfFile);
4507 cbradney 439
        ret = callGS(args);
440
        if (ret == 0)
441
        {
442
                QImage image;
443
                image.load(tmpFile);
10592 fschmid 444
                QFile::remove(tmpFile);
4507 cbradney 445
                QImage im2;
446
                *h = image.height();
447
                *w = image.width();
448
                double sx = image.width() / static_cast<double>(Size);
449
                double sy = image.height() / static_cast<double>(Size);
450
                double t = (sy < sx ? sx : sy);
10398 cbradney 451
                im2 = image.scaled(static_cast<int>(image.width() / t), static_cast<int>(image.height() / t), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
10401 cbradney 452
                pm=QPixmap::fromImage(im2);
4507 cbradney 453
                QPainter p;
454
                p.begin(&pm);
455
                p.setBrush(Qt::NoBrush);
456
                p.setPen(Qt::black);
457
                p.drawRect(0, 0, pm.width(), pm.height());
458
                p.end();
459
                im2.detach();
460
        }
461
        return pm;
462
}
463
 
10032 jghali 464