From 19041a525e20be6465fbe6ea7bcb67c180e7f21e Mon Sep 17 00:00:00 2001 From: "ext-philippe.leprince" Date: Mon, 7 Sep 2026 17:29:55 +0200 Subject: [PATCH] feat(viewport): add render-to-thumbnail handler for offscreen viewport Add a new CAF message handler to OffscreenViewport that renders a supplied full-resolution image down to a thumbnail via the viewport's colour-managed pipeline. The handler normalises the input image buffer to RGBA_16F format before generating the thumbnail, and converts the result to RGB24. This provides a fallback thumbnail generation path for the filesystem browser when native thumbnails are unavailable. The handler validates input dimensions and image buffers, returning a descriptive error on invalid input, and catches any exceptions during rendering to return them as CAF errors. Signed-off-by: ext-philippe.leprince --- .../src/offscreen_viewport.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ui/qt/viewport_widget/src/offscreen_viewport.cpp b/src/ui/qt/viewport_widget/src/offscreen_viewport.cpp index 4973aad92..b75c6c147 100644 --- a/src/ui/qt/viewport_widget/src/offscreen_viewport.cpp +++ b/src/ui/qt/viewport_widget/src/offscreen_viewport.cpp @@ -282,6 +282,39 @@ OffscreenViewport::OffscreenViewport(const std::string name, bool sync_with_main } }, + [=](render_viewport_to_image_atom, + const int width, + const int height, + const media_reader::ImageBufPtr image) -> result { + try { + // Render a supplied full-res image down to a thumbnail via the + // viewport's colour-managed pipeline. The image buffer may be in + // any reader-provided format; the offscreen render normalises it to + // RGBA_16F, which rgb96thumbFromHalfFloatImage expects. + if (!image || width <= 0 || height <= 0) + return caf::make_error( + xstudio_error::error, + "OffscreenViewport render-to-thumbnail: invalid image or " + "dimensions."); + media_reader::ImageBufPtr rendered(new media_reader::ImageBuffer()); + renderToImageBuffer( + width, + height, + rendered, + ImageFormat::RGBA_16F, + true, + utility::clock::now(), + image, + false, // include_overlays + true); // include_drawings + thumbnail::ThumbnailBufferPtr r = rgb96thumbFromHalfFloatImage(rendered); + r->convert_to(thumbnail::TF_RGB24); + return r; + } catch (std::exception &e) { + return caf::make_error(xstudio_error::error, e.what()); + } + }, + [=](render_viewport_to_image_atom, caf::actor media_actor, const int media_frame,