Increased the maximum image size for the scraper and improved the scaling function.

This commit is contained in:
Leon Styhre 2021-05-24 21:34:08 +02:00
parent 1e97133f21
commit ce6eed6c3a
3 changed files with 58 additions and 42 deletions
es-app/src/scrapers
es-core/src

View file

@ -22,6 +22,7 @@
#include "views/ViewController.h" #include "views/ViewController.h"
#endif #endif
#include <cmath>
#include <FreeImage.h> #include <FreeImage.h>
#include <fstream> #include <fstream>
@ -307,8 +308,7 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
// Resize it. // Resize it.
if (it->resizeFile) { if (it->resizeFile) {
if (!resizeImage(filePath, Settings::getInstance()->getInt("ScraperResizeMaxWidth"), if (!resizeImage(filePath, it->subDirectory)) {
Settings::getInstance()->getInt("ScraperResizeMaxHeight"))) {
setError("Error saving resized image.\nOut of memory? Disk full?"); setError("Error saving resized image.\nOut of memory? Disk full?");
return; return;
} }
@ -319,7 +319,7 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
// If it's not cached, then initiate the download. // If it's not cached, then initiate the download.
else { else {
mFuncs.push_back(ResolvePair(downloadMediaAsync(it->fileURL, filePath, mFuncs.push_back(ResolvePair(downloadMediaAsync(it->fileURL, filePath,
it->existingMediaFile, it->resizeFile, mResult.savedNewMedia), it->existingMediaFile, it->subDirectory, it->resizeFile, mResult.savedNewMedia),
[this, filePath] {})); [this, filePath] {}));
} }
} }
@ -353,6 +353,7 @@ std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
const std::string& url, const std::string& url,
const std::string& saveAs, const std::string& saveAs,
const std::string& existingMediaPath, const std::string& existingMediaPath,
const std::string& mediaType,
const bool resizeFile, const bool resizeFile,
bool& savedNewMedia) bool& savedNewMedia)
{ {
@ -360,25 +361,22 @@ std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
url, url,
saveAs, saveAs,
existingMediaPath, existingMediaPath,
mediaType,
resizeFile, resizeFile,
savedNewMedia, savedNewMedia));
Settings::getInstance()->getInt("ScraperResizeMaxWidth"),
Settings::getInstance()->getInt("ScraperResizeMaxHeight")));
} }
MediaDownloadHandle::MediaDownloadHandle( MediaDownloadHandle::MediaDownloadHandle(
const std::string& url, const std::string& url,
const std::string& path, const std::string& path,
const std::string& existingMediaPath, const std::string& existingMediaPath,
const std::string& mediaType,
const bool resizeFile, const bool resizeFile,
bool& savedNewMedia, bool& savedNewMedia)
int maxWidth,
int maxHeight)
: mSavePath(path), : mSavePath(path),
mExistingMediaFile(existingMediaPath), mExistingMediaFile(existingMediaPath),
mMediaType(mediaType),
mResizeFile(resizeFile), mResizeFile(resizeFile),
mMaxWidth(maxWidth),
mMaxHeight(maxHeight),
mReq(new HttpReq(url)) mReq(new HttpReq(url))
{ {
mSavedNewMediaPtr = &savedNewMedia; mSavedNewMediaPtr = &savedNewMedia;
@ -453,7 +451,7 @@ void MediaDownloadHandle::update()
// Resize it. // Resize it.
if (mResizeFile) { if (mResizeFile) {
if (!resizeImage(mSavePath, mMaxWidth, mMaxHeight)) { if (!resizeImage(mSavePath, mMediaType)) {
setError("Error saving resized image.\nOut of memory? Disk full?"); setError("Error saving resized image.\nOut of memory? Disk full?");
return; return;
} }
@ -465,17 +463,25 @@ void MediaDownloadHandle::update()
setStatus(ASYNC_DONE); setStatus(ASYNC_DONE);
} }
// You can pass 0 for width or height to keep aspect ratio. bool resizeImage(const std::string& path, const std::string& mediaType)
bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
{ {
// Nothing to do. float maxWidth = 0.0f;
if (maxWidth == 0 && maxHeight == 0) float maxHeight = 0.0f;
return true;
if (mediaType == "marquees") {
// We don't really need huge marquees.
maxWidth = 1000.0f;
maxHeight = 600.0f;
}
else {
maxWidth = 2560.0f;
maxHeight = 1440.0f;
}
FREE_IMAGE_FORMAT format = FIF_UNKNOWN; FREE_IMAGE_FORMAT format = FIF_UNKNOWN;
FIBITMAP* image = nullptr; FIBITMAP* image = nullptr;
// Detect the filetype. // Detect the file format.
format = FreeImage_GetFileType(path.c_str(), 0); format = FreeImage_GetFileType(path.c_str(), 0);
if (format == FIF_UNKNOWN) if (format == FIF_UNKNOWN)
format = FreeImage_GetFIFFromFilename(path.c_str()); format = FreeImage_GetFIFFromFilename(path.c_str());
@ -484,7 +490,7 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
return false; return false;
} }
// Make sure we can read this filetype first, then load it. // Make sure we can read this format, and if so, then load it.
if (FreeImage_FIFSupportsReading(format)) { if (FreeImage_FIFSupportsReading(format)) {
image = FreeImage_Load(format, path.c_str()); image = FreeImage_Load(format, path.c_str());
} }
@ -496,23 +502,37 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
float width = static_cast<float>(FreeImage_GetWidth(image)); float width = static_cast<float>(FreeImage_GetWidth(image));
float height = static_cast<float>(FreeImage_GetHeight(image)); float height = static_cast<float>(FreeImage_GetHeight(image));
// If the image is smaller than maxWidth or maxHeight, then don't do any // If the image is smaller than (or the same size as) maxWidth and maxHeight, then don't
// scaling. It doesn't make sense to upscale the image and waste disk space. // do any scaling. It doesn't make sense to upscale the image and waste disk space.
if (maxWidth > width || maxHeight > height) { if (maxWidth >= width && maxHeight >= height) {
LOG(LogDebug) << "Scraper::resizeImage(): Saving image \"" << path <<
"\" at its original resolution " << width << "x" << height;
FreeImage_Unload(image); FreeImage_Unload(image);
return true; return true;
} }
if (maxWidth == 0) float scaleFactor = 0.0f;
maxWidth = static_cast<int>((maxHeight / height) * width);
else if (maxHeight == 0)
maxHeight = static_cast<int>((maxWidth / width) * height);
FIBITMAP* imageRescaled = FreeImage_Rescale(image, maxWidth, maxHeight, FILTER_BILINEAR); // Calculate how much we should scale.
if (width > maxWidth) {
scaleFactor = maxWidth / width;
if (height * scaleFactor > maxHeight)
scaleFactor = maxHeight / height;
}
else {
scaleFactor = maxHeight / height;
}
maxWidth = floorf(width * scaleFactor);
maxHeight = floorf(height * scaleFactor);
// We use Lanczos3 which is the highest quality resampling method available in FreeImage.
FIBITMAP* imageRescaled = FreeImage_Rescale(image, static_cast<int>(maxWidth),
static_cast<int>(maxHeight), FILTER_LANCZOS3);
FreeImage_Unload(image); FreeImage_Unload(image);
if (imageRescaled == nullptr) { if (imageRescaled == nullptr) {
LOG(LogError) << "Could not resize image (not enough memory or invalid bitdepth?)"; LOG(LogError) << "Couldn't resize image, not enough memory or invalid bit depth?";
return false; return false;
} }
@ -522,6 +542,10 @@ bool resizeImage(const std::string& path, int maxWidth, int maxHeight)
if (!saved) { if (!saved) {
LOG(LogError) << "Failed to save resized image"; LOG(LogError) << "Failed to save resized image";
} }
else {
LOG(LogDebug) << "Scraper::resizeImage(): Downscaled image \"" << path << "\" from "
<< width << "x" << height << " to " << maxWidth << "x" << maxHeight;
}
return saved; return saved;
} }

