Add text overlays

This commit is contained in:
Manuel Dewald
2021-03-04 14:40:11 +01:00
parent c84f01434e
commit d4beb46f28
7 changed files with 262 additions and 4 deletions

View File

@@ -16,7 +16,7 @@ This project is maintained by myself during my spare time. If you like and use i
## Usage ## Usage
``` ```
slide [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder -r slide [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-O overlay_string]
``` ```
* `image_folder`: where to search for images (.jpg files) * `image_folder`: where to search for images (.jpg files)
@@ -26,6 +26,17 @@ slide [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p
* `rotation_seconds(default=30)`: time until next random image is chosen from the given folder * `rotation_seconds(default=30)`: time until next random image is chosen from the given folder
* `background_opacity(default=150)`: opacity of the background filling image between 0 (black background) and 255 * `background_opacity(default=150)`: opacity of the background filling image between 0 (black background) and 255
* `blur_radius(default=20)`: blur radius of the background filling image * `blur_radius(default=20)`: blur radius of the background filling image
* `-O` is used to create a overlay string.
* It defines overlays for all four edges in the order `top-left;top-right;bottom-left;bottom-right`
* All edges overlays are separated by `;`
* Each edge can either be just a test or contain formatting in the form `margin|fontsize|text`
* the text can contain special strings which are replaced during rendering:
* `<time>` current time
* `<date>` current date
* `<datetime>` current time and date
* `<filename>` filename of the current image
* `<exifdatetime>` time stamp from the EXIF data of the image
* Example: `slide -p ./images -O "20|60|Time: <time>;;;Picture taken at <exifdatetime>"`
## Dependencies ## Dependencies

View File

@@ -2,6 +2,7 @@
#include "imageselector.h" #include "imageselector.h"
#include "imageswitcher.h" #include "imageswitcher.h"
#include "pathtraverser.h" #include "pathtraverser.h"
#include "overlay.h"
#include <QApplication> #include <QApplication>
#include <iostream> #include <iostream>
#include <sys/file.h> #include <sys/file.h>
@@ -28,7 +29,8 @@ int main(int argc, char *argv[])
bool recursive = false; bool recursive = false;
bool shuffle = false; bool shuffle = false;
bool sorted = false; bool sorted = false;
while ((opt = getopt(argc, argv, "b:p:t:o:rsS")) != -1) { std::string overlay = "";
while ((opt = getopt(argc, argv, "b:p:t:o:O:rsS")) != -1) {
switch (opt) { switch (opt) {
case 'p': case 'p':
path = optarg; path = optarg;
@@ -52,6 +54,9 @@ int main(int argc, char *argv[])
case 'S': case 'S':
sorted = true; sorted = true;
break; break;
case 'O':
overlay = optarg;
break;
default: /* '?' */ default: /* '?' */
usage(argv[0]); usage(argv[0]);
return 1; return 1;
@@ -88,7 +93,9 @@ int main(int argc, char *argv[])
{ {
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser)); selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser));
} }
std::cout << "Overlay input: " << overlay << std::endl;
Overlay o(overlay);
w.setOverlay(&o);
w.show(); w.show();
ImageSwitcher switcher(w, rotationSeconds * 1000, selector); ImageSwitcher switcher(w, rotationSeconds * 1000, selector);

View File

@@ -1,4 +1,5 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "overlay.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include <QLabel> #include <QLabel>
#include <QPixmap> #include <QPixmap>
@@ -9,6 +10,7 @@
#include <iostream> #include <iostream>
#include <QPainter> #include <QPainter>
#include <QTimer> #include <QTimer>
#include <QRect>
#include <QGraphicsScene> #include <QGraphicsScene>
#include <QGraphicsPixmapItem> #include <QGraphicsPixmapItem>
#include <sstream> #include <sstream>
@@ -100,6 +102,14 @@ void MainWindow::updateImage()
QPixmap rotated = getRotatedPixmap(p); QPixmap rotated = getRotatedPixmap(p);
QPixmap scaled = getScaledPixmap(rotated); QPixmap scaled = getScaledPixmap(rotated);
if (overlay != NULL)
{
drawText(scaled, overlay->getMarginTopLeft(), overlay->getFontsizeTopLeft(), overlay->getRenderedTopLeft(currentImage).c_str(), Qt::AlignTop|Qt::AlignLeft);
drawText(scaled, overlay->getMarginTopRight(), overlay->getFontsizeTopRight(), overlay->getRenderedTopRight(currentImage).c_str(), Qt::AlignTop|Qt::AlignRight);
drawText(scaled, overlay->getMarginBottomLeft(), overlay->getFontsizeBottomLeft(), overlay->getRenderedBottomLeft(currentImage).c_str(), Qt::AlignBottom|Qt::AlignLeft);
drawText(scaled, overlay->getMarginBottomRight(), overlay->getFontsizeBottomRight(), overlay->getRenderedBottomRight(currentImage).c_str(), Qt::AlignBottom|Qt::AlignRight);
}
QLabel *label = this->findChild<QLabel*>("image"); QLabel *label = this->findChild<QLabel*>("image");
label->setPixmap(scaled); label->setPixmap(scaled);
@@ -112,6 +122,24 @@ void MainWindow::updateImage()
update(); update();
} }
void MainWindow::drawText(QPixmap& image, int margin, int fontsize, QString text, int alignment) {
//std::cout << "text: " << text.toStdString() << " margin: " << margin << " fontsize: " << fontsize<< std::endl;
QPainter pt(&image);
pt.setPen(QPen(Qt::white));
pt.setFont(QFont("Sans", fontsize, QFont::Bold));
QRect marginRect = image.rect().adjusted(
margin,
margin,
margin*-1,
margin*-1);
pt.drawText(marginRect, alignment, text);
}
void MainWindow::setOverlay(Overlay* o)
{
overlay = o;
}
QPixmap MainWindow::getRotatedPixmap(const QPixmap& p) QPixmap MainWindow::getRotatedPixmap(const QPixmap& p)
{ {
QMatrix matrix; QMatrix matrix;

View File

@@ -9,6 +9,7 @@ class MainWindow;
} }
class QLabel; class QLabel;
class QKeyEvent; class QKeyEvent;
class Overlay;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
@@ -23,6 +24,7 @@ public:
void setBlurRadius(unsigned int blurRadius); void setBlurRadius(unsigned int blurRadius);
void setBackgroundOpacity(unsigned int opacity); void setBackgroundOpacity(unsigned int opacity);
void warn(std::string text); void warn(std::string text);
void setOverlay(Overlay* overlay);
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
@@ -31,6 +33,10 @@ private:
unsigned int blurRadius = 20; unsigned int blurRadius = 20;
unsigned int backgroundOpacity = 150; unsigned int backgroundOpacity = 150;
Overlay* overlay;
void drawText(QPixmap& image, int margin, int fontsize, QString text, int alignment);
void updateImage(); void updateImage();
int getImageRotation(); int getImageRotation();

