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 #include "objpdffile.h"
8 #include "colormgmt/sccolormgmtengine.h"
9 #include "cmdutil.h"
10 #include "prefsmanager.h"
11 #include "scribusdoc.h"
12 #include "scribuscore.h"
13 #include "scribusview.h"
14 #include <structmember.h>
15 #include "ui/bookmarkpalette.h"
16 
17 #include <QFileInfo>
18 #include <QImage>
19 #include <QList>
20 #include <vector>
21 
22 // these functions are located at utils.cpp
23 void SCRIBUS_API ReOrderText(ScribusDoc *doc, ScribusView *view);
24 // end of utils.cpp
25 //this is in file scribus.cpp
26 
27 
minmaxi(int val,int min,int max)28 static int minmaxi(int val, int min, int max)
29 {
30 	if (val < min)
31 		return min;
32 	if (val > max)
33 		return max;
34 	return val;
35 }
36 
minmaxd(double val,double min,double max)37 static double minmaxd(double val, double min, double max)
38 {
39 	if (val < min)
40 		return min;
41 	if (val > max)
42 		return max;
43 	return val;
44 }
45 
46 typedef struct
47 {
48 	PyObject_HEAD
49 	PyObject *file; // string - file to save into
50 	PyObject *fontEmbedding; // int - 0: Embed fonts, 1:Outline fonts, 2:Dont embed any font
51 	PyObject *fonts; // list of string - fonts to  embed
52 	PyObject *subsetList; // list of string - fonts to outline
53 	PyObject *pages; // list of int - pages to print
54 	int thumbnails; // bool -
55 	int cropMarks; // bool -
56 	int bleedMarks; // bool -
57 	int registrationMarks; // bool -
58 	int colorMarks; // bool -
59 	int docInfoMarks; // bool -
60 	double markOffset; // double -
61 	double markLength; // double -
62 	int compress; // bool -
63 	int compressmtd; // int - 0=automatic 1=jpeg 2=zip 3=none
64 	int quality; // int - 0=Maximum 4=minimum
65 	PyObject *resolution; // int - 35 - 4000 default=300 dpi
66 	PyObject *downsample; // int - 35 - 4000 default=0 do not downsample ; other downsample to this resolution
67 	int bookmarks; // bool -
68 	int binding; // bool - 0 -left margin 1 -right margin
69 	int presentation; // bool -
70 	PyObject *effval; // list of list of 5 int - effect to apply to each page during presentation
71 	int article; // bool -
72 	int encrypt; // bool -
73 	int uselpi; // bool -
74 	int usespot;
75 	int domulti;
76 	PyObject *lpival; // list of elements which has structure [siii]
77 	PyObject *owner; // string - owner's password
78 	PyObject *user; // string - user's password
79 	int allowPrinting; // bool -  allow printing
80 	int allowChange; // bool - allow changing
81 	int allowCopy; // bool - allow copying
82 	int allowAnnots; // bool - allow adding annotation and fields
83 	int version; // int - version of pdf (12=1.2; 13=1.3; 14=1.4; 15=1.5)
84 	int outdst; // int - output destination 0 - screen, 1 - printer
85 
86 	int profiles; // bool
87 	int profilei; // bool
88 	int intents; // int - 0 - 3 QString tmp_ip[] = { tr("Perceptual"), tr("Relative Colorimetric"), tr("Saturation"), tr("Absolute Colorimetric")};
89 	int intenti; // int - 0 - 3 QString tmp_ip[] = { tr("Perceptual"), tr("Relative Colorimetric"), tr("Saturation"), tr("Absolute Colorimetric")};
90 	int noembicc; // bool - "Don't use embedded ICC profiles"
91 	PyObject *solidpr; // string
92 	PyObject *imagepr; // string
93 	PyObject *printprofc; // string
94 	PyObject *info; // string
95 	double bleedt; // double - 0 to height of page
96 	double bleedl; // double - 0 to width of page
97 	double bleedr; // double - 0 to width of page
98 	double bleedb; // double - 0 to height of page
99 	int useDocBleeds; // bool
100 	int useLayers;
101 	int embedPDF;
102 	int mirrorH;
103 	int mirrorV;
104 	int doClip;
105 	PyObject * rotateDeg; // int
106 	int isGrayscale;
107 	int pageLayout;
108 	int displayBookmarks;
109 	int displayThumbs;
110 	int displayLayers;
111 	int displayFullscreen;
112 	int hideToolBar;
113 	int hideMenuBar;
114 	int fitWindow;
115 	PyObject *openAction;
116 
117 } PDFfile;
118 
PDFfile_dealloc(PDFfile * self)119 static void PDFfile_dealloc(PDFfile *self)
120 {
121 	Py_XDECREF(self->file);
122 	Py_XDECREF(self->fontEmbedding);
123 	Py_XDECREF(self->fonts);
124 	Py_XDECREF(self->subsetList);
125 	Py_XDECREF(self->pages);
126 	Py_XDECREF(self->resolution);
127 	Py_XDECREF(self->downsample);
128 	Py_XDECREF(self->effval);
129 	Py_XDECREF(self->lpival);
130 	Py_XDECREF(self->owner);
131 	Py_XDECREF(self->user);
132 	Py_XDECREF(self->solidpr);
133 	Py_XDECREF(self->imagepr);
134 	Py_XDECREF(self->printprofc);
135 	Py_XDECREF(self->info);
136 	Py_XDECREF(self->rotateDeg);
137 	Py_XDECREF(self->openAction);
138 	Py_TYPE(self)->tp_free((PyObject *)self);
139 }
140 
PDFfile_new(PyTypeObject * type,PyObject *,PyObject *)141 static PyObject * PDFfile_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
142 {
143 	// Do not create new object if there is no opened document
144 	if (!checkHaveDocument())
145 		return nullptr;
146 
147 	PDFfile *self;
148 
149 	self = (PDFfile *)type->tp_alloc(type, 0);
150 	if (self)
151 	{
152 		// Set file attribute
153 		self->file = PyUnicode_FromString("");
154 		if (!self->file)
155 		{
156 			Py_DECREF(self);
157 			return nullptr;
158 		}
159 		// Set font embedding mode attribute
160 		self->fontEmbedding = PyLong_FromLong(0);
161 		if (!self->fontEmbedding)
162 		{
163 			Py_DECREF(self);
164 			return nullptr;
165 		}
166 		// Set fonts attribute
167 		self->fonts = PyList_New(0);
168 		if (!self->fonts)
169 		{
170 			Py_DECREF(self);
171 			return nullptr;
172 		}
173 		self->subsetList = PyList_New(0);
174 		if (!self->subsetList)
175 		{
176 			Py_DECREF(self);
177 			return nullptr;
178 		}
179 		// Set pages attribute
180 		self->pages = PyList_New(0);
181 		if (self->pages == nullptr)
182 		{
183 			Py_DECREF(self);
184 			return nullptr;
185 		}
186 		// Set thumbnails attribute
187 		self->thumbnails = 0;
188 		// Set cropMarks attribute
189 		self->cropMarks = 0;
190 		// Set bleedMarks attribute
191 		self->bleedMarks = 0;
192 		// Set registrationMarks attribute
193 		self->registrationMarks = 0;
194 		// Set colorMarks attribute
195 		self->colorMarks = 0;
196 		// Set docInfoMarks attribute
197 		self->docInfoMarks = 0;
198 		// Set mark offset attribute
199 		self->markOffset = 0;
200 		// Set mark length attribute
201 		self->markLength = 0;
202 		// Set compress attribute
203 		self->compress = 0;
204 		// Set compressmtd attribute
205 		self->compressmtd = 0;
206 		// Set quality attribute
207 		self->quality = 0;
208 		// Set resolution attribute
209 		self->resolution = PyLong_FromLong(300);
210 		if (!self->resolution)
211 		{
212 			Py_DECREF(self);
213 			return nullptr;
214 		}
215 		// Set downsample attribute
216 		self->downsample = PyLong_FromLong(0);
217 		if (!self->downsample)
218 		{
219 			Py_DECREF(self);
220 			return nullptr;
221 		}
222 		// Set bookmarks attribute
223 		self->bookmarks = 0;
224 		// Set binding attribute
225 		self->binding = 0;
226 		// Set presentation attribute
227 		self->presentation = 0;
228 		// Set effval attribute
229 		self->effval = PyList_New(0);
230 		if (!self->effval)
231 		{
232 			Py_DECREF(self);
233 			return nullptr;
234 		}
235 		// Set article attribute
236 		self->article = 0;
237 		// Set encrypt attribute
238 		self->encrypt = 0;
239 		// Set uselpi attribute
240 		self->uselpi = 0;
241 		self->usespot = 1;
242 		self->domulti = 0;
243 		// Set lpival attribute
244 		self->lpival = PyList_New(0);
245 		if (!self->lpival)
246 		{
247 			Py_DECREF(self);
248 			return nullptr;
249 		}
250 		// Set owner attribute
251 		self->owner = PyUnicode_FromString("");
252 		if (!self->owner)
253 		{
254 			Py_DECREF(self);
255 			return nullptr;
256 		}
257 		// Set user attribute
258 		self->user = PyUnicode_FromString("");
259 		if (!self->user)
260 		{
261 			Py_DECREF(self);
262 			return nullptr;
263 		}
264 		// Set allowPrinting attribute
265 		self->allowPrinting = 1;
266 		// Set allowChange attribute
267 		self->allowChange = 1;
268 		// Set allowCopy attribute
269 		self->allowCopy = 1;
270 		// Set allowAnnots attribute
271 		self->allowAnnots = 1;
272 		// Set version attribute
273 		self->version = 14;
274 		// Set output attribute
275 		self->outdst = 0;
276 
277 		self->profiles = 0; // bool
278 		self->profilei = 0; // bool
279 		self->intents = 0; // int - 0 - ?
280 		self->intenti = 0; // int - 0 - ?
281 		self->noembicc = 0; // bool
282 		self->solidpr = PyUnicode_FromString("");
283 		if (!self->solidpr)
284 		{
285 			Py_DECREF(self);
286 			return nullptr;
287 		}
288 		self->imagepr = PyUnicode_FromString("");
289 		if (!self->imagepr)
290 		{
291 			Py_DECREF(self);
292 			return nullptr;
293 		}
294 		self->printprofc = PyUnicode_FromString("");
295 		if (!self->printprofc)
296 		{
297 			Py_DECREF(self);
298 			return nullptr;
299 		}
300 		self->info = PyUnicode_FromString("");
301 		if (!self->info)
302 		{
303 			Py_DECREF(self);
304 			return nullptr;
305 		}
306 		self->bleedt = 0; // double -
307 		self->bleedl = 0; // double -
308 		self->bleedr = 0; // double -
309 		self->bleedb = 0; // double -
310 		self->useDocBleeds = 1; // bool
311 		self->useLayers = 0;
312 		self->embedPDF = 0;
313 		self->mirrorH = 0;
314 		self->mirrorV = 0;
315 		self->doClip = 0;
316 		self->rotateDeg = PyLong_FromLong(0);
317 		if (!self->rotateDeg)
318 		{
319 			Py_DECREF(self);
320 			return nullptr;
321 		}
322 		self->isGrayscale = 0;
323 		self->pageLayout = 0;
324 		self->displayBookmarks = 0;
325 		self->displayThumbs = 0;
326 		self->displayLayers = 0;
327 		self->displayFullscreen = 0;
328 		self->hideToolBar = 0;
329 		self->hideMenuBar = 0;
330 		self->fitWindow = 0;
331 		self->openAction = PyUnicode_FromString("");
332 		if (!self->openAction)
333 		{
334 			Py_DECREF(self);
335 			return nullptr;
336 		}
337 	}
338 	return (PyObject *) self;
339 }
340 
PDFfile_init(PDFfile * self,PyObject *,PyObject *)341 static int PDFfile_init(PDFfile *self, PyObject * /*args*/, PyObject * /*kwds*/)
342 {
343 	int i;
344 	if (!checkHaveDocument())
345 		return -1;
346 
347 	ScribusDoc* currentDoc = ScCore->primaryMainWindow()->doc;
348 	PDFOptions& pdfOptions = currentDoc->pdfOptions();
349 
350 	// Defaut save into file
351 	QString tf = pdfOptions.fileName;
352 	if (tf.isEmpty())
353 	{
354 		QFileInfo fi = QFileInfo(currentDoc->documentFileName());
355 		tf = fi.path() + "/" + fi.baseName() + ".pdf";
356 	}
357 
358 	PyObject *file = PyUnicode_FromString(tf.toUtf8());
359 	if (file)
360 	{
361 		Py_DECREF(self->file);
362 		self->file = file;
363 	}
364 	else
365 	{
366 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'file' attribute");
367 		return -1;
368 	}
369 
370 	// Font embedding mode
371 	PyObject *embeddingMode = PyLong_FromLong(pdfOptions.FontEmbedding);
372 	if (embeddingMode)
373 	{
374 		Py_DECREF(self->fontEmbedding);
375 		self->fontEmbedding = embeddingMode;
376 	}
377 	else
378 	{
379 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'fontEmbedding' attribute");
380 		return -1;
381 	}
382 
383 	// Embed all used fonts
384 	PyObject *fonts = PyList_New(0);
385 	if (fonts)
386 	{
387 		Py_DECREF(self->fonts);
388 		self->fonts = fonts;
389 	}
390 	else
391 	{
392 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'fonts' attribute");
393 		return -1;
394 	}
395 
396 	// Get all used fonts
397 	QMap<QString,int> ReallyUsed = currentDoc->UsedFonts;
398 	// Create list of all used fonts
399 	QList<QString> tmpEm = ReallyUsed.keys();
400 	for (int i = 0; i < tmpEm.count(); ++i)
401 	{
402 		const QString& fontName = tmpEm.at(i);
403 		PyObject *tmp = PyUnicode_FromString(fontName.toUtf8());
404 		if (tmp)
405 		{
406 			PyList_Append(self->fonts, tmp);
407 			// Do i need Py_DECREF(tmp) here?
408 			// Does PyList_Append increase reference or 'steal' one from provided argument
409 			// If it 'steal' reference comment next line
410 			Py_DECREF(tmp);
411 		}
412 		else
413 		{
414 			PyErr_SetString(PyExc_SystemError, "Can not initialize 'fonts' attribute");
415 			return -1;
416 		}
417 	}
418 
419 	// Init subsetList
420 	fonts = PyList_New(0);
421 	if (fonts)
422 	{
423 		Py_DECREF(self->subsetList);
424 		self->subsetList = fonts;
425 	}
426 	else
427 	{
428 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'subsetList' attribute");
429 		return -1;
430 	}
431 
432 	// Copied from TabPDFOptions::restoreDefaults()
433 	for (int fe = 0; fe < pdfOptions.SubsetList.count(); ++fe)
434 	{
435 		PyObject *tmp= nullptr;
436 		tmp = PyUnicode_FromString(pdfOptions.SubsetList[fe].toUtf8().data());
437 		if (tmp)
438 		{
439 			PyList_Append(self->subsetList, tmp);
440 			Py_DECREF(tmp);
441 		}
442 		else
443 		{
444 			PyErr_SetString(PyExc_SystemError, "Can not initialize 'subsetList' attribute");
445 			return -1;
446 		}
447 	}
448 
449 	// Set to print all pages
450 	int num = currentDoc->Pages->count();
451 	PyObject *pages = PyList_New(num);
452 	if (!pages)
453 	{
454 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'pages' attribute");
455 		return -1;
456 	}
457 	for (i = 0; i < num; ++i)
458 	{
459 		PyObject *tmp = PyLong_FromLong((long) i + 1L);
460 		if (tmp)
461 			PyList_SetItem(pages, i, tmp);
462 		else
463 		{
464 			PyErr_SetString(PyExc_SystemError, "Can not initialize 'pages' attribute");
465 			return -1;
466 		}
467 	}
468 	Py_DECREF(self->pages);
469 	self->pages = pages;
470 	// Print thumbnails ?
471 	self->thumbnails = pdfOptions.Thumbnails;
472 	// Output crop marks ?
473 	self->cropMarks = pdfOptions.cropMarks;
474 	// Output bleed marks ?
475 	self->bleedMarks = pdfOptions.bleedMarks;
476 	// Output registration marks ?
477 	self->registrationMarks = pdfOptions.registrationMarks;
478 	// Output color bars ?
479 	self->colorMarks = pdfOptions.colorMarks;
480 	// Output doc info marks ?
481 	self->docInfoMarks = pdfOptions.docInfoMarks;
482 	// Cropmarks offset
483 	self->markOffset = pdfOptions.markOffset * currentDoc->unitRatio();
484 	// Cropmarks length
485 	self->markLength = pdfOptions.markLength * currentDoc->unitRatio();
486 	// Set automatic compression
487 	self->compress = pdfOptions.Compress;
488 	self->compressmtd = pdfOptions.CompressMethod;
489 	// Use maximum image quality
490 	self->quality = pdfOptions.Quality;
491 	// Default resolution
492 	PyObject *resolution = nullptr;
493 	resolution = PyLong_FromLong(300);
494 	if (resolution)
495 	{
496 		Py_DECREF(self->resolution);
497 		self->resolution = resolution;
498 	}
499 	else
500 	{
501 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'resolution' attribute");
502 		return -1;
503 	}
504 	// Do not downsample images
505 	int down = pdfOptions.RecalcPic ? pdfOptions.PicRes : 0;
506 	PyObject *downsample = nullptr;
507 	downsample = PyLong_FromLong(down);
508 	if (downsample)
509 	{
510 		Py_DECREF(self->downsample);
511 		self->downsample = downsample;
512 	}
513 	else
514 	{
515 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'downsamle' attribute");
516 		return -1;
517 	}
518 	// No bookmarks
519 	self->bookmarks = pdfOptions.Bookmarks;
520 	// Left margin binding
521 	self->binding = pdfOptions.Binding;
522 	// Do not enable presentation effects
523 	self->presentation = pdfOptions.PresentMode;
524 	// Set effects values for all pages
525 	PyObject *effval = nullptr;
526 	num = currentDoc->Pages->count();
527 	effval = PyList_New(num);
528 	if (!effval)
529 	{
530 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute");
531 		return -1;
532 	}
533 	for (i = 0; i < num; ++i)
534 	{
535 		PyObject *tmp;
536 		PDFPresentationData t = currentDoc->Pages->at(i)->PresentVals;
537 		tmp = Py_BuildValue(const_cast<char*>("[iiiiii]"), t.pageEffectDuration, t.pageViewDuration, t.effectType, t.Dm, t.M, t.Di );
538 		if (tmp)
539 			PyList_SetItem(effval, i, tmp);
540 		else
541 		{
542 			PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute");
543 			return -1;
544 		}
545 		for (; i < num; ++i)
546 		{
547 			PyObject *tmp = Py_BuildValue(const_cast<char*>("[iiiiii]"), 1, 1, 0, 0, 0, 0);
548 			if (tmp)
549 				PyList_SetItem(effval, i, tmp);
550 			else
551 			{
552 				PyErr_SetString(PyExc_SystemError, "Can not initialize 'effval' attribute");
553 				return -1;
554 			}
555 		}
556 	}
557 	Py_DECREF(self->effval);
558 	self->effval = effval;
559 	// Do not save linked text frames as PDF article
560 	self->article = pdfOptions.Articles;
561 	// Do not encrypt file
562 	self->encrypt = pdfOptions.Encrypt;
563 	// Do not Use Custom Rendering Settings
564 	self->uselpi = pdfOptions.UseLPI;
565 	self->usespot = pdfOptions.UseSpotColors;
566 	self->domulti = pdfOptions.doMultiFile;
567 	// Get default values for lpival
568 	int n = pdfOptions.LPISettings.size();
569 	PyObject *lpival=PyList_New(n);
570 	if (!lpival)
571 	{
572 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'lpival' attribute");
573 		return -1;
574 	}
575 	QMap<QString,LPIData>::Iterator it = pdfOptions.LPISettings.begin();
576 	while (it != pdfOptions.LPISettings.end())
577 	{
578 		PyObject *tmp;
579 		tmp = Py_BuildValue(const_cast<char*>("[siii]"), it.key().toLatin1().constData(), it.value().Frequency, it.value().Angle, it.value().SpotFunc);
580 		if (!tmp)
581 		{
582 			PyErr_SetString(PyExc_SystemError, "Can not initialize 'lpival' attribute");
583 			return -1;
584 		}
585 		PyList_SetItem(lpival, --n, tmp);
586 		++it;
587 	}
588 	PyList_Reverse(lpival);
589 	Py_DECREF(self->lpival);
590 	self->lpival = lpival;
591 	// Set owner's password
592 	PyObject *owner = PyUnicode_FromString(pdfOptions.PassOwner.toUtf8());
593 	if (owner)
594 	{
595 		Py_DECREF(self->owner);
596 		self->owner = owner;
597 	}
598 	else
599 	{
600 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'owner' attribute");
601 		return -1;
602 	}
603 	// Set user'a password
604 	PyObject *user = PyUnicode_FromString(pdfOptions.PassUser.toUtf8());
605 	if (user)
606 	{
607 		Py_DECREF(self->user);
608 		self->user = user;
609 	}
610 	else
611 	{
612 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'user' attribute");
613 		return -1;
614 	}
615 	// Allow printing document
616 	self->allowPrinting = pdfOptions.Permissions & 4;
617 	// Allow changing document
618 	self->allowChange = pdfOptions.Permissions & 8;
619 	// Allow copying document
620 	self->allowCopy = pdfOptions.Permissions & 16;
621 	// Allow adding annotation and fields
622 	self->allowAnnots = pdfOptions.Permissions & 32;
623 	// Use 1.4 pdf version *aka. Acrobat 5)
624 	self->version = pdfOptions.Version;
625 	// Output destination is screen
626 	self->outdst = pdfOptions.UseRGB ? 0 : 1;
627 
628 	self->profiles = pdfOptions.UseProfiles; // bool
629 	self->profilei = pdfOptions.UseProfiles2; // bool
630 	self->noembicc = pdfOptions.EmbeddedI; // bool
631 	self->intents = pdfOptions.Intent; // int - 0 - 3
632 	self->intenti = pdfOptions.Intent2; // int - 0 - 3
633 	QString tp = pdfOptions.SolidProf;
634 	if (!ScCore->InputProfiles.contains(tp))
635 		tp = currentDoc->cmsSettings().DefaultSolidColorRGBProfile;
636 	PyObject *solidpr = PyUnicode_FromString(tp.toUtf8());
637 	if (solidpr)
638 	{
639 		Py_DECREF(self->solidpr);
640 		self->solidpr = solidpr;
641 	}
642 	else
643 	{
644 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'solidpr' attribute");
645 		return -1;
646 	}
647 	QString tp2 = pdfOptions.ImageProf;
648 	if (!ScCore->InputProfiles.contains(tp2))
649 		tp2 = currentDoc->cmsSettings().DefaultSolidColorRGBProfile;
650 	PyObject *imagepr = PyUnicode_FromString(tp2.toUtf8());
651 	if (imagepr)
652 	{
653 		Py_DECREF(self->imagepr);
654 		self->imagepr = imagepr;
655 	}
656 	else
657 	{
658 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'imagepr' attribute");
659 		return -1;
660 	}
661 	QString tp3 = pdfOptions.PrintProf;
662 	if (!ScCore->PDFXProfiles.contains(tp3))
663 		tp3 = currentDoc->cmsSettings().DefaultPrinterProfile;
664 	PyObject *printprofc = nullptr;
665 	printprofc = PyUnicode_FromString(tp3.toUtf8());
666 	if (printprofc)
667 	{
668 		Py_DECREF(self->printprofc);
669 		self->printprofc = printprofc;
670 	}
671 	else
672 	{
673 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'printprofc' attribute");
674 		return -1;
675 	}
676 	QString tinfo = pdfOptions.Info;
677 	PyObject *info = PyUnicode_FromString(tinfo.toUtf8());
678 	if (info)
679 	{
680 		Py_DECREF(self->info);
681 		self->info = info;
682 	}
683 	else
684 	{
685 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'info' attribute");
686 		return -1;
687 	}
688 	self->bleedt = pdfOptions.bleeds.top() * currentDoc->unitRatio(); // double -
689 	self->bleedl = pdfOptions.bleeds.left() * currentDoc->unitRatio(); // double -
690 	self->bleedr = pdfOptions.bleeds.right() * currentDoc->unitRatio(); // double -
691 	self->bleedb = pdfOptions.bleeds.bottom() * currentDoc->unitRatio(); // double -
692 	self->useDocBleeds = pdfOptions.useDocBleeds; // bool
693 	self->useLayers = pdfOptions.useLayers; // bool
694 	self->embedPDF = pdfOptions.embedPDF; // bool
695 	self->mirrorH = pdfOptions.MirrorH; // bool
696 	self->mirrorV = pdfOptions.MirrorV; // bool
697 	self->doClip = pdfOptions.doClip; // bool
698 	PyObject *rotateDeg = PyLong_FromLong(0);
699 	if (rotateDeg)
700 	{
701 		Py_DECREF(self->rotateDeg);
702 		self->rotateDeg = rotateDeg;
703 	}
704 	else
705 	{
706 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'rotateDeg' attribute");
707 		return -1;
708 	}
709 	self->isGrayscale = pdfOptions.isGrayscale; // bool
710 	self->pageLayout = pdfOptions.PageLayout; // int
711 	self->displayBookmarks = pdfOptions.displayBookmarks; // bool
712 	self->displayThumbs = pdfOptions.displayThumbs; // bool
713 	self->displayLayers = pdfOptions.displayLayers; // bool
714 	self->displayFullscreen = pdfOptions.displayFullscreen; // bool
715 	self->hideToolBar = pdfOptions.hideToolBar; // bool
716 	self->hideMenuBar = pdfOptions.hideMenuBar; // bool
717 	self->fitWindow = pdfOptions.fitWindow; // bool
718 
719 	PyObject *openAction = PyUnicode_FromString(pdfOptions.openAction.toUtf8().data());
720 	if (openAction)
721 	{
722 		Py_DECREF(self->openAction);
723 		self->openAction = openAction;
724 	}
725 	else
726 	{
727 		PyErr_SetString(PyExc_SystemError, "Can not initialize 'openAction' attribute");
728 		return -1;
729 	}
730 
731 	return 0;
732 }
733 
734 static PyMemberDef PDFfile_members[] = {
735 	{const_cast<char*>("thumbnails"), T_INT, offsetof(PDFfile, thumbnails), 0, const_cast<char*>("Generate thumbnails. Bool value.")},
736 	{const_cast<char*>("cropMarks"), T_INT, offsetof(PDFfile, cropMarks), 0, const_cast<char*>("Create crop marks in the PDF indicating where the paper should be cut or trimmed after printing.")},
737 	{const_cast<char*>("bleedMarks"), T_INT, offsetof(PDFfile, bleedMarks), 0, const_cast<char*>("Create marks delimiting the bleed area.")},
738 	{const_cast<char*>("registrationMarks"), T_INT, offsetof(PDFfile, registrationMarks), 0, const_cast<char*>("Add registration marks to each separation.")},
739 	{const_cast<char*>("colorMarks"), T_INT, offsetof(PDFfile, colorMarks), 0, const_cast<char*>("Add color calibration bars.")},
740 	{const_cast<char*>("docInfoMarks"), T_INT, offsetof(PDFfile, docInfoMarks), 0, const_cast<char*>("Add document information which includes the document title and page numbers.")},
741 	{const_cast<char*>("markOffset"), T_DOUBLE, offsetof(PDFfile, markOffset), 0, const_cast<char*>("Indicate the distance offset between mark and page area.")},
742 	{const_cast<char*>("markLength"), T_DOUBLE, offsetof(PDFfile, markLength), 0, const_cast<char*>("Indicate the length of crop and bleed marks.")},
743 	{const_cast<char*>("compress"), T_INT, offsetof(PDFfile, compress), 0, const_cast<char*>("Compression switch. Bool value.")},
744 	{const_cast<char*>("compressmtd"), T_INT, offsetof(PDFfile, compressmtd), 0, const_cast<char*>("Compression method.\n\t0 - Automatic\n\t1 - JPEG\n\t2 - zip\n\t3 - None.")},
745 	{const_cast<char*>("quality"), T_INT, offsetof(PDFfile, quality), 0, const_cast<char*>("Image quality\n\t0 - Maximum\n\t1 - High\n\t2 - Medium\n\t3 - Low\n\t4 - Minimum")},
746 	{const_cast<char*>("bookmarks"), T_INT, offsetof(PDFfile, bookmarks), 0, const_cast<char*>("Embed the bookmarks you created in your document.\nThese are useful for navigating long PDF documents.\nBool value")},
747 	{const_cast<char*>("binding"), T_INT, offsetof(PDFfile, binding), 0, const_cast<char*>("Choose binding.\n\t0 - Left binding\n\t1 - Right binding")},
748 	{const_cast<char*>("presentation"), T_INT, offsetof(PDFfile, presentation), 0, const_cast<char*>("Enable Presentation Effects.Bool value")},
749 	{const_cast<char*>("article"), T_INT, offsetof(PDFfile, article), 0, const_cast<char*>("Save Linked Text Frames as PDF Articles\n\tBool value")},
750 	{const_cast<char*>("encrypt"), T_INT, offsetof(PDFfile, encrypt), 0, const_cast<char*>("Use Encription. Bool value")},
751 	{const_cast<char*>("uselpi"), T_INT, offsetof(PDFfile, uselpi), 0, const_cast<char*>("Use Custom Rendering Settings. Bool value")},
752 	{const_cast<char*>("usespot"), T_INT, offsetof(PDFfile, usespot), 0, const_cast<char*>("Use Spot Colors. Bool value")},
753 	{const_cast<char*>("domulti"), T_INT, offsetof(PDFfile, domulti), 0, const_cast<char*>("Produce a PDF File for every Page. Bool value")},
754 	{const_cast<char*>("allowPrinting"), T_INT, offsetof(PDFfile, allowPrinting), 0, const_cast<char*>("Allow Printing the Document. Bool value")},
755 	{const_cast<char*>("allowChange"), T_INT, offsetof(PDFfile, allowChange), 0, const_cast<char*>("Allow Changing the Document. Bool value")},
756 	{const_cast<char*>("allowCopy"), T_INT, offsetof(PDFfile, allowCopy), 0, const_cast<char*>("Allow Copying Text and Graphics. Bool value")},
757 	{const_cast<char*>("allowAnnots"), T_INT, offsetof(PDFfile, allowAnnots), 0, const_cast<char*>("Allow Adding Annotations and Fields. Bool value")},
758 	{const_cast<char*>("version"), T_INT, offsetof(PDFfile, version), 0, const_cast<char*>("Choose PDF version to use:\n\t10 = PDF/X4\n\t11 = PDF/X1a\n\t12 = PDF/X-3\n\t13 = PDF 1.3 (Acrobat 4)\n\t14 = PDF 1.4 (Acrobat 5)\n\t15 = PDF 1.5 (Acrobat 6)")},
759 	{const_cast<char*>("outdst"), T_INT, offsetof(PDFfile, outdst), 0, const_cast<char*>("Output destination.\n\t0 - screen\n\t1 - printer")},
760 	{const_cast<char*>("profiles"), T_INT, offsetof(PDFfile, profiles), 0, const_cast<char*>("Embed a color profile for solid colors. Bool value.")},
761 	{const_cast<char*>("profilei"), T_INT, offsetof(PDFfile, profilei), 0, const_cast<char*>("Embed a color profile for images. Bool value.")},
762 	{const_cast<char*>("intents"), T_INT, offsetof(PDFfile, intents), 0, const_cast<char*>("Rendering intent for solid colors\n\t0 - Perceptual\n\t1 - Relative Colorimetric\n\t2 - Saturation\n\t3 - Absolute Colorimetric")},
763 	{const_cast<char*>("intenti"), T_INT, offsetof(PDFfile, intenti), 0, const_cast<char*>("Rendering intent for images\n\t0 - Perceptual\n\t1 - Relative Colorimetric\n\t2 - Saturation\n\t3 - Absolute Colorimetric")},
764 	{const_cast<char*>("noembicc"), T_INT, offsetof(PDFfile, noembicc), 0, const_cast<char*>("Don't use embedded ICC profiles. Bool value")},
765 	{const_cast<char*>("bleedt"), T_DOUBLE, offsetof(PDFfile, bleedt), 0, const_cast<char*>("Bleed Top\n""Distance for bleed from the top of the physical page")},
766 	{const_cast<char*>("bleedl"), T_DOUBLE, offsetof(PDFfile, bleedl), 0, const_cast<char*>("Bleed Left\n""Distance for bleed from the left of the physical page")},
767 	{const_cast<char*>("bleedr"), T_DOUBLE, offsetof(PDFfile, bleedr), 0, const_cast<char*>("Bleed Right\n""Distance for bleed from the right of the physical page")},
768 	{const_cast<char*>("bleedb"), T_DOUBLE, offsetof(PDFfile, bleedb), 0, const_cast<char*>("Bleed Bottom\n""Distance for bleed from the bottom of the physical page")},
769 	{const_cast<char*>("useDocBleeds"), T_INT, offsetof(PDFfile, useDocBleeds), 0, const_cast<char*>("Use the existing bleed settings from the document preferences. Bool value")},
770 	{const_cast<char*>("useLayers"), T_INT, offsetof(PDFfile, useLayers), 0, const_cast<char*>("Layers in your document are exported to the PDF. Only available if PDF 1.5 is chosen.")},
771 	{const_cast<char*>("embedPDF"), T_INT, offsetof(PDFfile, embedPDF), 0, const_cast<char*>("Export EPS and PDFs in image frames as embedded PDFs. This does *not* yet take care of colorspaces, so you should know what you are doing before setting this to 'true'.")},
772 	{const_cast<char*>("mirrorH"), T_INT, offsetof(PDFfile, mirrorH), 0, const_cast<char*>("Mirror Page(s) horizontally")},
773 	{const_cast<char*>("mirrorV"), T_INT, offsetof(PDFfile, mirrorV), 0, const_cast<char*>("Mirror Page(s) vertically")},
774 	{const_cast<char*>("doClip"), T_INT, offsetof(PDFfile, doClip), 0, const_cast<char*>("Do not show objects outside the margins in the exported file")},
775 	{const_cast<char*>("isGrayscale"), T_INT, offsetof(PDFfile, isGrayscale), 0, const_cast<char*>("Export PDF in grayscale")},
776 	{const_cast<char*>("pageLayout"), T_INT, offsetof(PDFfile, pageLayout), 0, const_cast<char*>("Document layout in PDF viewer:\n"
777 												     "\t0 - Show the document in single page mode\n"
778 												     "\t1 - Show the document in single page mode with the pages displayed continuously end to end like a scroll\n"
779 												     "\t2 - Show the document with facing pages, starting with the first page displayed on the left\n"
780 												     "\t3 - Show the document with facing pages, starting with the first page displayed on the right"
781 												     )},
782 	{const_cast<char*>("displayBookmarks"), T_INT, offsetof(PDFfile, displayBookmarks), 0, const_cast<char*>("Display the bookmarks upon opening")},
783 	{const_cast<char*>("displayThumbs"), T_INT, offsetof(PDFfile, displayThumbs), 0, const_cast<char*>("Display the page thumbnails upon opening")},
784 	{const_cast<char*>("displayLayers"), T_INT, offsetof(PDFfile, displayLayers), 0, const_cast<char*>("Display the layer list upon opening. Useful only for PDF 1.5+.")},
785 	{const_cast<char*>("displayFullscreen"), T_INT, offsetof(PDFfile, displayFullscreen), 0, const_cast<char*>("Display the document in full screen mode upon opening.")},
786 	{const_cast<char*>("hideToolBar"), T_INT, offsetof(PDFfile, hideToolBar), 0, const_cast<char*>("Hide the viewer toolbar. The toolbar has usually selection and other editing capabilities.")},
787 	{const_cast<char*>("hideMenuBar"), T_INT, offsetof(PDFfile, hideMenuBar), 0, const_cast<char*>("Hide the viewer menu bar, the PDF will display in a plain window.")},
788 	{const_cast<char*>("fitWindow"), T_INT, offsetof(PDFfile, fitWindow), 0, const_cast<char*>("Fit the document page or pages to the available space in the viewer window.")},
789 	/** Deprecated members */
790 	{const_cast<char*>("aprint"), T_INT, offsetof(PDFfile, allowPrinting), 0, const_cast<char*>("Deprecated. Use 'allowPrinting' instead.")},
791 	{const_cast<char*>("achange"), T_INT, offsetof(PDFfile, allowChange), 0, const_cast<char*>("Deprecated. Use 'allowChange' instead.")},
792 	{const_cast<char*>("acopy"), T_INT, offsetof(PDFfile, allowCopy), 0, const_cast<char*>("Deprecated. Use 'allowCopy' instead.")},
793 	{const_cast<char*>("aanot"), T_INT, offsetof(PDFfile, allowAnnots), 0, const_cast<char*>("Deprecated. Use 'allowAnnots' instead.")},
794 	{nullptr, 0, 0, 0, nullptr} // sentinel
795 };
796 
797 
798 /* Here begins Getter & Setter functions */
799 
PDFfile_getfile(PDFfile * self,void *)800 static PyObject *PDFfile_getfile(PDFfile *self, void * /*closure*/)
801 {
802 	Py_INCREF(self->file);
803 	return self->file;
804 }
805 
PDFfile_setfile(PDFfile * self,PyObject * value,void *)806 static int PDFfile_setfile(PDFfile *self, PyObject *value, void * /*closure*/)
807 {
808 	if (value == nullptr)
809 	{
810 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'file' attribute.");
811 		return -1;
812 	}
813 	if (!PyUnicode_Check(value))
814 	{
815 		PyErr_SetString(PyExc_TypeError, "The 'file' attribute value must be string.");
816 		return -1;
817 	}
818 	Py_DECREF(self->file);
819 	Py_INCREF(value);
820 	self->file = value;
821 	return 0;
822 }
823 
PDFfile_getFontEmbeddingMode(PDFfile * self,void *)824 static PyObject *PDFfile_getFontEmbeddingMode(PDFfile *self, void * /*closure*/)
825 {
826 	Py_INCREF(self->fontEmbedding);
827 	return self->fontEmbedding;
828 }
829 
PDFfile_setFontEmbeddingMode(PDFfile * self,PyObject * value,void *)830 static int PDFfile_setFontEmbeddingMode(PDFfile *self, PyObject *value, void * /*closure*/)
831 {
832 	if (value == nullptr)
833 	{
834 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'fontEmbedding' attribute.");
835 		return -1;
836 	}
837 	if (!PyLong_Check(value))
838 	{
839 		PyErr_SetString(PyExc_TypeError, "'fontEmbedding' attribute value must be integer.");
840 		return -1;
841 	}
842 	int n = PyLong_AsLong(value);
843 	if (n < 0 || n > 2)
844 	{
845 		PyErr_SetString(PyExc_ValueError, "'fontEmbedding' value must be an integer between 0 and 2");
846 		return -1;
847 	}
848 	Py_DECREF(self->fontEmbedding);
849 	Py_INCREF(value);
850 	self->fontEmbedding = value;
851 	return 0;
852 }
853 
PDFfile_getfonts(PDFfile * self,void *)854 static PyObject *PDFfile_getfonts(PDFfile *self, void * /*closure*/)
855 {
856 	Py_INCREF(self->fonts);
857 	return self->fonts;
858 }
859 
PDFfile_setfonts(PDFfile * self,PyObject * value,void *)860 static int PDFfile_setfonts(PDFfile *self, PyObject *value, void * /*closure*/)
861 {
862 	if (value == nullptr)
863 	{
864 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'fonts' attribute.");
865 		return -1;
866 	}
867 	if (!PyList_Check(value))
868 	{
869 		PyErr_SetString(PyExc_TypeError, "The 'fonts' attribute value must be list of strings.");
870 		return -1;
871 	}
872 	int n = PyList_Size(value);
873 	for (int i = 0; i < n; ++i)
874 	{
875 		if (!PyUnicode_Check(PyList_GetItem(value, i)))
876 		{
877 			PyErr_SetString(PyExc_TypeError, "The 'fonts' list must contain only strings.");
878 			return -1;
879 		}
880 	}
881 	// Do I need to check if supplied string is really
882 	// name of available font???
883 	// this is not implemented yet
884 	Py_DECREF(self->fonts);
885 	Py_INCREF(value);
886 	self->fonts = value;
887 	PyList_Sort(self->fonts);
888 	return 0;
889 }
890 
PDFfile_getSubsetList(PDFfile * self,void *)891 static PyObject *PDFfile_getSubsetList(PDFfile *self, void * /*closure*/)
892 {
893 	Py_INCREF(self->subsetList);
894 	return self->subsetList;
895 }
896 
PDFfile_setSubsetList(PDFfile * self,PyObject * value,void *)897 static int PDFfile_setSubsetList(PDFfile *self, PyObject *value, void * /*closure*/)
898 {
899 	if (value == nullptr)
900 	{
901 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'subsetList' attribute.");
902 		return -1;
903 	}
904 	if (!PyList_Check(value))
905 	{
906 		PyErr_SetString(PyExc_TypeError, "The 'subsetList' attribute value must be list of strings.");
907 		return -1;
908 	}
909 	int n = PyList_Size(value);
910 	for (int i = 0; i < n; ++i)
911 	{
912 		if (!PyUnicode_Check(PyList_GetItem(value, i)))
913 		{
914 			PyErr_SetString(PyExc_TypeError, "The 'subsetList' list must contain only strings.");
915 			return -1;
916 		}
917 	}
918 	Py_DECREF(self->subsetList);
919 	Py_INCREF(value);
920 	self->subsetList = value;
921 	PyList_Sort(self->subsetList);
922 	return 0;
923 }
924 
PDFfile_getpages(PDFfile * self,void *)925 static PyObject *PDFfile_getpages(PDFfile *self, void * /*closure*/)
926 {
927 	Py_INCREF(self->pages);
928 	return self->pages;
929 }
930 
PDFfile_setpages(PDFfile * self,PyObject * value,void *)931 static int PDFfile_setpages(PDFfile *self, PyObject *value, void * /*closure*/)
932 {
933 	if (value == nullptr)
934 	{
935 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'pages' attribute.");
936 		return -1;
937 	}
938 	if (!PyList_Check(value))
939 	{
940 		PyErr_SetString(PyExc_TypeError, "'pages' attribute value must be list of integers.");
941 		return -1;
942 	}
943 	int len = PyList_Size(value);
944 	for (int i = 0; i < len; i++)
945 	{
946 		PyObject *tmp = PyList_GetItem(value, i);
947 		// I did not check if tmp is nullptr
948 		// how can PyList_GetItem fail in this case (my guess: short of available memory?)
949 		// Also do I need Py_INCREF or Py_DECREF here?
950 		if (!PyLong_Check(tmp))
951 		{
952 			PyErr_SetString(PyExc_TypeError, "'pages' list must contain only integers.");
953 			return -1;
954 		}
955 		if (PyLong_AsLong(tmp) > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count()) || PyLong_AsLong(tmp) < 1)
956 		{
957 			PyErr_SetString(PyExc_ValueError, "'pages' value out of range.");
958 			return -1;
959 		}
960 	}
961 	Py_DECREF(self->pages);
962 	Py_INCREF(value);
963 	self->pages = value;
964 	return 0;
965 }
966 
967 
PDFfile_getresolution(PDFfile * self,void *)968 static PyObject *PDFfile_getresolution(PDFfile *self, void * /*closure*/)
969 {
970 	Py_INCREF(self->resolution);
971 	return self->resolution;
972 }
973 
PDFfile_setresolution(PDFfile * self,PyObject * value,void *)974 static int PDFfile_setresolution(PDFfile *self, PyObject *value, void * /*closure*/)
975 {
976 	if (value == nullptr)
977 	{
978 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'resolution' attribute.");
979 		return -1;
980 	}
981 	if (!PyLong_Check(value))
982 	{
983 		PyErr_SetString(PyExc_TypeError, "'resolution' attribute value must be integer.");
984 		return -1;
985 	}
986 	int n = PyLong_AsLong(value);
987 	if (n < 35 || n > 4000)
988 	{
989 		PyErr_SetString(PyExc_ValueError, "'resolution' value must be in interval from 35 to 4000");
990 		return -1;
991 	}
992 	Py_DECREF(self->resolution);
993 	Py_INCREF(value);
994 	self->resolution = value;
995 	return 0;
996 }
997 
PDFfile_getdownsample(PDFfile * self,void *)998 static PyObject *PDFfile_getdownsample(PDFfile *self, void * /*closure*/)
999 {
1000 	Py_INCREF(self->downsample);
1001 	return self->downsample;
1002 }
1003 
PDFfile_setdownsample(PDFfile * self,PyObject * value,void *)1004 static int PDFfile_setdownsample(PDFfile *self, PyObject *value, void * /*closure*/)
1005 {
1006 	if (value == nullptr)
1007 	{
1008 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'downsample' attribute.");
1009 		return -1;
1010 	}
1011 	if (!PyLong_Check(value))
1012 	{
1013 		PyErr_SetString(PyExc_TypeError, "'downsample' attribute value must be integer.");
1014 		return -1;
1015 	}
1016 	int n = PyLong_AsLong(value);
1017 	if (n != 0 && (n < 35 || n > PyLong_AsLong(self->resolution)))
1018 	{
1019 		PyErr_SetString(PyExc_TypeError, "'downsample' value must be 0 or in interval from 35 to value of 'resolution'");
1020 		return -1;
1021 	}
1022 	Py_DECREF(self->downsample);
1023 	Py_INCREF(value);
1024 	self->downsample = value;
1025 	return 0;
1026 }
1027 
PDFfile_geteffval(PDFfile * self,void *)1028 static PyObject *PDFfile_geteffval(PDFfile *self, void * /*closure*/)
1029 {
1030 	Py_INCREF(self->effval);
1031 	return self->effval;
1032 }
1033 
PDFfile_seteffval(PDFfile * self,PyObject * value,void *)1034 static int PDFfile_seteffval(PDFfile *self, PyObject *value, void * /*closure*/)
1035 {
1036 	if (value == nullptr)
1037 	{
1038 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'effval' attribute.");
1039 		return -1;
1040 	}
1041 	if (!PyList_Check(value))
1042 	{
1043 		PyErr_SetString(PyExc_TypeError, "'effval' must be list.");
1044 		return -1;
1045 	}
1046 	int n = PyList_Size(value);
1047 	for (int i = 0; i < n; ++i)
1048 	{
1049 		PyObject *tmp = PyList_GetItem(value, i);
1050 		if (!PyList_Check(tmp))
1051 		{
1052 			PyErr_SetString(PyExc_TypeError, "elemets of 'effval' must be list of five integers.");
1053 			return -1;
1054 		}
1055 		int j = PyList_Size(tmp);
1056 		if (j != 6)
1057 		{
1058 			PyErr_SetString(PyExc_TypeError, "elemets of 'effval' must have exactly six integers.");
1059 			return -1;
1060 		}
1061 		for (--j; j > -1; --j)
1062 		{
1063 			if (!PyLong_Check(PyList_GetItem(tmp, j)))
1064 			{
1065 				PyErr_SetString(PyExc_TypeError, "innermost element of 'effval' must be integers.");
1066 				return -1;
1067 			}
1068 		}
1069 	}
1070 	Py_DECREF(self->effval);
1071 	Py_INCREF(value);
1072 	self->effval = value;
1073 	return 0;
1074 }
1075 
PDFfile_getlpival(PDFfile * self,void *)1076 static PyObject *PDFfile_getlpival(PDFfile *self, void * /*closure*/)
1077 {
1078 	Py_INCREF(self->lpival);
1079 	return self->lpival;
1080 }
1081 
PDFfile_setlpival(PDFfile * self,PyObject * value,void *)1082 static int PDFfile_setlpival(PDFfile *self, PyObject *value, void * /*closure*/)
1083 {
1084 	if (value == nullptr)
1085 	{
1086 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'lpival' attribute.");
1087 		return -1;
1088 	}
1089 	if (!PyList_Check(value))
1090 	{
1091 		PyErr_SetString(PyExc_TypeError, "'lpival' must be list.");
1092 		return -1;
1093 	}
1094 	// Do I need Py_INCREF or Py_DECREF here?
1095 	int n = PyList_Size(value);
1096 	for (int i = 0; i < n; ++i)
1097 	{
1098 		PyObject *tmp = PyList_GetItem(value, i);
1099 		if (!PyList_Check(tmp))
1100 		{
1101 			PyErr_SetString(PyExc_TypeError, "elements of 'lpival' must be list of five integers.");
1102 			return -1;
1103 		}
1104 		int j = PyList_Size(tmp);
1105 		if (j != 4)
1106 		{
1107 			PyErr_SetString(PyExc_TypeError, "elements of 'lpival' must have exactly four members.");
1108 			return -1;
1109 		}
1110 		for (--j; j > 0; --j)
1111 		{
1112 			if (!PyLong_Check(PyList_GetItem(tmp, j)))
1113 			{
1114 				PyErr_SetString(PyExc_TypeError, "'lpival'elements must have structure [siii]");
1115 				return -1;
1116 			}
1117 		}
1118 		if (!PyUnicode_Check(PyList_GetItem(tmp, 0)))
1119 		{
1120 			PyErr_SetString(PyExc_TypeError, "'lpival'elements must have structure [siii]");
1121 			return -1;
1122 		}
1123 	}
1124 	Py_DECREF(self->lpival);
1125 	Py_INCREF(value);
1126 	self->lpival = value;
1127 	return 0;
1128 }
1129 
PDFfile_getowner(PDFfile * self,void *)1130 static PyObject *PDFfile_getowner(PDFfile *self, void * /*closure*/)
1131 {
1132 	Py_INCREF(self->owner);
1133 	return self->owner;
1134 }
1135 
PDFfile_setowner(PDFfile * self,PyObject * value,void *)1136 static int PDFfile_setowner(PDFfile *self, PyObject *value, void * /*closure*/)
1137 {
1138 	if (value == nullptr)
1139 	{
1140 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'owner' attribute.");
1141 		return -1;
1142 	}
1143 	if (!PyUnicode_Check(value))
1144 	{
1145 		PyErr_SetString(PyExc_TypeError, "'owner' attribute value must be string.");
1146 		return -1;
1147 	}
1148 	Py_DECREF(self->owner);
1149 	Py_INCREF(value);
1150 	self->owner = value;
1151 	return 0;
1152 }
1153 
PDFfile_getuser(PDFfile * self,void *)1154 static PyObject *PDFfile_getuser(PDFfile *self, void * /*closure*/)
1155 {
1156 	Py_INCREF(self->user);
1157 	return self->user;
1158 }
1159 
PDFfile_setuser(PDFfile * self,PyObject * value,void *)1160 static int PDFfile_setuser(PDFfile *self, PyObject *value, void * /*closure*/)
1161 {
1162 	if (value == nullptr)
1163 	{
1164 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'user' attribute.");
1165 		return -1;
1166 	}
1167 	if (!PyUnicode_Check(value))
1168 	{
1169 		PyErr_SetString(PyExc_TypeError, "'user' attribute value must be string.");
1170 		return -1;
1171 	}
1172 	Py_DECREF(self->user);
1173 	Py_INCREF(value);
1174 	self->user = value;
1175 	return 0;
1176 }
1177 
PDFfile_getsolidpr(PDFfile * self,void *)1178 static PyObject *PDFfile_getsolidpr(PDFfile *self, void * /*closure*/)
1179 {
1180 	Py_INCREF(self->solidpr);
1181 	return self->solidpr;
1182 }
1183 
PDFfile_setsolidpr(PDFfile * self,PyObject * value,void *)1184 static int PDFfile_setsolidpr(PDFfile *self, PyObject *value, void * /*closure*/)
1185 {
1186 	if (value == nullptr)
1187 	{
1188 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'solidpr' attribute.");
1189 		return -1;
1190 	}
1191 	if (!PyUnicode_Check(value))
1192 	{
1193 		PyErr_SetString(PyExc_TypeError, "The 'solidpr' attribute value must be string.");
1194 		return -1;
1195 	}
1196 	Py_DECREF(self->solidpr);
1197 	Py_INCREF(value);
1198 	self->solidpr = value;
1199 	return 0;
1200 }
1201 
PDFfile_getimagepr(PDFfile * self,void *)1202 static PyObject *PDFfile_getimagepr(PDFfile *self, void * /*closure*/)
1203 {
1204 	Py_INCREF(self->imagepr);
1205 	return self->imagepr;
1206 }
1207 
PDFfile_setimagepr(PDFfile * self,PyObject * value,void *)1208 static int PDFfile_setimagepr(PDFfile *self, PyObject *value, void * /*closure*/)
1209 {
1210 	if (value == nullptr)
1211 	{
1212 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'imagepr' attribute.");
1213 		return -1;
1214 	}
1215 	if (!PyUnicode_Check(value))
1216 	{
1217 		PyErr_SetString(PyExc_TypeError, "The 'imagepr' attribute value must be string.");
1218 		return -1;
1219 	}
1220 	Py_DECREF(self->imagepr);
1221 	Py_INCREF(value);
1222 	self->imagepr = value;
1223 	return 0;
1224 }
1225 
PDFfile_getprintprofc(PDFfile * self,void *)1226 static PyObject *PDFfile_getprintprofc(PDFfile *self, void * /*closure*/)
1227 {
1228 	Py_INCREF(self->printprofc);
1229 	return self->printprofc;
1230 }
1231 
PDFfile_setprintprofc(PDFfile * self,PyObject * value,void *)1232 static int PDFfile_setprintprofc(PDFfile *self, PyObject *value, void * /*closure*/)
1233 {
1234 	if (value == nullptr)
1235 	{
1236 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'printprofc' attribute.");
1237 		return -1;
1238 	}
1239 	if (!PyUnicode_Check(value))
1240 	{
1241 		PyErr_SetString(PyExc_TypeError, "The 'printprofc' attribute value must be string.");
1242 		return -1;
1243 	}
1244 	Py_DECREF(self->printprofc);
1245 	Py_INCREF(value);
1246 	self->printprofc = value;
1247 	return 0;
1248 }
1249 
PDFfile_getinfo(PDFfile * self,void *)1250 static PyObject *PDFfile_getinfo(PDFfile *self, void * /*closure*/)
1251 {
1252 	Py_INCREF(self->info);
1253 	return self->info;
1254 }
1255 
PDFfile_setinfo(PDFfile * self,PyObject * value,void *)1256 static int PDFfile_setinfo(PDFfile *self, PyObject *value, void * /*closure*/)
1257 {
1258 	if (value == nullptr)
1259 	{
1260 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'info' attribute.");
1261 		return -1;
1262 	}
1263 	if (!PyUnicode_Check(value))
1264 	{
1265 		PyErr_SetString(PyExc_TypeError, "The 'info' attribute value must be string.");
1266 		return -1;
1267 	}
1268 	Py_DECREF(self->info);
1269 	Py_INCREF(value);
1270 	self->info = value;
1271 	return 0;
1272 }
1273 
PDFfile_getRotateDeg(PDFfile * self,void *)1274 static PyObject *PDFfile_getRotateDeg(PDFfile *self, void * /*closure*/)
1275 {
1276 	Py_INCREF(self->rotateDeg);
1277 	return self->rotateDeg;
1278 }
1279 
PDFfile_setRotateDeg(PDFfile * self,PyObject * value,void *)1280 static int PDFfile_setRotateDeg(PDFfile *self, PyObject *value, void * /*closure*/)
1281 {
1282 	if (value == nullptr)
1283 	{
1284 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'rotateDeg' attribute.");
1285 		return -1;
1286 	}
1287 	if (!PyLong_Check(value))
1288 	{
1289 		PyErr_SetString(PyExc_TypeError, "'rotateDeg' attribute value must be integer.");
1290 		return -1;
1291 	}
1292 	int n = PyLong_AsLong(value);
1293 	if (n != 0 && n != 90 && n != 180 && n != 270)
1294 	{
1295 		PyErr_SetString(PyExc_TypeError, "'rotateDeg' value must be 0 or 90 or 180 or 270");
1296 		return -1;
1297 	}
1298 	Py_DECREF(self->rotateDeg);
1299 	Py_INCREF(value);
1300 	self->rotateDeg = value;
1301 	return 0;
1302 }
1303 
PDFfile_getopenAction(PDFfile * self,void *)1304 static PyObject *PDFfile_getopenAction(PDFfile *self, void * /*closure*/)
1305 {
1306 	Py_INCREF(self->openAction);
1307 	return self->openAction;
1308 }
1309 
PDFfile_setopenAction(PDFfile * self,PyObject * value,void *)1310 static int PDFfile_setopenAction(PDFfile *self, PyObject *value, void * /*closure*/)
1311 {
1312 	if (value == nullptr)
1313 	{
1314 		PyErr_SetString(PyExc_TypeError, "Cannot delete 'openAction' attribute.");
1315 		return -1;
1316 	}
1317 	if (!PyUnicode_Check(value))
1318 	{
1319 		PyErr_SetString(PyExc_TypeError, "'openAction' attribute value must be string.");
1320 		return -1;
1321 	}
1322 	Py_DECREF(self->openAction);
1323 	Py_INCREF(value);
1324 	self->openAction = value;
1325 	return 0;
1326 }
1327 
1328 static char *effval_doc = const_cast<char*>(
1329 "List of effection values for each saved page.\n"
1330 "It is list of list of six integers. Those int has followin meaning:\n\t"
1331 "- Length of time the page is shown before the presentation\n\tstarts on the selected page. (1-3600)\n\t"
1332 "- Length of time the effect runs. (1 - 3600)\n\t\tA shorter time will speed up the effect,\n\t\ta longer one will slow it down\n\t"
1333 "- Type of the display effect\n\t\t0 - No Effect\n\t\t1 - Blinds\n\t\t2 - Box\n\t\t3 - Dissolve\n\t\t4 - Glitter\n\t\t5 - Split\n\t\t6 - Wipe\n\t"
1334 "- Direction of the effect of moving lines\n\tfor the split and blind effects.\n\t\t0 - Horizontal\n\t\t1 - Vertical\n\t"
1335 "- Starting position for the box and split effects.\n\t\t0 - Inside\n\t\t1 - Outside\n\t"
1336 "- Direction of the glitter or wipe effects.\n\t\t0 - Left to Right\n\t\t1 - Top to Bottom\n\t\t2 - Bottom to Top\n\t\t3 - Right to Left\n\t\t4 - Top-left to Bottom-Right");
1337 
1338 static char *lpival_doc = const_cast<char*>(
1339 "Rendering Settings for individual colors.\n\n"
1340 "This is list of values for each color\n"
1341 "Color values have structure [siii] which stand for:\n\t"
1342 "s - Color name ('Black', 'Cyan', 'Magenta', 'Yellow')\n\t"
1343 "i - Frequency (10 to 1000)\n\t"
1344 "i - Angle (-180 to 180)\n\t"
1345 "i - Spot Function\n\t\t0 - Simple Dot\n\t\t1 - Line\n\t\t2 - Round\n\t\t3 - Ellipse\n"
1346 "Be careful when supplying these values as they\nare not checked for validity.");
1347 
1348 static PyGetSetDef PDFfile_getseters [] = {
1349 	{const_cast<char*>("file"), (getter)PDFfile_getfile, (setter)PDFfile_setfile, const_cast<char*>("Name of file to save into"), nullptr},
1350 	{const_cast<char*>("fontEmbedding"), (getter)PDFfile_getFontEmbeddingMode, (setter)PDFfile_setFontEmbeddingMode, const_cast<char*>("Font embedding mode.\n\tValue must be one of integers: 0 (Embed), 1 (Outline), 2 (No embedding)."), nullptr},
1351 	{const_cast<char*>("fonts"), (getter)PDFfile_getfonts, (setter)PDFfile_setfonts, const_cast<char*>("List of fonts to embed."), nullptr},
1352 	{const_cast<char*>("subsetList"), (getter)PDFfile_getSubsetList, (setter)PDFfile_setSubsetList, const_cast<char*>("List of fonts to subsetted."), nullptr},
1353 	{const_cast<char*>("pages"), (getter)PDFfile_getpages, (setter)PDFfile_setpages, const_cast<char*>("List of pages to print"), nullptr},
1354 	{const_cast<char*>("resolution"), (getter)PDFfile_getresolution, (setter)PDFfile_setresolution, const_cast<char*>("Resolution of output file. Values from 35 to 4000."), nullptr},
1355 	{const_cast<char*>("downsample"), (getter)PDFfile_getdownsample, (setter)PDFfile_setdownsample, const_cast<char*>("Downsample image resolusion to this value. Values from 35 to 4000\nSet 0 for not to downsample"), nullptr},
1356 	{const_cast<char*>("effval"), (getter)PDFfile_geteffval, (setter)PDFfile_seteffval, effval_doc, nullptr},
1357 	{const_cast<char*>("lpival"), (getter)PDFfile_getlpival, (setter)PDFfile_setlpival, lpival_doc, nullptr},
1358 	{const_cast<char*>("owner"), (getter)PDFfile_getowner, (setter)PDFfile_setowner, const_cast<char*>("Owner's password"), nullptr},
1359 	{const_cast<char*>("user"), (getter)PDFfile_getuser, (setter)PDFfile_setuser, const_cast<char*>("User's password"), nullptr},
1360 	{const_cast<char*>("solidpr"), (getter)PDFfile_getsolidpr, (setter)PDFfile_setsolidpr, const_cast<char*>("Color profile for solid colors"), nullptr},
1361 	{const_cast<char*>("imagepr"), (getter)PDFfile_getimagepr, (setter)PDFfile_setimagepr, const_cast<char*>("Color profile for images"), nullptr},
1362 	{const_cast<char*>("printprofc"), (getter)PDFfile_getprintprofc, (setter)PDFfile_setprintprofc, const_cast<char*>("Output profile for printing. If possible, get some guidance from your printer on profile selection."), nullptr},
1363 	{const_cast<char*>("info"), (getter)PDFfile_getinfo, (setter)PDFfile_setinfo, const_cast<char*>("Mandatory string for PDF/X or the PDF will fail\nPDF/X conformance. We recommend you use the title of the document."), nullptr},
1364 	{const_cast<char*>("rotateDeg"), (getter)PDFfile_getRotateDeg, (setter)PDFfile_setRotateDeg, const_cast<char*>("Automatically rotate the exported pages\n\tValue must be one of integers: 0, 90, 180 or 270"), nullptr},
1365 	{const_cast<char*>("openAction"), (getter)PDFfile_getopenAction, (setter)PDFfile_setopenAction, const_cast<char*>("Javascript to be executed when PDF document is opened."), nullptr},
1366 	{nullptr, nullptr, nullptr, nullptr, nullptr}  // sentinel
1367 };
1368 
PDFfile_save(PDFfile * self)1369 static PyObject *PDFfile_save(PDFfile *self)
1370 {
1371 	if (!checkHaveDocument())
1372 		return nullptr;
1373 
1374 	ScribusDoc* currentDoc = ScCore->primaryMainWindow()->doc;
1375 	PDFOptions& pdfOptions = currentDoc->pdfOptions();
1376 
1377 	// Copied from file scribus.cpp
1378 	// void ScribusMainWindow::SaveAsPDF()
1379 	if (ScCore->primaryMainWindow()->bookmarkPalette->BView->topLevelItemCount() == 0)
1380 		pdfOptions.Bookmarks = false;
1381 
1382 	// Get PDF version
1383 	self->version = minmaxi(self->version, PDFVersion::PDFVersion_Min, PDFVersion::PDFVersion_Max);
1384 	pdfOptions.Version = (PDFVersion::Version) self->version;
1385 
1386 	// Update used fonts
1387 	currentDoc->reorganiseFonts();
1388 
1389 	// Apply fonts attribute
1390 	pdfOptions.EmbedList.clear();
1391 	int n = PyList_Size(self->fonts);
1392 	for (int i = 0; i < n; ++i)
1393 	{
1394 		QString tmpFon;
1395 		tmpFon = PyUnicode_asQString(PyList_GetItem(self->fonts, i));
1396 		pdfOptions.EmbedList.append(tmpFon);
1397 	}
1398 	// Apply SubsetList attribute
1399 	pdfOptions.SubsetList.clear();
1400 	n = PyList_Size(self->subsetList);
1401 	for (int i = 0; i < n; ++i)
1402 	{
1403 		QString tmpFon;
1404 		tmpFon = PyUnicode_asQString(PyList_GetItem(self->subsetList, i));
1405 		pdfOptions.SubsetList.append(tmpFon);
1406 	}
1407 	// Apply font embedding mode
1408 	pdfOptions.FontEmbedding = (PDFOptions::PDFFontEmbedding) PyLong_AsLong(self->fontEmbedding);
1409 	if (pdfOptions.Version == PDFVersion::PDF_X1a ||
1410 	    pdfOptions.Version == PDFVersion::PDF_X3 ||
1411 	    pdfOptions.Version == PDFVersion::PDF_X4)
1412 	{
1413 		pdfOptions.FontEmbedding = PDFOptions::EmbedFonts;
1414 	}
1415 	if (pdfOptions.FontEmbedding == PDFOptions::EmbedFonts)
1416 	{
1417 		QStringList docFonts = currentDoc->UsedFonts.keys();
1418 		for (int i = 0; i < docFonts.count(); ++i)
1419 		{
1420 			const QString& fontName = docFonts.at(i);
1421 			if (pdfOptions.SubsetList.contains(fontName))
1422 				continue;
1423 			if (pdfOptions.EmbedList.contains(fontName))
1424 				continue;
1425 			pdfOptions.SubsetList.append(fontName);
1426 		}
1427 		pdfOptions.OutlineList = QStringList();
1428 	}
1429 	else if (pdfOptions.FontEmbedding == PDFOptions::OutlineFonts)
1430 	{
1431 		pdfOptions.EmbedList   = QStringList();
1432 		pdfOptions.SubsetList  = QStringList();
1433 		pdfOptions.OutlineList = currentDoc->UsedFonts.keys();
1434 	}
1435 	else
1436 	{
1437 		pdfOptions.EmbedList   = QStringList();
1438 		pdfOptions.SubsetList  = QStringList();
1439 		pdfOptions.OutlineList = QStringList();
1440 	}
1441 	// Apply file attribute
1442 	QString fn = PyUnicode_asQString(self->file);
1443 	pdfOptions.fileName = fn;
1444 	// Apply pages attribute
1445 	std::vector<int> pageNs;
1446 	int nn = PyList_Size(self->pages);
1447 	for (int i = 0; i < nn; ++i) {
1448 		pageNs.push_back((int) PyLong_AsLong(PyList_GetItem(self->pages, i)));
1449 	}
1450 	// Apply thumbnails attribute
1451 	pdfOptions.Thumbnails = self->thumbnails;
1452 	// Apply cropmarks attribute
1453 	pdfOptions.cropMarks = self->cropMarks;
1454 	// Apply bleedmarks attribute
1455 	pdfOptions.bleedMarks = self->bleedMarks;
1456 	// Apply registrationmarks attribute
1457 	pdfOptions.registrationMarks = self->registrationMarks;
1458 	// Apply colormarks attribute
1459 	pdfOptions.colorMarks = self->colorMarks;
1460 	// Apply docInfoMark attribute
1461 	pdfOptions.docInfoMarks = self->docInfoMarks;
1462 	// Apply mark offset attribute
1463 	pdfOptions.markOffset = qMax(0.0, self->markOffset / currentDoc->unitRatio());
1464 	// Apply mark length attribute
1465 	pdfOptions.markLength = qMax(0.0, self->markLength / currentDoc->unitRatio());
1466 	// Apply compress attribute
1467 	self->compressmtd = minmaxi(self->compressmtd, 0, 3);
1468 	pdfOptions.Compress = self->compress;
1469 	pdfOptions.CompressMethod = (PDFOptions::PDFCompression) self->compressmtd;
1470 	// Apply quality attribute
1471 	self->quality = minmaxi(self->quality, 0, 4);
1472 	pdfOptions.Quality = self->quality;
1473 	// Apply resolusion attribute
1474 	pdfOptions.Resolution = PyLong_AsLong(self->resolution);
1475 	// Apply downsample attribute
1476 	pdfOptions.RecalcPic = PyLong_AsLong(self->downsample);
1477 	if (pdfOptions.RecalcPic)
1478 		pdfOptions.PicRes = PyLong_AsLong(self->downsample);
1479 	else
1480 		pdfOptions.PicRes = pdfOptions.Resolution;
1481 	// Apply bookmarks attribute
1482 	pdfOptions.Bookmarks = self->bookmarks;
1483 	// Apply binding attribute
1484 	pdfOptions.Binding = self->binding;
1485 	// Apply presentation attribute
1486 	pdfOptions.PresentMode = self->presentation;
1487 
1488 	int tmpnum = PyList_Size(self->effval);
1489 	for (int i = 0; i < tmpnum; ++i)
1490 	{
1491 		PDFPresentationData t;
1492 		PyObject *ti = PyList_GetItem(self->effval, i);
1493 		if (!ti)
1494 			continue;
1495 		// Do I Need to check if every PyLong_AsLong and PyList_GetItem funtion succeed???
1496 		t.pageEffectDuration = PyLong_AsLong(PyList_GetItem(ti, 0));
1497 		t.pageViewDuration = PyLong_AsLong(PyList_GetItem(ti, 1));
1498 		t.effectType = PyLong_AsLong(PyList_GetItem(ti, 2));
1499 		t.Dm = PyLong_AsLong(PyList_GetItem(ti, 3));
1500 		t.M = PyLong_AsLong(PyList_GetItem(ti, 4));
1501 		t.Di = PyLong_AsLong(PyList_GetItem(ti, 5));
1502 		//	PresentVals.append(t);
1503 	}
1504 //	pdfOptions.PresentVals = PresentVals;
1505 
1506 	// Apply lpival
1507 	int n2 = PyList_Size(self->lpival);
1508 	for (int i = 0; i < n2; ++i)
1509 	{
1510 		LPIData lpi;
1511 		PyObject *t = PyList_GetItem(self->lpival, i);
1512 // This code always raise exception - WHY???
1513 //		char *s;
1514 //		if (!PyArg_ParseTuple(t, "[siii]", &s, &lpi.Frequency,
1515 //				 &lpi.Angle, &lpi.SpotFunc)) {
1516 //			PyErr_SetString(PyExc_SystemError, "while parsing 'lpival'. WHY THIS HAPPENED????");
1517 //			return nullptr;
1518 //		}
1519 //		pdfOptions.LPISettings[QString(s)]=lpi;
1520 		QString st = PyUnicode_asQString(PyList_GetItem(t, 0));
1521 		lpi.Frequency = PyLong_AsLong(PyList_GetItem(t, 1));
1522 		lpi.Angle = PyLong_AsLong(PyList_GetItem(t, 2));
1523 		lpi.SpotFunc = PyLong_AsLong(PyList_GetItem(t, 3));
1524 		pdfOptions.LPISettings[st] = lpi;
1525 	}
1526 
1527 	pdfOptions.Articles = self->article;
1528 	pdfOptions.Encrypt = self->encrypt;
1529 	pdfOptions.UseLPI = self->uselpi;
1530 	pdfOptions.UseSpotColors = self->usespot;
1531 	pdfOptions.doMultiFile = self->domulti;
1532 
1533 	if (self->encrypt)
1534 	{
1535 		int Perm = -64;
1536 		if (pdfOptions.Version == PDFVersion::PDF_14)
1537 			Perm &= ~0x00240000;
1538 		if (self->allowPrinting)
1539 			Perm += 4;
1540 		if (self->allowChange)
1541 			Perm += 8;
1542 		if (self->allowCopy)
1543 			Perm += 16;
1544 		if (self->allowAnnots)
1545 			Perm += 32;
1546 		pdfOptions.Permissions = Perm;
1547 		pdfOptions.PassOwner = PyUnicode_asQString(self->owner);
1548 		pdfOptions.PassUser = PyUnicode_asQString(self->user);
1549 	}
1550 	if (self->outdst == 0)
1551 	{
1552 		pdfOptions.UseRGB = true;
1553 		pdfOptions.UseProfiles = false;
1554 		pdfOptions.UseProfiles2 = false;
1555 	}
1556 	else
1557 	{
1558 		pdfOptions.UseRGB = false;
1559 		if (ScCore->primaryMainWindow()->doc->HasCMS)
1560 		{
1561 			pdfOptions.UseProfiles = self->profiles;
1562 			pdfOptions.UseProfiles2 = self->profilei;
1563 			self->intents = minmaxi(self->intents, 0, 3);
1564 			pdfOptions.Intent = self->intents;
1565 			self->intenti = minmaxi(self->intenti, 0, 3);
1566 			pdfOptions.Intent2 = self->intenti;
1567 			pdfOptions.EmbeddedI = self->noembicc;
1568 			pdfOptions.SolidProf = PyUnicode_asQString(self->solidpr);
1569 			pdfOptions.ImageProf = PyUnicode_asQString(self->imagepr);
1570 			pdfOptions.PrintProf = PyUnicode_asQString(self->printprofc);
1571 			if (pdfOptions.Version == PDFVersion::PDF_X1a ||
1572 				pdfOptions.Version == PDFVersion::PDF_X3 ||
1573 				pdfOptions.Version == PDFVersion::PDF_X4)
1574 			{
1575 				pdfOptions.Info = PyUnicode_asQString(self->info);
1576 				pdfOptions.Encrypt = false;
1577 				pdfOptions.PresentMode = false;
1578 			}
1579 		}
1580 		else
1581 		{
1582 			pdfOptions.UseProfiles = false;
1583 			pdfOptions.UseProfiles2 = false;
1584 		}
1585 	}
1586 
1587 	QMap<int, QImage> thumbs;
1588 	PageToPixmapFlags pixmapFlags = Pixmap_DontReloadImages | Pixmap_DrawWhiteBackground;
1589 	for (uint ap = 0; ap < pageNs.size(); ++ap)
1590 	{
1591 		QImage thumb(10, 10, QImage::Format_ARGB32_Premultiplied );
1592 		if (pdfOptions.Thumbnails)
1593 			thumb = ScCore->primaryMainWindow()->view->PageToPixmap(pageNs[ap] - 1, 100, pixmapFlags);
1594 		thumbs.insert(pageNs[ap], thumb);
1595 	}
1596 
1597 	ReOrderText(ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow()->view);
1598 
1599 	MarginStruct optBleeds(pdfOptions.bleeds);
1600 	pdfOptions.useDocBleeds = self->useDocBleeds;
1601 	if (self->useDocBleeds)
1602 		pdfOptions.bleeds = ScCore->primaryMainWindow()->doc->bleedsVal();
1603 	else
1604 	{
1605 		self->bleedt = minmaxd(self->bleedt, 0, currentDoc->pageHeight() * currentDoc->unitRatio());
1606 		pdfOptions.bleeds.setTop(self->bleedt / currentDoc->unitRatio());
1607 		self->bleedl = minmaxd(self->bleedl, 0, currentDoc->pageWidth() * currentDoc->unitRatio());
1608 		pdfOptions.bleeds.setLeft(self->bleedl / currentDoc->unitRatio());
1609 		self->bleedr = minmaxd(self->bleedr, 0, currentDoc->pageWidth() * currentDoc->unitRatio());
1610 		pdfOptions.bleeds.setRight(self->bleedr / currentDoc->unitRatio());
1611 		self->bleedb = minmaxd(self->bleedb, 0, currentDoc->pageHeight() * currentDoc->unitRatio());
1612 		pdfOptions.bleeds.setBottom(self->bleedb / currentDoc->unitRatio());
1613 	}
1614 	pdfOptions.useLayers = self->useLayers;
1615 	pdfOptions.embedPDF = self->embedPDF;
1616 	pdfOptions.MirrorH = self->mirrorH;
1617 	pdfOptions.MirrorV = self->mirrorV;
1618 	pdfOptions.doClip = self->doClip;
1619 	pdfOptions.RotateDeg = PyLong_AsLong(self->rotateDeg);
1620 	pdfOptions.isGrayscale = self->isGrayscale;
1621 	pdfOptions.PageLayout = minmaxi(self->pageLayout, 0, 3);
1622 	pdfOptions.displayBookmarks = self->displayBookmarks;
1623 	pdfOptions.displayThumbs = self->displayThumbs;
1624 	pdfOptions.displayLayers = self->displayLayers;
1625 	pdfOptions.displayFullscreen = self->displayFullscreen;
1626 	pdfOptions.hideToolBar = self->hideToolBar;
1627 	pdfOptions.hideMenuBar = self->hideMenuBar;
1628 	pdfOptions.fitWindow = self->fitWindow;
1629 	pdfOptions.openAction = PyUnicode_asQString(self->openAction);
1630 	pdfOptions.firstUse = false;
1631 
1632 	QString errorMessage;
1633 	bool success = ScCore->primaryMainWindow()->getPDFDriver(fn, pageNs, thumbs, errorMessage);
1634 	if (!success)
1635 	{
1636 		fn  = "Cannot write the File: " + fn;
1637 		if (!errorMessage.isEmpty())
1638 			fn += QString("\n%1").arg(errorMessage);
1639 		PyErr_SetString(PyExc_SystemError, fn.toLatin1());
1640 	}
1641 
1642 	if (self->useDocBleeds)
1643 		pdfOptions.bleeds = optBleeds;
1644 
1645 	if (success)
1646 		Py_RETURN_NONE;
1647 	return nullptr;
1648 }
1649 
1650 static PyMethodDef PDFfile_methods[] = {
1651 	{const_cast<char*>("save"), (PyCFunction)PDFfile_save, METH_NOARGS, pdffile_save__doc__},
1652 	{nullptr, (PyCFunction)(nullptr), 0, nullptr} // sentinel
1653 };
1654 
1655 PyTypeObject PDFfile_Type = {
1656 	PyVarObject_HEAD_INIT(nullptr, 0) // PyObject_VAR_HEAD	      //
1657 	const_cast<char*>("scribus.PDFfile"), // char *tp_name; /* For printing, in format "<module>.<name>" */
1658 	sizeof(PDFfile),     // int tp_basicsize, /* For allocation */
1659 	0,		    // int tp_itemsize; /* For allocation */
1660 
1661 	/* Methods to implement standard operations */
1662 
1663 	(destructor) PDFfile_dealloc, //     destructor tp_dealloc;
1664 #if PY_VERSION_HEX >= 0x03080000
1665 	0,       //     Py_ssize_t tp_vectorcall_offset
1666 #else
1667 	nullptr, //     printfunc tp_print;
1668 #endif
1669 	nullptr, //     getattrfunc tp_getattr;
1670 	nullptr, //     setattrfunc tp_setattr;
1671 	nullptr, //     cmpfunc tp_as_async;
1672 	nullptr, //     reprfunc tp_repr;
1673 
1674 	/* Method suites for standard classes */
1675 
1676 	nullptr, //     PyNumberMethods *tp_as_number;
1677 	nullptr, //     PySequenceMethods *tp_as_sequence;
1678 	nullptr, //     PyMappingMethods *tp_as_mapping;
1679 
1680 	/* More standard operations (here for binary compatibility) */
1681 
1682 	nullptr, //     hashfunc tp_hash;
1683 	nullptr, //     ternaryfunc tp_call;
1684 	nullptr, //     reprfunc tp_str;
1685 	nullptr, //     getattrofunc tp_getattro;
1686 	nullptr, //     setattrofunc tp_setattro;
1687 
1688 	/* Functions to access object as input/output buffer */
1689 	nullptr, //     PyBufferProcs *tp_as_buffer;
1690 
1691 	/* Flags to define presence of optional/expanded features */
1692 	Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,    // long tp_flags;
1693 
1694 	pdffile__doc__,      // char *tp_doc; /* Documentation string */
1695 
1696 	/* Assigned meaning in release 2.0 */
1697 	/* call function for all accessible objects */
1698 	nullptr, //     traverseproc tp_traverse;
1699 
1700 	/* delete references to contained objects */
1701 	nullptr, //     inquiry tp_clear;
1702 
1703 	/* Assigned meaning in release 2.1 */
1704 	/* rich comparisons */
1705 	nullptr, //     richcmpfunc tp_richcompare;
1706 
1707 	/* weak reference enabler */
1708 	0, //     long tp_weaklistoffset;
1709 
1710 	/* Added in release 2.2 */
1711 	/* Iterators */
1712 	nullptr, //     getiterfunc tp_iter;
1713 	nullptr, //     iternextfunc tp_iternext;
1714 
1715 	/* Attribute descriptor and subclassing stuff */
1716 	PDFfile_methods, //     struct PyMethodDef *tp_methods;
1717 	PDFfile_members, //     struct PyMemberDef *tp_members;
1718 	PDFfile_getseters, //     struct PyGetSetDef *tp_getset;
1719 	nullptr, //     struct _typeobject *tp_base;
1720 	nullptr, //     PyObject *tp_dict;
1721 	nullptr, //     descrgetfunc tp_descr_get;
1722 	nullptr, //     descrsetfunc tp_descr_set;
1723 	0, //     long tp_dictoffset;
1724 	(initproc)PDFfile_init, //     initproc tp_init;
1725 	nullptr, //     allocfunc tp_alloc;
1726 	PDFfile_new, //     newfunc tp_new;
1727 	nullptr, //     freefunc tp_free; /* Low-level free-memory routine */
1728 	nullptr, //     inquiry tp_is_gc; /* For PyObject_IS_GC */
1729 	nullptr, //     PyObject *tp_bases;
1730 	nullptr, //     PyObject *tp_mro; /* method resolution order */
1731 	nullptr, //     PyObject *tp_cache;
1732 	nullptr, //     PyObject *tp_subclasses;
1733 	nullptr, //     PyObject *tp_weaklist;
1734 	nullptr, //     destructor tp_del;
1735 	0, //	 unsigned int tp_version_tag;
1736 	0, //	 destructor tp_finalize;
1737 #if PY_VERSION_HEX >= 0x03080000
1738 	nullptr, // tp_vectorcall
1739 #endif
1740 #if PY_VERSION_HEX >= 0x03080000 && PY_VERSION_HEX < 0x03090000
1741 	nullptr, //deprecated tp_print
1742 #endif
1743 
1744 #ifdef COUNT_ALLOCS
1745 	/* these must be last and never explicitly initialized */
1746 	//    int tp_allocs;
1747 	//    int tp_frees;
1748 	//    int tp_maxalloc;
1749 	//    struct _typeobject *tp_prev;
1750 	//    struct _typeobject *tp_next;
1751 #endif
1752 };
1753