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 <cstdlib>
9 
10 #include <QByteArray>
11 #include <QCursor>
12 #include <QDebug>
13 #include <QDrag>
14 #include <QFile>
15 #include <QInputDialog>
16 #include <QList>
17 #include <QMimeData>
18 #include <QRegExp>
19 #include <QStack>
20 
21 #include <poppler/ErrorCodes.h>
22 #include <poppler/GlobalParams.h>
23 #include <poppler/OptionalContent.h>
24 #include <poppler/PageTransition.h>
25 #include <poppler/ViewerPreferences.h>
26 #include <poppler/poppler-config.h>
27 #include <poppler/cpp/poppler-version.h>
28 #include <poppler/SplashOutputDev.h>
29 #include <poppler/splash/SplashBitmap.h>
30 
31 #include "importpdf.h"
32 #include "importpdfconfig.h"
33 #include "pdftextrecognition.h"
34 #include "slaoutput.h"
35 
36 #include "commonstrings.h"
37 #include "loadsaveplugin.h"
38 #include "pagesize.h"
39 #include "pdfimportoptions.h"
40 #include "pdfoptions.h"
41 #include "prefscontext.h"
42 #include "prefsfile.h"
43 #include "prefsmanager.h"
44 #include "prefstable.h"
45 #include "rawimage.h"
46 #include "scclocale.h"
47 #include "sccolorengine.h"
48 #include "scconfig.h"
49 #include "scmimedata.h"
50 #include "scpaths.h"
51 #include "scribus.h"
52 #include "scribusXml.h"
53 #include "scribuscore.h"
54 #include "sctextstream.h"
55 #include "selection.h"
56 #include "undomanager.h"
57 #include "util.h"
58 #include "util_formats.h"
59 #include "util_math.h"
60 
61 #include "ui/customfdialog.h"
62 #include "ui/missing.h"
63 #include "ui/multiprogressdialog.h"
64 #include "ui/propertiespalette.h"
65 
PdfPlug(ScribusDoc * doc,int flags)66 PdfPlug::PdfPlug(ScribusDoc* doc, int flags)
67 {
68 	m_tmpSele = new Selection(this, false);
69 	m_Doc = doc;
70 	m_importerFlags = flags;
71 	m_interactive = (flags & LoadSavePlugin::lfInteractive);
72 	m_noDialogs = (flags & LoadSavePlugin::lfNoDialogs);
73 }
74 
readThumbnail(const QString & fName)75 QImage PdfPlug::readThumbnail(const QString& fName)
76 {
77 	QString pdfFile = QDir::toNativeSeparators(fName);
78 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 83, 0)
79 	globalParams.reset(new GlobalParams());
80 #else
81 	globalParams = new GlobalParams();
82 #endif
83 	if (globalParams)
84 	{
85 #if defined(Q_OS_WIN32) && POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 62, 0)
86 		GooString *fname = new GooString(pdfFile.toUtf8().data());
87 #else
88 		GooString *fname = new GooString(QFile::encodeName(pdfFile).data());
89 #endif
90 		globalParams->setErrQuiet(gTrue);
91 		PDFDoc *pdfDoc = new PDFDoc(fname, nullptr, nullptr, nullptr);
92 		if (pdfDoc)
93 		{
94 			if (pdfDoc->getErrorCode() == errEncrypted)
95 			{
96 				delete pdfDoc;
97 #if POPPLER_ENCODED_VERSION < POPPLER_VERSION_ENCODE(0, 83, 0)
98 				delete globalParams;
99 #endif
100 				return QImage();
101 			}
102 			if (pdfDoc->isOk())
103 			{
104 				double h = pdfDoc->getPageMediaHeight(1);
105 				double w = pdfDoc->getPageMediaWidth(1);
106 				double scale = qMin(500.0 / h, 500.0 / w);
107 				double hDPI = 72.0 * scale;
108 				double vDPI = 72.0 * scale;
109 				SplashColor bgColor;
110 				bgColor[0] = 255;
111 				bgColor[1] = 255;
112 				bgColor[2] = 255;
113 				SplashOutputDev *dev = new SplashOutputDev(splashModeXBGR8, 4, gFalse, bgColor, gTrue);
114 				dev->setVectorAntialias(gTrue);
115 				dev->setFreeTypeHinting(gTrue, gFalse);
116 				dev->startDoc(pdfDoc);
117 				pdfDoc->displayPage(dev, 1, hDPI, vDPI, 0, gTrue, gFalse, gFalse);
118 				SplashBitmap *bitmap = dev->getBitmap();
119 				int bw = bitmap->getWidth();
120 				int bh = bitmap->getHeight();
121 				SplashColorPtr dataPtr = bitmap->getDataPtr();
122 				if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
123 				{
124 					uchar c;
125 					int count = bw * bh * 4;
126 					for (int k = 0; k < count; k += 4)
127 					{
128 						c = dataPtr[k];
129 						dataPtr[k] = dataPtr[k+3];
130 						dataPtr[k+3] = c;
131 						c = dataPtr[k+1];
132 						dataPtr[k+1] = dataPtr[k+2];
133 						dataPtr[k+2] = c;
134 					}
135 				}
136 				// construct a qimage SHARING the raw bitmap data in memory
137 				QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
138 				QImage image = tmpimg.copy();
139 				image.setText("XSize", QString("%1").arg(w));
140 				image.setText("YSize", QString("%1").arg(h));
141 				delete dev;
142 				delete pdfDoc;
143 #if POPPLER_ENCODED_VERSION < POPPLER_VERSION_ENCODE(0, 83, 0)
144 				delete globalParams;
145 #endif
146 				return image;
147 			}
148 			delete pdfDoc;
149 #if POPPLER_ENCODED_VERSION < POPPLER_VERSION_ENCODE(0, 83, 0)
150 			delete globalParams;
151 #endif
152 		}
153 	}
154 	return QImage();
155 }
156 
import(const QString & fNameIn,const TransactionSettings & trSettings,int flags,bool showProgress)157 bool PdfPlug::import(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
158 {
159 #ifdef Q_OS_MACOS
160 	showProgress = false;
161 #endif
162 	bool success = false;
163 	m_interactive = (flags & LoadSavePlugin::lfInteractive);
164 	m_importerFlags = flags;
165 	m_cancel = false;
166 	bool ret = false;
167 	QFileInfo fi = QFileInfo(fNameIn);
168 	if ( !ScCore->usingGUI() )
169 	{
170 		m_interactive = false;
171 		showProgress = false;
172 	}
173 	m_baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath()+"/"));
174 	if ( showProgress )
175 	{
176 		ScribusMainWindow* mw = (m_Doc==nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
177 		m_progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
178 		QStringList barNames("GI");
179 		QStringList barTexts(tr("Analyzing File:"));
180 		QList<bool> barsNumeric;
181 		barsNumeric << false;
182 		m_progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
183 		m_progressDialog->setOverallTotalSteps(3);
184 		m_progressDialog->setOverallProgress(0);
185 		m_progressDialog->setProgress("GI", 0);
186 		m_progressDialog->show();
187 		connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
188 		qApp->processEvents();
189 	}
190 	else
191 		m_progressDialog = nullptr;
192 /* Set default Page to size defined in Preferences */
193 	if (m_progressDialog)
194 	{
195 		m_progressDialog->setOverallProgress(1);
196 		qApp->processEvents();
197 	}
198 	double docWidth = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
199 	double docHeight = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
200 	if (!m_interactive || (flags & LoadSavePlugin::lfInsertPage))
201 	{
202 		m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
203 		m_Doc->addPage(0);
204 		m_Doc->view()->addPage(0, true);
205 	}
206 	else
207 	{
208 		if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
209 		{
210 			m_Doc = ScCore->primaryMainWindow()->doFileNew(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, 0, 0, 0, 0, 1, "Custom", true);
211 			ScCore->primaryMainWindow()->HaveNewDoc();
212 			ret = true;
213 		}
214 	}
215 
216 	if ((ret) || (!m_interactive))
217 	{
218 		if (docWidth > docHeight)
219 			m_Doc->setPageOrientation(1);
220 		else
221 			m_Doc->setPageOrientation(0);
222 		m_Doc->setPageSize("Custom");
223 	}
224 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
225 		m_Doc->view()->deselectItems();
226 	m_elements.clear();
227 	m_Doc->setLoading(true);
228 	m_Doc->DoDrawing = false;
229 	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
230 		m_Doc->view()->updatesOn(false);
231 	m_Doc->scMW()->setScriptRunning(true);
232 	qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
233 	QString CurDirP = QDir::currentPath();
234 	QDir::setCurrent(fi.path());
235 	if (convert(fNameIn))
236 	{
237 		m_tmpSele->clear();
238 		QDir::setCurrent(CurDirP);
239 		if ((m_elements.count() == 1) && (!(m_importerFlags & LoadSavePlugin::lfCreateDoc)))
240 		{
241 			PageItem *gr = m_elements[0];
242 			if (gr->isGroup())
243 				m_Doc->resizeGroupToContents(gr);
244 		}
245 		if ((m_elements.count() > 1) && (!(m_importerFlags & LoadSavePlugin::lfCreateDoc)))
246 		{
247 			PageItem *gr = m_Doc->groupObjectsList(m_elements);
248 			m_Doc->resizeGroupToContents(gr);
249 		}
250 		m_Doc->DoDrawing = true;
251 		m_Doc->scMW()->setScriptRunning(false);
252 		m_Doc->setLoading(false);
253 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
254 		if ((m_elements.count() > 0) && (!ret) && (m_interactive))
255 		{
256 			if (flags & LoadSavePlugin::lfScripted)
257 			{
258 				bool loadF = m_Doc->isLoading();
259 				m_Doc->setLoading(false);
260 				m_Doc->changed();
261 				m_Doc->setLoading(loadF);
262 				if (!(flags & LoadSavePlugin::lfLoadAsPattern))
263 				{
264 					m_Doc->m_Selection->delaySignalsOn();
265 					for (int dre=0; dre < m_elements.count(); ++dre)
266 					{
267 						m_Doc->m_Selection->addItem(m_elements.at(dre), true);
268 					}
269 					m_Doc->m_Selection->delaySignalsOff();
270 					m_Doc->m_Selection->setGroupRect();
271 					if (m_Doc->view() != nullptr)
272 						m_Doc->view()->updatesOn(true);
273 				}
274 			}
275 			else
276 			{
277 				m_Doc->DragP = true;
278 				m_Doc->DraggedElem = nullptr;
279 				m_Doc->DragElements.clear();
280 				m_Doc->m_Selection->delaySignalsOn();
281 				for (int dre = 0; dre < m_elements.count(); ++dre)
282 				{
283 					m_tmpSele->addItem(m_elements.at(dre), true);
284 				}
285 				m_tmpSele->setGroupRect();
286 				ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, m_tmpSele);
287 				m_Doc->itemSelection_DeleteItem(m_tmpSele);
288 				m_Doc->view()->updatesOn(true);
289 				m_Doc->m_Selection->delaySignalsOff();
290 				// We must copy the TransationSettings object as it is owned
291 				// by handleObjectImport method afterwards
292 				TransactionSettings* transacSettings = new TransactionSettings(trSettings);
293 				m_Doc->view()->handleObjectImport(md, transacSettings);
294 				m_Doc->DragP = false;
295 				m_Doc->DraggedElem = nullptr;
296 				m_Doc->DragElements.clear();
297 			}
298 		}
299 		else
300 		{
301 			m_Doc->changed();
302 			m_Doc->reformPages();
303 			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
304 				m_Doc->view()->updatesOn(true);
305 		}
306 		success = true;
307 	}
308 	else
309 	{
310 		QDir::setCurrent(CurDirP);
311 		m_Doc->DoDrawing = true;
312 		m_Doc->scMW()->setScriptRunning(false);
313 		if (!(flags & LoadSavePlugin::lfLoadAsPattern))
314 			m_Doc->view()->updatesOn(true);
315 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
316 		success = false;
317 	}
318 	if (m_interactive)
319 		m_Doc->setLoading(false);
320 	//CB If we have a gui we must refresh it if we have used the progressbar
321 	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
322 	{
323 		if ((showProgress) && (!m_interactive))
324 			m_Doc->view()->DrawNew();
325 	}
326 	qApp->restoreOverrideCursor();
327 	return success;
328 }
329 
~PdfPlug()330 PdfPlug::~PdfPlug()
331 {
332 	delete m_progressDialog;
333 	delete m_tmpSele;
334 }
335 
convert(const QString & fn)336 bool PdfPlug::convert(const QString& fn)
337 {
338 	bool firstPg = true;
339 	int currentLayer = m_Doc->activeLayer();
340 	int baseLayer = m_Doc->activeLayer();
341 	m_importedColors.clear();
342 	if (m_progressDialog)
343 	{
344 		m_progressDialog->setOverallProgress(2);
345 		m_progressDialog->setLabel("GI", tr("Generating Items"));
346 		m_progressDialog->setBusyIndicator("GI");
347 		qApp->processEvents();
348 	}
349 
350 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 83, 0)
351 	globalParams.reset(new GlobalParams());
352 #else
353 	globalParams = new GlobalParams();
354 #endif
355 	GooString *userPW = nullptr;
356 	if (globalParams)
357 	{
358 #if defined(Q_OS_WIN32) && POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 62, 0)
359 		GooString *fname = new GooString(fn.toUtf8().data());
360 #else
361 		GooString *fname = new GooString(QFile::encodeName(fn).data());
362 #endif
363 		globalParams->setErrQuiet(gTrue);
364 		GBool hasOcg = gFalse;
365 		QList<OptionalContentGroup*> ocgGroups;
366 //		globalParams->setPrintCommands(gTrue);
367 		PDFDoc *pdfDoc = new PDFDoc(fname, nullptr, nullptr, nullptr);
368 		if (pdfDoc)
369 		{
370 			if (pdfDoc->getErrorCode() == errEncrypted)
371 			{
372 				delete pdfDoc;
373 				pdfDoc = nullptr;
374 				if (m_progressDialog)
375 					m_progressDialog->hide();
376 				qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
377 				ScribusMainWindow* mw = m_Doc->scMW();
378 				bool ok;
379 				QString text = QInputDialog::getText(mw, tr("Open PDF-File"), tr("Password"), QLineEdit::Normal, "", &ok);
380 				if (ok && !text.isEmpty())
381 				{
382 #if defined(Q_OS_WIN32) && POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 62, 0)
383 					fname = new GooString(fn.toUtf8().data());
384 #else
385 					fname = new GooString(QFile::encodeName(fn).data());
386 #endif
387 					userPW = new GooString(text.toLocal8Bit().data());
388 					pdfDoc = new PDFDoc(fname, userPW, userPW, nullptr);
389 					qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
390 				}
391 				if ((!pdfDoc) || (pdfDoc->getErrorCode() != errNone))
392 				{
393 					if (m_progressDialog)
394 						m_progressDialog->close();
395 					delete pdfDoc;
396 #if POPPLER_ENCODED_VERSION < POPPLER_VERSION_ENCODE(0, 83, 0)
397 					delete globalParams;
398 #endif
399 					return false;
400 				}
401 				if (m_progressDialog)
402 					m_progressDialog->show();
403 			}
404 			if (pdfDoc->isOk())
405 			{
406 				std::vector<int> pageNs;
407 				QString pageString = "*";
408 				m_pdfDoc = pdfDoc;
409 				double hDPI = 72.0;
410 				double vDPI = 72.0;
411 				int firstPage = 1;
412 				int lastPage = pdfDoc->getNumPages();
413 				GBool useMediaBox = gTrue;
414 				GBool crop = gTrue;
415 				GBool printing = gFalse;
416 				const PDFRectangle *mediaBox = pdfDoc->getPage(1)->getMediaBox();
417 				QRectF mediaRect = QRectF(QPointF(mediaBox->x1, mediaBox->y1), QPointF(mediaBox->x2, mediaBox->y2)).normalized();
418 				bool boxesAreDifferent = false;
419 				if (getCBox(Crop_Box, 1) != mediaRect)
420 					boxesAreDifferent = true;
421 				else if (getCBox(Trim_Box, 1) != mediaRect)
422 					boxesAreDifferent = true;
423 				else if (getCBox(Bleed_Box, 1) != mediaRect)
424 					boxesAreDifferent = true;
425 				else if (getCBox(Art_Box, 1) != mediaRect)
426 					boxesAreDifferent = true;
427 				bool cropped = false;
428 				bool importTextAsVectors = true;
429 				int contentRect = Media_Box;
430 				if ((m_interactive && !m_noDialogs) || (m_importerFlags & LoadSavePlugin::lfCreateDoc))
431 				{
432 					if (m_progressDialog)
433 						m_progressDialog->hide();
434 					qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
435 					PdfImportOptions *optImp = new PdfImportOptions(ScCore->primaryMainWindow());
436 					QFileInfo fi = QFileInfo(fn);
437 					optImp->setUpOptions(fi.fileName(), firstPage, lastPage, m_interactive, boxesAreDifferent, this);
438 					if (!optImp->exec())
439 					{
440 						if (m_progressDialog)
441 							m_progressDialog->close();
442 						delete optImp;
443 						delete pdfDoc;
444 #if POPPLER_ENCODED_VERSION < POPPLER_VERSION_ENCODE(0, 83, 0)
445 						delete globalParams;
446 #endif
447 						return false;
448 					}
449 					pageString = optImp->getPagesString();
450 					contentRect = optImp->getCropBox();
451 					cropped = optImp->croppingEnabled();
452 					if (!cropped)
453 						crop = cropped;
454 					importTextAsVectors = optImp->getImportAsVectors();
455 					// When displaying  pages slices, we should always set useMediaBox to true
456 					// in order to use MediaBox (x, y) as coordinate system
457 					if (contentRect != Media_Box)
458 						useMediaBox = gFalse;
459 					if (cropped)
460 						useMediaBox = gTrue;
461 					delete optImp;
462 					qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
463 					if (m_progressDialog)
464 						m_progressDialog->show();
465 				}
466 
467 				parsePagesString(pageString, &pageNs, lastPage);
468 				if (pageNs.size() <= 0)
469 					return false;
470 
471 				firstPage = pageNs[0];
472 				SlaOutputDev* dev = nullptr;
473 				if (importTextAsVectors)
474 					dev = new SlaOutputDev(m_Doc, &m_elements, &m_importedColors, m_importerFlags);
475 				else
476 					dev = new PdfTextOutputDev(m_Doc, &m_elements, &m_importedColors, m_importerFlags);
477 
478 				if (dev->isOk())
479 				{
480 					OCGs* ocg = pdfDoc->getOptContentConfig();
481 					if (ocg)
482 					{
483 						hasOcg = ocg->hasOCGs();
484 						if (hasOcg)
485 						{
486 							QStringList ocgNames;
487 							Array *order = ocg->getOrderArray();
488 							if (order)
489 							{
490 								for (int i = 0; i < order->getLength (); ++i)
491 								{
492 									Object orderItem = order->get(i);
493 									if (orderItem.isDict())
494 									{
495 										POPPLER_CONST_075 Object POPPLER_REF ref = order->getNF(i);
496 										if (ref.isRef())
497 										{
498 											OptionalContentGroup *oc = ocg->findOcgByRef(ref.getRef());
499 											QString ocgName = UnicodeParsedString(oc->getName());
500 											if (!ocgNames.contains(ocgName))
501 											{
502 												ocgGroups.prepend(oc);
503 												ocgNames.append(ocgName);
504 											}
505 										}
506 									}
507 									else
508 									{
509 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 69, 0)
510 										const auto& ocgs = ocg->getOCGs ();
511 										for (const auto& ocg : ocgs)
512 										{
513 											OptionalContentGroup *oc = ocg.second.get();
514 											QString ocgName = UnicodeParsedString(oc->getName());
515 											if (!ocgNames.contains(ocgName))
516 											{
517 												ocgGroups.prepend(oc);
518 												ocgNames.append(ocgName);
519 											}
520 										}
521 #else
522 										GooList *ocgs = ocg->getOCGs ();
523 										for (int i = 0; i < ocgs->getLength (); ++i)
524 										{
525 											OptionalContentGroup *oc = (OptionalContentGroup *)ocgs->get(i);
526 											QString ocgName = UnicodeParsedString(oc->getName());
527 											if (!ocgNames.contains(ocgName))
528 											{
529 												ocgGroups.prepend(oc);
530 												ocgNames.append(ocgName);
531 											}
532 										}
533 #endif
534 									}
535 								}
536 							}
537 							else
538 							{
539 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 69, 0)
540 								const auto& ocgs = ocg->getOCGs ();
541 								for (const auto& ocg : ocgs)
542 								{
543 									OptionalContentGroup *oc = ocg.second.get();
544 									QString ocgName = UnicodeParsedString(oc->getName());
545 									if (!ocgNames.contains(ocgName))
546 									{
547 										ocgGroups.prepend(oc);
548 										ocgNames.append(ocgName);
549 									}
550 								}
551 #else
552 								GooList *ocgs = ocg->getOCGs ();
553 								for (int i = 0; i < ocgs->getLength (); ++i)
554 								{
555 									OptionalContentGroup *oc = (OptionalContentGroup *)ocgs->get(i);
556 									QString ocgName = UnicodeParsedString(oc->getName());
557 									if (!ocgNames.contains(ocgName))
558 									{
559 										ocgGroups.prepend(oc);
560 										ocgNames.append(ocgName);
561 									}
562 								}
563 #endif
564 							}
565 						}
566 					}
567 
568 					const int zeroRotate = 0;
569 					dev->startDoc(pdfDoc, pdfDoc->getXRef(), pdfDoc->getCatalog());
570 					dev->rotate = pdfDoc->getPageRotate(firstPage);
571 					bool rotated = dev->rotate == 90 || dev->rotate == 270;
572 
573 					if (m_importerFlags & LoadSavePlugin::lfCreateDoc)
574 					{
575 						if (hasOcg)
576 						{
577 							QString actL(m_Doc->activeLayerName());
578 							for (int i = 0; i < ocgGroups.count(); i++)
579 							{
580 								OptionalContentGroup *oc = ocgGroups[i];
581 								if (actL != UnicodeParsedString(oc->getName()))
582 									currentLayer = m_Doc->addLayer(UnicodeParsedString(oc->getName()), false);
583 								else
584 									currentLayer = m_Doc->layerIDFromName(UnicodeParsedString(oc->getName()));
585 								if (oc->getState() == OptionalContentGroup::On)
586 									m_Doc->setLayerVisible(currentLayer, true);
587 								else if (oc->getViewState() == OptionalContentGroup::ocUsageOn)
588 									m_Doc->setLayerVisible(currentLayer, true);
589 								else
590 									m_Doc->setLayerVisible(currentLayer, false);
591 								if ((oc->getPrintState() == OptionalContentGroup::ocUsageOn) || (oc->getPrintState() == OptionalContentGroup::ocUsageUnset))
592 									m_Doc->setLayerPrintable(currentLayer, true);
593 								else
594 									m_Doc->setLayerPrintable(currentLayer, false);
595 								oc->setState(OptionalContentGroup::Off);
596 							}
597 							dev->layersSetByOCG = true;
598 						}
599 
600 						Object info = pdfDoc->getDocInfo();
601 						if (info.isDict())
602 						{
603 							Object obj;
604 							Dict *infoDict = info.getDict();
605 							obj = infoDict->lookup((char*) "Title");
606 							if (obj.isString())
607 							{
608 								m_Doc->documentInfo().setTitle(UnicodeParsedString(obj.getString()));
609 							}
610 							obj = infoDict->lookup((char*) "Author");
611 							if (obj.isString())
612 							{
613 								m_Doc->documentInfo().setAuthor(UnicodeParsedString(obj.getString()));
614 							}
615 							obj = infoDict->lookup((char*) "Subject");
616 							if (obj.isString())
617 							{
618 								m_Doc->documentInfo().setSubject(UnicodeParsedString(obj.getString()));
619 							}
620 							obj = infoDict->lookup((char*) "Keywords");
621 							if (obj.isString())
622 							{
623 								//		s1 = obj.getString();
624 								m_Doc->documentInfo().setKeywords(UnicodeParsedString(obj.getString()));
625 							}
626 						}
627 						info = Object();
628 
629 						if (cropped)
630 						{
631 							QRectF crBox = getCBox(contentRect, pageNs[0]);
632 							if (rotated)
633 							{
634 								m_Doc->setPageWidth(crBox.height());
635 								m_Doc->setPageHeight(crBox.width());
636 							}
637 							else
638 							{
639 								m_Doc->setPageHeight(crBox.height());
640 								m_Doc->setPageWidth(crBox.width());
641 							}
642 						}
643 						else
644 						{
645 							if (rotated)
646 							{
647 								m_Doc->setPageWidth(pdfDoc->getPageMediaHeight(pageNs[0]));
648 								m_Doc->setPageHeight(pdfDoc->getPageMediaWidth(pageNs[0]));
649 							}
650 							else
651 							{
652 								m_Doc->setPageHeight(pdfDoc->getPageMediaHeight(pageNs[0]));
653 								m_Doc->setPageWidth(pdfDoc->getPageMediaWidth(pageNs[0]));
654 							}
655 						}
656 						m_Doc->setPageSize("Custom");
657 					//	m_Doc->pdfOptions().PresentVals.clear();
658 						for (size_t i = 0; i < pageNs.size(); ++i)
659 						{
660 							int pp = pageNs[i];
661 							m_Doc->setActiveLayer(baseLayer);
662 							if (firstPg)
663 								firstPg = false;
664 							else
665 								m_Doc->addPage(i);
666 							QRectF mdBox = getCBox(0, pp);
667 							QRectF crBox = getCBox(contentRect, pp);
668 							if (cropped)
669 							{
670 								if (rotated)
671 								{
672 									m_Doc->currentPage()->setInitialWidth(crBox.height());
673 									m_Doc->currentPage()->setInitialHeight(crBox.width());
674 									m_Doc->currentPage()->setWidth(crBox.height());
675 									m_Doc->currentPage()->setHeight(crBox.width());
676 									dev->cropOffsetX = crBox.y();
677 									dev->cropOffsetY = crBox.x();
678 								}
679 								else
680 								{
681 									m_Doc->currentPage()->setInitialHeight(crBox.height());
682 									m_Doc->currentPage()->setInitialWidth(crBox.width());
683 									m_Doc->currentPage()->setHeight(crBox.height());
684 									m_Doc->currentPage()->setWidth(crBox.width());
685 									dev->cropOffsetX = crBox.x();
686 									dev->cropOffsetY = crBox.y();
687 								}
688 							}
689 							else
690 							{
691 								if (rotated)
692 								{
693 									m_Doc->currentPage()->setInitialWidth(pdfDoc->getPageMediaHeight(pp));
694 									m_Doc->currentPage()->setInitialHeight(pdfDoc->getPageMediaWidth(pp));
695 									m_Doc->currentPage()->setWidth(pdfDoc->getPageMediaHeight(pp));
696 									m_Doc->currentPage()->setHeight(pdfDoc->getPageMediaWidth(pp));
697 								}
698 								else
699 								{
700 									m_Doc->currentPage()->setInitialHeight(pdfDoc->getPageMediaHeight(pp));
701 									m_Doc->currentPage()->setInitialWidth(pdfDoc->getPageMediaWidth(pp));
702 									m_Doc->currentPage()->setHeight(pdfDoc->getPageMediaHeight(pp));
703 									m_Doc->currentPage()->setWidth(pdfDoc->getPageMediaWidth(pp));
704 								}
705 							}
706 							m_Doc->currentPage()->setMasterPageNameNormal();
707 							m_Doc->currentPage()->setSize("Custom");
708 							m_Doc->reformPages(true);
709 							if (hasOcg)
710 							{
711 								for (int j = 0; j < ocgGroups.count(); j++)
712 								{
713 									OptionalContentGroup *oc = ocgGroups[j];
714 									oc->setState(OptionalContentGroup::On);
715 									if (cropped)
716 										pdfDoc->displayPageSlice(dev, pp, hDPI, vDPI, zeroRotate, useMediaBox, crop, printing, crBox.x() - mdBox.x(), mdBox.bottom() - crBox.bottom(), crBox.width(), crBox.height(), nullptr, nullptr, dev->annotations_callback, dev);
717 									else
718 										pdfDoc->displayPage(dev, pp, hDPI, vDPI, zeroRotate, useMediaBox, crop, printing, nullptr, nullptr, dev->annotations_callback, dev);
719 									oc->setState(OptionalContentGroup::Off);
720 								}
721 							}
722 							else
723 							{
724 								if (cropped)
725 									pdfDoc->displayPageSlice(dev, pp, hDPI, vDPI, zeroRotate, useMediaBox, crop, printing, crBox.x() - mdBox.x(), mdBox.bottom() - crBox.bottom(), crBox.width(), crBox.height(), nullptr, nullptr, dev->annotations_callback, dev);
726 								else
727 									pdfDoc->displayPage(dev, pp, hDPI, vDPI, zeroRotate, useMediaBox, crop, printing, nullptr, nullptr, dev->annotations_callback, dev);
728 							}
729 
730 							PDFPresentationData ef;
731 							Object trans = pdfDoc->getPage(pp)->getTrans();
732 							Object *transi = &trans;
733 							if (transi->isDict())
734 							{
735 								m_Doc->pdfOptions().PresentMode = true;
736 								PageTransition *pgTrans = new PageTransition(transi);
737 								ef.pageViewDuration = pdfDoc->getPage(pp)->getDuration();
738 								ef.pageEffectDuration = pgTrans->getDuration();
739 								ef.Dm = pgTrans->getAlignment() == transitionHorizontal ? 0 : 1;
740 								ef.M = pgTrans->getDirection() == transitionInward ? 0 : 1;
741 								int ang = pgTrans->getAngle();
742 								if (ang == 0)
743 									ef.Di = 0;
744 								else if (ang == 270)
745 									ef.Di = 1;
746 								else if (ang == 90)
747 									ef.Di = 2;
748 								else if (ang == 180)
749 									ef.Di = 3;
750 								else if (ang == 315)
751 									ef.Di = 4;
752 								PageTransitionType trType = pgTrans->getType();
753 								if (trType == transitionReplace)
754 									ef.effectType = 0;
755 								else if (trType == transitionBlinds)
756 									ef.effectType = 1;
757 								else if (trType == transitionBox)
758 									ef.effectType = 2;
759 								else if (trType == transitionDissolve)
760 									ef.effectType = 3;
761 								else if (trType == transitionGlitter)
762 									ef.effectType = 4;
763 								else if (trType == transitionSplit)
764 									ef.effectType = 5;
765 								else if (trType == transitionWipe)
766 									ef.effectType = 6;
767 								else if (trType == transitionPush)
768 									ef.effectType = 7;
769 								else if (trType == transitionCover)
770 									ef.effectType = 8;
771 								else if (trType == transitionUncover)
772 									ef.effectType = 9;
773 								else if (trType == transitionFade)
774 									ef.effectType = 10;
775 								delete pgTrans;
776 							}
777 							m_Doc->currentPage()->PresentVals = ef;
778 						}
779 						int numjs = pdfDoc->getCatalog()->numJS();
780 						if (numjs > 0)
781 						{
782 							NameTree *jsNameTreeP = new NameTree();
783 							Object catDict = pdfDoc->getXRef()->getCatalog();
784 							if (catDict.isDict())
785 							{
786 								Object names = catDict.dictLookup("Names");
787 								if (names.isDict())
788 								{
789 									Object obj = names.dictLookup("JavaScript");
790 									jsNameTreeP->init(pdfDoc->getXRef(), &obj);
791 								}
792 								for (int a = 0; a < numjs; a++)
793 								{
794 									m_Doc->JavaScripts.insert(UnicodeParsedString(jsNameTreeP->getName(a)), UnicodeParsedString(pdfDoc->getCatalog()->getJS(a)));
795 								}
796 								names = catDict.dictLookup("OpenAction");
797 								if (names.isDict())
798 								{
799 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
800 									std::unique_ptr<LinkAction> linkActionUPtr = LinkAction::parseAction(&names, pdfDoc->getCatalog()->getBaseURI());
801 									LinkAction *linkAction = linkActionUPtr.get();
802 #else
803 									LinkAction *linkAction = nullptr;
804 									linkAction = LinkAction::parseAction(&names, pdfDoc->getCatalog()->getBaseURI());
805 #endif
806 									if (linkAction && (linkAction->getKind() == actionJavaScript))
807 									{
808 										LinkJavaScript *jsa = (LinkJavaScript*) linkAction;
809 										if (jsa->isOk())
810 										{
811 											QString script = UnicodeParsedString(jsa->getScript());
812 											if (script.startsWith("this."))
813 											{
814 												script.remove(0, 5);
815 												script.remove("()");
816 												if (m_Doc->JavaScripts.contains(script))
817 													m_Doc->pdfOptions().openAction = script;
818 											}
819 										}
820 									}
821 								}
822 							}
823 							delete jsNameTreeP;
824 						}
825 						m_Doc->pdfOptions().Version = (PDFVersion::Version) qMin(16, qMax(13, pdfDoc->getPDFMajorVersion() * 10 + pdfDoc->getPDFMinorVersion()));
826 						ViewerPreferences *viewPrefs = pdfDoc->getCatalog()->getViewerPreferences();
827 						if (viewPrefs)
828 						{
829 							m_Doc->pdfOptions().Binding = viewPrefs->getDirection() == ViewerPreferences::directionL2R ? 0 : 1;
830 							m_Doc->pdfOptions().hideMenuBar = viewPrefs->getHideMenubar();
831 							m_Doc->pdfOptions().hideToolBar = viewPrefs->getHideToolbar();
832 							m_Doc->pdfOptions().fitWindow = viewPrefs->getFitWindow();
833 						}
834 						Catalog::PageMode pgm = pdfDoc->getCatalog()->getPageMode();
835 						m_Doc->pdfOptions().displayFullscreen = (pgm == Catalog::pageModeFullScreen);
836 						m_Doc->pdfOptions().displayThumbs = (pgm == Catalog::pageModeThumbs);
837 						m_Doc->pdfOptions().displayBookmarks = (pgm == Catalog::pageModeOutlines);
838 						m_Doc->pdfOptions().displayLayers = (pgm == Catalog::pageModeOC);
839 						Catalog::PageLayout pgl = pdfDoc->getCatalog()->getPageLayout();
840 						if (pgl == Catalog::pageLayoutSinglePage)
841 							m_Doc->pdfOptions().PageLayout = PDFOptions::SinglePage;
842 						else if (pgl == Catalog::pageLayoutOneColumn)
843 							m_Doc->pdfOptions().PageLayout = PDFOptions::OneColumn;
844 						else if ((pgl == Catalog::pageLayoutTwoColumnLeft) || (pgl == Catalog::pageLayoutTwoPageLeft))
845 						{
846 							m_Doc->setPagePositioning(1);
847 							m_Doc->setPageSetFirstPage(1, 0);
848 							m_Doc->pdfOptions().PageLayout = PDFOptions::TwoColumnLeft;
849 						}
850 						else if ((pgl == Catalog::pageLayoutTwoColumnRight) || (pgl == Catalog::pageLayoutTwoPageRight))
851 						{
852 							m_Doc->setPagePositioning(1);
853 							m_Doc->setPageSetFirstPage(1, 1);
854 							m_Doc->pdfOptions().PageLayout = PDFOptions::TwoColumnRight;
855 						}
856 					}
857 					else
858 					{
859 						if (hasOcg)
860 						{
861 							for (int a = 0; a < ocgGroups.count(); a++)
862 							{
863 								ocgGroups[a]->setState(OptionalContentGroup::On);
864 							}
865 						}
866 						pdfDoc->displayPage(dev, firstPage, hDPI, vDPI, zeroRotate, useMediaBox, crop, printing, nullptr, nullptr, dev->annotations_callback, dev);
867 					}
868 				}
869 				delete dev;
870 			}
871 		}
872 		delete pdfDoc;
873 	}
874 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 83, 0)
875 	globalParams.release();
876 #else
877 	delete globalParams;
878 	globalParams = nullptr;
879 #endif
880 
881 //	qDebug() << "converting finished";
882 //	qDebug() << "Imported" << m_elements.count() << "Elements";
883 
884 	if (m_elements.count() == 0)
885 	{
886 		for (int i = 0; i < m_importedColors.count(); i++)
887 		{
888 			m_Doc->PageColors.remove(m_importedColors[i]);
889 		}
890 	}
891 
892 	if (m_progressDialog)
893 		m_progressDialog->close();
894 	return true;
895 }
896 
readPreview(int pgNum,int width,int height,int box)897 QImage PdfPlug::readPreview(int pgNum, int width, int height, int box)
898 {
899 	if (!m_pdfDoc)
900 		return QImage();
901 
902 	double h = m_pdfDoc->getPageMediaHeight(pgNum);
903 	double w = m_pdfDoc->getPageMediaWidth(pgNum);
904 	double scale = qMin(height / h, width / w);
905 	double hDPI = 72.0 * scale;
906 	double vDPI = 72.0 * scale;
907 	SplashColor bgColor;
908 	bgColor[0] = 255;
909 	bgColor[1] = 255;
910 	bgColor[2] = 255;
911 	SplashOutputDev *dev = new SplashOutputDev(splashModeXBGR8, 4, gFalse, bgColor, gTrue);
912 	dev->setVectorAntialias(gTrue);
913 	dev->setFreeTypeHinting(gTrue, gFalse);
914 	dev->startDoc(m_pdfDoc);
915 	m_pdfDoc->displayPage(dev, pgNum, hDPI, vDPI, 0, gTrue, gFalse, gFalse);
916 	SplashBitmap *bitmap = dev->getBitmap();
917 	int bw = bitmap->getWidth();
918 	int bh = bitmap->getHeight();
919 	SplashColorPtr dataPtr = bitmap->getDataPtr();
920 	if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
921 	{
922 		uchar c;
923 		int count = bw * bh * 4;
924 		for (int k = 0; k < count; k += 4)
925 		{
926 			c = dataPtr[k];
927 			dataPtr[k] = dataPtr[k+3];
928 			dataPtr[k+3] = c;
929 			c = dataPtr[k+1];
930 			dataPtr[k+1] = dataPtr[k+2];
931 			dataPtr[k+2] = c;
932 		}
933 	}
934 	// construct a qimage SHARING the raw bitmap data in memory
935 	QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
936 	QImage image = tmpimg.copy();
937 	image.setText("XSize", QString("%1").arg(w));
938 	image.setText("YSize", QString("%1").arg(h));
939 	if (box > Media_Box)
940 	{
941 		QRectF cRect = getCBox(box, pgNum);
942 		QRectF mediaRect = getCBox(0, pgNum);
943 		cRect.moveTo(cRect.x() - mediaRect.x(), cRect.y() - mediaRect.y());
944 		QPainter pp;
945 		pp.begin(&image);
946 		pp.setBrush(Qt::NoBrush);
947 		pp.setPen(QPen(Qt::red, 3.0));
948 		pp.translate(0, bh);
949 		pp.scale(scale, -scale);
950 		pp.drawRect(cRect);
951 		pp.end();
952 	}
953 	delete dev;
954 	return image;
955 }
956 
getCBox(int box,int pgNum)957 QRectF PdfPlug::getCBox(int box, int pgNum)
958 {
959 	const PDFRectangle *cBox = nullptr;
960 	if (box == Media_Box)
961 		cBox = m_pdfDoc->getPage(pgNum)->getMediaBox();
962 	else if (box == Bleed_Box)
963 		cBox = m_pdfDoc->getPage(pgNum)->getBleedBox();
964 	else if (box == Trim_Box)
965 		cBox = m_pdfDoc->getPage(pgNum)->getTrimBox();
966 	else if (box == Crop_Box)
967 		cBox = m_pdfDoc->getPage(pgNum)->getCropBox();
968 	else if (box == Art_Box)
969 		cBox = m_pdfDoc->getPage(pgNum)->getArtBox();
970 	QRectF cRect = QRectF(QPointF(cBox->x1, cBox->y1), QPointF(cBox->x2, cBox->y2)).normalized();
971 	return cRect;
972 }
973 
UnicodeParsedString(POPPLER_CONST GooString * s1)974 QString PdfPlug::UnicodeParsedString(POPPLER_CONST GooString *s1)
975 {
976 	if ( !s1 || s1->getLength() == 0 )
977 		return QString();
978 	GBool isUnicode;
979 	int i;
980 	Unicode u;
981 	QString result;
982 	if ((s1->getChar(0) & 0xff) == 0xfe && (s1->getLength() > 1 && (s1->getChar(1) & 0xff) == 0xff))
983 	{
984 		isUnicode = gTrue;
985 		i = 2;
986 		result.reserve((s1->getLength() - 2) / 2);
987 	}
988 	else
989 	{
990 		isUnicode = gFalse;
991 		i = 0;
992 		result.reserve(s1->getLength());
993 	}
994 	while (i < s1->getLength())
995 	{
996 		if (isUnicode)
997 		{
998 			u = ((s1->getChar(i) & 0xff) << 8) | (s1->getChar(i+1) & 0xff);
999 			i += 2;
1000 		}
1001 		else
1002 		{
1003 			u = s1->getChar(i) & 0xff;
1004 			++i;
1005 		}
1006 		// #15616: imagemagick may write unicode strings incorrectly in PDF
1007 		if (u == 0)
1008 			continue;
1009 		result += QChar( u );
1010 	}
1011 	return result;
1012 }
1013 
UnicodeParsedString(const std::string & s1)1014 QString PdfPlug::UnicodeParsedString(const std::string& s1)
1015 {
1016 	if (s1.length() == 0)
1017 		return QString();
1018 	GBool isUnicode;
1019 	size_t i;
1020 	Unicode u;
1021 	QString result;
1022 	if ((s1.at(0) & 0xff) == 0xfe && (s1.length() > 1 && (s1.at(1) & 0xff) == 0xff))
1023 	{
1024 		isUnicode = gTrue;
1025 		i = 2;
1026 		result.reserve((s1.length() - 2) / 2);
1027 	}
1028 	else
1029 	{
1030 		isUnicode = gFalse;
1031 		i = 0;
1032 		result.reserve(s1.length());
1033 	}
1034 	while (i < s1.length())
1035 	{
1036 		if (isUnicode)
1037 		{
1038 			u = ((s1.at(i) & 0xff) << 8) | (s1.at(i+1) & 0xff);
1039 			i += 2;
1040 		}
1041 		else
1042 		{
1043 			u = s1.at(i) & 0xff;
1044 			++i;
1045 		}
1046 		// #15616: imagemagick may write unicode strings incorrectly in PDF
1047 		if (u == 0)
1048 			continue;
1049 		result += QChar( u );
1050 	}
1051 	return result;
1052 }
1053