From 3d3b52e42cd8cf1fb9f918ee03f7d2d90c0a34cd Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Fri, 19 Jul 2024 23:20:31 +0200 Subject: [PATCH] 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 --- src/renderer/AsyncResourceGatherer.cpp | 120 ++++++++++++------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/src/renderer/AsyncResourceGatherer.cpp b/src/renderer/AsyncResourceGatherer.cpp index 18282ff..17627ed 100644 --- a/src/renderer/AsyncResourceGatherer.cpp +++ b/src/renderer/AsyncResourceGatherer.cpp @@ -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);