From 36222d14a2ad126d2aef0a1000b6d65584e6a2bc Mon Sep 17 00:00:00 2001 From: Pandagrapher Date: Sun, 21 Aug 2022 15:45:07 +0200 Subject: [PATCH] Fixes blur rendering with RTSurface on hidpi screen Other fixes: - Fixes splash image not rendered - Cleans commented code - Replaces deprecated librsvg functions - Updates Makefile librsvg required minimum version - Correctly uses RTSurface getWidth / getHeight functions - Improves lwbutton aspect Known issues: - Blur rendering with RTPixbuf on hidpi screen --- CMakeLists.txt | 2 +- rtgui/batchqueueentry.cc | 4 +-- rtgui/filebrowserentry.cc | 4 +-- rtgui/lwbutton.cc | 14 +++++----- rtgui/rtscalable.cc | 57 ++++++++++++++++++++++----------------- rtgui/rtsurface.cc | 52 +++++++++++++++++++++++++++++++---- rtgui/splash.cc | 8 +++--- 7 files changed, 95 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53480968c..7806af000 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -467,7 +467,7 @@ pkg_check_modules(GTHREAD REQUIRED gthread-2.0>=2.48) pkg_check_modules(GOBJECT REQUIRED gobject-2.0>=2.48) pkg_check_modules(SIGC REQUIRED sigc++-2.0>=2.3.1) pkg_check_modules(LENSFUN REQUIRED lensfun>=0.2) -pkg_check_modules(RSVG REQUIRED librsvg-2.0>=2.46) +pkg_check_modules(RSVG REQUIRED librsvg-2.0>=2.52) if(WIN32) add_definitions(-DWIN32) diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 6ab6ccf83..a04ede5b8 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -168,8 +168,8 @@ std::vector> BatchQueueEntry::getIconsOnImageArea () void BatchQueueEntry::getIconSize (int& w, int& h) const { - w = savedAsIcon->get()->get_width (); - h = savedAsIcon->get()->get_height (); + w = savedAsIcon->getWidth (); + h = savedAsIcon->getHeight (); } diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index b3d4e6904..f922e2084 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -195,8 +195,8 @@ void FileBrowserEntry::customBackBufferUpdate (Cairo::RefPtr c) void FileBrowserEntry::getIconSize (int& w, int& h) const { - w = editedIcon->get()->get_width (); - h = editedIcon->get()->get_height (); + w = editedIcon->getWidth (); + h = editedIcon->getHeight (); } FileThumbnailButtonSet* FileBrowserEntry::getThumbButtonSet () diff --git a/rtgui/lwbutton.cc b/rtgui/lwbutton.cc index 9f65218cf..cd6678ed5 100644 --- a/rtgui/lwbutton.cc +++ b/rtgui/lwbutton.cc @@ -25,8 +25,8 @@ LWButton::LWButton (std::shared_ptr i, int aCode, void* aData, Alignm { if (i) { - w = i->getWidth () + 2; - h = i->getHeight () + 2; + w = i->getWidth (); + h = i->getHeight (); } else { w = h = 2; } @@ -65,8 +65,8 @@ void LWButton::setIcon (std::shared_ptr i) icon = i; if (i) { - w = i->getWidth () + 2; - h = i->getHeight () + 2; + w = i->getWidth (); + h = i->getHeight (); } else { w = h = 2; } @@ -186,9 +186,9 @@ void LWButton::redraw (Cairo::RefPtr context) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected - context->set_line_width (1.0); + context->set_line_width (2.0); // Line width shall be even to avoid blur effect when upscaling context->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - context->rectangle (xpos + 0.5, ypos + 0.5, w - 1.0, h - 1.0); + context->rectangle (xpos, ypos, w, h); if (state == Pressed_In) { context->set_source_rgb (fgr, fgg, fgb); @@ -205,7 +205,7 @@ void LWButton::redraw (Cairo::RefPtr context) } context->stroke (); - int dilat = 1; + int dilat = 0; if (state == Pressed_In) { dilat++; diff --git a/rtgui/rtscalable.cc b/rtgui/rtscalable.cc index 5606fe677..b161591cb 100644 --- a/rtgui/rtscalable.cc +++ b/rtgui/rtscalable.cc @@ -36,7 +36,13 @@ void RTScalable::updateDPInScale(const Gtk::Window* window, double &newDPI, int if (window) { const auto screen = window->get_screen(); newDPI = screen->get_resolution(); // Get DPI retrieved from the OS - newScale = window->get_scale_factor(); // Get scale factor associated to the window + + if (window->get_scale_factor() > 0) { + // Get scale factor associated to the window + newScale = window->get_scale_factor(); + } else { + newScale = 1; // Default minimum value of 1 as scale is used to scale surface + } } } @@ -88,21 +94,6 @@ Cairo::RefPtr RTScalable::loadSurfaceFromIcon(const Glib::u } } - /* - // Scale current surface size to desired scaled size - if (surface) { - // Note: surface is considered made from squared icon - const double scale_factor = static_cast(size) / static_cast(surface->get_width()); - surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, - static_cast(surface->get_width() * scale_factor + 0.5), - static_cast(surface->get_height() * scale_factor + 0.5)); - const auto cr = Cairo::Context::create(surf); - cr->scale(scale_factor, scale_factor); - cr->set_source(surface, 0, 0); - cr->paint(); - } - */ - return surf; } @@ -174,33 +165,44 @@ Cairo::RefPtr RTScalable::loadSurfaceFromSVG(const Glib::us return surf; } + int w, h; + if (width == -1 || height == -1) { // Use SVG image natural width and height - RsvgDimensionData dim; - rsvg_handle_get_dimensions(handle, &dim); // Get SVG image dimensions - surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, dim.width, dim.height); + double _w, _h; + const bool has_dim = rsvg_handle_get_intrinsic_size_in_pixels(handle, &_w, &_h); // Get SVG image dimensions + if (has_dim) { + w = std::ceil(_w); + h = std::ceil(_h); + } else { + w = h = 16; // Set to a default size of 16px (i.e. Gtk::ICON_SIZE_SMALL_TOOLBAR one) + } } else { // Use given width and height - surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, width, height); + w = width; + h = height; } + // Create an upscaled surface to avoid blur effect + surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, + w * RTScalable::getScale(), + h * RTScalable::getScale()); + // Render (and erase with) default surface background Cairo::RefPtr c = Cairo::Context::create(surf); c->set_source_rgba (0., 0., 0., 0.); c->set_operator (Cairo::OPERATOR_CLEAR); c->paint(); - // Render surface based on SVG image + // Render upscaled surface based on SVG image error = nullptr; RsvgRectangle rect = { .x = 0., .y = 0., - .width = static_cast(width * RTScalable::getScale()), // SVG image is upscaled to avoid blur effect - .height = static_cast(height * RTScalable::getScale()) // SVG image is upscaled to avoid blur effect + .width = static_cast(w * RTScalable::getScale()), + .height = static_cast(h * RTScalable::getScale()) }; c->set_operator (Cairo::OPERATOR_OVER); - c->scale(1. / RTScalable::getScale(), 1. / RTScalable::getScale()); // Cairo surface is scaled to match image dimensions - const bool success = rsvg_handle_render_document(handle, c->cobj(), &rect, &error); if (!success && error) { @@ -210,6 +212,11 @@ Cairo::RefPtr RTScalable::loadSurfaceFromSVG(const Glib::us } rsvg_handle_free(handle); + + // Set device scale to avoid blur effect + cairo_surface_set_device_scale(surf->cobj(), + static_cast(RTScalable::getScale()), + static_cast(RTScalable::getScale())); } else { if (rtengine::settings->verbose) { std::cerr << "Failed to load SVG file \"" << fname << "\"" << std::endl; diff --git a/rtgui/rtsurface.cc b/rtgui/rtsurface.cc index 46bddcaa1..b72a87d0d 100644 --- a/rtgui/rtsurface.cc +++ b/rtgui/rtsurface.cc @@ -90,7 +90,7 @@ int RTSurface::getWidth() { return surface - ? surface->get_width() + ? (surface->get_width() / RTScalable::getScale()) : -1; } @@ -98,7 +98,7 @@ int RTSurface::getHeight() { return surface - ? surface->get_height() + ? (surface->get_height() / RTScalable::getScale()) : -1; } @@ -152,8 +152,22 @@ RTPixbuf::RTPixbuf(const Glib::ustring &icon_name, const Gtk::IconSize iconSize) const Cairo::RefPtr surface = RTScalable::loadSurfaceFromIcon(icon_name, iconSize); if (surface) { + // Downscale surface before creating pixbuf + const Cairo::RefPtr _surface = Cairo::Surface::create(surface, + Cairo::CONTENT_COLOR_ALPHA, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); + const auto c = Cairo::Context::create(_surface); + c->scale(1. / static_cast(RTScalable::getScale()), 1. / static_cast(RTScalable::getScale())); + c->set_source(surface, 0., 0.); + c->paint(); + // Create pixbuf from surface - pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height()); + pixbuf = Gdk::Pixbuf::create(_surface, + 0, + 0, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); // Save private parameters type = RTPixbuf::IconType; @@ -177,8 +191,22 @@ RTPixbuf::RTPixbuf(const Glib::ustring &fname) : const Cairo::RefPtr surface = RTScalable::loadSurfaceFromPNG(fname); if (surface) { + // Downscale surface before creating pixbuf + const Cairo::RefPtr _surface = Cairo::Surface::create(surface, + Cairo::CONTENT_COLOR_ALPHA, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); + const auto c = Cairo::Context::create(_surface); + c->scale(1. / static_cast(RTScalable::getScale()), 1. / static_cast(RTScalable::getScale())); + c->set_source(surface, 0., 0.); + c->paint(); + // Create pixbuf from surface - pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height()); + pixbuf = Gdk::Pixbuf::create(_surface, + 0, + 0, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); // Save private parameter type = RTPixbuf::PNGType; @@ -192,8 +220,22 @@ RTPixbuf::RTPixbuf(const Glib::ustring &fname) : const Cairo::RefPtr surface = RTScalable::loadSurfaceFromSVG(fname); if (surface) { + // Downscale surface before creating pixbuf + const Cairo::RefPtr _surface = Cairo::Surface::create(surface, + Cairo::CONTENT_COLOR_ALPHA, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); + const auto c = Cairo::Context::create(_surface); + c->scale(1. / static_cast(RTScalable::getScale()), 1. / static_cast(RTScalable::getScale())); + c->set_source(surface, 0., 0.); + c->paint(); + // Create pixbuf from surface - pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height()); + pixbuf = Gdk::Pixbuf::create(_surface, + 0, + 0, + surface->get_width() / RTScalable::getScale(), + surface->get_height() / RTScalable::getScale()); // Save private parameter type = RTPixbuf::SVGType; diff --git a/rtgui/splash.cc b/rtgui/splash.cc index d00a074dc..9b2aa67d0 100644 --- a/rtgui/splash.cc +++ b/rtgui/splash.cc @@ -34,7 +34,7 @@ bool SplashImage::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { if (surface->hasSurface()) { cr->set_source(surface->get(), 0., 0.); - cr->rectangle(0, 0, surface->get()->get_width(), surface->get()->get_height()); + cr->rectangle(0, 0, surface->getWidth(), surface->getHeight()); cr->fill(); Cairo::FontOptions cfo; @@ -68,7 +68,7 @@ bool SplashImage::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) cr->set_source_rgb (0., 0., 0.); cr->set_line_width(3.); cr->set_line_join(Cairo::LINE_JOIN_ROUND); - cr->move_to (surface->get()->get_width() - w - 32, surface->get()->get_height() - h - 20); + cr->move_to (surface->getWidth() - w - 32, surface->getHeight() - h - 20); version->add_to_cairo_context (cr); cr->stroke_preserve(); cr->set_source_rgb (1., 1., 1.); @@ -87,12 +87,12 @@ Gtk::SizeRequestMode SplashImage::get_request_mode_vfunc () const void SplashImage::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const { - minimum_height = natural_height = surface ? surface->get()->get_height() : RTScalable::scalePixelSize(100); + minimum_height = natural_height = surface ? surface->getHeight() : RTScalable::scalePixelSize(100); } void SplashImage::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const { - minimum_width = natural_width = surface ? surface->get()->get_width() : RTScalable::scalePixelSize(100); + minimum_width = natural_width = surface ? surface->getWidth() : RTScalable::scalePixelSize(100); } void SplashImage::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const