asyncResourceGatherer: deduplicate image rendering code (#433)

* asyncResourceGatherer: deduplicate image rendering code

Also happens to add support for JPEG and WEBP for image widgets

* asyncResourceGatherer: use a reference for path in getFileType
This commit is contained in:
Maximilian Seidler 2024-07-19 23:20:31 +02:00 committed by GitHub
parent 20c01d91d4
commit 3d3b52e42c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -91,6 +91,51 @@ enum class FileType {
UNKNOWN,
};
FileType getFileType(const std::filesystem::path& path) {
std::string ext = path.extension().string();
// convert the extension to lower case
std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return c <= 'Z' && c >= 'A' ? c - ('Z' - 'z') : c; });
FileType ft = FileType::UNKNOWN;
Debug::log(TRACE, "Extension: {}", ext);
if (ext == ".png")
ft = FileType::PNG;
else if (ext == ".jpg" || ext == ".jpeg")
ft = FileType::JPEG;
else if (ext == ".webp")
ft = FileType::WEBP;
else {
// magic is slow, so only use it when no recognized extension is found
auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS);
magic_load(handle, nullptr);
const auto type_str = std::string(magic_file(handle, path.c_str()));
const auto first_word = type_str.substr(0, type_str.find(" "));
magic_close(handle);
if (first_word == "PNG")
ft = FileType::PNG;
else if (first_word == "JPEG")
ft = FileType::JPEG;
else if (first_word == "RIFF" && type_str.find("Web/P image") != std::string::npos)
ft = FileType::WEBP;
}
return ft;
}
cairo_surface_t* getCairoSurfaceFromImageFile(const std::filesystem::path& path) {
cairo_surface_t* cairoSurface = nullptr;
switch (getFileType(path)) {
case FileType::PNG: cairoSurface = cairo_image_surface_create_from_png(path.c_str()); break;
case FileType::JPEG: cairoSurface = JPEG::createSurfaceFromJPEG(path); break;
case FileType::WEBP: cairoSurface = WEBP::createSurfaceFromWEBP(path); break;
default: Debug::log(ERR, "unrecognized image format of {}", path.c_str());
}
return cairoSurface;
}
void CAsyncResourceGatherer::gather() {
const auto CWIDGETS = g_pConfigManager->getWidgetConfigs();
@ -117,67 +162,15 @@ void CAsyncResourceGatherer::gather() {
if (path.empty() || path == "screenshot")
continue;
std::string id = (c.type == "background" ? std::string{"background:"} : std::string{"image:"}) + path;
std::filesystem::path ABSOLUTEPATH(absolutePath(path, ""));
std::string id = (c.type == "background" ? std::string{"background:"} : std::string{"image:"}) + path;
// determine the file type
std::string ext = ABSOLUTEPATH.extension().string();
// convert the extension to lower case
std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return c <= 'Z' && c >= 'A' ? c - ('Z' - 'z') : c; });
// render the image directly, since we are in a seperate thread
CAsyncResourceGatherer::SPreloadRequest rq;
rq.type = CAsyncResourceGatherer::TARGET_IMAGE;
rq.asset = path;
rq.id = id;
FileType ft = FileType::UNKNOWN;
Debug::log(WARN, "Extension: {}", ext);
if (ext == ".png")
ft = FileType::PNG;
else if (ext == ".jpg" || ext == ".jpeg")
ft = FileType::JPEG;
else if (ext == ".webp")
ft = FileType::WEBP;
else {
// magic is slow, so only use it when no recognized extension is found
auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS);
magic_load(handle, nullptr);
const auto type_str = std::string(magic_file(handle, ABSOLUTEPATH.c_str()));
const auto first_word = type_str.substr(0, type_str.find(" "));
magic_close(handle);
if (first_word == "PNG")
ft = FileType::PNG;
else if (first_word == "JPEG")
ft = FileType::JPEG;
else if (first_word == "RIFF" && type_str.find("Web/P image") != std::string::npos)
ft = FileType::WEBP;
}
// preload bg img
cairo_surface_t* CAIROISURFACE = nullptr;
switch (ft) {
case FileType::PNG: CAIROISURFACE = cairo_image_surface_create_from_png(ABSOLUTEPATH.c_str()); break;
case FileType::JPEG: CAIROISURFACE = JPEG::createSurfaceFromJPEG(ABSOLUTEPATH); break;
case FileType::WEBP: CAIROISURFACE = WEBP::createSurfaceFromWEBP(ABSOLUTEPATH); break;
default: Debug::log(ERR, "unrecognized image format of {}", path.c_str()); continue;
}
if (CAIROISURFACE == nullptr)
continue;
const auto CAIRO = cairo_create(CAIROISURFACE);
cairo_scale(CAIRO, 1, 1);
{
std::lock_guard lg{preloadTargetsMutex};
const auto TARGET = &preloadTargets.emplace_back(CAsyncResourceGatherer::SPreloadTarget{});
TARGET->size = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)};
TARGET->type = TARGET_IMAGE;
TARGET->id = id;
const auto DATA = cairo_image_surface_get_data(CAIROISURFACE);
TARGET->cairo = CAIRO;
TARGET->cairosurface = CAIROISURFACE;
TARGET->data = DATA;
}
renderImage(rq);
}
}
@ -243,8 +236,13 @@ void CAsyncResourceGatherer::renderImage(const SPreloadRequest& rq) {
target.type = TARGET_IMAGE;
target.id = rq.id;
const auto ABSOLUTEPATH = absolutePath(rq.asset, "");
const auto CAIROISURFACE = cairo_image_surface_create_from_png(ABSOLUTEPATH.c_str());
std::filesystem::path ABSOLUTEPATH(absolutePath(rq.asset, ""));
const auto CAIROISURFACE = getCairoSurfaceFromImageFile(ABSOLUTEPATH);
if (!CAIROISURFACE) {
Debug::log(ERR, "No cairo surface!");
return;
}
const auto CAIRO = cairo_create(CAIROISURFACE);
cairo_scale(CAIRO, 1, 1);