From 3d5ef4038e33082dcac1513ba55f13c0e88f697e Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Tue, 26 Dec 2023 22:28:45 +0100 Subject: [PATCH] image: Rename background_color module --- src/widgets/image.rs | 2 +- src/widgets/image/guess_background_color.rs | 186 -------------------- 2 files changed, 1 insertion(+), 187 deletions(-) delete mode 100644 src/widgets/image/guess_background_color.rs diff --git a/src/widgets/image.rs b/src/widgets/image.rs index f35d2ff..ef6aa2d 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -29,8 +29,8 @@ //! //! [`decoder`]: crate::decoder +mod background_color; mod drag; -mod guess_background_color; mod input_handling; mod loading; mod metadata; diff --git a/src/widgets/image/guess_background_color.rs b/src/widgets/image/guess_background_color.rs deleted file mode 100644 index 9544cd1..0000000 --- a/src/widgets/image/guess_background_color.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (c) 2023 Sophie Herold -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use super::*; - -impl LpImage { - /// Returns the background color that should be used with this image - /// - /// Returns the default color if no one has been guessed yet - pub fn background_color(&self) -> gdk::RGBA { - let imp = self.imp(); - - if let Some(fixed) = *imp.fixed_background_color.borrow() { - return fixed; - } - - (*imp.background_color.borrow()).unwrap_or_else(Self::default_background_color) - } - - pub fn set_fixed_background_color(&self, color: Option) { - self.imp().fixed_background_color.replace(color); - } - - pub(super) fn set_background_color(&self, color: Option) { - self.imp().background_color.replace(color); - } - - pub fn default_background_color() -> gdk::RGBA { - if adw::StyleManager::default().is_dark() { - *BACKGROUND_COLOR_DEFAULT - } else { - *BACKGROUND_COLOR_DEFAULT_LIGHT_MODE - } - } - - pub fn alternate_background_color() -> gdk::RGBA { - if adw::StyleManager::default().is_dark() { - *BACKGROUND_COLOR_ALTERNATE - } else { - *BACKGROUND_COLOR_ALTERNATE_LIGHT_MODE - } - } - - /// Returns a background color that should give suitable contrast with - /// transparent images - /// - /// For non-transparent images this always returns - /// `BACKGROUND_COLOR_DEFAULT` - pub async fn background_color_guess(&self) -> Option { - let imp = self.imp(); - - if imp.fixed_background_color.borrow().is_some() { - return None; - } - - // Shortcut for formats that don't support transparency - if !self - .metadata() - .format() - .map_or(true, |x| x.is_potentially_transparent()) - { - log::debug!("This format does not support transparency"); - return Some(Self::default_background_color()); - } - - let (width, height) = self.original_dimensions(); - let max_size = i32::max(width, height); - - // Only use max 200px size scaled image for analysis - let zoom = f64::min(1., 200. / max_size as f64); - - let snapshot = gtk::Snapshot::new(); - let render_options = tiling::RenderOptions { - scaling_filter: gsk::ScalingFilter::Nearest, - background_color: None, - scaling: 1., - }; - self.imp() - .frame_buffer - .load() - .add_to_snapshot(&snapshot, zoom, &render_options); - - let node = snapshot.to_node()?; - - let renderer = self.root()?.renderer(); - if !renderer.is_realized() { - return None; - } - - // Render the small version of the image and download to RAM - let texture = renderer.render_texture(node, None); - let mut downloader = gdk::TextureDownloader::new(&texture); - downloader.set_format(gdk::MemoryFormat::R8g8b8a8); - let (bytes, stride) = downloader.download_bytes(); - - // Get here because only available in main thread - let alternate_color = Self::alternate_background_color(); - let default_color = Self::default_background_color(); - - gio::spawn_blocking(move || { - let mut has_transparency = false; - let mut bytes_iter = bytes.iter(); - // Number of transparent pixels - let mut completely_transparent = 0; - // Number of non-transparent pixels with bad contrast - let mut bad_contrast = 0; - 'img: loop { - for _ in 0..texture.width() { - let Some(r) = bytes_iter.next() else { - break 'img; - }; - let Some(g) = bytes_iter.next() else { - break 'img; - }; - let Some(b) = bytes_iter.next() else { - break 'img; - }; - let Some(a) = bytes_iter.next() else { - break 'img; - }; - - if *a < 255 { - has_transparency = true; - } - - if *a == 0 { - completely_transparent += 1; - } else { - let fg = gdk::RGBA::new( - *r as f32 / 255., - *g as f32 / 255., - *b as f32 / 255., - *a as f32 / 255., - ); - let contrast = crate::util::contrast_ratio(&default_color, &fg); - - if contrast < BACKGROUND_GUESS_LOW_CONTRAST_RATIO { - bad_contrast += 1; - } - } - } - - let advance_by = stride - 4 * texture.width() as usize; - - if advance_by > 0 { - bytes_iter.nth(advance_by - 1); - } - } - - if !has_transparency { - log::debug!("This image does not have transparency"); - return Some(default_color); - } - - let n_pixels = texture.width() * texture.height(); - - let part_bad_contrast = if completely_transparent < n_pixels { - bad_contrast as f64 / (n_pixels as f64 - completely_transparent as f64) - } else { - 1. - }; - - if part_bad_contrast > BACKGROUND_GUESS_LOW_CONTRAST_TRHESHOLD { - Some(alternate_color) - } else { - Some(default_color) - } - }) - .await - .ok()? - } -}