1 /*
2 SPDX-FileCopyrightText: 2013 Akarsh Simha <akarsh.simha@kdemail.net>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 /* Project Includes */
8 #include "imageexporter.h"
9 #include "kstars.h"
10 #include "skyqpainter.h"
11 #include "skymap.h"
12
13 #include <KJob>
14 #include <KIO/StoredTransferJob>
15
16 /* Qt Includes */
17 #include <QTemporaryFile>
18 #include <QStatusBar>
19 #include <QSvgGenerator>
20
ImageExporter(QObject * parent)21 ImageExporter::ImageExporter(QObject *parent) : QObject(parent), m_includeLegend(false), m_Size(nullptr)
22 {
23 m_Legend = new Legend;
24
25 // set font for legend labels
26 m_Legend->setFont(QFont("Courier New", 8));
27
28 // set up the default alpha
29 setLegendAlpha(160);
30 }
31
exportSvg(const QString & fileName)32 void ImageExporter::exportSvg(const QString &fileName)
33 {
34 SkyMap *map = SkyMap::Instance();
35
36 // export as SVG
37 QSvgGenerator svgGenerator;
38 svgGenerator.setFileName(fileName);
39 svgGenerator.setTitle(i18n("KStars Exported Sky Image"));
40 svgGenerator.setDescription(i18n("KStars Exported Sky Image"));
41 svgGenerator.setSize(QSize(map->width(), map->height()));
42 svgGenerator.setResolution(qMax(map->logicalDpiX(), map->logicalDpiY()));
43 svgGenerator.setViewBox(QRect(0, 0, map->width(), map->height()));
44
45 SkyQPainter painter(KStars::Instance(), &svgGenerator);
46 painter.begin();
47
48 map->exportSkyImage(&painter);
49
50 if (m_includeLegend)
51 {
52 addLegend(&painter);
53 }
54
55 painter.end();
56 }
57
exportRasterGraphics(const QString & fileName)58 bool ImageExporter::exportRasterGraphics(const QString &fileName)
59 {
60 //Determine desired image format from filename extension
61 QString ext = fileName.mid(fileName.lastIndexOf(".") + 1);
62
63 // export as raster graphics
64 const char *format = "PNG";
65
66 if (ext.toLower() == "png")
67 {
68 format = "PNG";
69 }
70 else if (ext.toLower() == "jpg" || ext.toLower() == "jpeg")
71 {
72 format = "JPG";
73 }
74 else if (ext.toLower() == "gif")
75 {
76 format = "GIF";
77 }
78 else if (ext.toLower() == "pnm")
79 {
80 format = "PNM";
81 }
82 else if (ext.toLower() == "bmp")
83 {
84 format = "BMP";
85 }
86 else
87 {
88 qWarning() << "Could not parse image format of" << fileName << "assuming PNG";
89 }
90
91 SkyMap *map = SkyMap::Instance();
92
93 int width, height;
94 if (m_Size)
95 {
96 width = m_Size->width();
97 height = m_Size->height();
98 }
99 else
100 {
101 width = map->width();
102 height = map->height();
103 }
104
105 QPixmap skyimage(map->width(), map->height());
106 QPixmap outimage(width, height);
107 outimage.fill();
108
109 map->exportSkyImage(&skyimage);
110 qApp->processEvents();
111
112 //skyImage is the size of the sky map. The requested image size is w x h.
113 //If w x h is smaller than the skymap, then we simply crop the image.
114 //If w x h is larger than the skymap, pad the skymap image with a white border.
115 if (width == map->width() && height == map->height())
116 {
117 outimage = skyimage.copy();
118 }
119
120 else
121 {
122 int dx(0), dy(0), sx(0), sy(0);
123 int sw(map->width()), sh(map->height());
124
125 if (width > map->width())
126 {
127 dx = (width - map->width()) / 2;
128 }
129
130 else
131 {
132 sx = (map->width() - width) / 2;
133 sw = width;
134 }
135
136 if (height > map->height())
137 {
138 dy = (height - map->height()) / 2;
139 }
140
141 else
142 {
143 sy = (map->height() - height) / 2;
144 sh = height;
145 }
146
147 QPainter p;
148 p.begin(&outimage);
149 p.fillRect(outimage.rect(), QBrush(Qt::white));
150 p.drawImage(dx, dy, skyimage.toImage(), sx, sy, sw, sh);
151 p.end();
152 }
153
154 if (m_includeLegend)
155 {
156 addLegend(&outimage);
157 }
158
159 if (!outimage.save(fileName, format))
160 {
161 m_lastErrorMessage = i18n("Error: Unable to save image: %1", fileName);
162 qDebug() << m_lastErrorMessage;
163 return false;
164 }
165
166 else
167 {
168 KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName));
169 return true;
170 }
171 }
addLegend(SkyQPainter * painter)172 void ImageExporter::addLegend(SkyQPainter *painter)
173 {
174 m_Legend->paintLegend(painter);
175 }
176
addLegend(QPaintDevice * pd)177 void ImageExporter::addLegend(QPaintDevice *pd)
178 {
179 SkyQPainter painter(KStars::Instance(), pd);
180 painter.begin();
181
182 addLegend(&painter);
183
184 painter.end();
185 }
186
exportImage(QString url)187 bool ImageExporter::exportImage(QString url)
188 {
189 QUrl fileURL = QUrl::fromUserInput(url);
190
191 m_lastErrorMessage = QString();
192 if (fileURL.isValid())
193 {
194 QTemporaryFile tmpfile;
195 QString fname;
196 bool isLocalFile = fileURL.isLocalFile();
197
198 if (isLocalFile)
199 {
200 fname = fileURL.toLocalFile();
201 }
202
203 else
204 {
205 tmpfile.open();
206 fname = tmpfile.fileName();
207 }
208
209 //Determine desired image format from filename extension
210 QString ext = fname.mid(fname.lastIndexOf(".") + 1);
211 if (ext.toLower() == "svg")
212 {
213 exportSvg(fname);
214 }
215
216 else
217 {
218 return exportRasterGraphics(fname);
219 }
220
221 if (!isLocalFile)
222 {
223 //attempt to upload image to remote location
224 KIO::StoredTransferJob *put_job = KIO::storedHttpPost(&tmpfile, fileURL, -1);
225 //if(!KIO::NetAccess::upload(tmpfile.fileName(), fileURL, m_KStars))
226 if (put_job->exec() == false)
227 {
228 m_lastErrorMessage = i18n("Could not upload image to remote location: %1", fileURL.url());
229 qWarning() << m_lastErrorMessage;
230 return false;
231 }
232 }
233 return true;
234 }
235 m_lastErrorMessage = i18n("Could not export image: URL %1 invalid", fileURL.url());
236 qWarning() << m_lastErrorMessage;
237 return false;
238 }
239
setLegendProperties(Legend::LEGEND_TYPE type,Legend::LEGEND_ORIENTATION orientation,Legend::LEGEND_POSITION position,int alpha,bool include)240 void ImageExporter::setLegendProperties(Legend::LEGEND_TYPE type, Legend::LEGEND_ORIENTATION orientation,
241 Legend::LEGEND_POSITION position, int alpha, bool include)
242 {
243 // set background color (alpha)
244 setLegendAlpha(alpha);
245 // set legend orientation
246 m_Legend->setOrientation(orientation);
247
248 // set legend type
249 m_Legend->setType(type);
250
251 // set legend position
252 m_Legend->setPosition(position);
253
254 m_includeLegend = include;
255 }
256
~ImageExporter()257 ImageExporter::~ImageExporter()
258 {
259 delete m_Legend;
260 }
261
setRasterOutputSize(const QSize * size)262 void ImageExporter::setRasterOutputSize(const QSize *size)
263 {
264 if (size)
265 m_Size = new QSize(*size); // make a copy, so it's safe if the original gets deleted
266 else
267 m_Size = nullptr;
268 }
269
setLegendAlpha(int alpha)270 void ImageExporter::setLegendAlpha(int alpha)
271 {
272 Q_ASSERT(alpha >= 0 && alpha <= 255);
273 Q_ASSERT(m_Legend);
274 QColor bgColor = m_Legend->getBgColor();
275 bgColor.setAlpha(alpha);
276 m_Legend->setBgColor(bgColor);
277 }
278