Merge pull request #37 from alfred-reynolds/master
Add support for filtering images by aspect ratio
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
make
|
make
|
||||||
.swp
|
.swp
|
||||||
.git
|
.git
|
||||||
|
build
|
||||||
|
.vscode
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -20,7 +20,7 @@ check-deps-deb:
|
|||||||
clean:
|
clean:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
|
||||||
build:
|
build: $(shell find src -type f)
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
qmake src/slide.pro -o build/Makefile
|
qmake src/slide.pro -o build/Makefile
|
||||||
make -C build
|
make -C build
|
||||||
|
|||||||
@@ -17,7 +17,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] [-O overlay_string]
|
slide [-t rotation_seconds] [-a aspect] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-O overlay_string] [-v] [--verbose] [--stretch]
|
||||||
```
|
```
|
||||||
|
|
||||||
* `image_folder`: where to search for images (.jpg files)
|
* `image_folder`: where to search for images (.jpg files)
|
||||||
@@ -25,8 +25,11 @@ slide [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p
|
|||||||
* `-s` for shuffle instead of random image rotation
|
* `-s` for shuffle instead of random image rotation
|
||||||
* `-S` for sorted rotation (files ordered by name, first images then subfolders)
|
* `-S` for sorted rotation (files ordered by name, first images then subfolders)
|
||||||
* `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
|
||||||
|
* `aspect(default=a)`: the required aspect ratio of the picture to display. Valid values are 'a' (all), 'l' (landscape) and 'p' (portrait)
|
||||||
* `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
|
||||||
|
* `-v` or `--verbose`: Verbose debug output when running, plus a thumbnail of the original image in the bottom left of the screen
|
||||||
|
* `--stretch`: When in aspect mode 'l' or 'p' crop the image rather than leaving a blurred background. For example, in landscape mode this will make images as wide as the screen and crop the top and bottom to fit.
|
||||||
* `-O` is used to create a overlay string.
|
* `-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`
|
* It defines overlays for all four edges in the order `top-left;top-right;bottom-left;bottom-right`
|
||||||
* All edges overlays are separated by `;`
|
* All edges overlays are separated by `;`
|
||||||
|
|||||||
@@ -5,21 +5,86 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <libexif/exif-data.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdlib.h> /* srand, rand */
|
#include <stdlib.h> /* srand, rand */
|
||||||
#include <time.h> /* time */
|
#include <time.h> /* time */
|
||||||
#include <algorithm> // std::shuffle
|
#include <algorithm> // std::shuffle
|
||||||
#include <random> // std::default_random_engine
|
#include <random> // std::default_random_engine
|
||||||
|
|
||||||
ImageSelector::ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
ImageSelector::ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspectIn):
|
||||||
pathTraverser(pathTraverser)
|
pathTraverser(pathTraverser), aspect(aspectIn)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageSelector::~ImageSelector(){}
|
ImageSelector::~ImageSelector(){}
|
||||||
|
|
||||||
RandomImageSelector::RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
int ImageSelector::getImageRotation(const std::string &fileName)
|
||||||
ImageSelector(pathTraverser)
|
{
|
||||||
|
int orientation = 0;
|
||||||
|
ExifData *exifData = exif_data_new_from_file(fileName.c_str());
|
||||||
|
if (exifData)
|
||||||
|
{
|
||||||
|
ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
|
||||||
|
ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
|
||||||
|
|
||||||
|
if (exifEntry)
|
||||||
|
{
|
||||||
|
orientation = exif_get_short(exifEntry->data, byteOrder);
|
||||||
|
}
|
||||||
|
exif_data_free(exifData);
|
||||||
|
}
|
||||||
|
|
||||||
|
int degrees = 0;
|
||||||
|
switch(orientation) {
|
||||||
|
case 8:
|
||||||
|
degrees = 270;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
degrees = 180;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
degrees = 90;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return degrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageSelector::imageValidForAspect(const std::string &fileName)
|
||||||
|
{
|
||||||
|
QPixmap p( fileName.c_str() );
|
||||||
|
int imageWidth = p.width();
|
||||||
|
int imageHeight = p.height();
|
||||||
|
int rotation = getImageRotation(fileName);
|
||||||
|
if ( rotation == 90 || rotation == 270 )
|
||||||
|
{
|
||||||
|
std::swap(imageWidth,imageHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(aspect)
|
||||||
|
{
|
||||||
|
case 'a':
|
||||||
|
// allow all
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if ( imageWidth < imageHeight )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if ( imageHeight < imageWidth )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RandomImageSelector::RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect):
|
||||||
|
ImageSelector(pathTraverser, aspect)
|
||||||
{
|
{
|
||||||
srand (time(NULL));
|
srand (time(NULL));
|
||||||
}
|
}
|
||||||
@@ -31,9 +96,17 @@ std::string RandomImageSelector::getNextImage()
|
|||||||
std:: string filename;
|
std:: string filename;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QStringList images = pathTraverser->getImages();
|
while (filename.empty())
|
||||||
unsigned int selectedImage = selectRandom(images);
|
{
|
||||||
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
QStringList images = pathTraverser->getImages();
|
||||||
|
unsigned int selectedImage = selectRandom(images);
|
||||||
|
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
||||||
|
if (!imageValidForAspect(filename))
|
||||||
|
{
|
||||||
|
filename.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(const std::string& err)
|
catch(const std::string& err)
|
||||||
{
|
{
|
||||||
@@ -45,7 +118,10 @@ std::string RandomImageSelector::getNextImage()
|
|||||||
|
|
||||||
unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
||||||
{
|
{
|
||||||
std::cout << "images: " << images.size() << std::endl;
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "images: " << images.size() << std::endl;
|
||||||
|
}
|
||||||
if (images.size() == 0)
|
if (images.size() == 0)
|
||||||
{
|
{
|
||||||
throw std::string("No jpg images found in given folder");
|
throw std::string("No jpg images found in given folder");
|
||||||
@@ -53,8 +129,8 @@ unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
|||||||
return rand() % images.size();
|
return rand() % images.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShuffleImageSelector::ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
ShuffleImageSelector::ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect):
|
||||||
ImageSelector(pathTraverser),
|
ImageSelector(pathTraverser, aspect),
|
||||||
current_image_shuffle(-1),
|
current_image_shuffle(-1),
|
||||||
images()
|
images()
|
||||||
{
|
{
|
||||||
@@ -83,8 +159,20 @@ std::string ShuffleImageSelector::getNextImage()
|
|||||||
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
||||||
if(!QFileInfo::exists(QString(filename.c_str())))
|
if(!QFileInfo::exists(QString(filename.c_str())))
|
||||||
{
|
{
|
||||||
std::cout << "file not found: " << filename << std::endl;
|
if(debugMode)
|
||||||
current_image_shuffle = images.size();
|
{
|
||||||
|
std::cout << "file not found: " << filename << std::endl;
|
||||||
|
}
|
||||||
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
|
return getNextImage();
|
||||||
|
}
|
||||||
|
if (!imageValidForAspect(filename))
|
||||||
|
{
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "image has invalid aspect: " << filename << "(images left:" << (images.size()-current_image_shuffle) << ")" << std::endl;
|
||||||
|
}
|
||||||
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
return getNextImage();
|
return getNextImage();
|
||||||
}
|
}
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << filename << std::endl;
|
||||||
@@ -92,8 +180,8 @@ std::string ShuffleImageSelector::getNextImage()
|
|||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect):
|
||||||
ImageSelector(pathTraverser),
|
ImageSelector(pathTraverser, aspect),
|
||||||
images()
|
images()
|
||||||
{
|
{
|
||||||
srand (time(NULL));
|
srand (time(NULL));
|
||||||
@@ -121,10 +209,13 @@ std::string SortedImageSelector::getNextImage()
|
|||||||
{
|
{
|
||||||
images = pathTraverser->getImages();
|
images = pathTraverser->getImages();
|
||||||
std::sort(images.begin(), images.end());
|
std::sort(images.begin(), images.end());
|
||||||
std::cout << "read " << images.size() << " images." << std::endl;
|
if(debugMode)
|
||||||
for (int i = 0;i <images.size();i++){
|
{
|
||||||
|
std::cout << "read " << images.size() << " images." << std::endl;
|
||||||
std::cout << images[i].toStdString() << std::endl;
|
for (int i = 0;i <images.size();i++){
|
||||||
|
|
||||||
|
std::cout << images[i].toStdString() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (images.size() == 0)
|
if (images.size() == 0)
|
||||||
@@ -134,9 +225,21 @@ std::string SortedImageSelector::getNextImage()
|
|||||||
std::string filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
std::string filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
||||||
if(!QFileInfo::exists(QString(filename.c_str())))
|
if(!QFileInfo::exists(QString(filename.c_str())))
|
||||||
{
|
{
|
||||||
std::cout << "file not found: " << filename << std::endl;
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "file not found: " << filename << std::endl;
|
||||||
|
}
|
||||||
return getNextImage();
|
return getNextImage();
|
||||||
}
|
}
|
||||||
|
if (!imageValidForAspect(filename))
|
||||||
|
{
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "image has invalid aspect: " << filename << std::endl;
|
||||||
|
}
|
||||||
|
return getNextImage();
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << filename << std::endl;
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,18 +11,23 @@ class PathTraverser;
|
|||||||
class ImageSelector
|
class ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspectIn);
|
||||||
virtual ~ImageSelector();
|
virtual ~ImageSelector();
|
||||||
virtual std::string getNextImage() = 0;
|
virtual std::string getNextImage() = 0;
|
||||||
|
void setDebugMode(bool debugModeIn) { debugMode = debugModeIn;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
int getImageRotation(const std::string &fileName);
|
||||||
|
bool imageValidForAspect(const std::string &fileName);
|
||||||
std::unique_ptr<PathTraverser>& pathTraverser;
|
std::unique_ptr<PathTraverser>& pathTraverser;
|
||||||
|
char aspect;
|
||||||
|
bool debugMode = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomImageSelector : public ImageSelector
|
class RandomImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect);
|
||||||
virtual ~RandomImageSelector();
|
virtual ~RandomImageSelector();
|
||||||
virtual std::string getNextImage();
|
virtual std::string getNextImage();
|
||||||
|
|
||||||
@@ -33,7 +38,7 @@ private:
|
|||||||
class ShuffleImageSelector : public ImageSelector
|
class ShuffleImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect);
|
||||||
virtual ~ShuffleImageSelector();
|
virtual ~ShuffleImageSelector();
|
||||||
virtual std::string getNextImage();
|
virtual std::string getNextImage();
|
||||||
|
|
||||||
@@ -45,7 +50,7 @@ private:
|
|||||||
class SortedImageSelector : public ImageSelector
|
class SortedImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect);
|
||||||
virtual ~SortedImageSelector();
|
virtual ~SortedImageSelector();
|
||||||
virtual std::string getNextImage();
|
virtual std::string getNextImage();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ ImageSwitcher::ImageSwitcher(MainWindow& w, unsigned int timeout, std::unique_pt
|
|||||||
window(w),
|
window(w),
|
||||||
timeout(timeout),
|
timeout(timeout),
|
||||||
selector(selector),
|
selector(selector),
|
||||||
timer(this)
|
timer(this),
|
||||||
|
timerNoContent(this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,10 +25,12 @@ void ImageSwitcher::updateImage()
|
|||||||
if (filename == "")
|
if (filename == "")
|
||||||
{
|
{
|
||||||
window.warn("No image found.");
|
window.warn("No image found.");
|
||||||
|
timerNoContent.start(timeoutNoContent);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.setImage(filename);
|
window.setImage(filename);
|
||||||
|
timerNoContent.stop(); // we have loaded content so stop the fast polling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,5 +38,6 @@ void ImageSwitcher::start()
|
|||||||
{
|
{
|
||||||
updateImage();
|
updateImage();
|
||||||
connect(&timer, SIGNAL(timeout()), this, SLOT(updateImage()));
|
connect(&timer, SIGNAL(timeout()), this, SLOT(updateImage()));
|
||||||
|
connect(&timerNoContent, SIGNAL(timeout()), this, SLOT(updateImage()));
|
||||||
timer.start(timeout);
|
timer.start(timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ private:
|
|||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
std::unique_ptr<ImageSelector>& selector;
|
std::unique_ptr<ImageSelector>& selector;
|
||||||
QTimer timer;
|
QTimer timer;
|
||||||
|
const unsigned int timeoutNoContent = 5 * 1000; // 5 sec
|
||||||
|
QTimer timerNoContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMAGESWITCHER_H
|
#endif // IMAGESWITCHER_H
|
||||||
|
|||||||
60
src/main.cpp
60
src/main.cpp
@@ -8,13 +8,14 @@
|
|||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
void usage(std::string programName) {
|
void usage(std::string programName) {
|
||||||
std::cerr << "Usage: " << programName << " [-t rotation_seconds] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-s]" << std::endl;
|
std::cerr << "Usage: " << programName << " [-t rotation_seconds] [-a aspect('l','p','a')] [-o background_opacity(0..255)] [-b blur_radius] -p image_folder [-r] [-s] [-v] [--verbose] [--stretch]" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@@ -29,12 +30,39 @@ int main(int argc, char *argv[])
|
|||||||
bool recursive = false;
|
bool recursive = false;
|
||||||
bool shuffle = false;
|
bool shuffle = false;
|
||||||
bool sorted = false;
|
bool sorted = false;
|
||||||
|
bool debugMode = false;
|
||||||
|
char aspect = 'a';
|
||||||
|
bool fitAspectAxisToWindow = false;
|
||||||
|
std::string valid_aspects = "alp"; // all, landscape, portait
|
||||||
std::string overlay = "";
|
std::string overlay = "";
|
||||||
while ((opt = getopt(argc, argv, "b:p:t:o:O:rsS")) != -1) {
|
int debugInt = 0;
|
||||||
|
int stretchInt = 0;
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"verbose", no_argument, &debugInt, 1},
|
||||||
|
{"stretch", no_argument, &stretchInt, 1},
|
||||||
|
};
|
||||||
|
int option_index = 0;
|
||||||
|
while ((opt = getopt_long(argc, argv, "b:p:t:o:O:a:rsSv", long_options, &option_index)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 0:
|
||||||
|
/* If this option set a flag, do nothing else now. */
|
||||||
|
if (long_options[option_index].flag != 0)
|
||||||
|
break;
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
path = optarg;
|
path = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
aspect = optarg[0];
|
||||||
|
if ( valid_aspects.find(aspect) == std::string::npos )
|
||||||
|
{
|
||||||
|
std::cout << "Invalid Aspect option, defaulting to all" << std::endl;
|
||||||
|
aspect = 'a';
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
rotationSeconds = atoi(optarg);
|
rotationSeconds = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
@@ -57,11 +85,22 @@ int main(int argc, char *argv[])
|
|||||||
case 'O':
|
case 'O':
|
||||||
overlay = optarg;
|
overlay = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
debugMode = true;
|
||||||
|
break;
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(debugInt==1)
|
||||||
|
{
|
||||||
|
debugMode = true;
|
||||||
|
}
|
||||||
|
if(stretchInt==1)
|
||||||
|
{
|
||||||
|
fitAspectAxisToWindow = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
{
|
{
|
||||||
@@ -83,19 +122,28 @@ int main(int argc, char *argv[])
|
|||||||
std::unique_ptr<ImageSelector> selector;
|
std::unique_ptr<ImageSelector> selector;
|
||||||
if (sorted)
|
if (sorted)
|
||||||
{
|
{
|
||||||
selector = std::unique_ptr<ImageSelector>(new SortedImageSelector(pathTraverser));
|
selector = std::unique_ptr<ImageSelector>(new SortedImageSelector(pathTraverser, aspect));
|
||||||
}
|
}
|
||||||
else if (shuffle)
|
else if (shuffle)
|
||||||
{
|
{
|
||||||
selector = std::unique_ptr<ImageSelector>(new ShuffleImageSelector(pathTraverser));
|
selector = std::unique_ptr<ImageSelector>(new ShuffleImageSelector(pathTraverser, aspect));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser));
|
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser, aspect));
|
||||||
|
}
|
||||||
|
selector->setDebugMode(debugMode);
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "Rotation Time: " << rotationSeconds << std::endl;
|
||||||
|
std::cout << "Overlay input: " << overlay << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "Overlay input: " << overlay << std::endl;
|
|
||||||
Overlay o(overlay);
|
Overlay o(overlay);
|
||||||
|
o.setDebugMode(debugMode);
|
||||||
w.setOverlay(&o);
|
w.setOverlay(&o);
|
||||||
|
w.setAspect(aspect);
|
||||||
|
w.setDebugMode(debugMode);
|
||||||
|
w.setFitAspectAxisToWindow(fitAspectAxisToWindow);
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
ImageSwitcher switcher(w, rotationSeconds * 1000, selector);
|
ImageSwitcher switcher(w, rotationSeconds * 1000, selector);
|
||||||
|
|||||||
@@ -109,6 +109,11 @@ void MainWindow::updateImage(bool immediately)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QPixmap p( currentImage.c_str() );
|
QPixmap p( currentImage.c_str() );
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "size:" << p.width() << "x" << p.height() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap rotated = getRotatedPixmap(p);
|
QPixmap rotated = getRotatedPixmap(p);
|
||||||
QPixmap scaled = getScaledPixmap(rotated);
|
QPixmap scaled = getScaledPixmap(rotated);
|
||||||
QPixmap background = getBlurredBackground(rotated, scaled);
|
QPixmap background = getBlurredBackground(rotated, scaled);
|
||||||
@@ -120,6 +125,21 @@ void MainWindow::updateImage(bool immediately)
|
|||||||
drawText(background, overlay->getMarginTopRight(), overlay->getFontsizeTopRight(), overlay->getRenderedTopRight(currentImage).c_str(), Qt::AlignTop|Qt::AlignRight);
|
drawText(background, overlay->getMarginTopRight(), overlay->getFontsizeTopRight(), overlay->getRenderedTopRight(currentImage).c_str(), Qt::AlignTop|Qt::AlignRight);
|
||||||
drawText(background, overlay->getMarginBottomLeft(), overlay->getFontsizeBottomLeft(), overlay->getRenderedBottomLeft(currentImage).c_str(), Qt::AlignBottom|Qt::AlignLeft);
|
drawText(background, overlay->getMarginBottomLeft(), overlay->getFontsizeBottomLeft(), overlay->getRenderedBottomLeft(currentImage).c_str(), Qt::AlignBottom|Qt::AlignLeft);
|
||||||
drawText(background, overlay->getMarginBottomRight(), overlay->getFontsizeBottomRight(), overlay->getRenderedBottomRight(currentImage).c_str(), Qt::AlignBottom|Qt::AlignRight);
|
drawText(background, overlay->getMarginBottomRight(), overlay->getFontsizeBottomRight(), overlay->getRenderedBottomRight(currentImage).c_str(), Qt::AlignBottom|Qt::AlignRight);
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
// draw a thumbnail version of the source image in the bottom left, to check for cropping issues
|
||||||
|
QPainter pt(&background);
|
||||||
|
QBrush brush(QColor(255, 255, 255, 255));
|
||||||
|
int margin = 10;
|
||||||
|
QPixmap thumbNail = p.scaledToWidth(200, Qt::SmoothTransformation);
|
||||||
|
pt.fillRect(background.width() - thumbNail.width() - 2*margin,
|
||||||
|
background.height()-thumbNail.height() - 2*margin,
|
||||||
|
thumbNail.width() +2*margin, thumbNail.height()+2*margin, brush);
|
||||||
|
|
||||||
|
pt.drawPixmap( background.width() - thumbNail.width() - margin,
|
||||||
|
background.height()-thumbNail.height() - margin,
|
||||||
|
thumbNail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
label->setPixmap(background);
|
label->setPixmap(background);
|
||||||
@@ -164,13 +184,22 @@ void MainWindow::setOverlay(Overlay* o)
|
|||||||
overlay = o;
|
overlay = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setAspect(char aspectIn)
|
||||||
|
{
|
||||||
|
aspect = aspectIn;
|
||||||
|
}
|
||||||
|
|
||||||
QPixmap MainWindow::getBlurredBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
QPixmap MainWindow::getBlurredBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
||||||
{
|
{
|
||||||
if (scaled.width() < width()) {
|
if (fitAspectAxisToWindow) {
|
||||||
|
// our scaled version will just fill the whole screen, us it directly
|
||||||
|
return scaled.copy();
|
||||||
|
} else if (scaled.width() < width()) {
|
||||||
QPixmap background = blur(originalSize.scaledToWidth(width(), Qt::SmoothTransformation));
|
QPixmap background = blur(originalSize.scaledToWidth(width(), Qt::SmoothTransformation));
|
||||||
QRect rect(0, (background.height() - height())/2, width(), height());
|
QRect rect(0, (background.height() - height())/2, width(), height());
|
||||||
return background.copy(rect);
|
return background.copy(rect);
|
||||||
} else {
|
} else {
|
||||||
|
// aspect 'p' or the image is not as wide as the screen
|
||||||
QPixmap background = blur(originalSize.scaledToHeight(height(), Qt::SmoothTransformation));
|
QPixmap background = blur(originalSize.scaledToHeight(height(), Qt::SmoothTransformation));
|
||||||
QRect rect((background.width() - width())/2, 0, width(), height());
|
QRect rect((background.width() - width())/2, 0, width(), height());
|
||||||
return background.copy(rect);
|
return background.copy(rect);
|
||||||
@@ -186,9 +215,28 @@ QPixmap MainWindow::getRotatedPixmap(const QPixmap& p)
|
|||||||
|
|
||||||
QPixmap MainWindow::getScaledPixmap(const QPixmap& p)
|
QPixmap MainWindow::getScaledPixmap(const QPixmap& p)
|
||||||
{
|
{
|
||||||
int w = width();
|
if (fitAspectAxisToWindow)
|
||||||
int h = height();
|
{
|
||||||
return p.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
if ( aspect == 'p')
|
||||||
|
{
|
||||||
|
// potrait mode, make height of image fit screen and crop top/bottom
|
||||||
|
QPixmap pTemp = p.scaledToHeight(height(), Qt::SmoothTransformation);
|
||||||
|
return pTemp.copy(0,0,width(),height());
|
||||||
|
}
|
||||||
|
else if ( aspect == 'l')
|
||||||
|
{
|
||||||
|
// landscape mode, make width of image fit screen and crop top/bottom
|
||||||
|
QPixmap pTemp = p.scaledToWidth(width(), Qt::SmoothTransformation);
|
||||||
|
//int imageTempWidth = pTemp.width();
|
||||||
|
//int imageTempHeight = pTemp.height();
|
||||||
|
return pTemp.copy(0,0,width(),height());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just scale the best we can for the given photo
|
||||||
|
int w = width();
|
||||||
|
int h = height();
|
||||||
|
return p.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::drawBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
void MainWindow::drawBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
||||||
|
|||||||
@@ -25,13 +25,18 @@ public:
|
|||||||
void setBackgroundOpacity(unsigned int opacity);
|
void setBackgroundOpacity(unsigned int opacity);
|
||||||
void warn(std::string text);
|
void warn(std::string text);
|
||||||
void setOverlay(Overlay* overlay);
|
void setOverlay(Overlay* overlay);
|
||||||
|
void setAspect(char aspectIn);
|
||||||
|
void setDebugMode(bool debugModeIn) {debugMode = debugModeIn;}
|
||||||
|
void setFitAspectAxisToWindow(bool fitAspectAxisToWindowIn) { fitAspectAxisToWindow = fitAspectAxisToWindowIn; }
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
std::string currentImage;
|
std::string currentImage;
|
||||||
unsigned int blurRadius = 20;
|
unsigned int blurRadius = 20;
|
||||||
unsigned int backgroundOpacity = 150;
|
unsigned int backgroundOpacity = 150;
|
||||||
|
char aspect = 'a';
|
||||||
|
bool debugMode = false;
|
||||||
|
bool fitAspectAxisToWindow = false;
|
||||||
|
|
||||||
Overlay* overlay;
|
Overlay* overlay;
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ void Overlay::parseInput() {
|
|||||||
|
|
||||||
QString Overlay::getTemplate(QStringList components){
|
QString Overlay::getTemplate(QStringList components){
|
||||||
if (components.size()>3) {
|
if (components.size()>3) {
|
||||||
std::cout << "template: " << components[3].toStdString() << std::endl;
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "template: " << components[3].toStdString() << std::endl;
|
||||||
|
}
|
||||||
return components[3];
|
return components[3];
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -58,7 +61,10 @@ QString Overlay::getTemplate(QStringList components){
|
|||||||
|
|
||||||
int Overlay::getMargin(QStringList components){
|
int Overlay::getMargin(QStringList components){
|
||||||
if (components.size()>1) {
|
if (components.size()>1) {
|
||||||
std::cout << "margin: " << components[1].toStdString() << std::endl;
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "margin: " << components[1].toStdString() << std::endl;
|
||||||
|
}
|
||||||
int num = components[1].toInt();
|
int num = components[1].toInt();
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
return num;
|
return num;
|
||||||
@@ -70,7 +76,10 @@ int Overlay::getMargin(QStringList components){
|
|||||||
|
|
||||||
int Overlay::getFontsize(QStringList components){
|
int Overlay::getFontsize(QStringList components){
|
||||||
if (components.size()>2) {
|
if (components.size()>2) {
|
||||||
std::cout << "fontsize: " << components[2].toStdString() << std::endl;
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "fontsize: " << components[2].toStdString() << std::endl;
|
||||||
|
}
|
||||||
int num = components[2].toInt();
|
int num = components[2].toInt();
|
||||||
if (num > 0) {
|
if (num > 0) {
|
||||||
return num;
|
return num;
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ class Overlay
|
|||||||
int getMarginBottomRight();
|
int getMarginBottomRight();
|
||||||
int getFontsizeBottomRight();
|
int getFontsizeBottomRight();
|
||||||
|
|
||||||
|
void setDebugMode(const bool debugModeIn) { debugMode = debugModeIn; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string overlayInput;
|
const std::string overlayInput;
|
||||||
int margin;
|
int margin;
|
||||||
int fontsize;
|
int fontsize;
|
||||||
|
bool debugMode = false;
|
||||||
|
|
||||||
QString topLeftTemplate;
|
QString topLeftTemplate;
|
||||||
QString topRightTemplate;
|
QString topRightTemplate;
|
||||||
|
|||||||
Reference in New Issue
Block a user