144
src/overlay.cpp Normal file
View File

@@ -0,0 +1,144 @@
#include "overlay.h"
#include <QString>
#include <QDateTime>
#include <libexif/exif-data.h>
#include <unistd.h>
#include <QDate>
#include <QLocale>
#include <QTime>
#include <QStringList>
#include <QRegExp>
#include <iostream>
Overlay::Overlay(const std::string overlayInput):
overlayInput(overlayInput)
{
parseInput();
}
Overlay::~Overlay() {}
void Overlay::parseInput() {
QString str = QString(overlayInput.c_str());
QStringList corners = str.split(QLatin1Char(';'));
if (corners.size() > 0) {
QStringList components = getOverlayComponents(corners[0]);
topLeftTemplate = getTemplate(components);
topLeftMargin = getMargin(components);
topLeftFontsize = getFontsize(components);
}
if (corners.size() > 1) {
QStringList components = getOverlayComponents(corners[1]);
topRightTemplate = getTemplate(components);
topRightMargin = getMargin(components);
topRightFontsize = getFontsize(components);
}
if (corners.size() > 2) {
QStringList components = getOverlayComponents(corners[2]);
bottomLeftTemplate = getTemplate(components);
bottomLeftMargin = getMargin(components);
bottomLeftFontsize = getFontsize(components);
}
if (corners.size() > 3) {
QStringList components = getOverlayComponents(corners[3]);
bottomRightTemplate = getTemplate(components);
bottomRightMargin = getMargin(components);
bottomRightFontsize = getFontsize(components);
}
}
QString Overlay::getTemplate(QStringList components){
if (components.size()>3) {
std::cout << "template: " << components[3].toStdString() << std::endl;
return components[3];
}
return "";
}
int Overlay::getMargin(QStringList components){
if (components.size()>1) {
std::cout << "margin: " << components[1].toStdString() << std::endl;
int num = components[1].toInt();
if (num > 0) {
return num;
}
}
return 20;
}
int Overlay::getFontsize(QStringList components){
if (components.size()>2) {
std::cout << "fontsize: " << components[2].toStdString() << std::endl;
int num = components[2].toInt();
if (num > 0) {
return num;
}
}
return 12;
}
QStringList Overlay::getOverlayComponents(QString corner) {
QRegExp regex("([\\d]*)\\|([\\d]*)\\|(.*)");
if (regex.exactMatch(corner)){
return regex.capturedTexts();
}
QStringList malformed;
malformed << "" << "" << "" << corner;
return malformed;
}
std::string Overlay::getRenderedTopLeft(std::string filename) {
return renderString(topLeftTemplate, filename);
}
std::string Overlay::getRenderedTopRight(std::string filename) {
return renderString(topRightTemplate, filename);
}
std::string Overlay::getRenderedBottomLeft(std::string filename) {
return renderString(bottomLeftTemplate, filename);
}
std::string Overlay::getRenderedBottomRight(std::string filename) {
return renderString(bottomRightTemplate, filename);
}
int Overlay::getMarginTopLeft() {return topLeftMargin;}
int Overlay::getFontsizeTopLeft() {return topLeftFontsize;}
int Overlay::getMarginTopRight() {return topRightMargin;}
int Overlay::getFontsizeTopRight() {return topRightFontsize;}
int Overlay::getMarginBottomLeft() {return bottomLeftMargin;}
int Overlay::getFontsizeBottomLeft() {return bottomLeftFontsize;}
int Overlay::getMarginBottomRight() {return bottomRightMargin;}
int Overlay::getFontsizeBottomRight() {return bottomRightFontsize;}
std::string Overlay::renderString(QString overlayTemplate, std::string filename) {
QString result = overlayTemplate;
result.replace("<datetime>", QLocale::system().toString(QDateTime::currentDateTime()));
result.replace("<date>", QLocale::system().toString(QDate::currentDate()));
result.replace("<time>", QTime::currentTime().toString("hh:mm"));
result.replace("<filename>", filename.c_str());
result.replace("<exifdatetime>", getExifDate(filename));
return result.toStdString();
}
QString Overlay::getExifDate(std::string filename) {
QString dateTime;
ExifData *exifData = exif_data_new_from_file(filename.c_str());
if (exifData)
{
ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_DATE_TIME_ORIGINAL);
if (exifEntry)
{
char buf[2048];
dateTime = exif_entry_get_value(exifEntry, buf, sizeof(buf));
}
exif_data_free(exifData);
QString exifDateFormat = "yyyy:MM:dd hh:mm:ss";
QDateTime exifDateTime = QDateTime::fromString(dateTime, exifDateFormat);
return QLocale::system().toString(exifDateTime);
}
return dateTime;
}