View file

@ -195,10 +195,9 @@ public:
const std::string& url, const std::string& url,
const std::string& path, const std::string& path,
const std::string& existingMediaPath, const std::string& existingMediaPath,
const std::string& mediaType,
const bool resizeFile, const bool resizeFile,
bool& savedNewMedia, bool& savedNewMedia);
int maxWidth,
int maxHeight);
void update() override; void update() override;
@ -206,10 +205,9 @@ private:
std::unique_ptr<HttpReq> mReq; std::unique_ptr<HttpReq> mReq;
std::string mSavePath; std::string mSavePath;
std::string mExistingMediaFile; std::string mExistingMediaFile;
std::string mMediaType;
bool mResizeFile; bool mResizeFile;
bool *mSavedNewMediaPtr; bool *mSavedNewMediaPtr;
int mMaxWidth;
int mMaxHeight;
}; };
// Downloads to the home directory, using this subdirectory structure: // Downloads to the home directory, using this subdirectory structure:
@ -218,12 +216,11 @@ private:
std::string getSaveAsPath(const ScraperSearchParams& params, std::string getSaveAsPath(const ScraperSearchParams& params,
const std::string& filetypeSubdirectory, const std::string& url); const std::string& filetypeSubdirectory, const std::string& url);
// Will resize according to Settings::getInt("ScraperResizeMaxWidth") and
// Settings::getInt("ScraperResizeMaxHeight").
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync( std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
const std::string& url, const std::string& url,
const std::string& saveAs, const std::string& saveAs,
const std::string& existingMediaPath, const std::string& existingMediaPath,
const std::string& mediaType,
const bool resizeFile, const bool resizeFile,
bool& savedNewMedia); bool& savedNewMedia);
@ -231,9 +228,6 @@ std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result, std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,
const ScraperSearchParams& search); const ScraperSearchParams& search);
// You can pass 0 for maxWidth or maxHeight to automatically keep the aspect ratio. bool resizeImage(const std::string& path, const std::string& mediaType);
// It will overwrite the image at [path] with the new resized one.
// Returns true if successful, false otherwise.
bool resizeImage(const std::string& path, int maxWidth, int maxHeight);
#endif // ES_APP_SCRAPERS_SCRAPER_H #endif // ES_APP_SCRAPERS_SCRAPER_H

View file

@ -301,8 +301,7 @@ void Settings::setDefaults()
// //
mStringMap["ROMDirectory"] = { "", "" }; mStringMap["ROMDirectory"] = { "", "" };
mIntMap["ScraperResizeMaxWidth"] = { 600, 600 }; mStringMap["UIMode_passkey"] = { "uuddlrlrba", "uuddlrlrba" };
mIntMap["ScraperResizeMaxHeight"] = { 0, 0 };
// //
// Hardcoded or program-internal settings. // Hardcoded or program-internal settings.
@ -313,7 +312,6 @@ void Settings::setDefaults()
mBoolMap["DebugImage"] = { false, false }; mBoolMap["DebugImage"] = { false, false };
mBoolMap["SplashScreenProgress"] = { true, true }; mBoolMap["SplashScreenProgress"] = { true, true };
mIntMap["ScraperFilter"] = { 0, 0 }; mIntMap["ScraperFilter"] = { 0, 0 };
mStringMap["UIMode_passkey"] = { "uuddlrlrba", "uuddlrlrba" };
} }
template <typename K, typename V> template <typename K, typename V>