File indexing completed on 2024-04-21 14:43:59

0001 /*
0002     SPDX-FileCopyrightText: 2013 Akarsh Simha <akarsh.simha@kdemail.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /* Project Includes */
0008 #include "imageexporter.h"
0009 #include "kstars.h"
0010 #include "skyqpainter.h"
0011 #include "skymap.h"
0012 
0013 #include <KJob>
0014 #include <KIO/StoredTransferJob>
0015 
0016 /* Qt Includes */
0017 #include <QTemporaryFile>
0018 #include <QStatusBar>
0019 #include <QSvgGenerator>
0020 #include <QApplication>
0021 
0022 ImageExporter::ImageExporter(QObject *parent) : QObject(parent), m_includeLegend(false), m_Size(nullptr)
0023 {
0024     m_Legend = new Legend;
0025 
0026     // set font for legend labels
0027     m_Legend->setFont(QFont("Courier New", 8));
0028 
0029     // set up the default alpha
0030     setLegendAlpha(160);
0031 }
0032 
0033 void ImageExporter::exportSvg(const QString &fileName)
0034 {
0035     SkyMap *map = SkyMap::Instance();
0036 
0037     // export as SVG
0038     QSvgGenerator svgGenerator;
0039     svgGenerator.setFileName(fileName);
0040     svgGenerator.setTitle(i18n("KStars Exported Sky Image"));
0041     svgGenerator.setDescription(i18n("KStars Exported Sky Image"));
0042     svgGenerator.setSize(QSize(map->width(), map->height()));
0043     svgGenerator.setResolution(qMax(map->logicalDpiX(), map->logicalDpiY()));
0044     svgGenerator.setViewBox(QRect(0, 0, map->width(), map->height()));
0045 
0046     SkyQPainter painter(KStars::Instance(), &svgGenerator);
0047     painter.begin();
0048 
0049     map->exportSkyImage(&painter);
0050 
0051     if (m_includeLegend)
0052     {
0053         addLegend(&painter);
0054     }
0055 
0056     painter.end();
0057 }
0058 
0059 bool ImageExporter::exportRasterGraphics(const QString &fileName)
0060 {
0061     //Determine desired image format from filename extension
0062     QString ext = fileName.mid(fileName.lastIndexOf(".") + 1);
0063 
0064     // export as raster graphics
0065     const char *format = "PNG";
0066 
0067     if (ext.toLower() == "png")
0068     {
0069         format = "PNG";
0070     }
0071     else if (ext.toLower() == "jpg" || ext.toLower() == "jpeg")
0072     {
0073         format = "JPG";
0074     }
0075     else if (ext.toLower() == "gif")
0076     {
0077         format = "GIF";
0078     }
0079     else if (ext.toLower() == "pnm")
0080     {
0081         format = "PNM";
0082     }
0083     else if (ext.toLower() == "bmp")
0084     {
0085         format = "BMP";
0086     }
0087     else
0088     {
0089         qWarning() << "Could not parse image format of" << fileName << "assuming PNG";
0090     }
0091 
0092     SkyMap *map = SkyMap::Instance();
0093 
0094     int width, height;
0095     if (m_Size)
0096     {
0097         width  = m_Size->width();
0098         height = m_Size->height();
0099     }
0100     else
0101     {
0102         width  = map->width();
0103         height = map->height();
0104     }
0105 
0106     QPixmap skyimage(map->width(), map->height());
0107     QPixmap outimage(width, height);
0108     outimage.fill();
0109 
0110     map->exportSkyImage(&skyimage);
0111     qApp->processEvents();
0112 
0113     //skyImage is the size of the sky map.  The requested image size is w x h.
0114     //If w x h is smaller than the skymap, then we simply crop the image.
0115     //If w x h is larger than the skymap, pad the skymap image with a white border.
0116     if (width == map->width() && height == map->height())
0117     {
0118         outimage = skyimage.copy();
0119     }
0120 
0121     else
0122     {
0123         int dx(0), dy(0), sx(0), sy(0);
0124         int sw(map->width()), sh(map->height());
0125 
0126         if (width > map->width())
0127         {
0128             dx = (width - map->width()) / 2;
0129         }
0130 
0131         else
0132         {
0133             sx = (map->width() - width) / 2;
0134             sw = width;
0135         }
0136 
0137         if (height > map->height())
0138         {
0139             dy = (height - map->height()) / 2;
0140         }
0141 
0142         else
0143         {
0144             sy = (map->height() - height) / 2;
0145             sh = height;
0146         }
0147 
0148         QPainter p;
0149         p.begin(&outimage);
0150         p.fillRect(outimage.rect(), QBrush(Qt::white));
0151         p.drawImage(dx, dy, skyimage.toImage(), sx, sy, sw, sh);
0152         p.end();
0153     }
0154 
0155     if (m_includeLegend)
0156     {
0157         addLegend(&outimage);
0158     }
0159 
0160     if (!outimage.save(fileName, format))
0161     {
0162         m_lastErrorMessage = i18n("Error: Unable to save image: %1", fileName);
0163         qDebug() << Q_FUNC_INFO << m_lastErrorMessage;
0164         return false;
0165     }
0166 
0167     else
0168     {
0169         KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName));
0170         return true;
0171     }
0172 }
0173 void ImageExporter::addLegend(SkyQPainter *painter)
0174 {
0175     m_Legend->paintLegend(painter);
0176 }
0177 
0178 void ImageExporter::addLegend(QPaintDevice *pd)
0179 {
0180     SkyQPainter painter(KStars::Instance(), pd);
0181     painter.begin();
0182 
0183     addLegend(&painter);
0184 
0185     painter.end();
0186 }
0187 
0188 bool ImageExporter::exportImage(QString url)
0189 {
0190     QUrl fileURL = QUrl::fromUserInput(url);
0191 
0192     m_lastErrorMessage = QString();
0193     if (fileURL.isValid())
0194     {
0195         QTemporaryFile tmpfile;
0196         QString fname;
0197         bool isLocalFile = fileURL.isLocalFile();
0198 
0199         if (isLocalFile)
0200         {
0201             fname = fileURL.toLocalFile();
0202         }
0203 
0204         else
0205         {
0206             tmpfile.open();
0207             fname = tmpfile.fileName();
0208         }
0209 
0210         //Determine desired image format from filename extension
0211         QString ext = fname.mid(fname.lastIndexOf(".") + 1);
0212         if (ext.toLower() == "svg")
0213         {
0214             exportSvg(fname);
0215         }
0216 
0217         else
0218         {
0219             return exportRasterGraphics(fname);
0220         }
0221 
0222         if (!isLocalFile)
0223         {
0224             //attempt to upload image to remote location
0225             KIO::StoredTransferJob *put_job = KIO::storedHttpPost(&tmpfile, fileURL, -1);
0226             //if(!KIO::NetAccess::upload(tmpfile.fileName(), fileURL, m_KStars))
0227             if (put_job->exec() == false)
0228             {
0229                 m_lastErrorMessage = i18n("Could not upload image to remote location: %1", fileURL.url());
0230                 qWarning() << m_lastErrorMessage;
0231                 return false;
0232             }
0233         }
0234         return true;
0235     }
0236     m_lastErrorMessage = i18n("Could not export image: URL %1 invalid", fileURL.url());
0237     qWarning() << m_lastErrorMessage;
0238     return false;
0239 }
0240 
0241 void ImageExporter::setLegendProperties(Legend::LEGEND_TYPE type, Legend::LEGEND_ORIENTATION orientation,
0242                                         Legend::LEGEND_POSITION position, int alpha, bool include)
0243 {
0244     // set background color (alpha)
0245     setLegendAlpha(alpha);
0246     // set legend orientation
0247     m_Legend->setOrientation(orientation);
0248 
0249     // set legend type
0250     m_Legend->setType(type);
0251 
0252     // set legend position
0253     m_Legend->setPosition(position);
0254 
0255     m_includeLegend = include;
0256 }
0257 
0258 ImageExporter::~ImageExporter()
0259 {
0260     delete m_Legend;
0261 }
0262 
0263 void ImageExporter::setRasterOutputSize(const QSize *size)
0264 {
0265     if (size)
0266         m_Size = new QSize(*size); // make a copy, so it's safe if the original gets deleted
0267     else
0268         m_Size = nullptr;
0269 }
0270 
0271 void ImageExporter::setLegendAlpha(int alpha)
0272 {
0273     Q_ASSERT(alpha >= 0 && alpha <= 255);
0274     Q_ASSERT(m_Legend);
0275     QColor bgColor = m_Legend->getBgColor();
0276     bgColor.setAlpha(alpha);
0277     m_Legend->setBgColor(bgColor);
0278 }