Add text overlays
This commit is contained in:
15
README.md
15
README.md
@@ -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,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
|
* `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
|
||||||
|
|
||||||
* libexif
|
* libexif
|
||||||
|
|||||||
11
src/main.cpp
11
src/main.cpp
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -99,6 +101,14 @@ void MainWindow::updateImage()
|
|||||||
QPixmap p( currentImage.c_str() );
|
QPixmap p( currentImage.c_str() );
|
||||||
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;
|
||||||
|
|||||||
@@ -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
144
src/overlay.cpp
Normal 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
60
src/overlay.h
Normal 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
|
||||||
@@ -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 += \
|
||||||
|
|||||||
Reference in New Issue
Block a user