1 /*
2
3 Copyright 2013 Alexander Volkov
4 Copyright 2013 Adam Reichold
5
6 This file is part of qpdfview.
7
8 qpdfview is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 qpdfview is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with qpdfview. If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23 #include "psmodel.h"
24
25 #include <QFile>
26 #include <QFormLayout>
27 #include <qmath.h>
28 #include <QSettings>
29 #include <QSpinBox>
30
31 #include <libspectre/spectre-document.h>
32
33 namespace
34 {
35
36 using namespace qpdfview;
37 using namespace qpdfview::Model;
38
39 namespace Defaults
40 {
41
42 const int graphicsAntialiasBits = 4;
43 const int textAntialiasBits = 2;
44
45 } // Defaults
46
47 } // anonymous
48
49 namespace qpdfview
50 {
51
52 namespace Model
53 {
54
PsPage(QMutex * mutex,SpectrePage * page,SpectreRenderContext * renderContext)55 PsPage::PsPage(QMutex* mutex, SpectrePage* page, SpectreRenderContext* renderContext) :
56 m_mutex(mutex),
57 m_page(page),
58 m_renderContext(renderContext)
59 {
60 }
61
~PsPage()62 PsPage::~PsPage()
63 {
64 spectre_page_free(m_page);
65 m_page = 0;
66 }
67
size() const68 QSizeF PsPage::size() const
69 {
70 QMutexLocker mutexLocker(m_mutex);
71
72 int w;
73 int h;
74
75 spectre_page_get_size(m_page, &w, &h);
76
77 return QSizeF(w, h);
78 }
79
render(qreal horizontalResolution,qreal verticalResolution,Rotation rotation,QRect boundingRect) const80 QImage PsPage::render(qreal horizontalResolution, qreal verticalResolution, Rotation rotation, QRect boundingRect) const
81 {
82 QMutexLocker mutexLocker(m_mutex);
83
84 double xscale;
85 double yscale;
86
87 switch(rotation)
88 {
89 default:
90 case RotateBy0:
91 case RotateBy180:
92 xscale = horizontalResolution / 72.0;
93 yscale = verticalResolution / 72.0;
94 break;
95 case RotateBy90:
96 case RotateBy270:
97 xscale = verticalResolution / 72.0;
98 yscale = horizontalResolution / 72.0;
99 break;
100 }
101
102 spectre_render_context_set_scale(m_renderContext, xscale, yscale);
103
104 switch(rotation)
105 {
106 default:
107 case RotateBy0:
108 spectre_render_context_set_rotation(m_renderContext, 0);
109 break;
110 case RotateBy90:
111 spectre_render_context_set_rotation(m_renderContext, 90);
112 break;
113 case RotateBy180:
114 spectre_render_context_set_rotation(m_renderContext, 180);
115 break;
116 case RotateBy270:
117 spectre_render_context_set_rotation(m_renderContext, 270);
118 break;
119 }
120
121 int w;
122 int h;
123
124 spectre_page_get_size(m_page, &w, &h);
125
126 w = qRound(w * xscale);
127 h = qRound(h * yscale);
128
129 if(rotation == RotateBy90 || rotation == RotateBy270)
130 {
131 qSwap(w, h);
132 }
133
134 unsigned char* pageData = 0;
135 int rowLength = 0;
136
137 spectre_page_render(m_page, m_renderContext, &pageData, &rowLength);
138
139 if (spectre_page_status(m_page) != SPECTRE_STATUS_SUCCESS)
140 {
141 free(pageData);
142 pageData = 0;
143
144 return QImage();
145 }
146
147 QImage auxiliaryImage(pageData, rowLength / 4, h, QImage::Format_RGB32);
148 QImage image(boundingRect.isNull() ? auxiliaryImage.copy(0, 0, w, h) : auxiliaryImage.copy(boundingRect));
149
150 free(pageData);
151 pageData = 0;
152
153 return image;
154 }
155
PsDocument(SpectreDocument * document,SpectreRenderContext * renderContext)156 PsDocument::PsDocument(SpectreDocument* document, SpectreRenderContext* renderContext) :
157 m_mutex(),
158 m_document(document),
159 m_renderContext(renderContext)
160 {
161 }
162
~PsDocument()163 PsDocument::~PsDocument()
164 {
165 spectre_render_context_free(m_renderContext);
166 m_renderContext = 0;
167
168 spectre_document_free(m_document);
169 m_document = 0;
170 }
171
numberOfPages() const172 int PsDocument::numberOfPages() const
173 {
174 QMutexLocker mutexLocker(&m_mutex);
175
176 return spectre_document_get_n_pages(m_document);
177 }
178
page(int index) const179 Page* PsDocument::page(int index) const
180 {
181 QMutexLocker mutexLocker(&m_mutex);
182
183 if(SpectrePage* page = spectre_document_get_page(m_document, index))
184 {
185 return new PsPage(&m_mutex, page, m_renderContext);
186 }
187
188 return 0;
189 }
190
saveFilter() const191 QStringList PsDocument::saveFilter() const
192 {
193 QMutexLocker mutexLocker(&m_mutex);
194
195 if(spectre_document_is_eps(m_document))
196 {
197 return QStringList() << QLatin1String("Encapsulated PostScript (*.eps)");
198 }
199 else
200 {
201 return QStringList() << QLatin1String("PostScript (*.ps)");
202 }
203 }
204
canSave() const205 bool PsDocument::canSave() const
206 {
207 return true;
208 }
209
save(const QString & filePath,bool withChanges) const210 bool PsDocument::save(const QString& filePath, bool withChanges) const
211 {
212 Q_UNUSED(withChanges)
213
214 QMutexLocker mutexLocker(&m_mutex);
215
216 spectre_document_save(m_document, QFile::encodeName(filePath));
217
218 return spectre_document_status(m_document) == SPECTRE_STATUS_SUCCESS;
219 }
220
canBePrintedUsingCUPS() const221 bool PsDocument::canBePrintedUsingCUPS() const
222 {
223 return true;
224 }
225
properties() const226 Properties PsDocument::properties() const
227 {
228 Properties properties;
229
230 QMutexLocker mutexLocker(&m_mutex);
231
232 const QString title = QString::fromLocal8Bit(spectre_document_get_title(m_document));
233 const QString createdFor = QString::fromLocal8Bit(spectre_document_get_for(m_document));
234 const QString creator = QString::fromLocal8Bit(spectre_document_get_creator(m_document));
235 const QString creationDate = QString::fromLocal8Bit(spectre_document_get_creation_date(m_document));
236 const QString format = QString::fromLocal8Bit(spectre_document_get_format(m_document));
237 const QString languageLevel = QString::number(spectre_document_get_language_level(m_document));
238
239 properties.push_back(qMakePair(tr("Title"), title));
240 properties.push_back(qMakePair(tr("Created for"), createdFor));
241 properties.push_back(qMakePair(tr("Creator"), creator));
242 properties.push_back(qMakePair(tr("Creation date"), creationDate));
243 properties.push_back(qMakePair(tr("Format"), format));
244 properties.push_back(qMakePair(tr("Language level"), languageLevel));
245
246 return properties;
247 }
248
249 } // Model
250
PsSettingsWidget(QSettings * settings,QWidget * parent)251 PsSettingsWidget::PsSettingsWidget(QSettings* settings, QWidget* parent) : SettingsWidget(parent),
252 m_settings(settings)
253 {
254 m_layout = new QFormLayout(this);
255
256 // graphics antialias bits
257
258 m_graphicsAntialiasBitsSpinBox = new QSpinBox(this);
259 m_graphicsAntialiasBitsSpinBox->setRange(1, 4);
260 m_graphicsAntialiasBitsSpinBox->setValue(m_settings->value("graphicsAntialiasBits", Defaults::graphicsAntialiasBits).toInt());
261
262 m_layout->addRow(tr("Graphics antialias bits:"), m_graphicsAntialiasBitsSpinBox);
263
264 // text antialias bits
265
266 m_textAntialiasBitsSpinBox = new QSpinBox(this);
267 m_textAntialiasBitsSpinBox->setRange(1, 2);
268 m_textAntialiasBitsSpinBox->setValue(m_settings->value("textAntialiasBits", Defaults::textAntialiasBits).toInt());
269
270 m_layout->addRow(tr("Text antialias bits:"), m_textAntialiasBitsSpinBox);
271 }
272
accept()273 void PsSettingsWidget::accept()
274 {
275 m_settings->setValue("graphicsAntialiasBits", m_graphicsAntialiasBitsSpinBox->value());
276 m_settings->setValue("textAntialiasBits", m_textAntialiasBitsSpinBox->value());
277 }
278
reset()279 void PsSettingsWidget::reset()
280 {
281 m_graphicsAntialiasBitsSpinBox->setValue(Defaults::graphicsAntialiasBits);
282 m_textAntialiasBitsSpinBox->setValue(Defaults::textAntialiasBits);
283 }
284
PsPlugin(QObject * parent)285 PsPlugin::PsPlugin(QObject* parent) : QObject(parent)
286 {
287 setObjectName("PsPlugin");
288
289 m_settings = new QSettings("qpdfview", "ps-plugin", this);
290 }
291
loadDocument(const QString & filePath) const292 Model::Document* PsPlugin::loadDocument(const QString& filePath) const
293 {
294 SpectreDocument* document = spectre_document_new();
295
296 spectre_document_load(document, QFile::encodeName(filePath));
297
298 if (spectre_document_status(document) != SPECTRE_STATUS_SUCCESS)
299 {
300 spectre_document_free(document);
301
302 return 0;
303 }
304
305 SpectreRenderContext* renderContext = spectre_render_context_new();
306
307 spectre_render_context_set_antialias_bits(renderContext,
308 m_settings->value("graphicsAntialiasBits", Defaults::graphicsAntialiasBits).toInt(),
309 m_settings->value("textAntialiasBits", Defaults::textAntialiasBits).toInt());
310
311 return new Model::PsDocument(document, renderContext);
312 }
313
createSettingsWidget(QWidget * parent) const314 SettingsWidget* PsPlugin::createSettingsWidget(QWidget* parent) const
315 {
316 return new PsSettingsWidget(m_settings, parent);
317 }
318
319 } // qpdfview
320
321 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
322
323 Q_EXPORT_PLUGIN2(qpdfview_ps, qpdfview::PsPlugin)
324
325 #endif // QT_VERSION
326