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 "export.h"
8 #include "dialog.h"
9 
10 #include <QCursor>
11 #include <QDir>
12 #include <QMessageBox>
13 #include <QPixmap>
14 #include <QString>
15 #include <QSharedPointer>
16 
17 #include "scribus.h"
18 #include "scribusdoc.h"
19 #include "scribusview.h"
20 #include "scraction.h"
21 #include "ui/scmwmenumanager.h"
22 #include "util.h"
23 #include "commonstrings.h"
24 #include "scpaths.h"
25 
scribusexportpixmap_getPluginAPIVersion()26 int scribusexportpixmap_getPluginAPIVersion()
27 {
28 	return PLUGIN_API_VERSION;
29 }
30 
scribusexportpixmap_getPlugin()31 ScPlugin* scribusexportpixmap_getPlugin()
32 {
33 	PixmapExportPlugin* plug = new PixmapExportPlugin();
34 	Q_CHECK_PTR(plug);
35 	return plug;
36 }
37 
scribusexportpixmap_freePlugin(ScPlugin * plugin)38 void scribusexportpixmap_freePlugin(ScPlugin* plugin)
39 {
40 	PixmapExportPlugin* plug = qobject_cast<PixmapExportPlugin*>(plugin);
41 	Q_ASSERT(plug);
42 	delete plug;
43 }
44 
PixmapExportPlugin()45 PixmapExportPlugin::PixmapExportPlugin()
46 {
47 	// Set action info in languageChange, so we only have to do
48 	// it in one place. This includes registering file formats.
49 	languageChange();
50 }
51 
~PixmapExportPlugin()52 PixmapExportPlugin::~PixmapExportPlugin()
53 {
54 };
55 
languageChange()56 void PixmapExportPlugin::languageChange()
57 {
58 	// Note that we leave the unused members unset. They'll be initialised
59 	// with their default ctors during construction.
60 	// Action name
61 	m_actionInfo.name = "ExportAsImage";
62 	// Action text for menu, including accel
63 	m_actionInfo.text = tr("Save as &Image...");
64 	// Keyboard shortcut
65 	m_actionInfo.keySequence = "CTRL+SHIFT+E";
66 	// Menu
67 	m_actionInfo.menu = "FileExport";
68 	m_actionInfo.enabledOnStartup = false;
69 	m_actionInfo.needsNumObjects = -1;
70 }
71 
fullTrName() const72 QString PixmapExportPlugin::fullTrName() const
73 {
74 	return tr("Export As Image");
75 }
76 
getAboutData() const77 const ScActionPlugin::AboutData* PixmapExportPlugin::getAboutData() const
78 {
79 	AboutData* about = new AboutData;
80 	Q_CHECK_PTR(about);
81 	about->authors = QString::fromUtf8("Petr Van\xc4\x9bk <petr@scribus.info>");
82 	about->shortDescription = tr("Export As Image");
83 	about->description = tr("Exports selected pages as bitmap images.");
84 	// about->version
85 	// about->releaseDate
86 	// about->copyright
87 	about->license = "GPL";
88 	return about;
89 }
90 
deleteAboutData(const AboutData * about) const91 void PixmapExportPlugin::deleteAboutData(const AboutData* about) const
92 {
93 	Q_ASSERT(about);
94 	delete about;
95 }
96 
run(ScribusDoc * doc,const QString & target)97 bool PixmapExportPlugin::run(ScribusDoc* doc, const QString& target)
98 {
99 	Q_ASSERT(target.isEmpty());
100 	Q_ASSERT(!doc->masterPageMode());
101 	QSharedPointer<ExportBitmap> ex( new ExportBitmap() );
102 	QSharedPointer<ExportForm>  dia( new ExportForm(nullptr, doc, ex->pageDPI, ex->quality, ex->bitmapType) );
103 
104 	// interval widgets handling
105 	QString tmp;
106 	dia->rangeVal->setText(tmp.setNum(doc->currentPageNumber()+1));
107 	QFileInfo docFileInfo(doc->documentFileName());
108 	dia->prefixLineEdit->setText(docFileInfo.baseName());
109 	// main "loop"
110 	if (dia->exec() != QDialog::Accepted)
111 		return true;
112 
113 	std::vector<int> pageNs;
114 	ex->pageDPI = dia->DPIBox->value();
115 	ex->enlargement = dia->enlargementBox->value();
116 	ex->quality     = dia->qualityBox->value();
117 	ex->exportDir   = QDir::fromNativeSeparators(dia->outputDirectory->text());
118 	ex->bitmapType  = dia->bitmapType->currentText();
119 	ex->filenamePrefix = dia->prefixLineEdit->text();
120 
121 	// check availability of the destination
122 	QFileInfo fi(ex->exportDir);
123 	if (!fi.isDir())
124 	{
125 		ScMessageBox::warning(doc->scMW(), tr("Save as Image"),
126 			                    tr("The target location %1 must be an existing directory").arg(ex->exportDir));
127 		return false;
128 	}
129 	if (!fi.isWritable())
130 	{
131 		ScMessageBox::warning(doc->scMW(), tr("Save as Image"),
132 			                    tr("The target location %1 must be writable").arg(ex->exportDir));
133 		return false;
134 	}
135 
136 	QApplication::changeOverrideCursor(QCursor(Qt::WaitCursor));
137 	doc->scMW()->mainWindowProgressBar->reset();
138 	bool res;
139 	if (dia->onePageRadio->isChecked())
140 		res = ex->exportCurrent(doc, !dia->noBackground->isChecked());
141 	else
142 	{
143 		if (dia->allPagesRadio->isChecked())
144 			parsePagesString("*", &pageNs, doc->DocPages.count());
145 		else
146 			parsePagesString(dia->rangeVal->text(), &pageNs, doc->DocPages.count());
147 		res = ex->exportInterval(doc, pageNs, !dia->noBackground->isChecked());
148 	}
149 	doc->scMW()->mainWindowProgressBar->reset();
150 	QApplication::changeOverrideCursor(Qt::ArrowCursor);
151 //		QApplication::restoreOverrideCursor();
152 	if (res)
153 		doc->scMW()->setStatusBarInfoText( tr("Export successful"));
154 
155 	return true;
156 }
157 
158 
ExportBitmap()159 ExportBitmap::ExportBitmap()
160 {
161 	pageDPI = 72;
162 	quality = -1;
163 	enlargement = 100.0;
164 	exportDir = QDir::currentPath();
165 	bitmapType = QString("png");
166 	overwrite = false;
167 }
168 
getFileName(ScribusDoc * doc,uint pageNr)169 QString ExportBitmap::getFileName(ScribusDoc* doc, uint pageNr)
170 {
171 	return QDir::cleanPath(QDir::toNativeSeparators(exportDir + "/" + getFileNameByPage(doc, pageNr, bitmapType.toLower(), filenamePrefix)));
172 }
173 
~ExportBitmap()174 ExportBitmap::~ExportBitmap()
175 {
176 }
177 
exportPage(ScribusDoc * doc,uint pageNr,bool background,bool single=true)178 bool ExportBitmap::exportPage(ScribusDoc* doc, uint pageNr, bool background, bool single = true)
179 {
180 	uint over   = 0;
181 	bool saved = false, doFileSave = true;
182 	QString fileName(getFileName(doc, pageNr));
183 
184 	if (!doc->Pages->at(pageNr))
185 		return false;
186 	ScPage* page = doc->Pages->at(pageNr);
187 
188 	/* a little magic here - I need to compute the "maxGr" value...
189 	* We need to know the right size of the page for landscape,
190 	* portrait and user defined sizes.
191 	*/
192 	double pixmapSize = (page->height() > page->width()) ? page->height() : page->width();
193 	PageToPixmapFlags flags;
194 	if (background)
195 		flags |= Pixmap_DrawBackground;
196 	QImage im(doc->view()->PageToPixmap(pageNr, qRound(pixmapSize * enlargement * (pageDPI / 72.0) / 100.0), flags));
197 	if (im.isNull())
198 	{
199 		ScMessageBox::warning(doc->scMW(), tr("Save as Image"), tr("Insufficient memory for this image size."));
200 		doc->scMW()->setStatusBarInfoText( tr("Insufficient memory for this image size."));
201 		return false;
202 	}
203 	int dpm = qRound(100.0 / 2.54 * pageDPI);
204 	im.setDotsPerMeterY(dpm);
205 	im.setDotsPerMeterX(dpm);
206 	if (QFile::exists(fileName) && !overwrite)
207 	{
208 		doFileSave = false;
209 		QString fn = QDir::toNativeSeparators(fileName);
210 //		QApplication::restoreOverrideCursor();
211 		QApplication::changeOverrideCursor(Qt::ArrowCursor);
212 		over = ScMessageBox::question(doc->scMW(), tr("File exists. Overwrite?"),
213 				fn +"\n"+ tr("exists already. Overwrite?"),
214 				// hack for multiple overwriting (petr)
215 				(single) ? QMessageBox::Yes | QMessageBox::No : QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll,
216 				QMessageBox::NoButton,	// GUI default
217 				QMessageBox::YesToAll);	// batch default
218 		QApplication::changeOverrideCursor(QCursor(Qt::WaitCursor));
219 		if (over == QMessageBox::Yes || over == QMessageBox::YesToAll)
220 			doFileSave = true;
221 		if (over == QMessageBox::YesToAll)
222 			overwrite = true;
223 	}
224 	if (doFileSave)
225 		saved = im.save(fileName, bitmapType.toLocal8Bit().constData(), quality);
226 	if (!saved && doFileSave)
227 	{
228 		ScMessageBox::warning(doc->scMW(), tr("Save as Image"), tr("Error writing the output file(s)."));
229 		doc->scMW()->setStatusBarInfoText( tr("Error writing the output file(s)."));
230 	}
231 	return saved;
232 }
233 
exportCurrent(ScribusDoc * doc,bool background)234 bool ExportBitmap::exportCurrent(ScribusDoc* doc,  bool background)
235 {
236 	return exportPage(doc, doc->currentPageNumber(), background, true);
237 }
238 
exportInterval(ScribusDoc * doc,std::vector<int> & pageNs,bool background)239 bool ExportBitmap::exportInterval(ScribusDoc* doc, std::vector<int> &pageNs, bool background)
240 {
241 	doc->scMW()->mainWindowProgressBar->setMaximum(pageNs.size());
242 	for (uint a = 0; a < pageNs.size(); ++a)
243 	{
244 		doc->scMW()->mainWindowProgressBar->setValue(a);
245 		if (!exportPage(doc, pageNs[a]-1, background, false))
246 			return false;
247 	}
248 	return true;
249 }
250