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 #include <QApplication>
9 #include <QDesktopWidget>
10 #include <QMap>
11 #include <QTemporaryFile>
12 
13 #include "outputpreview_pdf.h"
14 #include "cmsettings.h"
15 #include "filewatcher.h"
16 #include "iconmanager.h"
17 #include "pageitemiterator.h"
18 #include "pdflib.h"
19 #include "pdflib_core.h"
20 #include "prefsfile.h"
21 #include "prefsmanager.h"
22 #include "prefstable.h"
23 #include "sccolor.h"
24 #include "sccolorengine.h"
25 #include "scpaths.h"
26 #include "scribus.h"
27 #include "scribuscore.h"
28 #include "scribusdoc.h"
29 #include "util.h"
30 #include "util_ghostscript.h"
31 
32 #include "ui_outputpreviewbase.h"
33 #include "ui_outputpreview_pdf.h"
34 
OutputPreview_PDF(QWidget * parent,ScribusDoc * doc)35 OutputPreview_PDF::OutputPreview_PDF(QWidget* parent, ScribusDoc* doc) :
36 	OutputPreviewBase(parent, doc),
37 	m_pdfOptions(doc->pdfOptions()),
38 	m_prefsManager(PrefsManager::instance())
39 {
40 	int inkTableWidth = 0;
41 
42 	setModal(true);
43 	setWindowIcon(IconManager::instance().loadIcon("AppIcon.png"));
44 
45 	QString caption = tr("PDF Output Preview");
46 	setWindowTitle(caption);
47 
48 	m_havePngAlpha = ScCore->havePNGAlpha();
49 	m_haveTiffSep  = ScCore->haveTIFFSep();
50 	getNumericGSVersion(m_gsVersion);
51 
52 	m_optionsUi = new Ui::OutputPreview_PDF();
53 	m_optionsUi->setupUi(m_uiBase->optionWidget);
54 
55 	if (m_haveTiffSep)
56 	{
57 		ColorList usedSpots;
58 		doc->getUsedColors(usedSpots, true);
59 		QStringList spots = usedSpots.keys();
60 
61 		m_inkMax = (spots.count() + 4) * 255;
62 		m_optionsUi->coverThresholdValue->setMaximum((spots.count() + 4) * 100.0);
63 
64 		m_optionsUi->inkTable->setColumnCount(2);
65 		m_optionsUi->inkTable->setRowCount(4 + spots.count());
66 		m_optionsUi->inkTable->setHorizontalHeaderItem(0, new QTableWidgetItem(IconManager::instance().loadIcon("16/show-object.png"), ""));
67 		m_optionsUi->inkTable->setHorizontalHeaderItem(1, new QTableWidgetItem( tr("Separation Name")));
68 
69 		QHeaderView *header = m_optionsUi->inkTable->horizontalHeader();
70 		header->setStretchLastSection(true);
71 		header->setSectionsMovable(false);
72 		header->setSectionResizeMode(QHeaderView::Fixed);
73 
74 		m_optionsUi->inkTable->setColumnWidth(0, 24);
75 		m_optionsUi->inkTable->verticalHeader()->hide();
76 		m_optionsUi->inkTable->setFocusPolicy(Qt::NoFocus);
77 		m_optionsUi->inkTable->setSizeAdjustPolicy(QTableWidget::AdjustToContentsOnFirstShow);
78 
79 		m_optionsUi->inkTable->setItem(0, 1, new QTableWidgetItem( tr("Cyan")));
80 		QCheckBox *cp = new QCheckBox(this);
81 		cp->setFocusPolicy(Qt::NoFocus);
82 		cp->setChecked(true);
83 		connect(cp, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
84 		m_optionsUi->inkTable->setCellWidget(0, 0, cp);
85 		m_inkVisibilities.insert("Cyan", cp);
86 
87 		m_optionsUi->inkTable->setItem(1, 1, new QTableWidgetItem( tr("Magenta")));
88 		cp = new QCheckBox(this);
89 		cp->setFocusPolicy(Qt::NoFocus);
90 		cp->setChecked(true);
91 		connect(cp, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
92 		m_optionsUi->inkTable->setCellWidget(1, 0, cp);
93 		m_inkVisibilities.insert("Magenta", cp);
94 
95 		m_optionsUi->inkTable->setItem(2, 1, new QTableWidgetItem( tr("Yellow")));
96 		cp = new QCheckBox(this);
97 		cp->setFocusPolicy(Qt::NoFocus);
98 		cp->setChecked(true);
99 		connect(cp, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
100 		m_optionsUi->inkTable->setCellWidget(2, 0, cp);
101 		m_inkVisibilities.insert("Yellow", cp);
102 
103 		m_optionsUi->inkTable->setItem(3, 1, new QTableWidgetItem( tr("Black")));
104 		cp = new QCheckBox(this);
105 		cp->setFocusPolicy(Qt::NoFocus);
106 		cp->setChecked(true);
107 		connect(cp, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
108 		m_optionsUi->inkTable->setCellWidget(3, 0, cp);
109 		m_inkVisibilities.insert("Black", cp);
110 
111 		for (int sp = 0; sp < spots.count(); ++sp)
112 		{
113 			const QString& spotName = spots.at(sp);
114 			m_optionsUi->inkTable->setItem(sp + 4, 1, new QTableWidgetItem(spotName));
115 			cp = new QCheckBox(this);
116 			cp->setFocusPolicy(Qt::NoFocus);
117 			cp->setChecked(true);
118 			connect(cp, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
119 			m_optionsUi->inkTable->setCellWidget(sp + 4, 0, cp);
120 			m_inkVisibilities.insert(spotName, cp);
121 		}
122 
123 		inkTableWidth = m_optionsUi->inkTable->columnWidth(1);
124 
125 		bool inkCoverageEnabled = (m_optionsUi->enableCMYK->isChecked()) && (m_optionsUi->displayInkCoverage->isChecked());
126 		m_optionsUi->coverThresholdLabel->setEnabled(inkCoverageEnabled);
127 		m_optionsUi->coverThresholdValue->setEnabled(inkCoverageEnabled);
128 		m_optionsUi->coverThresholdValue->setSuffix( tr(" %"));
129 
130 		connect(header, SIGNAL(sectionClicked(int)), this, SLOT(toggleAllFromHeader()));
131 		connect(m_optionsUi->enableCMYK, SIGNAL(clicked()), this, SLOT(toggleCMYK()));
132 		connect(m_optionsUi->displayInkCoverage, SIGNAL(clicked()), this, SLOT(toggleCMYK_Colour()));
133 		connect(m_optionsUi->inkTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(onInkTableCellDoubleClicked(int)));
134 	}
135 	else
136 	{
137 		m_optionsUi->enableCMYK->setChecked(false);
138 		m_optionsUi->enableCMYK->setVisible(false);
139 		m_optionsUi->inkTable->setVisible(false);
140 		m_optionsUi->displayInkCoverage->setChecked(false);
141 		m_optionsUi->displayInkCoverage->setVisible(false);
142 		m_optionsUi->coverThresholdLabel->setVisible(false);
143 		m_optionsUi->coverThresholdValue->setVisible(false);
144 	}
145 
146 	bool cmykEnabled = m_optionsUi->enableCMYK->isChecked();
147 	m_optionsUi->inkTable->setEnabled(cmykEnabled);
148 	m_optionsUi->displayInkCoverage->setEnabled(cmykEnabled);
149 	bool isInkCoverageEnabled = m_optionsUi->displayInkCoverage->isChecked();
150 	m_optionsUi->coverThresholdLabel->setEnabled(cmykEnabled && isInkCoverageEnabled);
151 	m_optionsUi->coverThresholdValue->setEnabled(cmykEnabled && isInkCoverageEnabled);
152 
153 	if (m_optionsUi->inkTable->isVisible())
154 		m_optionsUi->inkTable->setEnabled(m_optionsUi->enableCMYK->isChecked());
155 
156 	// Restore display settings from preferences
157 	m_optionsUi->antiAliasing->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.enableAntiAliasing);
158 	m_optionsUi->showTransparency->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.showTransparency);
159 	if (m_optionsUi->inkTable->isVisible() && m_optionsUi->inkTable->isEnabled())
160 	{
161 		m_optionsUi->enableCMYK->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.cmykPreviewMode);
162 		m_inkVisibilities["Cyan"]->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.isCyanVisible);
163 		m_inkVisibilities["Magenta"]->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.isMagentaVisible);
164 		m_inkVisibilities["Magenta"]->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.isYellowVisible);
165 		m_inkVisibilities["Yellow"]->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.isBlackVisible);
166 	}
167 	m_optionsUi->displayInkCoverage->setChecked(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.displayInkCoverage);
168 	m_optionsUi->coverThresholdValue->setValue(m_prefsManager.appPrefs.pdfOutputPreviewPrefs.inkCoverageThreshold);
169 
170 	// Generate a template name for temporary files
171 	QTemporaryFile *tempFile = new QTemporaryFile(ScPaths::tempFileDir() + "/scpreview_XXXXXX.pdf");
172 	if (tempFile->open())
173 	{
174 		QString tempFileBase = tempFile->fileName();
175 		tempFile->setAutoRemove(false);
176 		tempFile->close();
177 		m_tempBaseName = QFileInfo(tempFileBase).completeBaseName();
178 	}
179 	if (m_tempBaseName.isEmpty())
180 		m_tempBaseName = "scpreview";
181 	delete tempFile;
182 
183 	setPDFOptionsToUi(m_pdfOptions);
184 
185 	// Display preview
186 	QPixmap previewPix = createPreview(m_doc->currentPageNumber(), qRound(72 * m_scaleFactor));
187 	m_previewLabel->setPixmap(previewPix);
188 	m_previewLabel->resize(previewPix.size());
189 
190 	m_uiBase->pageSelector->setGUIForPage(m_doc->currentPage()->pageNr());
191 
192 	int w = m_previewLabel->width() + inkTableWidth + 50;
193 	resize(qMin(QApplication::desktop()->width() - 30, w), 500);
194 
195 	//signals and slots
196 	connect(m_uiBase->pageSelector, SIGNAL(pageChanged(int)), this, SLOT(jumpToPage(int)));
197 	connect(m_uiBase->closeButton, SIGNAL(clicked()), this, SLOT(close()));
198 	connect(m_uiBase->exportButton, SIGNAL(clicked()), this, SIGNAL(doExport()));
199 	connect(m_uiBase->scaleBox, SIGNAL(activated(int)), this, SLOT(onScaleBoxValueChanged(int)));
200 
201 	connect(m_optionsUi->pdfVersionCombo, SIGNAL(activated(int)), this, SLOT(onPdfVersionChanged(int)));
202 	connect(m_optionsUi->outputModeCombo, SIGNAL(activated(int)), this, SLOT(onPdfOutputModeChanged(int)));
203 	connect(m_optionsUi->mirrorH, SIGNAL(clicked()), this, SLOT(redisplay()));
204 	connect(m_optionsUi->mirrorV, SIGNAL(clicked()), this, SLOT(redisplay()));
205 	connect(m_optionsUi->clipToMargins, SIGNAL(clicked()), this, SLOT(redisplay()));
206 	connect(m_optionsUi->convertSpots, SIGNAL(clicked()), this, SLOT(redisplay()));
207 
208 	connect(m_optionsUi->antiAliasing, SIGNAL(clicked()), this, SLOT(redisplay()));
209 	connect(m_optionsUi->showTransparency, SIGNAL(clicked()), this, SLOT(redisplay()));
210 
211 	connect(m_optionsUi->coverThresholdValue, SIGNAL(valueChanged(double)), this, SLOT(toggleCMYK_Colour()));
212 }
213 
~OutputPreview_PDF()214 OutputPreview_PDF::~OutputPreview_PDF()
215 {
216 	cleanupTemporaryFiles();
217 	delete m_optionsUi;
218 }
219 
isCMYKPreviewEnabled() const220 bool OutputPreview_PDF::isCMYKPreviewEnabled() const
221 {
222 	return m_optionsUi->enableCMYK->isChecked();
223 }
224 
isAntialiasingEnabled() const225 bool OutputPreview_PDF::isAntialiasingEnabled() const
226 {
227 	return m_optionsUi->antiAliasing->isChecked();
228 }
229 
isTransparencyEnabled() const230 bool OutputPreview_PDF::isTransparencyEnabled() const
231 {
232 	return m_optionsUi->showTransparency->isChecked();
233 }
234 
isInkChannelVisible(const QString & ink)235 bool OutputPreview_PDF::isInkChannelVisible(const QString& ink)
236 {
237 	if (m_inkVisibilities.contains(ink))
238 		return m_inkVisibilities[ink]->isChecked();
239 	return false;
240 }
241 
isInkCoverageEnabled() const242 bool OutputPreview_PDF::isInkCoverageEnabled() const
243 {
244 	return m_optionsUi->displayInkCoverage->isChecked();
245 }
246 
inkCoverageThreshold() const247 double OutputPreview_PDF::inkCoverageThreshold() const
248 {
249 	return m_optionsUi->coverThresholdValue->value();
250 }
251 
cleanupTemporaryFiles()252 void OutputPreview_PDF::cleanupTemporaryFiles()
253 {
254 	QString tempFileDir = ScPaths::tempFileDir();
255 	QFile::remove(tempFileDir + "/" + m_tempBaseName + ".pdf");
256 	QFile::remove(tempFileDir + "/" + m_tempBaseName + ".png");
257 	QDir d(tempFileDir + "/", m_tempBaseName + "*", QDir::Name, QDir::Files | QDir::NoSymLinks);
258 	if ((d.exists()) && (d.count() != 0))
259 	{
260 		for (uint i = 0; i < d.count(); i++)
261 			QFile::remove(tempFileDir + "/" + d[i]);
262 	}
263 }
264 
createPreview(int pageIndex,int res)265 QPixmap OutputPreview_PDF::createPreview(int pageIndex, int res)
266 {
267 	int ret = -1;
268 	int gsRes = qRound(res * devicePixelRatioF());
269 	int w = qRound(m_doc->Pages->at(pageIndex)->width() * gsRes / 72.0);
270 	int h = qRound(m_doc->Pages->at(pageIndex)->height() * gsRes / 72.0);
271 
272 	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
273 
274 	QPixmap pixmap;
275 	if (pdfOptionsHaveChanged(pageIndex))
276 	{
277 		bool success = createPreviewFile(pageIndex);
278 		if (!success)
279 		{
280 			imageLoadError(pixmap);
281 			return pixmap;
282 		}
283 	}
284 
285 	if (optionsHaveChanged(pageIndex))
286 	{
287 		if (m_optionsUi->enableCMYK->isChecked() && m_haveTiffSep)
288 			ret = renderPreviewSep(pageIndex, gsRes);
289 		else
290 			ret = renderPreview(pageIndex, gsRes);
291 		if (ret > 0)
292 		{
293 			imageLoadError(pixmap);
294 			return pixmap;
295 		}
296 	}
297 
298 	QImage image;
299 	if (m_optionsUi->enableCMYK->isChecked() && m_haveTiffSep)
300 	{
301 		bool loadError;
302 		int cyan, magenta, yellow, black;
303 
304 		ScImage im;
305 		bool mode;
306 		int w2 = w;
307 		int h2 = h;
308 		image = QImage(w2, h2, QImage::Format_ARGB32);
309 		image.fill(qRgba(0, 0, 0, 0));
310 
311 		QStringList separationNames { "Cyan", "Magenta", "Yellow" };
312 		CMSettings cms(m_doc, "", Intent_Perceptual);
313 		cms.allowColorManagement(false);
314 		for (int i = 0; i < separationNames.count(); ++i)
315 		{
316 			QString separationName = separationNames.at(i);
317 			if (!m_inkVisibilities[separationName]->isChecked())
318 				continue;
319 			if (m_gsVersion < 854)
320 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".tif." + separationName + ".tif", 1, cms, ScImage::RGBData, 72, &mode);
321 			else if (m_gsVersion <= 905)
322 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + "." + separationName + ".tif", 1, cms, ScImage::RGBData, 72, &mode);
323 			else
324 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + "(" + separationName + ").tif", 1, cms, ScImage::RGBData, 72, &mode);
325 			if (!loadError)
326 			{
327 				imageLoadError(pixmap);
328 				return pixmap;
329 			}
330 			if (m_optionsUi->displayInkCoverage->isChecked())
331 				blendImagesSumUp(image, im);
332 			else
333 			{
334 				int c = (i == 0) ? 255 : 0;
335 				int m = (i == 1) ? 255 : 0;
336 				int j = (i == 2) ? 255 : 0;
337 				blendImages(image, im, ScColor(c, m, j, 0));
338 			}
339 		}
340 
341 		for (auto sepit = m_sepsToFileNum.begin(); sepit != m_sepsToFileNum.end(); ++sepit)
342 		{
343 			const QCheckBox* checkBox = m_inkVisibilities.value(sepit.key(), nullptr);
344 			if (!checkBox || !checkBox->isChecked())
345 				continue;
346 			QString sepFileName;
347 			if (m_gsVersion < 854)
348 				sepFileName = QString(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".tif.s%1.tif").arg(sepit.value());
349 			else if (m_gsVersion <= 905)
350 				sepFileName = QString(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".s%1.tif").arg(sepit.value());
351 			else
352 				sepFileName = QString(ScPaths::tempFileDir() + "/" + m_tempBaseName + "(%1).tif").arg(sepit.key());
353 			if (!im.loadPicture(sepFileName, 1, cms, ScImage::RGBData, 72, &mode))
354 			{
355 				imageLoadError(pixmap);
356 				return pixmap;
357 			}
358 			if (m_optionsUi->displayInkCoverage->isChecked())
359 				blendImagesSumUp(image, im);
360 			else
361 				blendImages(image, im, m_doc->PageColors[sepit.key()]);
362 		}
363 
364 		if (m_inkVisibilities["Black"]->isChecked())
365 		{
366 			CMSettings cms(m_doc, "", Intent_Perceptual);
367 			cms.allowColorManagement(false);
368 			if (m_gsVersion < 854)
369 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".tif.Black.tif", 1, cms, ScImage::RGBData, 72, &mode);
370 			else if (m_gsVersion <= 905)
371 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".Black.tif", 1, cms, ScImage::RGBData, 72, &mode);
372 			else
373 				loadError = im.loadPicture(ScPaths::tempFileDir() + "/" + m_tempBaseName + "(Black).tif", 1, cms, ScImage::RGBData, 72, &mode);
374 			if (!loadError)
375 			{
376 				imageLoadError(pixmap);
377 				return pixmap;
378 			}
379 			if (m_optionsUi->displayInkCoverage->isChecked())
380 				blendImagesSumUp(image, im);
381 			else
382 				blendImages(image, im, ScColor(0, 0, 0, 255));
383 		}
384 
385 		if (m_optionsUi->displayInkCoverage->isChecked())
386 		{
387 			uint limitVal = (m_optionsUi->coverThresholdValue->value() * 255) / 100;
388 			for (int yi = 0; yi < h2; ++yi)
389 			{
390 				QRgb *q = (QRgb*) image.scanLine(yi);
391 				for (int xi = 0; xi < w2; ++xi)
392 				{
393 					uint greyVal = *q;
394 					if (greyVal != 0)
395 					{
396 						if (limitVal == 0)
397 						{
398 							QColor tmpC;
399 							tmpC.setHsv((greyVal * 359) / m_inkMax, 255, 255);
400 							*q = tmpC.rgba();
401 						}
402 						else
403 						{
404 							int col = qMin(255 - static_cast<int>(((greyVal * 128) / m_inkMax) * 2), 255);
405 							if ((*q > 0) && (*q < limitVal))
406 								*q = qRgba(col, col, col, 255);
407 							else
408 								*q = qRgba(col, 0, 0, 255);
409 						}
410 					}
411 					else
412 					{
413 						if (!m_optionsUi->showTransparency->isChecked())
414 							*q = qRgba(255, 255, 255, 255);
415 					}
416 					q++;
417 				}
418 			}
419 		}
420 		else if (m_doc->HasCMS || ScCore->haveCMS())
421 		{
422 			QRgb alphaFF = qRgba(0,0,0,255);
423 			QRgb alphaOO = qRgba(255,255,255,0);
424 			ScColorMgmtEngine engine = m_doc->colorEngine;
425 			ScColorProfile cmykProfile = m_doc->HasCMS ? m_doc->DocPrinterProf : ScCore->defaultCMYKProfile;
426 			ScColorProfile rgbProfile  = m_doc->HasCMS ? m_doc->DocDisplayProf : ScCore->defaultRGBProfile;
427 			ScColorTransform transCMYK = engine.createTransform(cmykProfile, Format_YMCK_8, rgbProfile, Format_BGRA_8, Intent_Relative_Colorimetric, 0);
428 			for (int yi = 0; yi < h2; ++yi)
429 			{
430 				uchar* ptr = image.scanLine( yi );
431 				transCMYK.apply(ptr, ptr, image.width());
432 				QRgb *q = (QRgb *) ptr;
433 				for (int xi = 0; xi < image.width(); xi++, q++)
434 				{
435 					if (m_optionsUi->showTransparency->isChecked())
436 					{
437 						cyan = qRed(*q);
438 						magenta = qGreen(*q);
439 						yellow = qBlue(*q);
440 						if	((cyan == 255) && (magenta == 255) && (yellow == 255))
441 							*q = alphaOO;
442 						else
443 							*q |= alphaFF;
444 					}
445 					else
446 						*q |= alphaFF;
447 				}
448 			}
449 		}
450 		else
451 		{
452 			for (int yi = 0; yi < h2; ++yi)
453 			{
454 				QRgb *q = (QRgb*) image.scanLine(yi);
455 				for (int xi = 0; xi < w2; ++xi)
456 				{
457 					cyan = qRed(*q);
458 					magenta = qGreen(*q);
459 					yellow = qBlue(*q);
460 					black = qAlpha(*q);
461 					if ((cyan != 0) || (magenta != 0) || (yellow != 0 ) || (black != 0))
462 						*q = qRgba(255 - qMin(255, cyan + black), 255 - qMin(255, magenta + black), 255 - qMin(255, yellow + black), 255);
463 					else
464 					{
465 						if (!m_optionsUi->showTransparency->isChecked())
466 							*q = qRgba(255, 255, 255, 255);
467 					}
468 					q++;
469 				}
470 			}
471 		}
472 	}
473 	else
474 	{
475 		QString previewFile;
476 		if (m_optionsUi->showTransparency->isChecked() && m_havePngAlpha)
477 			previewFile = ScPaths::tempFileDir() + "/" + m_tempBaseName + ".png";
478 		else
479 			previewFile = ScPaths::tempFileDir() + "/" + m_tempBaseName + ".tif";
480 		if (!image.load(previewFile))
481 		{
482 			imageLoadError(pixmap);
483 			return pixmap;
484 		}
485 		image = image.convertToFormat(QImage::Format_ARGB32);
486 		if (m_optionsUi->showTransparency->isChecked() && m_havePngAlpha)
487 		{
488 			int wi = image.width();
489 			int hi = image.height();
490 			for (int yi = 0; yi < hi; ++yi)
491 			{
492 				QRgb *s = (QRgb*) image.scanLine(yi);
493 				for (int xi = 0; xi < wi; ++xi)
494 				{
495 					if ((*s) == 0xffffffff)
496 						(*s) &= 0x00ffffff;
497 					s++;
498 				}
499 			}
500 		}
501 	}
502 
503 	image.setDevicePixelRatio(devicePixelRatioF());
504 	if (m_optionsUi->showTransparency->isChecked())
505 	{
506 		pixmap = QPixmap(image.width(), image.height());
507 		pixmap.setDevicePixelRatio(devicePixelRatioF());
508 		QPainter p;
509 		QBrush b(QColor(205,205,205), IconManager::instance().loadPixmap("testfill.png"));
510 		p.begin(&pixmap);
511 		p.fillRect(0, 0, image.width(), image.height(), b);
512 		p.drawImage(0, 0, image);
513 		p.end();
514 	}
515 	else
516 		pixmap = QPixmap::fromImage(image);
517 	pixmap.setDevicePixelRatio(devicePixelRatioF());
518 
519 	qApp->restoreOverrideCursor();
520 	updateOptionsFromUI();
521 	return pixmap;
522 }
523 
createPreviewFile(int pageIndex)524 bool OutputPreview_PDF::createPreviewFile(int pageIndex)
525 {
526 	if (!m_fontEmbeddingWasSet)
527 	{
528 		setupFontEmbedding(m_pdfOptions);
529 		m_fontEmbeddingWasSet = true;
530 	}
531 
532 	std::vector<int> pageNumbers { pageIndex + 1 };
533 
534 	setUiOptionsToPDFOptions(m_pdfOptions);
535 	m_pdfOptions.Encrypt = false; // Disable PDF encryption for preview
536 	m_pdfOptions.Thumbnails = false; //Disable thumbnails too
537 
538 	QString profileDescription;
539 	if ((m_pdfOptions.Version == PDFVersion::PDF_X3) || (m_pdfOptions.Version == PDFVersion::PDF_X1a) || (m_pdfOptions.Version == PDFVersion::PDF_X4))
540 	{
541 		if (m_pdfOptions.Info.isEmpty())
542 		{
543 			auto& printerProfiles = ScCore->PrinterProfiles;
544 			ScColorProfile outputProfile = m_doc->colorEngine.openProfileFromFile( printerProfiles[m_pdfOptions.PrintProf] );
545 			profileDescription = outputProfile.productDescription();
546 			m_pdfOptions.Info = profileDescription;
547 		}
548 		m_pdfOptions.MirrorH = false;
549 		m_pdfOptions.MirrorV = false;
550 		m_pdfOptions.PresentMode = false;
551 	}
552 
553 	// Disable crop marks
554 	m_pdfOptions.cropMarks = false;
555 	m_pdfOptions.bleedMarks = false;
556 	m_pdfOptions.registrationMarks = false;
557 	m_pdfOptions.colorMarks = false;
558 	m_pdfOptions.markLength = 20.0;
559 	m_pdfOptions.markOffset = 0.0;
560 	m_pdfOptions.bleeds.set(0, 0, 0, 0);
561 
562 	// Generate PDF
563 //	QString errorString;
564 	QString pdfFileName = ScPaths::tempFileDir() + "/"  + m_tempBaseName + ".pdf";
565 
566 	ScCore->fileWatcher->forceScan();
567 	ScCore->fileWatcher->stop();
568 	PDFlib pdflib(*m_doc, m_pdfOptions);
569 	bool success = pdflib.doExport(pdfFileName, pageNumbers, QMap<int, QImage>());
570 	success &= !pdflib.exportAborted();
571 	ScCore->fileWatcher->start();
572 
573 	return success;
574 }
575 
renderPreview(int pageIndex,int res)576 int OutputPreview_PDF::renderPreview(int pageIndex, int res)
577 {
578 	int ret = -1;
579 	QString cmd1;
580 
581 	QStringList args;
582 	QString tmp, tmp2, tmp3;
583 	int w = qRound(m_doc->Pages->at(pageIndex)->width() * res / 72.0);
584 	int h = qRound(m_doc->Pages->at(pageIndex)->height() * res / 72.0);
585 
586 	args.append( "-q" );
587 	args.append( "-dNOPAUSE" );
588 	args.append( "-dPARANOIDSAFER" );
589 	args.append( QString("-r%1").arg(tmp.setNum(res)) );
590 	args.append( QString("-g%1x%2").arg(tmp2.setNum(w), tmp3.setNum(h)) );
591 	if (m_optionsUi->enableCMYK->isChecked())
592 	{
593 		if (!m_haveTiffSep)
594 			return 1;
595 		args.append("-sDEVICE=tiffsep");
596 	}
597 	else
598 	{
599 		if (m_optionsUi->showTransparency->isChecked() && m_havePngAlpha)
600 			args.append("-sDEVICE=pngalpha");
601 		else
602 			args.append("-sDEVICE=tiff24nc");
603 	}
604 	if (m_optionsUi->antiAliasing->isChecked())
605 	{
606 		args.append("-dTextAlphaBits=4");
607 		args.append("-dGraphicsAlphaBits=4");
608 	}
609 	if ((m_doc->HasCMS) && (m_gsVersion >= 900))
610 	{
611 		args.append("-sDefaultCMYKProfile=" + QDir::toNativeSeparators(m_doc->DocPrinterProf.profilePath()));
612 		if (m_optionsUi->enableCMYK->isChecked())
613 			args.append("-sOutputICCProfile=" + QDir::toNativeSeparators(m_doc->DocPrinterProf.profilePath()));
614 		else
615 			args.append("-sOutputICCProfile=" + QDir::toNativeSeparators(m_doc->DocDisplayProf.profilePath()));
616 	}
617 	else if (ScCore->haveCMS() && (m_gsVersion >= 900))
618 	{
619 		args.append("-sDefaultCMYKProfile=" + QDir::toNativeSeparators(ScCore->defaultCMYKProfile.profilePath()));
620 		if (m_optionsUi->enableCMYK->isChecked())
621 			args.append("-sOutputICCProfile=" + QDir::toNativeSeparators(ScCore->defaultCMYKProfile.profilePath()));
622 		else
623 			args.append("-sOutputICCProfile=" + QDir::toNativeSeparators(ScCore->defaultRGBProfile.profilePath()));
624 	}
625 
626 	// Add any extra font paths being used by Scribus to gs's font search path
627 	PrefsContext *pc = m_prefsManager.prefsFile->getContext("Fonts");
628 	PrefsTable *extraFonts = pc->getTable("ExtraFontDirs");
629 	const char sep = ScPaths::envPathSeparator;
630 	if (extraFonts->getRowCount() >= 1)
631 		cmd1 = QString("-sFONTPATH=%1").arg(QDir::toNativeSeparators(extraFonts->get(0,0)));
632 	for (int i = 1; i < extraFonts->getRowCount(); ++i)
633 		cmd1 += QString("%1%2").arg(sep).arg(QDir::toNativeSeparators(extraFonts->get(i,0)));
634 	if (!cmd1.isEmpty())
635 		args.append( cmd1 );
636 
637 	// then add any final args and call gs
638 	QString tempFileDir = ScPaths::tempFileDir() ;
639 	if (m_optionsUi->enableCMYK->isChecked())
640 		args.append( QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(tempFileDir + "/" + m_tempBaseName + ".tif")) );
641 	else if (m_optionsUi->showTransparency->isChecked() && m_havePngAlpha)
642 		args.append( QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(tempFileDir + "/" + m_tempBaseName + ".png")) );
643 	else
644 		args.append(QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(tempFileDir + "/" + m_tempBaseName + ".tif")));
645 	args.append( QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".pdf") );
646 	args.append( "-c" );
647 	args.append( "showpage" );
648 	args.append( "-c" );
649 	args.append( "quit" );
650 	ret = System(m_prefsManager.ghostscriptExecutable(), args);
651 	return ret;
652 }
653 
renderPreviewSep(int pageIndex,int res)654 int OutputPreview_PDF::renderPreviewSep(int pageIndex, int res)
655 {
656 	int ret = -1;
657 	QString cmd;
658 	QStringList args, args1, args2, args3;
659 
660 	QString tmp, tmp2, tmp3;
661 	int w = qRound(m_doc->Pages->at(pageIndex)->width() * res / 72.0);
662 	int h = qRound(m_doc->Pages->at(pageIndex)->height() * res / 72.0);
663 
664 	args1.append( "-q" );
665 	args1.append( "-dNOPAUSE" );
666 	args1.append( "-dPARANOIDSAFER" );
667 	args1.append( QString("-r%1").arg(tmp.setNum(res)) );
668 	args1.append( QString("-g%1x%2").arg(tmp2.setNum(w), tmp3.setNum(h)) );
669 	if (m_optionsUi->antiAliasing->isChecked())
670 	{
671 		args1.append("-dTextAlphaBits=4");
672 		args1.append("-dGraphicsAlphaBits=4");
673 	}
674 	if ((m_doc->HasCMS) && (m_gsVersion >= 900))
675 	{
676 		args1.append("-sDefaultCMYKProfile=" + QDir::toNativeSeparators(m_doc->DocPrinterProf.profilePath()));
677 		args1.append("-sOutputICCProfile=" + QDir::toNativeSeparators(m_doc->DocPrinterProf.profilePath()));
678 	}
679 	else if (ScCore->haveCMS() && (m_gsVersion >= 900))
680 	{
681 		args.append("-sDefaultCMYKProfile=" + QDir::toNativeSeparators(ScCore->defaultCMYKProfile.profilePath()));
682 		args.append("-sOutputICCProfile=" + QDir::toNativeSeparators(ScCore->defaultCMYKProfile.profilePath()));
683 	}
684 
685 	// Add any extra font paths being used by Scribus to gs's font search path
686 	PrefsContext *pc = m_prefsManager.prefsFile->getContext("Fonts");
687 	PrefsTable *extraFonts = pc->getTable("ExtraFontDirs");
688 	const char sep = ScPaths::envPathSeparator;
689 	if (extraFonts->getRowCount() >= 1)
690 		cmd = QString("-sFONTPATH=%1").arg(QDir::toNativeSeparators(extraFonts->get(0,0)));
691 	for (int i = 1; i < extraFonts->getRowCount(); ++i)
692 		cmd += QString("%1%2").arg(sep).arg(QDir::toNativeSeparators(extraFonts->get(i,0)));
693 	if (!cmd.isEmpty())
694 		args1.append(cmd);
695 	args1.append( QString("-sOutputFile=%1").arg(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".tif")) );
696 
697 	args2.append( QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" + m_tempBaseName + ".pdf") );
698 	args2.append("-c");
699 	args2.append("quit");
700 
701 	ColorList usedSpots;
702 	m_doc->getUsedColors(usedSpots, true);
703 	QStringList spots = usedSpots.keys();
704 	args3.append( "-sDEVICE=tiffsep" );
705 
706 //	args3.append( "-c" );
707 	cmd = "<< /SeparationColorNames ";
708 	QString allSeps ="[ /Cyan /Magenta /Yellow /Black ";
709 	for (int sp = 0; sp < spots.count(); ++sp)
710 	{
711 		allSeps += "(" + spots[sp] + ") ";
712 	}
713 	allSeps += "]";
714 	cmd += allSeps + " /SeparationOrder [ /Cyan /Magenta /Yellow /Black] >> setpagedevice";
715 	QFile fx(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".sep.ps"));
716 	if (fx.open(QIODevice::WriteOnly))
717 	{
718 		QTextStream tsx(&fx);
719 		tsx << cmd;
720 		fx.close();
721 	}
722 
723 	QString gsExe(getShortPathName(m_prefsManager.ghostscriptExecutable()));
724 	ret = System(gsExe, args1 + args3 + args2, ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".tif.txt" );
725 
726 	QFile sepInfo(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".tif.txt"));
727 	m_sepsToFileNum.clear();
728 	if (sepInfo.open(QIODevice::ReadOnly))
729 	{
730 		QString Sname;
731 		QTextStream tsC(&sepInfo);
732 		int counter = 0;
733 		while (!tsC.atEnd())
734 		{
735 			Sname = tsC.readLine();
736 			QString tt = Sname.remove("%%SeparationName:").trimmed();
737 			if (!tt.isEmpty())
738 			{
739 				m_sepsToFileNum.insert(tt, counter);
740 				counter++;
741 			}
742 		}
743 	}
744 	sepInfo.close();
745 	QString currSeps = "";
746 	uint spc = 0;
747 	for (int sp = 0; sp < spots.count(); ++sp)
748 	{
749 		currSeps += "(" + spots[sp] + ") ";
750 		spc++;
751 		if (sp > 6)
752 		{
753 			args3.clear();
754 			args3.append("-sDEVICE=tiffsep");
755 			QFile fx(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".sep.ps"));
756 			if (fx.open(QIODevice::WriteOnly))
757 			{
758 				QTextStream tsx(&fx);
759 				tsx << QString("<< /SeparationColorNames " + allSeps + " /SeparationOrder [ " + currSeps + " ] >> setpagedevice");
760 				fx.close();
761 			}
762 			args3.append("-f");
763 			args3.append(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".sep.ps"));
764 			ret = System(gsExe, args1 + args3 + args2);
765 			currSeps = "";
766 			spc = 0;
767 		}
768 	}
769 	if (spc != 0)
770 	{
771 		args3.clear();
772 		args3.append("-sDEVICE=tiffsep");
773 		QFile fx(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".sep.ps"));
774 		if (fx.open(QIODevice::WriteOnly))
775 		{
776 			QTextStream tsx(&fx);
777 			tsx << QString("<< /SeparationColorNames " + allSeps + " /SeparationOrder [ " + currSeps + " ] >> setpagedevice");
778 			fx.close();
779 		}
780 		args3.append("-f");
781 		args3.append(QDir::toNativeSeparators(ScPaths::tempFileDir() + "/" +  m_tempBaseName + ".sep.ps"));
782 		ret = System(gsExe, args1 + args3 + args2);
783 	}
784 	return ret;
785 }
786 
setupFontEmbedding(PDFOptions & options)787 void OutputPreview_PDF::setupFontEmbedding(PDFOptions& options)
788 {
789 	QMap<QString, int> usedFonts = m_doc->reorganiseFonts();
790 	QStringList docFonts = usedFonts.keys();
791 
792 	// Simple case: no font embedding
793 	if (m_pdfOptions.FontEmbedding == PDFOptions::DontEmbed)
794 	{
795 		m_pdfOptions.OutlineList.clear();
796 		m_pdfOptions.EmbedList.clear();
797 		m_pdfOptions.SubsetList.clear();
798 		return;
799 	}
800 
801 	// Simple case: all fonts are outlined
802 	if (m_pdfOptions.FontEmbedding == PDFOptions::OutlineFonts)
803 	{
804 		m_pdfOptions.OutlineList = docFonts;
805 		m_pdfOptions.EmbedList.clear();
806 		m_pdfOptions.SubsetList.clear();
807 		return;
808 	}
809 
810 	if (m_pdfOptions.EmbedList.count() != 0)
811 	{
812 		QList<QString> tmpEm;
813 		for (auto itef = m_pdfOptions.EmbedList.begin(); itef != m_pdfOptions.EmbedList.end(); ++itef)
814 		{
815 			if (usedFonts.contains((*itef)))
816 				tmpEm.append((*itef));
817 		}
818 		m_pdfOptions.EmbedList = tmpEm;
819 	}
820 	if (m_pdfOptions.SubsetList.count() != 0)
821 	{
822 		QList<QString> tmpEm;
823 		for (auto itef = m_pdfOptions.SubsetList.begin(); itef != m_pdfOptions.SubsetList.end(); ++itef)
824 		{
825 			if (usedFonts.contains((*itef)))
826 				tmpEm.append((*itef));
827 		}
828 		m_pdfOptions.SubsetList = tmpEm;
829 	}
830 
831 	// Build a list of all fonts used in Annotations
832 	QMap<QString, QString> annotationFonts;
833 
834 	int pageItOptions = PageItemIterator::IterateInGroups | PageItemIterator::IterateInDocItems | PageItemIterator::IterateInMasterItems | PageItemIterator::IterateInFrameItems;
835 	for (PageItemIterator it(m_doc, pageItOptions); *it; ++it)
836 	{
837 		PageItem *currItem = *it;
838 		if (((currItem->itemType() == PageItem::TextFrame) || (currItem->itemType() == PageItem::PathText)) && (currItem->isAnnotation()))
839 		{
840 			int annotType  = currItem->annotation().Type();
841 			bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
842 			if (currItem->itemText.length() > 0 || mustEmbed)
843 				annotationFonts.insert(currItem->itemText.defaultStyle().charStyle().font().replacementName(), QString());
844 		}
845 	}
846 
847 	const auto& allFonts = m_prefsManager.appPrefs.fontPrefs.AvailFonts;
848 	PDFVersion pdfVer = m_pdfOptions.Version;
849 
850 	if ((m_pdfOptions.EmbedList.count() == 0) && (m_pdfOptions.SubsetList.count() == 0) && (m_pdfOptions.firstUse))
851 	{
852 		for (int i = 0; i < docFonts.count(); ++i)
853 		{
854 			QString fontName = docFonts.at(i);
855 			const ScFace fontFace = allFonts[fontName];
856 			if (!fontFace.subset() && (!fontFace.isOTF() || pdfVer.supportsEmbeddedOpenTypeFonts()))
857 				m_pdfOptions.EmbedList.append(fontName);
858 			else if (annotationFonts.contains(fontName))
859 				m_pdfOptions.EmbedList.append(fontName);
860 			else
861 				m_pdfOptions.SubsetList.append(fontName);
862 		}
863 	}
864 	else
865 	{
866 		for (int i = 0; i < docFonts.count(); ++i)
867 		{
868 			QString fontName = docFonts.at(i);
869 			const ScFace fontFace = allFonts[fontName];
870 			if (m_pdfOptions.EmbedList.contains(fontName) && (!fontFace.isOTF() || m_pdfOptions.supportsEmbeddedOpenTypeFonts()) && !fontFace.subset())
871 				continue;
872 			if (!m_pdfOptions.SubsetList.contains(fontName))
873 				m_pdfOptions.SubsetList.append(fontName);
874 		}
875 
876 		for (auto itAnn = annotationFonts.begin(); itAnn != annotationFonts.end(); ++itAnn)
877 		{
878 			QString annotFont = itAnn.key();
879 			if (!m_pdfOptions.EmbedList.contains(annotFont))
880 				m_pdfOptions.EmbedList.append(annotFont);
881 			int subsetIndex = m_pdfOptions.SubsetList.indexOf(annotFont);
882 			if (subsetIndex >= 0)
883 				m_pdfOptions.SubsetList.removeAll(annotFont);
884 		}
885 	}
886 }
887 
optionsHaveChanged(int pageIndex) const888 bool OutputPreview_PDF::optionsHaveChanged(int pageIndex) const
889 {
890 	if (m_currentPage != pageIndex)
891 		return true;
892 	if (m_scaleMode != m_uiBase->scaleBox->currentIndex())
893 		return true;
894 	if (m_cmykPreviewMode != m_optionsUi->enableCMYK->isChecked())
895 		return true;
896 	if (m_useAntialiasing != m_optionsUi->antiAliasing->isChecked())
897 		return true;
898 	if (m_showTransparency != m_optionsUi->showTransparency->isChecked())
899 		return true;
900 
901 	if (m_pdfVersion != m_optionsUi->pdfVersionCombo->version())
902 		return true;
903 	if (m_pdfOutputMode != m_optionsUi->outputModeCombo->currentIndex())
904 		return true;
905 	if (m_mirrorH != m_optionsUi->mirrorH->isChecked())
906 		return true;
907 	if (m_mirrorV != m_optionsUi->mirrorV->isChecked())
908 		return true;
909 	if (m_clipToMargins != m_optionsUi->clipToMargins->isChecked())
910 		return true;
911 	if (m_convertSpots != m_optionsUi->convertSpots->isChecked())
912 		return true;
913 
914 	return false;
915 }
916 
pdfOptionsHaveChanged(int pageIndex) const917 bool OutputPreview_PDF::pdfOptionsHaveChanged(int pageIndex) const
918 {
919 	if (m_currentPage != pageIndex)
920 		return true;
921 
922 	if (m_pdfVersion != m_optionsUi->pdfVersionCombo->version())
923 		return true;
924 	if (m_pdfOutputMode != m_optionsUi->outputModeCombo->currentIndex())
925 		return true;
926 	if (m_mirrorH != m_optionsUi->mirrorH->isChecked())
927 		return true;
928 	if (m_mirrorV != m_optionsUi->mirrorV->isChecked())
929 		return true;
930 	if (m_clipToMargins != m_optionsUi->clipToMargins->isChecked())
931 		return true;
932 	if (m_convertSpots != m_optionsUi->convertSpots->isChecked())
933 		return true;
934 
935 	return false;
936 }
937 
setPDFOptionsToOptions(PDFOptions & pdfOptions)938 void OutputPreview_PDF::setPDFOptionsToOptions(PDFOptions& pdfOptions)
939 {
940 	m_pdfVersion = pdfOptions.Version;
941 
942 	if (pdfOptions.UseRGB)
943 		m_pdfOutputMode = 0;
944 	else if (pdfOptions.isGrayscale)
945 		m_pdfOutputMode = 2;
946 	else
947 		m_pdfOutputMode = 1;
948 
949 	m_mirrorH = pdfOptions.MirrorH;
950 	m_mirrorV = pdfOptions.MirrorV;
951 	m_clipToMargins = pdfOptions.doClip;
952 	m_convertSpots  = !pdfOptions.UseSpotColors;
953 }
954 
setPDFOptionsToUi(PDFOptions & pdfOptions)955 void OutputPreview_PDF::setPDFOptionsToUi(PDFOptions& pdfOptions)
956 {
957 	m_optionsUi->pdfVersionCombo->setPDFXEnabled(m_doc->HasCMS && !ScCore->PDFXProfiles.isEmpty());
958 	m_optionsUi->pdfVersionCombo->setVersion(pdfOptions.Version);
959 
960 	if (pdfOptions.UseRGB)
961 		m_optionsUi->outputModeCombo->setCurrentIndex(0);
962 	else if (pdfOptions.isGrayscale)
963 		m_optionsUi->outputModeCombo->setCurrentIndex(2);
964 	else
965 		m_optionsUi->outputModeCombo->setCurrentIndex(1);
966 
967 	m_optionsUi->mirrorH->setChecked(pdfOptions.MirrorH);
968 	m_optionsUi->mirrorV->setChecked(pdfOptions.MirrorV);
969 	m_optionsUi->clipToMargins->setChecked(pdfOptions.doClip);
970 	m_optionsUi->convertSpots->setChecked(!pdfOptions.UseSpotColors);
971 
972 	bool cmykEnabled = (m_optionsUi->outputModeCombo->currentIndex() > 0);
973 	bool cmykUserEnabled = m_optionsUi->enableCMYK->isChecked();
974 
975 	m_optionsUi->enableCMYK->setEnabled(cmykEnabled);
976 	m_optionsUi->enableCMYK->setChecked(cmykEnabled && cmykUserEnabled);
977 	m_optionsUi->inkTable->setEnabled(cmykEnabled && cmykUserEnabled);
978 	m_optionsUi->displayInkCoverage->setEnabled(cmykEnabled && cmykUserEnabled);
979 	bool isInkCoverageEnabled = m_optionsUi->displayInkCoverage->isChecked();
980 	m_optionsUi->coverThresholdLabel->setEnabled(cmykEnabled && cmykUserEnabled && isInkCoverageEnabled);
981 	m_optionsUi->coverThresholdValue->setEnabled(cmykEnabled && cmykUserEnabled && isInkCoverageEnabled);
982 }
983 
setUiOptionsToPDFOptions(PDFOptions & pdfOptions)984 void OutputPreview_PDF::setUiOptionsToPDFOptions(PDFOptions& pdfOptions)
985 {
986 	pdfOptions.Version = m_optionsUi->pdfVersionCombo->version();
987 	if (!pdfOptions.Version.supportsOCGs())
988 		pdfOptions.useLayers = false;
989 
990 	if (m_optionsUi->outputModeCombo->currentIndex() == 0)
991 	{
992 		pdfOptions.isGrayscale = false;
993 		pdfOptions.UseRGB = true;
994 		pdfOptions.UseProfiles = false;
995 		pdfOptions.UseProfiles2 = false;
996 	}
997 	else if (m_optionsUi->outputModeCombo->currentIndex() == 2)
998 	{
999 		pdfOptions.isGrayscale = true;
1000 		pdfOptions.UseRGB = false;
1001 		pdfOptions.UseProfiles = false;
1002 		pdfOptions.UseProfiles2 = false;
1003 	}
1004 	else
1005 	{
1006 		pdfOptions.isGrayscale = false;
1007 		pdfOptions.UseRGB = false;
1008 		/*if (ScCore->haveCMS())
1009 		{
1010 			pdfOptions.UseProfiles = EmbedProfs->isChecked();
1011 			pdfOptions.UseProfiles2 = EmbedProfs2->isChecked();
1012 			pdfOptions.Intent = IntendS->currentIndex();
1013 			pdfOptions.Intent2 = IntendI->currentIndex();
1014 			pdfOptions.EmbeddedI = NoEmbedded->isChecked();
1015 			pdfOptions.SolidProf = SolidPr->currentText();
1016 			pdfOptions.ImageProf = ImageP->currentText();
1017 			pdfOptions.PrintProf = PrintProfC->currentText();
1018 		}*/
1019 	}
1020 
1021 	// Force font embedding for PDF-X/1
1022 	if (pdfOptions.Version.isPDFX() && (pdfOptions.FontEmbedding == PDFOptions::DontEmbed))
1023 	{
1024 		m_fontEmbeddingWasSet = false;
1025 		pdfOptions.EmbedList.clear();
1026 		pdfOptions.SubsetList.clear();
1027 		pdfOptions.FontEmbedding = PDFOptions::EmbedFonts;
1028 		setupFontEmbedding(m_pdfOptions);
1029 		m_fontEmbeddingWasSet = true;
1030 	}
1031 
1032 	// PDF/X-1, no profile embedding
1033 	if (pdfOptions.Version == PDFVersion::PDF_X1a)
1034 	{
1035 		pdfOptions.UseProfiles = false;
1036 		pdfOptions.UseProfiles2 = false;
1037 	}
1038 	// PDF/X-3 or PDF/X-4, enforcing color profiles on images
1039 	if (pdfOptions.Version == PDFVersion::PDF_X3 || pdfOptions.Version == PDFVersion::PDF_X4)
1040 		pdfOptions.UseProfiles2 = true;
1041 
1042 	pdfOptions.MirrorH = m_optionsUi->mirrorH->isChecked();
1043 	pdfOptions.MirrorV = m_optionsUi->mirrorV->isChecked();
1044 	pdfOptions.doClip  = m_optionsUi->clipToMargins->isChecked();
1045 	pdfOptions.UseSpotColors = !m_optionsUi->convertSpots->isChecked();
1046 }
1047 
updateOptionsFromUI()1048 void OutputPreview_PDF::updateOptionsFromUI()
1049 {
1050 	m_pdfVersion = m_optionsUi->pdfVersionCombo->version();
1051 	m_pdfOutputMode = m_optionsUi->outputModeCombo->currentIndex();
1052 	m_mirrorH = m_optionsUi->mirrorH->isChecked();
1053 	m_mirrorV = m_optionsUi->mirrorV->isChecked();
1054 	m_clipToMargins = m_optionsUi->clipToMargins->isChecked();
1055 	m_convertSpots = m_optionsUi->convertSpots->isChecked();
1056 
1057 	m_currentPage = m_uiBase->pageSelector->getCurrentPage() - 1;
1058 	m_scaleMode = m_uiBase->scaleBox->currentIndex();
1059 	m_cmykPreviewMode = m_optionsUi->enableCMYK->isChecked();
1060 	m_useAntialiasing = m_optionsUi->antiAliasing->isChecked();
1061 	m_showTransparency = m_optionsUi->showTransparency->isChecked();
1062 }
1063 
onPdfVersionChanged(int index)1064 void OutputPreview_PDF::onPdfVersionChanged(int index)
1065 {
1066 	bool isPDFX = m_optionsUi->pdfVersionCombo->versionIsPDFX();
1067 	m_optionsUi->outputModeCombo->setEnabled(!isPDFX);
1068 
1069 	if (isPDFX)
1070 	{
1071 		m_optionsUi->outputModeCombo->setCurrentIndex(1);
1072 		m_optionsUi->outputModeCombo->setEnabled(false);
1073 		onPdfOutputModeChanged(1);
1074 	}
1075 
1076 	redisplay();
1077 }
1078 
onPdfOutputModeChanged(int)1079 void OutputPreview_PDF::onPdfOutputModeChanged(int /*index*/)
1080 {
1081 	bool cmykEnabled = (m_optionsUi->outputModeCombo->currentIndex() > 0);
1082 	bool cmykUserEnabled = m_optionsUi->enableCMYK->isChecked();
1083 
1084 	m_optionsUi->enableCMYK->setEnabled(cmykEnabled);
1085 	m_optionsUi->enableCMYK->setChecked(cmykEnabled && cmykUserEnabled);
1086 	m_optionsUi->inkTable->setEnabled(cmykEnabled && cmykUserEnabled);
1087 	m_optionsUi->displayInkCoverage->setEnabled(cmykEnabled && cmykUserEnabled);
1088 	bool isInkCoverageEnabled = m_optionsUi->displayInkCoverage->isChecked();
1089 	m_optionsUi->coverThresholdLabel->setEnabled(cmykEnabled && cmykUserEnabled && isInkCoverageEnabled);
1090 	m_optionsUi->coverThresholdValue->setEnabled(cmykEnabled && cmykUserEnabled && isInkCoverageEnabled);
1091 
1092 	redisplay();
1093 }
1094 
onInkTableCellDoubleClicked(int row)1095 void OutputPreview_PDF::onInkTableCellDoubleClicked(int row)
1096 {
1097 	if (!m_haveTiffSep)
1098 		return;
1099 
1100 	for (auto sepIt = m_inkVisibilities.begin(); sepIt != m_inkVisibilities.end(); ++sepIt)
1101 		sepIt.value()->setChecked(false);
1102 	((QCheckBox*)(m_optionsUi->inkTable->cellWidget(row, 0)))->setChecked(true);
1103 
1104 	if (m_optionsUi->enableCMYK->isChecked())
1105 		m_previewLabel->setPixmap(createPreview(m_currentPage, qRound(72 * m_scaleFactor)));
1106 	m_previewLabel->resize(m_previewLabel->pixmap()->size());
1107 }
1108 
toggleAllFromHeader()1109 void OutputPreview_PDF::toggleAllFromHeader()
1110 {
1111 	if (!m_haveTiffSep)
1112 		return;
1113 
1114 	for (auto sepIt = m_inkVisibilities.begin(); sepIt != m_inkVisibilities.end(); ++sepIt)
1115 		sepIt.value()->setChecked(true);
1116 
1117 	if (m_optionsUi->enableCMYK->isChecked())
1118 		m_previewLabel->setPixmap(createPreview(m_currentPage, qRound(72 * m_scaleFactor)));
1119 	m_previewLabel->resize(m_previewLabel->pixmap()->size());
1120 }
1121 
toggleCMYK()1122 void OutputPreview_PDF::toggleCMYK()
1123 {
1124 	if (!m_haveTiffSep)
1125 		return;
1126 
1127 	bool cmykEnabled = m_optionsUi->enableCMYK->isChecked();
1128 	m_optionsUi->inkTable->setEnabled(cmykEnabled);
1129 	m_optionsUi->displayInkCoverage->setEnabled(cmykEnabled);
1130 	bool isInkCoverageEnabled = m_optionsUi->displayInkCoverage->isChecked();
1131 	m_optionsUi->coverThresholdLabel->setEnabled(cmykEnabled && isInkCoverageEnabled);
1132 	m_optionsUi->coverThresholdValue->setEnabled(cmykEnabled && isInkCoverageEnabled);
1133 
1134 	redisplay();
1135 }
1136 
toggleCMYK_Colour()1137 void OutputPreview_PDF::toggleCMYK_Colour()
1138 {
1139 	if (m_haveTiffSep)
1140 	{
1141 		bool inkCoverageEnabled = (m_optionsUi->enableCMYK->isChecked()) && (m_optionsUi->displayInkCoverage->isChecked());
1142 		m_optionsUi->coverThresholdLabel->setEnabled(inkCoverageEnabled);
1143 		m_optionsUi->coverThresholdValue->setEnabled(inkCoverageEnabled);
1144 	}
1145 	if (m_optionsUi->enableCMYK->isChecked())
1146 		m_previewLabel->setPixmap(createPreview(m_currentPage, qRound(72 * m_scaleFactor)));
1147 	m_previewLabel->resize(m_previewLabel->pixmap()->size());
1148 }
1149 
imageLoadError(QPixmap & pixmap)1150 void OutputPreview_PDF::imageLoadError(QPixmap &pixmap)
1151 {
1152 	pixmap = QPixmap(1, 1);
1153 	qApp->restoreOverrideCursor();
1154 	updateOptionsFromUI();
1155 }
1156