- Change display options to be passed down from the window, and have the imageselector pass a struct back that contains image metadata
- Added ImageDisplayOptions_t to control user controllable options for how we show an image (aspect filtering, stretching) - Added ImageDetails_t to encapsulate image metadata along with its image options
This commit is contained in:
@@ -12,26 +12,54 @@
|
|||||||
#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, char aspectIn, bool fitAspectAxisToWindowIn):
|
ImageSelector::ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
||||||
pathTraverser(pathTraverser), aspect(aspectIn), fitAspectAxisToWindow(fitAspectAxisToWindowIn)
|
pathTraverser(pathTraverser)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageSelector::~ImageSelector(){}
|
ImageSelector::~ImageSelector(){}
|
||||||
|
|
||||||
int ImageSelector::getImageRotation(const std::string& fileName)
|
int ReadExifTag(ExifData* exifData, ExifTag tag, bool shortRead = false)
|
||||||
{
|
|
||||||
int orientation = 0;
|
|
||||||
ExifData *exifData = exif_data_new_from_file(fileName.c_str());
|
|
||||||
if (exifData)
|
|
||||||
{
|
{
|
||||||
|
int value = -1;
|
||||||
ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
|
ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
|
||||||
ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
|
ExifEntry *exifEntry = exif_data_get_entry(exifData, tag);
|
||||||
|
|
||||||
if (exifEntry)
|
if (exifEntry)
|
||||||
{
|
{
|
||||||
orientation = exif_get_short(exifEntry->data, byteOrder);
|
if (shortRead)
|
||||||
|
{
|
||||||
|
value = exif_get_short(exifEntry->data, byteOrder);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = exif_get_long(exifEntry->data, byteOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageSelector::populateImageDetails(const std::string&fileName, ImageDetails_t &imageDetails, const ImageDisplayOptions_t &baseOptions)
|
||||||
|
{
|
||||||
|
int orientation = -1;
|
||||||
|
int imageWidth = -1;
|
||||||
|
int imageHeight = -1;
|
||||||
|
ExifData *exifData = exif_data_new_from_file(fileName.c_str());
|
||||||
|
if (exifData)
|
||||||
|
{
|
||||||
|
orientation = ReadExifTag(exifData, EXIF_TAG_ORIENTATION, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// It looks like you can't trust Exif dimensions, so just forcefully load the file below
|
||||||
|
// try to get the image dimensions from exifData so we don't need to fully load the file
|
||||||
|
imageWidth = ReadExifTag(exifData, EXIF_TAG_IMAGE_WIDTH);
|
||||||
|
if ( imageWidth == -1)
|
||||||
|
imageWidth = ReadExifTag(exifData, EXIF_TAG_PIXEL_X_DIMENSION);
|
||||||
|
|
||||||
|
imageHeight = ReadExifTag(exifData, EXIF_TAG_RELATED_IMAGE_WIDTH); // means height, height is related to width
|
||||||
|
if ( imageHeight == -1)
|
||||||
|
imageHeight = ReadExifTag(exifData, EXIF_TAG_PIXEL_Y_DIMENSION);*/
|
||||||
|
|
||||||
exif_data_free(exifData);
|
exif_data_free(exifData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,97 +74,103 @@ int ImageSelector::getImageRotation(const std::string& fileName)
|
|||||||
case 6:
|
case 6:
|
||||||
degrees = 90;
|
degrees = 90;
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
return degrees;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageSelector::imageMatchesFilter(const std::string& fileName, const int rotation)
|
if (imageWidth <=0 || imageHeight <=0)
|
||||||
{
|
|
||||||
if(!QFileInfo::exists(QString(fileName.c_str())))
|
|
||||||
{
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "file not found: " << fileName << std::endl;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!imageValidForAspect(fileName, rotation)) {
|
|
||||||
if(debugMode)
|
|
||||||
{
|
|
||||||
std::cout << "image aspect ratio doesn't match filter '" << aspect << "' : " << fileName << std::endl;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImageSelector::imageValidForAspect(const std::string &fileName, const int rotation)
|
|
||||||
{
|
{
|
||||||
|
// fallback to QPixmap to determine image size
|
||||||
QPixmap p( fileName.c_str() );
|
QPixmap p( fileName.c_str() );
|
||||||
int imageWidth = p.width();
|
imageWidth = p.width();
|
||||||
int imageHeight = p.height();
|
imageHeight = p.height();
|
||||||
if ( rotation == 90 || rotation == 270 )
|
}
|
||||||
|
|
||||||
|
// if the image is rotated then swap height/width here to show displayed sizes
|
||||||
|
if( degrees == 90 || degrees == 270 )
|
||||||
{
|
{
|
||||||
std::swap(imageWidth,imageHeight);
|
std::swap(imageWidth,imageHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(aspect)
|
// setup the imageDetails structure
|
||||||
|
imageDetails.filename = fileName;
|
||||||
|
|
||||||
|
imageDetails.width = imageWidth;
|
||||||
|
imageDetails.height = imageHeight;
|
||||||
|
imageDetails.rotation = degrees;
|
||||||
|
if (imageWidth > imageHeight) {
|
||||||
|
imageDetails.aspect = EImageAspect_Landscape;
|
||||||
|
} else if (imageHeight > imageWidth) {
|
||||||
|
imageDetails.aspect = EImageAspect_Portrait;
|
||||||
|
} else {
|
||||||
|
imageDetails.aspect = EImageAspect_Any;
|
||||||
|
}
|
||||||
|
imageDetails.options = baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImageSelector::imageMatchesFilter(const ImageDetails_t& imageDetails)
|
||||||
{
|
{
|
||||||
case 'a':
|
if(!QFileInfo::exists(QString(imageDetails.filename.c_str())))
|
||||||
// allow all
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
if ( imageWidth < imageHeight )
|
|
||||||
{
|
{
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "file not found: " << imageDetails.filename << std::endl;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'p':
|
if(!imageValidForAspect(imageDetails))
|
||||||
if ( imageHeight < imageWidth )
|
|
||||||
{
|
{
|
||||||
|
if(debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "image aspect ratio doesn't match filter '" << imageDetails.options.onlyAspect << "' : " << imageDetails.filename << std::endl;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImageSelector::imageValidForAspect(const ImageDetails_t& imageDetails)
|
||||||
|
{
|
||||||
|
if (imageDetails.options.onlyAspect == EImageAspect_Any ||
|
||||||
|
imageDetails.aspect == imageDetails.options.onlyAspect)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
RandomImageSelector::RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow):
|
|
||||||
ImageSelector(pathTraverser, aspect, fitAspectAxisToWindow)
|
RandomImageSelector::RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
||||||
|
ImageSelector(pathTraverser)
|
||||||
{
|
{
|
||||||
srand (time(NULL));
|
srand (time(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomImageSelector::~RandomImageSelector(){}
|
RandomImageSelector::~RandomImageSelector(){}
|
||||||
|
|
||||||
const std::string RandomImageSelector::getNextImage(ImageOptions_t &options)
|
const ImageDetails_t RandomImageSelector::getNextImage(const ImageDisplayOptions_t &baseOptions)
|
||||||
{
|
{
|
||||||
std:: string filename;
|
ImageDetails_t imageDetails;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
QStringList images = pathTraverser->getImages();
|
QStringList images = pathTraverser->getImages();
|
||||||
unsigned int selectedImage = selectRandom(images);
|
unsigned int selectedImage = selectRandom(images);
|
||||||
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.at(selectedImage).toStdString()), imageDetails, baseOptions);
|
||||||
options.rotation = getImageRotation(filename);
|
while(!imageMatchesFilter(imageDetails))
|
||||||
while(!imageMatchesFilter(filename, options.rotation))
|
|
||||||
{
|
{
|
||||||
unsigned int selectedImage = selectRandom(images);
|
unsigned int selectedImage = selectRandom(images);
|
||||||
filename = pathTraverser->getImagePath(images.at(selectedImage).toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.at(selectedImage).toStdString()), imageDetails, baseOptions);
|
||||||
options.rotation = getImageRotation(filename);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const std::string& err)
|
catch(const std::string& err)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: " << err << std::endl;
|
std::cerr << "Error: " << err << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << imageDetails.filename << std::endl;
|
||||||
options.aspect = aspect;
|
pathTraverser->UpdateOptionsForImage(imageDetails.filename, imageDetails.options);
|
||||||
options.fitAspectAxisToWindow = fitAspectAxisToWindow;
|
return imageDetails;
|
||||||
pathTraverser->UpdateOptionsForImage(filename, options);
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
||||||
@@ -152,8 +186,8 @@ unsigned int RandomImageSelector::selectRandom(const QStringList& images) const
|
|||||||
return rand() % images.size();
|
return rand() % images.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShuffleImageSelector::ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow):
|
ShuffleImageSelector::ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
||||||
ImageSelector(pathTraverser, aspect, fitAspectAxisToWindow),
|
ImageSelector(pathTraverser),
|
||||||
current_image_shuffle(-1),
|
current_image_shuffle(-1),
|
||||||
images()
|
images()
|
||||||
{
|
{
|
||||||
@@ -164,27 +198,24 @@ ShuffleImageSelector::~ShuffleImageSelector()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string ShuffleImageSelector::getNextImage(ImageOptions_t &options)
|
const ImageDetails_t ShuffleImageSelector::getNextImage(const ImageDisplayOptions_t &baseOptions)
|
||||||
{
|
{
|
||||||
reloadImagesIfNoneLeft();
|
reloadImagesIfNoneLeft();
|
||||||
|
ImageDetails_t imageDetails;
|
||||||
if (images.size() == 0)
|
if (images.size() == 0)
|
||||||
{
|
{
|
||||||
return "";
|
return imageDetails;
|
||||||
}
|
}
|
||||||
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()), imageDetails, baseOptions);
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
options.rotation = getImageRotation(filename);
|
while(!imageMatchesFilter(imageDetails)) {
|
||||||
while(!imageMatchesFilter(filename, options.rotation)) {
|
|
||||||
reloadImagesIfNoneLeft();
|
reloadImagesIfNoneLeft();
|
||||||
std::string filename = pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()), imageDetails,baseOptions);
|
||||||
options.rotation = getImageRotation(filename);
|
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
}
|
}
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << imageDetails.filename << std::endl;
|
||||||
options.aspect = aspect;
|
pathTraverser->UpdateOptionsForImage(imageDetails.filename, imageDetails.options);
|
||||||
options.fitAspectAxisToWindow = fitAspectAxisToWindow;
|
return imageDetails;
|
||||||
pathTraverser->UpdateOptionsForImage(filename, options);
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShuffleImageSelector::reloadImagesIfNoneLeft()
|
void ShuffleImageSelector::reloadImagesIfNoneLeft()
|
||||||
@@ -200,8 +231,8 @@ void ShuffleImageSelector::reloadImagesIfNoneLeft()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow):
|
SortedImageSelector::SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser):
|
||||||
ImageSelector(pathTraverser, aspect, fitAspectAxisToWindow),
|
ImageSelector(pathTraverser),
|
||||||
images()
|
images()
|
||||||
{
|
{
|
||||||
srand (time(NULL));
|
srand (time(NULL));
|
||||||
@@ -223,26 +254,23 @@ bool operator<(const QString& lhs, const QString& rhs) noexcept{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string SortedImageSelector::getNextImage(ImageOptions_t &options)
|
const ImageDetails_t SortedImageSelector::getNextImage(const ImageDisplayOptions_t &baseOptions)
|
||||||
{
|
{
|
||||||
reloadImagesIfEmpty();
|
reloadImagesIfEmpty();
|
||||||
|
ImageDetails_t imageDetails;
|
||||||
if (images.size() == 0)
|
if (images.size() == 0)
|
||||||
{
|
{
|
||||||
return "";
|
return imageDetails;
|
||||||
}
|
}
|
||||||
std::string filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), imageDetails, baseOptions);
|
||||||
options.rotation = getImageRotation(filename);
|
while(!imageMatchesFilter(imageDetails)) {
|
||||||
while(!imageMatchesFilter(filename, options.rotation)) {
|
|
||||||
reloadImagesIfEmpty();
|
reloadImagesIfEmpty();
|
||||||
filename = pathTraverser->getImagePath(images.takeFirst().toStdString());
|
populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), imageDetails, baseOptions);
|
||||||
options.rotation = getImageRotation(filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "updating image: " << filename << std::endl;
|
std::cout << "updating image: " << imageDetails.filename << std::endl;
|
||||||
options.aspect = aspect;
|
pathTraverser->UpdateOptionsForImage(imageDetails.filename, imageDetails.options);
|
||||||
options.fitAspectAxisToWindow = fitAspectAxisToWindow;
|
return imageDetails;
|
||||||
pathTraverser->UpdateOptionsForImage(filename, options);
|
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SortedImageSelector::reloadImagesIfEmpty()
|
void SortedImageSelector::reloadImagesIfEmpty()
|
||||||
|
|||||||
@@ -4,41 +4,33 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include "imagestructs.h"
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class PathTraverser;
|
class PathTraverser;
|
||||||
|
|
||||||
struct ImageOptions_t
|
|
||||||
{
|
|
||||||
char aspect;
|
|
||||||
bool fitAspectAxisToWindow;
|
|
||||||
int rotation;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ImageSelector
|
class ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspectIn, bool fitAspectAxisToWindow);
|
ImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
||||||
virtual ~ImageSelector();
|
virtual ~ImageSelector();
|
||||||
virtual const std::string getNextImage(ImageOptions_t &options) = 0;
|
virtual const ImageDetails_t getNextImage(const ImageDisplayOptions_t &baseOptions) = 0;
|
||||||
void setDebugMode(bool debugModeIn) { debugMode = debugModeIn;}
|
void setDebugMode(bool debugModeIn) { debugMode = debugModeIn;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int getImageRotation(const std::string &fileName);
|
void populateImageDetails(const std::string&filename, ImageDetails_t &imageDetails, const ImageDisplayOptions_t &baseOptions);
|
||||||
bool imageValidForAspect(const std::string &fileName, const int rotation);
|
bool imageValidForAspect(const ImageDetails_t& imageDetails);
|
||||||
bool imageMatchesFilter(const std::string& fileName, const int rotation);
|
bool imageMatchesFilter(const ImageDetails_t& imageDetails);
|
||||||
std::unique_ptr<PathTraverser>& pathTraverser;
|
std::unique_ptr<PathTraverser>& pathTraverser;
|
||||||
char aspect;
|
|
||||||
bool fitAspectAxisToWindow = false;
|
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomImageSelector : public ImageSelector
|
class RandomImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow);
|
RandomImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
||||||
virtual ~RandomImageSelector();
|
virtual ~RandomImageSelector();
|
||||||
virtual const std::string getNextImage(ImageOptions_t &options);
|
virtual const ImageDetails_t getNextImage(const ImageDisplayOptions_t &baseOptions);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int selectRandom(const QStringList& images) const;
|
unsigned int selectRandom(const QStringList& images) const;
|
||||||
@@ -47,9 +39,9 @@ private:
|
|||||||
class ShuffleImageSelector : public ImageSelector
|
class ShuffleImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow);
|
ShuffleImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
||||||
virtual ~ShuffleImageSelector();
|
virtual ~ShuffleImageSelector();
|
||||||
virtual const std::string getNextImage(ImageOptions_t &options);
|
virtual const ImageDetails_t getNextImage(const ImageDisplayOptions_t &baseOptions);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reloadImagesIfNoneLeft();
|
void reloadImagesIfNoneLeft();
|
||||||
@@ -60,9 +52,9 @@ private:
|
|||||||
class SortedImageSelector : public ImageSelector
|
class SortedImageSelector : public ImageSelector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser, char aspect, bool fitAspectAxisToWindow);
|
SortedImageSelector(std::unique_ptr<PathTraverser>& pathTraverser);
|
||||||
virtual ~SortedImageSelector();
|
virtual ~SortedImageSelector();
|
||||||
virtual const std::string getNextImage(ImageOptions_t &options);
|
virtual const ImageDetails_t getNextImage(const ImageDisplayOptions_t &baseOptions);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reloadImagesIfEmpty();
|
void reloadImagesIfEmpty();
|
||||||
|
|||||||
28
src/imagestructs.h
Normal file
28
src/imagestructs.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef IMAGESTRUCTS_H
|
||||||
|
#define IMAGESTRUCTS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// possible aspect ratios of an image
|
||||||
|
enum EImageAspect { EImageAspect_Landscape = 0, EImageAspect_Portrait, EImageAspect_Any };
|
||||||
|
|
||||||
|
// options to consider when displaying an image
|
||||||
|
struct ImageDisplayOptions_t
|
||||||
|
{
|
||||||
|
EImageAspect onlyAspect = EImageAspect_Any;
|
||||||
|
bool fitAspectAxisToWindow = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// details of a particular image
|
||||||
|
struct ImageDetails_t
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
int rotation = 0;
|
||||||
|
EImageAspect aspect = EImageAspect_Any;
|
||||||
|
std::string filename;
|
||||||
|
ImageDisplayOptions_t options;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IMAGESTRUCTS_H
|
||||||
@@ -21,16 +21,15 @@ ImageSwitcher::ImageSwitcher(MainWindow& w, unsigned int timeout, std::unique_pt
|
|||||||
|
|
||||||
void ImageSwitcher::updateImage()
|
void ImageSwitcher::updateImage()
|
||||||
{
|
{
|
||||||
ImageOptions_t options;
|
ImageDetails_t imageDetails = selector->getNextImage(window.getBaseOptions());
|
||||||
std::string filename(selector->getNextImage(options));
|
if (imageDetails.filename == "")
|
||||||
if (filename == "")
|
|
||||||
{
|
{
|
||||||
window.warn("No image found.");
|
window.warn("No image found.");
|
||||||
timerNoContent.start(timeoutNoContent);
|
timerNoContent.start(timeoutNoContent);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window.setImage(filename, options);
|
window.setImage(imageDetails);
|
||||||
timerNoContent.stop(); // we have loaded content so stop the fast polling
|
timerNoContent.stop(); // we have loaded content so stop the fast polling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/main.cpp
33
src/main.cpp
@@ -31,8 +31,7 @@ int main(int argc, char *argv[])
|
|||||||
bool shuffle = false;
|
bool shuffle = false;
|
||||||
bool sorted = false;
|
bool sorted = false;
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
char aspect = 'a';
|
ImageDisplayOptions_t baseDisplayOptions;
|
||||||
bool fitAspectAxisToWindow = false;
|
|
||||||
std::string valid_aspects = "alp"; // all, landscape, portait
|
std::string valid_aspects = "alp"; // all, landscape, portait
|
||||||
std::string overlay = "";
|
std::string overlay = "";
|
||||||
std::string imageList = ""; // comma delimited list of images to show
|
std::string imageList = ""; // comma delimited list of images to show
|
||||||
@@ -57,11 +56,26 @@ int main(int argc, char *argv[])
|
|||||||
path = optarg;
|
path = optarg;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
aspect = optarg[0];
|
if ( valid_aspects.find(optarg[0]) == std::string::npos )
|
||||||
if ( valid_aspects.find(aspect) == std::string::npos )
|
|
||||||
{
|
{
|
||||||
std::cout << "Invalid Aspect option, defaulting to all" << std::endl;
|
std::cout << "Invalid Aspect option, defaulting to all" << std::endl;
|
||||||
aspect = 'a';
|
baseDisplayOptions.onlyAspect = EImageAspect_Any;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(optarg[0])
|
||||||
|
{
|
||||||
|
case 'l':
|
||||||
|
baseDisplayOptions.onlyAspect = EImageAspect_Landscape;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
baseDisplayOptions.onlyAspect = EImageAspect_Portrait;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case 'a':
|
||||||
|
baseDisplayOptions.onlyAspect = EImageAspect_Any;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
@@ -103,7 +117,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if(stretchInt==1)
|
if(stretchInt==1)
|
||||||
{
|
{
|
||||||
fitAspectAxisToWindow = true;
|
baseDisplayOptions.fitAspectAxisToWindow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.empty() && imageList.empty())
|
if (path.empty() && imageList.empty())
|
||||||
@@ -130,15 +144,15 @@ 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, aspect, fitAspectAxisToWindow));
|
selector = std::unique_ptr<ImageSelector>(new SortedImageSelector(pathTraverser));
|
||||||
}
|
}
|
||||||
else if (shuffle)
|
else if (shuffle)
|
||||||
{
|
{
|
||||||
selector = std::unique_ptr<ImageSelector>(new ShuffleImageSelector(pathTraverser, aspect, fitAspectAxisToWindow));
|
selector = std::unique_ptr<ImageSelector>(new ShuffleImageSelector(pathTraverser));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser, aspect, fitAspectAxisToWindow));
|
selector = std::unique_ptr<ImageSelector>(new RandomImageSelector(pathTraverser));
|
||||||
}
|
}
|
||||||
selector->setDebugMode(debugMode);
|
selector->setDebugMode(debugMode);
|
||||||
if(debugMode)
|
if(debugMode)
|
||||||
@@ -150,6 +164,7 @@ int main(int argc, char *argv[])
|
|||||||
o.setDebugMode(debugMode);
|
o.setDebugMode(debugMode);
|
||||||
w.setOverlay(&o);
|
w.setOverlay(&o);
|
||||||
w.setDebugMode(debugMode);
|
w.setDebugMode(debugMode);
|
||||||
|
w.setBaseOptions(baseDisplayOptions);
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
ImageSwitcher switcher(w, rotationSeconds * 1000, selector);
|
ImageSwitcher switcher(w, rotationSeconds * 1000, selector);
|
||||||
|
|||||||
@@ -108,16 +108,15 @@ void MainWindow::resizeEvent(QResizeEvent* event)
|
|||||||
updateImage(true);
|
updateImage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setImage(const std::string& path, const ImageOptions_t& options)
|
void MainWindow::setImage(const ImageDetails_t &imageDetails)
|
||||||
{
|
{
|
||||||
currentImage = path;
|
currentImage = imageDetails;
|
||||||
imageOptions = options;
|
|
||||||
updateImage(false);
|
updateImage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateImage(bool immediately)
|
void MainWindow::updateImage(bool immediately)
|
||||||
{
|
{
|
||||||
if (currentImage == "")
|
if (currentImage.filename == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QLabel *label = this->findChild<QLabel*>("image");
|
QLabel *label = this->findChild<QLabel*>("image");
|
||||||
@@ -129,7 +128,7 @@ void MainWindow::updateImage(bool immediately)
|
|||||||
this->setPalette(palette);
|
this->setPalette(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap p( currentImage.c_str() );
|
QPixmap p( currentImage.filename.c_str() );
|
||||||
if(debugMode)
|
if(debugMode)
|
||||||
{
|
{
|
||||||
std::cout << "size:" << p.width() << "x" << p.height() << std::endl;
|
std::cout << "size:" << p.width() << "x" << p.height() << std::endl;
|
||||||
@@ -142,10 +141,10 @@ void MainWindow::updateImage(bool immediately)
|
|||||||
|
|
||||||
if (overlay != NULL)
|
if (overlay != NULL)
|
||||||
{
|
{
|
||||||
drawText(background, overlay->getMarginTopLeft(), overlay->getFontsizeTopLeft(), overlay->getRenderedTopLeft(currentImage).c_str(), Qt::AlignTop|Qt::AlignLeft);
|
drawText(background, overlay->getMarginTopLeft(), overlay->getFontsizeTopLeft(), overlay->getRenderedTopLeft(currentImage.filename).c_str(), Qt::AlignTop|Qt::AlignLeft);
|
||||||
drawText(background, overlay->getMarginTopRight(), overlay->getFontsizeTopRight(), overlay->getRenderedTopRight(currentImage).c_str(), Qt::AlignTop|Qt::AlignRight);
|
drawText(background, overlay->getMarginTopRight(), overlay->getFontsizeTopRight(), overlay->getRenderedTopRight(currentImage.filename).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.filename).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.filename).c_str(), Qt::AlignBottom|Qt::AlignRight);
|
||||||
if (debugMode)
|
if (debugMode)
|
||||||
{
|
{
|
||||||
// draw a thumbnail version of the source image in the bottom left, to check for cropping issues
|
// draw a thumbnail version of the source image in the bottom left, to check for cropping issues
|
||||||
@@ -207,7 +206,7 @@ void MainWindow::setOverlay(Overlay* o)
|
|||||||
|
|
||||||
QPixmap MainWindow::getBlurredBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
QPixmap MainWindow::getBlurredBackground(const QPixmap& originalSize, const QPixmap& scaled)
|
||||||
{
|
{
|
||||||
if (imageOptions.fitAspectAxisToWindow) {
|
if (currentImage.options.fitAspectAxisToWindow) {
|
||||||
// our scaled version will just fill the whole screen, us it directly
|
// our scaled version will just fill the whole screen, us it directly
|
||||||
return scaled.copy();
|
return scaled.copy();
|
||||||
} else if (scaled.width() < width()) {
|
} else if (scaled.width() < width()) {
|
||||||
@@ -225,21 +224,21 @@ QPixmap MainWindow::getBlurredBackground(const QPixmap& originalSize, const QPix
|
|||||||
QPixmap MainWindow::getRotatedPixmap(const QPixmap& p)
|
QPixmap MainWindow::getRotatedPixmap(const QPixmap& p)
|
||||||
{
|
{
|
||||||
QMatrix matrix;
|
QMatrix matrix;
|
||||||
matrix.rotate(imageOptions.rotation);
|
matrix.rotate(currentImage.rotation);
|
||||||
return p.transformed(matrix);
|
return p.transformed(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap MainWindow::getScaledPixmap(const QPixmap& p)
|
QPixmap MainWindow::getScaledPixmap(const QPixmap& p)
|
||||||
{
|
{
|
||||||
if (imageOptions.fitAspectAxisToWindow)
|
if (currentImage.options.fitAspectAxisToWindow)
|
||||||
{
|
{
|
||||||
if (imageOptions.aspect == 'p')
|
if (currentImage.aspect == EImageAspect_Portrait)
|
||||||
{
|
{
|
||||||
// potrait mode, make height of image fit screen and crop top/bottom
|
// potrait mode, make height of image fit screen and crop top/bottom
|
||||||
QPixmap pTemp = p.scaledToHeight(height(), Qt::SmoothTransformation);
|
QPixmap pTemp = p.scaledToHeight(height(), Qt::SmoothTransformation);
|
||||||
return pTemp.copy(0,0,width(),height());
|
return pTemp.copy(0,0,width(),height());
|
||||||
}
|
}
|
||||||
else if (imageOptions.aspect == 'l')
|
else if (currentImage.aspect == EImageAspect_Landscape)
|
||||||
{
|
{
|
||||||
// landscape mode, make width of image fit screen and crop top/bottom
|
// landscape mode, make width of image fit screen and crop top/bottom
|
||||||
QPixmap pTemp = p.scaledToWidth(width(), Qt::SmoothTransformation);
|
QPixmap pTemp = p.scaledToWidth(width(), Qt::SmoothTransformation);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include "imagestructs.h"
|
||||||
#include "imageselector.h"
|
#include "imageselector.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
@@ -22,19 +23,21 @@ public:
|
|||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
void resizeEvent(QResizeEvent* event) override;
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
void setImage(const std::string& path, const ImageOptions_t &options);
|
void setImage(const ImageDetails_t &imageDetails);
|
||||||
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);
|
void setOverlay(Overlay* overlay);
|
||||||
void setDebugMode(bool debugModeIn) {debugMode = debugModeIn;}
|
void setDebugMode(bool debugModeIn) {debugMode = debugModeIn;}
|
||||||
|
void setBaseOptions(const ImageDisplayOptions_t &baseOptionsIn) { baseImageOptions = baseOptionsIn; }
|
||||||
|
const ImageDisplayOptions_t &getBaseOptions() { return baseImageOptions; }
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
std::string currentImage;
|
|
||||||
unsigned int blurRadius = 20;
|
unsigned int blurRadius = 20;
|
||||||
unsigned int backgroundOpacity = 150;
|
unsigned int backgroundOpacity = 150;
|
||||||
ImageOptions_t imageOptions;
|
ImageDisplayOptions_t baseImageOptions;
|
||||||
|
ImageDetails_t currentImage;
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
|
|
||||||
Overlay* overlay;
|
Overlay* overlay;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ QStringList PathTraverser::getImageFormats() const {
|
|||||||
return imageFormats;
|
return imageFormats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathTraverser::LoadOptionsForDirectory(const std::string &directoryPath, ImageOptions_t &options) const
|
void PathTraverser::LoadOptionsForDirectory(const std::string &directoryPath, ImageDisplayOptions_t &options) const
|
||||||
{
|
{
|
||||||
QDir directory(directoryPath.c_str());
|
QDir directory(directoryPath.c_str());
|
||||||
QString jsonFile = directory.filePath(QString("options.json"));
|
QString jsonFile = directory.filePath(QString("options.json"));
|
||||||
@@ -79,7 +79,7 @@ const std::string RecursivePathTraverser::getImagePath(const std::string image)
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecursivePathTraverser::UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const
|
void RecursivePathTraverser::UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const
|
||||||
{
|
{
|
||||||
QDir d = QFileInfo(filename.c_str()).absoluteDir();
|
QDir d = QFileInfo(filename.c_str()).absoluteDir();
|
||||||
LoadOptionsForDirectory(d.absolutePath().toStdString(), options);
|
LoadOptionsForDirectory(d.absolutePath().toStdString(), options);
|
||||||
@@ -103,7 +103,7 @@ const std::string DefaultPathTraverser::getImagePath(const std::string image) co
|
|||||||
return directory.filePath(QString(image.c_str())).toStdString();
|
return directory.filePath(QString(image.c_str())).toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultPathTraverser::UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const
|
void DefaultPathTraverser::UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const
|
||||||
{
|
{
|
||||||
UNUSED(filename);
|
UNUSED(filename);
|
||||||
LoadOptionsForDirectory(directory.absolutePath().toStdString(), options);
|
LoadOptionsForDirectory(directory.absolutePath().toStdString(), options);
|
||||||
@@ -129,7 +129,7 @@ const std::string ImageListPathTraverser::getImagePath(const std::string image)
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageListPathTraverser::UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const
|
void ImageListPathTraverser::UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const
|
||||||
{
|
{
|
||||||
// no per file options modification supported
|
// no per file options modification supported
|
||||||
UNUSED(filename);
|
UNUSED(filename);
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ class PathTraverser
|
|||||||
virtual ~PathTraverser();
|
virtual ~PathTraverser();
|
||||||
virtual QStringList getImages() const = 0;
|
virtual QStringList getImages() const = 0;
|
||||||
virtual const std::string getImagePath(const std::string image) const = 0;
|
virtual const std::string getImagePath(const std::string image) const = 0;
|
||||||
virtual void UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const = 0;
|
virtual void UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const std::string path;
|
const std::string path;
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
QStringList getImageFormats() const;
|
QStringList getImageFormats() const;
|
||||||
void LoadOptionsForDirectory(const std::string &directoryPath, ImageOptions_t &options) const;
|
void LoadOptionsForDirectory(const std::string &directoryPath, ImageDisplayOptions_t &options) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RecursivePathTraverser : public PathTraverser
|
class RecursivePathTraverser : public PathTraverser
|
||||||
@@ -32,7 +32,7 @@ class RecursivePathTraverser : public PathTraverser
|
|||||||
virtual ~RecursivePathTraverser();
|
virtual ~RecursivePathTraverser();
|
||||||
QStringList getImages() const;
|
QStringList getImages() const;
|
||||||
virtual const std::string getImagePath(const std::string image) const;
|
virtual const std::string getImagePath(const std::string image) const;
|
||||||
virtual void UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const;
|
virtual void UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DefaultPathTraverser : public PathTraverser
|
class DefaultPathTraverser : public PathTraverser
|
||||||
@@ -42,7 +42,7 @@ class DefaultPathTraverser : public PathTraverser
|
|||||||
virtual ~DefaultPathTraverser();
|
virtual ~DefaultPathTraverser();
|
||||||
QStringList getImages() const;
|
QStringList getImages() const;
|
||||||
virtual const std::string getImagePath(const std::string image) const;
|
virtual const std::string getImagePath(const std::string image) const;
|
||||||
virtual void UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const;
|
virtual void UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const;
|
||||||
private:
|
private:
|
||||||
QDir directory;
|
QDir directory;
|
||||||
};
|
};
|
||||||
@@ -54,7 +54,7 @@ class ImageListPathTraverser : public PathTraverser
|
|||||||
virtual ~ImageListPathTraverser();
|
virtual ~ImageListPathTraverser();
|
||||||
QStringList getImages() const;
|
QStringList getImages() const;
|
||||||
virtual const std::string getImagePath(const std::string image) const;
|
virtual const std::string getImagePath(const std::string image) const;
|
||||||
virtual void UpdateOptionsForImage(const std::string& filename, ImageOptions_t& options) const;
|
virtual void UpdateOptionsForImage(const std::string& filename, ImageDisplayOptions_t& options) const;
|
||||||
private:
|
private:
|
||||||
QStringList imageList;
|
QStringList imageList;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user