60
src/overlay.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef OVERLAY_H
#define OVERLAY_H
#include <iostream>
#include <QDir>
#include <iostream>
#include <QString>
#include <QStringList>
class MainWindow;
class Overlay
{
public:
Overlay(const std::string path);
virtual ~Overlay();
std::string getRenderedTopLeft(std::string filename);
std::string getRenderedTopRight(std::string filename);
std::string getRenderedBottomLeft(std::string filename);
std::string getRenderedBottomRight(std::string filename);
int getMarginTopLeft();
int getFontsizeTopLeft();
int getMarginTopRight();
int getFontsizeTopRight();
int getMarginBottomLeft();
int getFontsizeBottomLeft();
int getMarginBottomRight();
int getFontsizeBottomRight();
private:
const std::string overlayInput;
int margin;
int fontsize;
QString topLeftTemplate;
QString topRightTemplate;
QString bottomLeftTemplate;
QString bottomRightTemplate;
int topLeftMargin;
int topRightMargin;
int bottomLeftMargin;
int bottomRightMargin;
int topLeftFontsize;
int topRightFontsize;
int bottomLeftFontsize;
int bottomRightFontsize;
QStringList getOverlayComponents(QString corner);
int getMargin(QStringList components);
int getFontsize(QStringList components);
QString getTemplate(QStringList components);
QString getExifDate(std::string filename);
void parseInput();
std::string renderString(QString overlayTemplate, std::string filename);
};
#endif

View File

@@ -32,12 +32,14 @@ SOURCES += \
mainwindow.cpp \ mainwindow.cpp \
imageswitcher.cpp \ imageswitcher.cpp \
pathtraverser.cpp \ pathtraverser.cpp \
overlay.cpp \
imageselector.cpp imageselector.cpp
HEADERS += \ HEADERS += \
mainwindow.h \ mainwindow.h \
imageselector.h \ imageselector.h \
pathtraverser.h \ pathtraverser.h \
overlay.h \
imageswitcher.h imageswitcher.h
FORMS += \ FORMS += \