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 <vector>
8 #include <iostream>
9
10 #include "objprinter.h"
11
12 #include <structmember.h>
13 #include <QFileInfo>
14 #include <QDir>
15 #include <QScopedPointer>
16
17 #include "cmdutil.h"
18 #include "prefsmanager.h"
19 #include "pslib.h"
20 #include "scpaths.h"
21 #include "scprintengine_pdf.h"
22 #include "scprintengine_ps.h"
23 #include "scribuscore.h"
24 #include "scribusdoc.h"
25 #include "util_file.h"
26 #include "util_ghostscript.h"
27 #include "util_printer.h"
28
29 #if defined(_WIN32)
30 #include "scprintengine_gdi.h"
31 #endif
32
33 // these functions are located at utils.cpp
34 void SCRIBUS_API ReOrderText(ScribusDoc *doc, ScribusView *view);
35 // end of utils.cpp
36
37 typedef struct
38 {
39 PyObject_HEAD
40 PyObject *allPrinters; // list of strings - names of installed printers
41 PyObject *printer; // string - selected printer
42 PyObject *file; // string - name of file to print into (eg. output.ps)
43 PyObject *cmd; // string - if "" use standard command else use this as command (eg. "kprinter", "xpp" ...)
44 PyObject *pages; // list of integers - pages to be printed
45 int copies; // numer of printed copies
46 PyObject *separation; // string - No; All; Cyan; Magenta; Yellow; Black
47 int color; // bool - do we print in color=1 or greyscale=0
48 int useICC; // bool - do we use ICC Profiles 0 = No 1 = Yes
49 int prnLang; // integer - print language
50 int mph; // bool - mirror pages horizontally
51 int mpv; // bool - mirror pages vertically
52 int ucr; // bool - Under Color Removal
53 } Printer;
54
55
Printer_dealloc(Printer * self)56 static void Printer_dealloc(Printer* self)
57 {
58 Py_XDECREF(self->allPrinters);
59 Py_XDECREF(self->printer);
60 Py_XDECREF(self->file);
61 Py_XDECREF(self->cmd);
62 Py_XDECREF(self->pages);
63 Py_XDECREF(self->separation);
64 self->ob_type->tp_free((PyObject *)self);
65 }
66
Printer_new(PyTypeObject * type,PyObject *,PyObject *)67 static PyObject * Printer_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/)
68 {
69 // do not create new object if there is no opened document
70 if (!checkHaveDocument()) {
71 return nullptr;
72 }
73
74 Printer *self = (Printer *)type->tp_alloc(type, 0);
75 if (self != nullptr) {
76 // set allPrinters attribute
77 self->allPrinters = PyList_New(0);
78 if (self->allPrinters == nullptr) {
79 Py_DECREF(self);
80 return nullptr;
81 }
82 // set printer attribute
83 self->printer = PyString_FromString("");
84 if (self->printer == nullptr) {
85 Py_DECREF(self);
86 return nullptr;
87 }
88 // set file attribute
89 self->file = PyString_FromString("");
90 if (self->file == nullptr) {
91 Py_DECREF(self);
92 return nullptr;
93 }
94 // set cmd attribute
95 self->cmd = PyString_FromString("");
96 if (self->cmd == nullptr) {
97 Py_DECREF(self);
98 return nullptr;
99 }
100 // set pages attribute
101 self->pages = PyList_New(0);
102 if (self->pages == nullptr) {
103 Py_DECREF(self);
104 return nullptr;
105 }
106 // set separation attribute
107 self->separation = PyString_FromString("No");
108 if (self->separation == nullptr) {
109 Py_DECREF(self);
110 return nullptr;
111 }
112 // set color attribute
113 self->color = 1;
114 // set useICC attribute
115 self->useICC = 0;
116 // set prnLanguage attribute
117 self->prnLang = (int) PrintLanguage::PostScript3;
118 // set mph attribute
119 self->mph = 0;
120 // set mpv attribute
121 self->mpv = 0;
122 // set ucr attribute
123 self->ucr = 1;
124 // set copies attribute
125 self->copies = 1;
126 }
127 return (PyObject *) self;
128 }
129
Printer_init(Printer * self,PyObject *,PyObject *)130 static int Printer_init(Printer *self, PyObject * /*args*/, PyObject * /*kwds*/)
131 {
132 if (!checkHaveDocument()) {
133 return -1;
134 }
135 // pool system for installed printers
136 // most code is stolen and little adopted from druck.cpp
137 PyObject *allPrinters = PyList_New(0);
138 if (allPrinters) {
139 Py_DECREF(self->allPrinters);
140 self->allPrinters = allPrinters;
141 }
142 QStringList printers = PrinterUtil::getPrinterNames();
143 for (int i = 0; i < printers.count(); ++i)
144 {
145 QString prn = printers[i];
146 if (prn.isEmpty())
147 continue;
148 PyObject *tmppr = PyString_FromString(prn.toLocal8Bit().constData());
149 if (tmppr) {
150 PyList_Append(self->allPrinters, tmppr);
151 Py_DECREF(tmppr);
152 }
153 }
154 PyObject *tmp2 = PyString_FromString("File");
155 PyList_Append(self->allPrinters, tmp2);
156 Py_DECREF(tmp2);
157 // as defaut set to print into file
158 PyObject *printer = nullptr;
159 printer = PyString_FromString("File");
160 if (printer) {
161 Py_DECREF(self->printer);
162 self->printer = printer;
163 }
164 // set defaul name of file to print into
165 QString tf(ScCore->primaryMainWindow()->doc->pdfOptions().fileName);
166 if (tf.isEmpty()) {
167 QFileInfo fi = QFileInfo(ScCore->primaryMainWindow()->doc->documentFileName());
168 tf = fi.path() + "/" + fi.baseName() + ".pdf";
169 }
170 PyObject *file = nullptr;
171 file = PyString_FromString(tf.toLatin1());
172 if (file) {
173 Py_DECREF(self->file);
174 self->file = file;
175 } else {
176 PyErr_SetString(PyExc_SystemError, "Can not initialize 'file' attribute");
177 return -1;
178 }
179 // alternative printer commands default to ""
180 PyObject *cmd = nullptr;
181 cmd = PyString_FromString("");
182 if (cmd) {
183 Py_DECREF(self->cmd);
184 self->cmd = cmd;
185 }
186 // if document exist when created Printer instance
187 // set to print all pages
188 PyObject *pages = nullptr;
189 int num = ScCore->primaryMainWindow()->doc->Pages->count();
190 pages = PyList_New(num);
191 if (pages) {
192 Py_DECREF(self->pages);
193 self->pages = pages;
194 }
195 for (int i = 0; i < num; i++) {
196 PyObject *tmp = nullptr;
197 tmp = PyInt_FromLong((long)i+1L); // instead of 1 put here first page number
198 if (tmp)
199 PyList_SetItem(self->pages, i, tmp);
200 }
201 // do not print separation
202 PyObject *separation = nullptr;
203 separation = PyString_FromString("No");
204 if (separation) {
205 Py_DECREF(self->separation);
206 self->separation = separation;
207 }
208 // print in color
209 self->color = 1;
210 // do not use ICC Profile
211 self->useICC = 0;
212 // use PostScrip level 3
213 self->prnLang = (int) PrintLanguage::PostScript3;
214 // do not mirror pages
215 self->mph = 0;
216 // do not mirror pages
217 self->mpv = 0;
218 // apply Under Color Removal as default
219 self->ucr = 1;
220 // number of copies
221 self->copies = 1;
222 return 0;
223 }
224
225 static PyMemberDef Printer_members[] = {
226 {const_cast<char*>("copies"), T_INT, offsetof(Printer, copies), 0, const_cast<char*>("Number of copies")},
227 {const_cast<char*>("color"), T_INT, offsetof(Printer, color), 0, const_cast<char*>("Print in color.\n\t True - color -- Default\n\t False - greyscale")},
228 {const_cast<char*>("useICC"), T_INT, offsetof(Printer, useICC), 0, const_cast<char*>("Use ICC Profile\n\tTrue\n\tFalse -- Default")},
229 {const_cast<char*>("pslevel"), T_INT, offsetof(Printer, prnLang), 0, const_cast<char*>("Deprecated, use prnLanguage instead.")}, // Deprecated
230 {const_cast<char*>("prnLanguage"), T_INT, offsetof(Printer, prnLang), 0, const_cast<char*>("Print Language\nOne of PRNLANG_* constants -- Default is PRNLANG_POSTSCRIPT3.")},
231 {const_cast<char*>("mph"), T_INT, offsetof(Printer, mph), 0, const_cast<char*>("Mirror Pages Horizontal\n\tTrue\n\tFalse -- Default")},
232 {const_cast<char*>("mpv"), T_INT, offsetof(Printer, mpv), 0, const_cast<char*>("Mirror Pages Vertical\n\t True\n\tFalse -- Default")},
233 {const_cast<char*>("ucr"), T_INT, offsetof(Printer, ucr), 0, const_cast<char*>("Apply Under Color Removal\n\tTrue -- Default\n\tFalse")},
234 {nullptr, 0, 0, 0, nullptr} // sentinel
235 };
236
237 /* Here begins Getter & Setter functions */
238
Printer_getallPrinters(Printer * self,void *)239 static PyObject *Printer_getallPrinters(Printer *self, void * /*closure*/)
240 {
241 Py_INCREF(self->allPrinters);
242 return self->allPrinters;
243 }
244
Printer_setallPrinters(Printer *,PyObject *,void *)245 static int Printer_setallPrinters(Printer * /*self*/, PyObject * /*value*/, void * /*closure*/)
246 {
247 PyErr_SetString(PyExc_ValueError, "'allPrinters' attribute is READ-ONLY");
248 return -1;
249 }
250
Printer_getprinter(Printer * self,void *)251 static PyObject *Printer_getprinter(Printer *self, void * /*closure*/)
252 {
253 Py_INCREF(self->printer);
254 return self->printer;
255 }
256
Printer_setprinter(Printer * self,PyObject * value,void *)257 static int Printer_setprinter(Printer *self, PyObject *value, void * /*closure*/)
258 {
259 if (value == nullptr) {
260 PyErr_SetString(PyExc_TypeError, "Cannot delete 'printer' attribute.");
261 return -1;
262 }
263 if (!PyString_Check(value)) {
264 PyErr_SetString(PyExc_TypeError, "The 'printer' attribute value must be string.");
265 return -1;
266 }
267
268 int n = PyList_Size(self->allPrinters);
269 bool same = 0;
270 for (int i = 0; i < n; i++) {
271 if (PyObject_RichCompareBool(value, PyList_GetItem(self->allPrinters, i), Py_EQ) == 1) {
272 same = true;
273 break;
274 }
275 }
276 if (!same) {
277 PyErr_SetString(PyExc_ValueError, "'printer' value can be only one of string in 'allPrinters' attribute ");
278 return -1;
279 }
280
281 Py_DECREF(self->printer);
282 Py_INCREF(value);
283 self->printer = value;
284 return 0;
285 }
286
Printer_getfile(Printer * self,void *)287 static PyObject *Printer_getfile(Printer *self, void * /*closure*/)
288 {
289 Py_INCREF(self->file);
290 return self->file;
291 }
292
Printer_setfile(Printer * self,PyObject * value,void *)293 static int Printer_setfile(Printer *self, PyObject *value, void * /*closure*/)
294 {
295 if (value == nullptr) {
296 PyErr_SetString(PyExc_TypeError, "Cannot delete 'file' attribute.");
297 return -1;
298 }
299 if (!PyString_Check(value)) {
300 PyErr_SetString(PyExc_TypeError, "The 'file' attribute value must be string.");
301 return -1;
302 }
303 Py_DECREF(self->file);
304 Py_INCREF(value);
305 self->file = value;
306 return 0;
307 }
308
Printer_getcmd(Printer * self,void *)309 static PyObject *Printer_getcmd(Printer *self, void * /*closure*/)
310 {
311 Py_INCREF(self->cmd);
312 return self->cmd;
313 }
314
Printer_setcmd(Printer * self,PyObject * value,void *)315 static int Printer_setcmd(Printer *self, PyObject *value, void * /*closure*/)
316 {
317 if (value == nullptr) {
318 PyErr_SetString(PyExc_TypeError, "Cannot delete 'cmd' attribute.");
319 return -1;
320 }
321 if (!PyString_Check(value)) {
322 PyErr_SetString(PyExc_TypeError, "The 'cmd' attribute value must be string.");
323 return -1;
324 }
325 Py_DECREF(self->cmd);
326 Py_INCREF(value);
327 self->cmd = value;
328 return 0;
329 }
330
Printer_getpages(Printer * self,void *)331 static PyObject *Printer_getpages(Printer *self, void * /*closure*/)
332 {
333 Py_INCREF(self->pages);
334 return self->pages;
335 }
336
Printer_setpages(Printer * self,PyObject * value,void *)337 static int Printer_setpages(Printer *self, PyObject *value, void * /*closure*/)
338 {
339 if (value == nullptr) {
340 PyErr_SetString(PyExc_TypeError, "Cannot delete 'pages' attribute.");
341 return -1;
342 }
343 if (!PyList_Check(value)) {
344 PyErr_SetString(PyExc_TypeError, "'pages' attribute value must be list of integers.");
345 return -1;
346 }
347 int len = PyList_Size(value);
348 for (int i = 0; i < len; i++) {
349 PyObject *tmp = PyList_GetItem(value, i);
350 if (!PyInt_Check(tmp)) {
351 PyErr_SetString(PyExc_TypeError, "'pages' attribute must be list containing only integers.");
352 return -1;
353 }
354 if (PyInt_AsLong(tmp) > static_cast<int>(ScCore->primaryMainWindow()->doc->Pages->count()) || PyInt_AsLong(tmp) < 1) {
355 PyErr_SetString(PyExc_ValueError, "'pages' value out of range.");
356 return -1;
357 }
358 }
359 Py_DECREF(self->pages);
360 Py_INCREF(value);
361 self->pages = value;
362 return 0;
363 }
364
Printer_getseparation(Printer * self,void *)365 static PyObject *Printer_getseparation(Printer *self, void * /*closure*/)
366 {
367 Py_INCREF(self->separation);
368 return self->separation;
369 }
370
Printer_setseparation(Printer * self,PyObject * value,void *)371 static int Printer_setseparation(Printer *self, PyObject *value, void * /*closure*/)
372 {
373 if (value == nullptr) {
374 PyErr_SetString(PyExc_TypeError, "Cannot delete 'separation' attribute.");
375 return -1;
376 }
377 if (!PyString_Check(value)) {
378 PyErr_SetString(PyExc_TypeError, "The 'separation' attribute value must be string.");
379 return -1;
380 }
381 Py_DECREF(self->separation);
382 Py_INCREF(value);
383 self->separation = value;
384 return 0;
385 }
386
387
388 static PyGetSetDef Printer_getseters [] = {
389 {const_cast<char*>("allPrinters"), (getter)Printer_getallPrinters, (setter)Printer_setallPrinters, const_cast<char*>("List of installed printers -- read only"), nullptr},
390 {const_cast<char*>("printer"), (getter)Printer_getprinter, (setter)Printer_setprinter, const_cast<char*>("Name of printer to use.\nDefault is 'File' for printing into file"), nullptr},
391 {const_cast<char*>("file"), (getter)Printer_getfile, (setter)Printer_setfile, const_cast<char*>("Name of file to print into"), nullptr},
392 {const_cast<char*>("cmd"), (getter)Printer_getcmd, (setter)Printer_setcmd, const_cast<char*>("Alternative Printer Command"), nullptr},
393 {const_cast<char*>("pages"), (getter)Printer_getpages, (setter)Printer_setpages, const_cast<char*>("List of pages to be printed"), nullptr},
394 {const_cast<char*>("separation"), (getter)Printer_getseparation, (setter)Printer_setseparation, const_cast<char*>("Print separationl\n\t 'No' -- Default\n\t 'All'\n\t 'Cyan'\n\t 'Magenta'\n\t 'Yellow'\n\t 'Black'\nBeware of misspelling because check is not performed"), nullptr},
395 {nullptr, nullptr, nullptr, nullptr, nullptr} // sentinel
396 };
397
398 // Here we actually print
Printer_print(Printer * self)399 static PyObject *Printer_print(Printer *self)
400 {
401 if (!checkHaveDocument()) {
402 return nullptr;
403 }
404
405 // ReOrderText(ScCore->primaryMainWindow()->doc, ScCore->primaryMainWindow()->view);
406 QString prn = QString(PyString_AsString(self->printer));
407 QString fna = QString(PyString_AsString(self->file));
408 bool fil = QString(PyString_AsString(self->printer)) == QString("File");
409 QString sepName = QString(PyString_AsString(self->separation));
410
411 PrintOptions options;
412 for (int i = 0; i < PyList_Size(self->pages); ++i) {
413 options.pageNumbers.push_back((int) PyInt_AsLong(PyList_GetItem(self->pages, i)));
414 }
415 options.printer = prn;
416 options.prnLanguage = (PrintLanguage) self->prnLang;
417 options.copies = (self->copies < 1) ? 1 : self->copies;
418 options.toFile = fil;
419 options.filename = fil ? fna : QString();
420 options.separationName = sepName;
421 options.outputSeparations = sepName != QString("No");
422 options.useSpotColors = true;
423 options.useColor = self->color;
424 options.mirrorH = self->mph;
425 options.mirrorV = self->mpv;
426 options.doGCR = self->ucr;
427 options.doClip = false;
428 options.setDevParam = false;
429 options.cropMarks = false;
430 options.bleedMarks = false;
431 options.registrationMarks = false;
432 options.colorMarks = false;
433 options.includePDFMarks = false;
434 options.markOffset = 0.0;
435 options.bleeds.set(0, 0, 0, 0);
436 if (!PrinterUtil::checkPrintLanguageSupport(options.printer, options.prnLanguage, options.toFile))
437 options.prnLanguage = PrinterUtil::getDefaultPrintLanguage(options.printer, options.toFile);
438 if (options.prnLanguage == PrintLanguage::PDF || options.prnLanguage == PrintLanguage::WindowsGDI)
439 {
440 options.separationName = "All";
441 options.outputSeparations = false;
442 }
443 options.printerCommand = QString(PyString_AsString(self->cmd));
444
445 ScribusDoc* currentDoc = ScCore->primaryMainWindow()->doc;
446
447 #if defined(_WIN32)
448 if (!options.toFile)
449 {
450 QByteArray devMode;
451 bool printDone = false;
452 if (PrinterUtil::getDefaultSettings(prn, options.devMode))
453 {
454 ScPrintEngine_GDI winPrint(*currentDoc);
455 printDone = winPrint.print(options);
456 }
457 if (!printDone)
458 PyErr_SetString(PyExc_SystemError, "Printing failed");
459 Py_RETURN_NONE;
460 }
461 #endif
462
463 if (options.prnLanguage == PrintLanguage::PostScript1 || options.prnLanguage == PrintLanguage::PostScript2)
464 {
465 if (!ScCore->haveGS())
466 {
467 PyErr_SetString(PyExc_SystemError, "Printing failed : GhostScript is needed to print to PostScript Level 1 or Level 2");
468 Py_RETURN_NONE;
469 }
470 }
471
472 QScopedPointer<ScPrintEngine> printEngine;
473 if (options.prnLanguage == PrintLanguage::PDF)
474 printEngine.reset(new ScPrintEngine_PDF(*currentDoc));
475 else
476 printEngine.reset(new ScPrintEngine_PS(*currentDoc));
477
478 bool printDone = printEngine->print(options);
479 if (!printDone)
480 {
481 QString error = printEngine->errorMessage();
482 PyErr_SetString(PyExc_SystemError, error.toLocal8Bit().constData());
483 }
484
485 Py_RETURN_NONE;
486 }
487
488 static PyMethodDef Printer_methods[] = {
489 {const_cast<char*>("printNow"), (PyCFunction)Printer_print, METH_NOARGS, printer_printnow__doc__},
490 {nullptr, (PyCFunction)(nullptr), 0, nullptr} // sentinel
491 };
492
493 PyTypeObject Printer_Type = {
494 PyObject_HEAD_INIT(nullptr) // PyObject_VAR_HEAD
495 0, //
496 const_cast<char*>("scribus.Printer"), // char *tp_name; /* For printing, in format "<module>.<name>" */
497 sizeof(Printer), // int tp_basicsize, /* For allocation */
498 0, // int tp_itemsize; /* For allocation */
499
500 /* Methods to implement standard operations */
501
502 (destructor) Printer_dealloc, // destructor tp_dealloc;
503 nullptr, // printfunc tp_print;
504 nullptr, // getattrfunc tp_getattr;
505 nullptr, // setattrfunc tp_setattr;
506 nullptr, // cmpfunc tp_compare;
507 nullptr, // reprfunc tp_repr;
508
509 /* Method suites for standard classes */
510
511 nullptr, // PyNumberMethods *tp_as_number;
512 nullptr, // PySequenceMethods *tp_as_sequence;
513 nullptr, // PyMappingMethods *tp_as_mapping;
514
515 /* More standard operations (here for binary compatibility) */
516
517 nullptr, // hashfunc tp_hash;
518 nullptr, // ternaryfunc tp_call;
519 nullptr, // reprfunc tp_str;
520 nullptr, // getattrofunc tp_getattro;
521 nullptr, // setattrofunc tp_setattro;
522
523 /* Functions to access object as input/output buffer */
524 nullptr, // PyBufferProcs *tp_as_buffer;
525
526 /* Flags to define presence of optional/expanded features */
527 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, // long tp_flags;
528
529 printer__doc__, // char *tp_doc; /* Documentation string */
530
531 /* Assigned meaning in release 2.0 */
532 /* call function for all accessible objects */
533 nullptr, // traverseproc tp_traverse;
534
535 /* delete references to contained objects */
536 nullptr, // inquiry tp_clear;
537
538 /* Assigned meaning in release 2.1 */
539 /* rich comparisons */
540 nullptr, // richcmpfunc tp_richcompare;
541
542 /* weak reference enabler */
543 0, // long tp_weaklistoffset;
544
545 /* Added in release 2.2 */
546 /* Iterators */
547 nullptr, // getiterfunc tp_iter;
548 nullptr, // iternextfunc tp_iternext;
549
550 /* Attribute descriptor and subclassing stuff */
551 Printer_methods, // struct PyMethodDef *tp_methods;
552 Printer_members, // struct PyMemberDef *tp_members;
553 Printer_getseters, // struct PyGetSetDef *tp_getset;
554 nullptr, // struct _typeobject *tp_base;
555 nullptr, // PyObject *tp_dict;
556 nullptr, // descrgetfunc tp_descr_get;
557 nullptr, // descrsetfunc tp_descr_set;
558 0, // long tp_dictoffset;
559 (initproc)Printer_init, // initproc tp_init;
560 nullptr, // allocfunc tp_alloc;
561 Printer_new, // newfunc tp_new;
562 nullptr, // freefunc tp_free; /* Low-level free-memory routine */
563 nullptr, // inquiry tp_is_gc; /* For PyObject_IS_GC */
564 nullptr, // PyObject *tp_bases;
565 nullptr, // PyObject *tp_mro; /* method resolution order */
566 nullptr, // PyObject *tp_cache;
567 nullptr, // PyObject *tp_subclasses;
568 nullptr, // PyObject *tp_weaklist;
569 nullptr, // destructor tp_del;
570
571 #ifdef COUNT_ALLOCS
572 /* these must be last and never explicitly initialized */
573 // int tp_allocs;
574 // int tp_frees;
575 // int tp_maxalloc;
576 // struct _typeobject *tp_next;
577 #endif
578 };
579