Skip to content

Commit

Permalink
asyncResourceGatherer: deduplicate image rendering code (#433)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
PaideiaDilemma authored Jul 19, 2024
1 parent 20c01d9 commit 3d3b52e
Showing 1 changed file with 59 additions and 61 deletions.
120 changes: 59 additions & 61 deletions src/renderer/AsyncResourceGatherer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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, ""));

// 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; });

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;
}
std::string id = (c.type == "background" ? std::string{"background:"} : std::string{"image:"}) + path;

// 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{});
// 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;

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);
}
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 3d3b52e

Please sign in to comment.