File indexing completed on 2025-01-19 03:57:01

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2021-07-24
0007  * Description : frame on screen display.
0008  *
0009  * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2021      by Quoc Hưng Tran <quochungtran1999 at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "frameosd.h"
0017 
0018 // Qt includes
0019 
0020 #include <QString>
0021 #include <QBuffer>
0022 #include <QApplication>
0023 #include <QFontMetrics>
0024 #include <QPainter>
0025 
0026 // KDE includes
0027 
0028 #include <klocalizedstring.h>
0029 
0030 // Local includes
0031 
0032 #include "digikam_debug.h"
0033 #include "itempropertiestab.h"
0034 
0035 namespace Digikam
0036 {
0037 
0038 FrameOsd::FrameOsd()
0039   : m_desc     (QLatin1String("")),
0040     m_descPos  (QPoint(10, 10)),
0041     m_descFnt  (QFont(QLatin1String("Monospace"))),
0042     m_descAlign(Qt::AlignLeft),
0043     m_descBg   (Qt::darkGray)
0044 {
0045     m_descFnt.setStyleHint(QFont::Monospace);
0046     m_descFnt.setPixelSize(8);
0047     m_descFnt.setBold(true);
0048 }
0049 
0050 FrameOsd::~FrameOsd()
0051 {
0052 }
0053 
0054 void FrameOsd::populateOSD(const QUrl& url,
0055                            const FrameOsdSettings& settings,
0056                            DInfoInterface* const iface)
0057 {
0058     // First stage is to get the information map from host application.
0059 
0060     DItemInfo item(iface->itemInfo(url));
0061 
0062     QString comment               = item.comment();
0063     QString title                 = item.title();
0064     QStringList tags              = item.keywords();
0065     int rating                    = item.rating();
0066     m_descFnt                     = settings.osdFont;
0067 
0068     QString str;
0069 
0070     // Display image File Name.
0071 
0072     if (settings.printName)
0073     {
0074         str.clear();
0075         QString name = url.fileName();
0076 
0077         if (!name.isEmpty())
0078         {
0079             str     += name;
0080             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0081         }
0082     }
0083 
0084     // Display Creation Date.
0085 
0086     if (settings.printDate)
0087     {
0088         str.clear();
0089         QDateTime dateTime = item.dateTime();
0090 
0091         if (dateTime.isValid())
0092         {
0093             str = QLocale().toString(dateTime, QLocale::ShortFormat);
0094             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0095         }
0096     }
0097 
0098     // Display tag names.
0099 
0100     if (settings.printTags)
0101     {
0102         printTags(tags);
0103     }
0104 
0105     // Display descs.
0106 
0107     if (settings.printTitle)
0108     {
0109         str.clear();
0110 
0111         if (!title.isEmpty())
0112         {
0113             str     += title;
0114             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0115         }
0116     }
0117 
0118     // Display Captions if no Titles.
0119 
0120     if (settings.printCapIfNoTitle)
0121     {
0122         str.clear();
0123 
0124         if (title.isEmpty())
0125         {
0126             str     += comment;
0127             printComments(str);
0128         }
0129     }
0130 
0131     //  Display Comments.
0132 
0133     if (settings.printComment)
0134     {
0135         str.clear();
0136 
0137         if (title.isEmpty())
0138         {
0139             str     += comment;
0140             printComments(str);
0141         }
0142     }
0143 
0144     // Display Make and Model.
0145 
0146     if (settings.printMakeModel)
0147     {
0148         str.clear();
0149 
0150         QString make  = item.make();
0151         QString model = item.model();
0152 
0153         if (!make.isEmpty())
0154         {
0155             ItemPropertiesTab::shortenedMakeInfo(make);
0156             str      = make;
0157         }
0158 
0159         if (!model.isEmpty())
0160         {
0161             if (!make.isEmpty())
0162             {
0163                 str += QLatin1String(" / ");
0164             }
0165 
0166             ItemPropertiesTab::shortenedModelInfo(model);
0167             str     += model;
0168         }
0169 
0170         if (!str.isEmpty())
0171         {
0172             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0173         }
0174     }
0175 
0176     // Display Lens model.
0177 
0178     if (settings.printLensModel)
0179     {
0180         str.clear();
0181 
0182         QString lens = item.lens();
0183 
0184         if (!lens.isEmpty())
0185         {
0186             str     += lens;
0187             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0188         }
0189     }
0190 
0191     // Display Exposure and Sensitivity.
0192 
0193     if (settings.printExpoSensitivity)
0194     {
0195         str.clear();
0196 
0197         QString exposureTime = item.exposureTime();
0198         QString sensitivity  = item.sensitivity();
0199 
0200         if (!exposureTime.isEmpty())
0201         {
0202             str = exposureTime;
0203         }
0204 
0205         if (!sensitivity.isEmpty())
0206         {
0207             if (!exposureTime.isEmpty())
0208             {
0209                 str += QLatin1String(" / ");
0210             }
0211 
0212             str += i18n("%1 ISO", sensitivity);
0213         }
0214 
0215         if (!str.isEmpty())
0216         {
0217             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0218         }
0219     }
0220 
0221     // Display Aperture and Focal.
0222 
0223     if (settings.printApertureFocal)
0224     {
0225         str.clear();
0226 
0227         QString aperture        = item.aperture();
0228         QString focalLength     = item.focalLength();
0229         QString focalLength35mm = item.focalLength35mm();
0230 
0231         if (!aperture.isEmpty())
0232         {
0233             str = aperture;
0234         }
0235 
0236         if (focalLength35mm.isEmpty())
0237         {
0238             if (!focalLength.isEmpty())
0239             {
0240                 if (!aperture.isEmpty())
0241                 {
0242                     str += QLatin1String(" / ");
0243                 }
0244 
0245                 str += focalLength;
0246             }
0247         }
0248         else
0249         {
0250             if (!aperture.isEmpty())
0251             {
0252                 str += QLatin1String(" / ");
0253             }
0254 
0255             if (!focalLength.isEmpty())
0256             {
0257                 str += QString::fromUtf8("%1 (%2)").arg(focalLength).arg(focalLength35mm);
0258             }
0259             else
0260             {
0261                 str += QString::fromUtf8("%1").arg(focalLength35mm);
0262             }
0263         }
0264 
0265         if (!str.isEmpty())
0266         {
0267             m_desc.append(QString::fromLatin1("\n%1").arg(str));
0268         }
0269     }
0270 
0271 
0272     // Display rating
0273 
0274     if (settings.printRating)
0275     {
0276         if (rating != -1)
0277         {
0278             m_desc.append(QString::fromLatin1("\n%1/5").arg(rating));
0279         }
0280     }
0281 
0282     m_desc.append(QString::fromLatin1("\n"));
0283 }
0284 
0285 void FrameOsd::printTags(QStringList& tags)
0286 {
0287     tags.removeDuplicates();
0288     tags.sort();
0289 
0290     QString str = tags.join(QLatin1String(", "));
0291 
0292     if (!str.isEmpty())
0293     {
0294         m_desc.append(QString::fromLatin1("%1").arg(str));
0295     }
0296 }
0297 
0298 void FrameOsd::printComments(const QString& comments)
0299 {
0300     QStringList commentsByLines;
0301 
0302     uint commentsIndex = 0;     // Comments QString index
0303 
0304     while (commentsIndex < (uint)comments.length())
0305     {
0306         QString newLine;
0307         bool breakLine = false; // End Of Line found
0308         uint currIndex;         // Comments QString current index
0309 
0310         // Check minimal lines dimension
0311 
0312         uint maxStringLen = 80;
0313 
0314         uint commentsLinesLengthLocal = maxStringLen;
0315 
0316         for (currIndex = commentsIndex ;
0317              (currIndex < (uint)comments.length()) && !breakLine ; ++currIndex)
0318         {
0319             if ((comments.at(currIndex) == QLatin1Char('\n')) || comments.at(currIndex).isSpace())
0320             {
0321                 breakLine = true;
0322             }
0323         }
0324 
0325         if (commentsLinesLengthLocal <= (currIndex - commentsIndex))
0326         {
0327             commentsLinesLengthLocal = (currIndex - commentsIndex);
0328         }
0329 
0330         breakLine = false;
0331 
0332         for (currIndex = commentsIndex ;
0333              (currIndex <= (commentsIndex + commentsLinesLengthLocal)) &&
0334              (currIndex < (uint)comments.length()) && !breakLine ;
0335              ++currIndex)
0336         {
0337             breakLine = (comments.at(currIndex) == QLatin1Char('\n')) ? true : false;
0338 
0339             if (breakLine)
0340             {
0341                 newLine.append(QLatin1Char(' '));
0342             }
0343             else
0344             {
0345                 newLine.append(comments.at(currIndex));
0346             }
0347         }
0348 
0349         commentsIndex = currIndex; // The line is ended
0350 
0351         if (commentsIndex != (uint)comments.length())
0352         {
0353             while (!newLine.endsWith(QLatin1Char(' ')))
0354             {
0355                 newLine.truncate(newLine.length() - 1);
0356                 --commentsIndex;
0357             }
0358         }
0359 
0360         commentsByLines.prepend(newLine.trimmed());
0361     }
0362 
0363     for (int i = 0 ; i < (int)commentsByLines.count() ; ++i)
0364     {
0365         m_desc.append(QString::fromLatin1("\n%1").arg(commentsByLines.at(i)));
0366     }
0367 }
0368 
0369 void FrameOsd::insertOsdToFrame(QImage& frm,
0370                                 const QUrl& url,
0371                                 const FrameOsdSettings& settings,
0372                                 DInfoInterface* const iface)
0373 {
0374     // Populate items properties based on url,
0375     // eg. album name, rating, tags, labels, date, etc.
0376 
0377     populateOSD(url, settings, iface);
0378 
0379     QPainter p(&frm);
0380 
0381     QFontMetrics descMt(m_descFnt);
0382     p.setFont(m_descFnt);
0383 
0384     QRect descRect = descMt.boundingRect(0, 0, frm.width(), frm.height(), 0, m_desc);
0385     QRect bgdescRect(m_descPos.x(),
0386                      m_descPos.y(),
0387                      descRect.width(),
0388                      descRect.height() + 3);
0389 
0390     p.fillRect(bgdescRect, m_descBg);
0391 
0392     p.setPen(QPen(Qt::white));
0393     p.drawText(bgdescRect, m_descAlign, m_desc);
0394 
0395     m_desc.clear();
0396 }
0397 
0398 void FrameOsd::insertMessageOsdToFrame(QImage& frm,
0399                                        const QSize& JPEGsize,
0400                                        const QString& mess)
0401 {
0402     QPoint messPos          = QPoint(10, 10);
0403     Qt::Alignment messAlign = Qt::AlignLeft;
0404     QColor messBg           = Qt::darkGray;
0405     QFont messFnt           = QFont(QLatin1String("Monospace"));
0406 
0407     messFnt.setStyleHint(QFont::Monospace);
0408     messFnt.setBold(true);
0409 
0410     if ((JPEGsize.width() <= 480) && (JPEGsize.height() <= 480))
0411     {
0412         messFnt.setPixelSize(18);
0413     }
0414     else
0415     {
0416         messFnt.setPixelSize(60);
0417     }
0418 
0419     //---
0420 
0421     QPainter p(&frm);
0422     p.setFont(messFnt);
0423 
0424     QFontMetrics messMt(messFnt);
0425 
0426     QRect messRect = messMt.boundingRect(0, 0, frm.width(), frm.height(), 0, mess);
0427 
0428     // print message in the middle of frame
0429 
0430     QRect bgErreurRect(messPos.x(),
0431                        messPos.y(),
0432                        messRect.width(),
0433                        messRect.height() + 3);
0434 
0435     p.fillRect(bgErreurRect, messBg);
0436 
0437     p.setPen(QPen(Qt::white));
0438     p.drawText(bgErreurRect, messAlign, mess);
0439 }
0440 
0441 } // namespace Digikam