Skip to content

Commit

Permalink
Add text overlays
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuel Dewald committed Mar 4, 2021
1 parent c84f014 commit d4beb46
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 4 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This project is maintained by myself during my spare time. If you like and use i
## 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)
Expand All @@ -26,7 +26,18 @@ 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
* `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

* `-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

* libexif
Expand Down
11 changes: 9 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "imageselector.h"
#include "imageswitcher.h"
#include "pathtraverser.h"
#include "overlay.h"
#include <QApplication>
#include <iostream>
#include <sys/file.h>
Expand All @@ -28,7 +29,8 @@ int main(int argc, char *argv[])
bool recursive = false;
bool shuffle = 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) {
case 'p':
path = optarg;
Expand All @@ -52,6 +54,9 @@ int main(int argc, char *argv[])
case 'S':
sorted = true;
break;
case 'O':
overlay = optarg;
break;
default: /* '?' */
usage(argv[0]);
return 1;
Expand Down Expand Up @@ -88,7 +93,9 @@ int main(int argc, char *argv[])
{
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser));
}

std::cout << "Overlay input: " << overlay << std::endl;
Overlay o(overlay);
w.setOverlay(&o);
w.show();

ImageSwitcher switcher(w, rotationSeconds * 1000, selector);
Expand Down
28 changes: 28 additions & 0 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "mainwindow.h"
#include "overlay.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QPixmap>
Expand All @@ -9,6 +10,7 @@
#include <iostream>
#include <QPainter>
#include <QTimer>
#include <QRect>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <sstream>
Expand Down Expand Up @@ -99,6 +101,14 @@ void MainWindow::updateImage()
QPixmap p( currentImage.c_str() );
QPixmap rotated = getRotatedPixmap(p);
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");
label->setPixmap(scaled);
Expand All @@ -112,6 +122,24 @@ void MainWindow::updateImage()
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)
{
QMatrix matrix;
Expand Down
6 changes: 6 additions & 0 deletions src/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class MainWindow;
}
class QLabel;
class QKeyEvent;
class Overlay;

class MainWindow : public QMainWindow
{
Expand All @@ -23,6 +24,7 @@ class MainWindow : public QMainWindow
void setBlurRadius(unsigned int blurRadius);
void setBackgroundOpacity(unsigned int opacity);
void warn(std::string text);
void setOverlay(Overlay* overlay);

private:
Ui::MainWindow *ui;
Expand All @@ -31,6 +33,10 @@ class MainWindow : public QMainWindow
unsigned int blurRadius = 20;
unsigned int backgroundOpacity = 150;

Overlay* overlay;

void drawText(QPixmap& image, int margin, int fontsize, QString text, int alignment);

void updateImage();
int getImageRotation();

Expand Down
144 changes: 144 additions & 0 deletions src/overlay.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 60 additions & 0 deletions src/overlay.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions src/slide.pro
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ SOURCES += \
mainwindow.cpp \
imageswitcher.cpp \
pathtraverser.cpp \
overlay.cpp \
imageselector.cpp

HEADERS += \
mainwindow.h \
imageselector.h \
pathtraverser.h \
overlay.h \
imageswitcher.h

FORMS += \
Expand Down

2 comments on commit d4beb46

@mikey4321
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, thank you!

@NautiluX
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, thank you!

Added more template strings with the latest version (0.9.11), please take a look

Please sign in to comment.