From adc456b8f69678ad068da97362efd53786076bb8 Mon Sep 17 00:00:00 2001 From: darktohka Date: Tue, 17 Mar 2026 00:53:05 +0200 Subject: [PATCH] Remove PNG loading --- .../clean_flash_installer/src/install_form.rs | 56 +--- rust/crates/clean_flash_ui/Cargo.toml | 1 - rust/crates/clean_flash_ui/src/flash_logo.rs | 265 ++++++++++++++++++ rust/crates/clean_flash_ui/src/lib.rs | 1 + rust/crates/clean_flash_ui/src/renderer.rs | 71 ----- .../clean_flash_ui/src/widgets/checkbox.rs | 137 +++++---- .../src/uninstall_form.rs | 21 +- 7 files changed, 377 insertions(+), 175 deletions(-) create mode 100644 rust/crates/clean_flash_ui/src/flash_logo.rs diff --git a/rust/crates/clean_flash_installer/src/install_form.rs b/rust/crates/clean_flash_installer/src/install_form.rs index c2ba7d7..b889c04 100644 --- a/rust/crates/clean_flash_installer/src/install_form.rs +++ b/rust/crates/clean_flash_installer/src/install_form.rs @@ -2,7 +2,7 @@ use crate::install_flags::{self, InstallFlags}; use crate::installer; use clean_flash_common::{uninstaller, redirection, update_checker, ProgressCallback}; use clean_flash_ui::font::FontManager; -use clean_flash_ui::renderer::{Renderer, RgbaImage}; +use clean_flash_ui::renderer::Renderer; use clean_flash_ui::widgets::button::GradientButton; use clean_flash_ui::widgets::checkbox::ImageCheckBox; use clean_flash_ui::widgets::label::Label; @@ -59,10 +59,7 @@ pub struct InstallForm { // Header pub title_text: String, pub subtitle_text: String, - pub flash_logo: RgbaImage, - // Checkbox images - pub checkbox_on: RgbaImage, - pub checkbox_off: RgbaImage, + flash_logo_cache: clean_flash_ui::flash_logo::FlashLogoCache, // Navigation buttons pub prev_button: GradientButton, pub next_button: GradientButton, @@ -132,12 +129,6 @@ impl InstallForm { let title_text = "Clean Flash Player".to_string(); let subtitle_text = format!("built from version {} (China)", version); - // Load images from the common resources folder. - // These are loaded from the C# project's assets alongside the binary. - let flash_logo = load_resource_image("flashLogo.png"); - let checkbox_on = load_resource_image("checkboxOn.png"); - let checkbox_off = load_resource_image("checkboxOff.png"); - let fonts = FontManager::new(); Self { @@ -145,9 +136,7 @@ impl InstallForm { panel: Panel::Disclaimer, title_text, subtitle_text, - flash_logo, - checkbox_on, - checkbox_off, + flash_logo_cache: clean_flash_ui::flash_logo::FlashLogoCache::new(), prev_button: btn(90, 286, 138, 31, "QUIT"), next_button: btn(497, 286, 138, 31, "AGREE"), // Disclaimer panel @@ -240,10 +229,10 @@ The following details could be useful. Press the Retry button to try again.", // ----- Draw ----- renderer.clear(BG_COLOR); - // Header: flash logo. - let lw = (self.flash_logo.width as f32 * self.scale) as i32; - let lh = (self.flash_logo.height as f32 * self.scale) as i32; - renderer.draw_image_scaled(self.s(90), self.s(36), lw, lh, &self.flash_logo); + // Header: flash logo (cached software render). + self.flash_logo_cache.draw( + renderer, self.s(90), self.s(36), self.s(109), self.s(107), + ); // Title. self.fonts.draw_text( @@ -561,34 +550,27 @@ including Clean Flash Player and older versions of Adobe Flash Player." // ---- Drawing helpers ---- fn draw_disclaimer(&self, r: &mut Renderer) { - self.disclaimer_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.disclaimer_box.draw(r); self.disclaimer_label.draw(r, &self.fonts); } fn draw_choice(&self, r: &mut Renderer) { self.browser_ask_label.draw(r, &self.fonts); - self.pepper_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.pepper_box.draw(r); self.pepper_label.draw(r, &self.fonts); - self.netscape_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.netscape_box.draw(r); self.netscape_label.draw(r, &self.fonts); - self.activex_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.activex_box.draw(r); self.activex_label.draw(r, &self.fonts); } fn draw_player_choice(&self, r: &mut Renderer) { self.player_ask_label.draw(r, &self.fonts); - self.player_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.player_box.draw(r); self.player_label.draw(r, &self.fonts); - self.player_desktop_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.player_desktop_box.draw(r); self.player_desktop_label.draw(r, &self.fonts); - self.player_start_menu_box - .draw(r, &self.checkbox_on, &self.checkbox_off); + self.player_start_menu_box.draw(r); self.player_start_menu_label.draw(r, &self.fonts); } @@ -664,13 +646,3 @@ fn join_with_and(items: &[&str]) -> String { } } -/// Try to load a resource image from the original C# project's asset folder. -fn load_resource_image(name: &str) -> RgbaImage { - let bytes: &[u8] = match name { - "flashLogo.png" => include_bytes!("../../../resources/flashLogo.png"), - "checkboxOn.png" => include_bytes!("../../../resources/checkboxOn.png"), - "checkboxOff.png" => include_bytes!("../../../resources/checkboxOff.png"), - _ => return RgbaImage::empty(), - }; - RgbaImage::from_png_bytes(bytes) -} diff --git a/rust/crates/clean_flash_ui/Cargo.toml b/rust/crates/clean_flash_ui/Cargo.toml index 2aafea1..00eace9 100644 --- a/rust/crates/clean_flash_ui/Cargo.toml +++ b/rust/crates/clean_flash_ui/Cargo.toml @@ -5,6 +5,5 @@ edition = "2021" [dependencies] ab_glyph = { workspace = true } -image = { workspace = true } minifb = { workspace = true } windows-sys = { workspace = true } diff --git a/rust/crates/clean_flash_ui/src/flash_logo.rs b/rust/crates/clean_flash_ui/src/flash_logo.rs new file mode 100644 index 0000000..9327633 --- /dev/null +++ b/rust/crates/clean_flash_ui/src/flash_logo.rs @@ -0,0 +1,265 @@ +use crate::renderer::Renderer; + +/// Cached flash logo bitmap. Stores a pre-rendered pixel buffer so the +/// expensive MSAA polygon fill only runs when the target size changes. +pub struct FlashLogoCache { + width: i32, + height: i32, + /// Pre-rendered pixels in 0x00RRGGBB format, row-major, size = width * height. + pixels: Vec, + /// Shadow offset derived from width. + shadow_off: i32, +} + +impl FlashLogoCache { + pub fn new() -> Self { + Self { + width: 0, + height: 0, + pixels: Vec::new(), + shadow_off: 0, + } + } + + /// Draw the flash logo at (x, y) with size (w, h). + /// Re-renders into the cache only if the size changed. + pub fn draw(&mut self, renderer: &mut Renderer, x: i32, y: i32, w: i32, h: i32) { + if w <= 0 || h <= 0 { + return; + } + + if self.width != w || self.height != h { + self.rebuild(w, h); + } + + // Draw subtle drop shadow first. + let shadow_color = Renderer::rgb(0, 0, 0); + let shadow_alpha: u8 = 40; + let so = self.shadow_off; + for dy in 0..h { + for dx in 0..w { + renderer.blend_pixel(x + dx + so, y + dy + so, shadow_color, shadow_alpha); + } + } + + // Blit cached pixels onto the renderer. + for dy in 0..h { + for dx in 0..w { + let px = self.pixels[dy as usize * w as usize + dx as usize]; + renderer.set_pixel(x + dx, y + dy, px); + } + } + } + + /// Render the logo into the internal cache at the given size. + fn rebuild(&mut self, w: i32, h: i32) { + self.width = w; + self.height = h; + self.shadow_off = ((w as f32 * 0.02).round() as i32).max(1); + + // Render into a temporary offscreen renderer. + let mut tmp = Renderer::new(w as usize, h as usize); + + let vw = 500.0_f32; + let vh = 487.0_f32; + let sx = w as f32 / vw; + let sy = h as f32 / vh; + + let blue = Renderer::rgb(0x00, 0x3A, 0x74); + tmp.fill_rect(0, 0, w, h, blue); + + let white = Renderer::rgb(255, 255, 255); + let points = build_f_polygon(); + fill_polygon(&mut tmp, &points, 0.0, 0.0, sx, sy, white); + + self.pixels = tmp.buffer; + } +} + +/// Evaluate a cubic bezier curve and return `segments` points (excluding the start point). +fn cubic_bezier( + p0: (f32, f32), + p1: (f32, f32), + p2: (f32, f32), + p3: (f32, f32), + segments: usize, +) -> Vec<(f32, f32)> { + let mut pts = Vec::with_capacity(segments); + for i in 1..=segments { + let t = i as f32 / segments as f32; + let u = 1.0 - t; + let x = u * u * u * p0.0 + + 3.0 * u * u * t * p1.0 + + 3.0 * u * t * t * p2.0 + + t * t * t * p3.0; + let y = u * u * u * p0.1 + + 3.0 * u * u * t * p1.1 + + 3.0 * u * t * t * p2.1 + + t * t * t * p3.1; + pts.push((x, y)); + } + pts +} + +/// Build the "f" shape polygon by tracing the SVG path data, flattening beziers +/// into line segments. Coordinates are in the SVG viewBox space (500×487). +fn build_f_polygon() -> Vec<(f32, f32)> { + let mut pts = Vec::with_capacity(128); + const N: usize = 16; // segments per bezier curve + + // M 269.2,138.7 + pts.push((269.2, 138.7)); + + // c -22.5,27.5 -35.8,61.8 -48.7,95 + pts.extend(cubic_bezier( + (269.2, 138.7), + (246.7, 166.2), + (233.4, 200.5), + (220.5, 233.7), + N, + )); + + // c -26.1,67.3 -43.6,105.8 -99.7,105.8 + pts.extend(cubic_bezier( + (220.5, 233.7), + (194.4, 301.0), + (176.9, 339.5), + (120.8, 339.5), + N, + )); + + // V 402 + pts.push((120.8, 402.0)); + + // c 46.4,0 84.1,-17.2 112,-51.2 + pts.extend(cubic_bezier( + (120.8, 402.0), + (167.2, 402.0), + (204.9, 384.8), + (232.8, 350.8), + N, + )); + + // c 17.9,-21.9 30.3,-49.3 40.9,-75.8 + pts.extend(cubic_bezier( + (232.8, 350.8), + (250.7, 328.9), + (263.1, 301.5), + (273.7, 275.0), + N, + )); + + // h 74.1 + pts.push((347.8, 275.0)); + + // v -62.5 + pts.push((347.8, 212.5)); + + // h -48.8 + pts.push((299.0, 212.5)); + + // c 18.9,-40.6 39.2,-62.5 82.1,-62.5 + pts.extend(cubic_bezier( + (299.0, 212.5), + (317.9, 171.9), + (338.2, 150.0), + (381.1, 150.0), + N, + )); + + // V 87.5 + pts.push((381.1, 87.5)); + + // C 334.8,87.5 297.1,104.7 269.2,138.7 (absolute cubic, closes the shape) + pts.extend(cubic_bezier( + (381.1, 87.5), + (334.8, 87.5), + (297.1, 104.7), + (269.2, 138.7), + N, + )); + + pts +} + +/// Test whether a point is inside the polygon using the even-odd (parity) rule. +fn point_in_polygon(transformed: &[(f32, f32)], px: f32, py: f32) -> bool { + let n = transformed.len(); + let mut inside = false; + let mut j = n - 1; + for i in 0..n { + let (xi, yi) = transformed[i]; + let (xj, yj) = transformed[j]; + if ((yi > py) != (yj > py)) && (px < (xj - xi) * (py - yi) / (yj - yi) + xi) { + inside = !inside; + } + j = i; + } + inside +} + +/// Scanline-fill a polygon with 4×4 MSAA antialiasing after transforming from +/// viewBox to screen coordinates: screen_x = ox + vx * sx, screen_y = oy + vy * sy. +fn fill_polygon( + renderer: &mut Renderer, + points: &[(f32, f32)], + ox: f32, + oy: f32, + sx: f32, + sy: f32, + color: u32, +) { + if points.len() < 3 { + return; + } + + // Transform to screen space. + let transformed: Vec<(f32, f32)> = points + .iter() + .map(|&(px, py)| (ox + px * sx, oy + py * sy)) + .collect(); + + // Bounding box. + let mut min_x = f32::MAX; + let mut max_x = f32::MIN; + let mut min_y = f32::MAX; + let mut max_y = f32::MIN; + for &(x, y) in &transformed { + if x < min_x { min_x = x; } + if x > max_x { max_x = x; } + if y < min_y { min_y = y; } + if y > max_y { max_y = y; } + } + + let x_start = (min_x.floor() as i32).max(0); + let x_end = (max_x.ceil() as i32).min(renderer.width as i32 - 1); + let y_start = (min_y.floor() as i32).max(0); + let y_end = (max_y.ceil() as i32).min(renderer.height as i32 - 1); + + // 4×4 sub-pixel grid offsets (16 samples per pixel). + const GRID: usize = 4; + const SAMPLES: usize = GRID * GRID; + let step = 1.0 / GRID as f32; + let half_step = step / 2.0; + + for y in y_start..=y_end { + for x in x_start..=x_end { + let mut hits = 0u32; + for sy_i in 0..GRID { + let sample_y = y as f32 + half_step + sy_i as f32 * step; + for sx_i in 0..GRID { + let sample_x = x as f32 + half_step + sx_i as f32 * step; + if point_in_polygon(&transformed, sample_x, sample_y) { + hits += 1; + } + } + } + if hits == SAMPLES as u32 { + renderer.set_pixel(x, y, color); + } else if hits > 0 { + let alpha = ((hits * 255 + SAMPLES as u32 / 2) / SAMPLES as u32) as u8; + renderer.blend_pixel(x, y, color, alpha); + } + } + } +} diff --git a/rust/crates/clean_flash_ui/src/lib.rs b/rust/crates/clean_flash_ui/src/lib.rs index 9794928..580d967 100644 --- a/rust/crates/clean_flash_ui/src/lib.rs +++ b/rust/crates/clean_flash_ui/src/lib.rs @@ -1,3 +1,4 @@ +pub mod flash_logo; pub mod font; pub mod renderer; pub mod widgets; diff --git a/rust/crates/clean_flash_ui/src/renderer.rs b/rust/crates/clean_flash_ui/src/renderer.rs index a16e00d..a3d56b3 100644 --- a/rust/crates/clean_flash_ui/src/renderer.rs +++ b/rust/crates/clean_flash_ui/src/renderer.rs @@ -108,77 +108,6 @@ impl Renderer { self.fill_rect(x + dx, y, 1, h, c); } } - - /// Draw an RGBA image scaled to (w, h) at (x, y) using nearest-neighbor interpolation. - pub fn draw_image_scaled(&mut self, x: i32, y: i32, w: i32, h: i32, img: &RgbaImage) { - if w <= 0 || h <= 0 || img.width == 0 || img.height == 0 { - return; - } - for dy in 0..h { - for dx in 0..w { - let src_x = (dx as f32 * img.width as f32 / w as f32) as usize; - let src_y = (dy as f32 * img.height as f32 / h as f32) as usize; - let idx = (src_y * img.width + src_x) * 4; - let r = img.data[idx]; - let g = img.data[idx + 1]; - let b = img.data[idx + 2]; - let a = img.data[idx + 3]; - if a == 255 { - self.set_pixel(x + dx, y + dy, Self::rgb(r, g, b)); - } else if a > 0 { - self.blend_pixel(x + dx, y + dy, Self::rgb(r, g, b), a); - } - } - } - } - - /// Draw an RGBA image onto the framebuffer at (x, y). - pub fn draw_image(&mut self, x: i32, y: i32, img: &RgbaImage) { - for iy in 0..img.height as i32 { - for ix in 0..img.width as i32 { - let idx = (iy as usize * img.width + ix as usize) * 4; - let r = img.data[idx]; - let g = img.data[idx + 1]; - let b = img.data[idx + 2]; - let a = img.data[idx + 3]; - if a == 255 { - self.set_pixel(x + ix, y + iy, Self::rgb(r, g, b)); - } else if a > 0 { - self.blend_pixel(x + ix, y + iy, Self::rgb(r, g, b), a); - } - } - } - } -} - -/// Simple RGBA image stored as raw bytes. -pub struct RgbaImage { - pub width: usize, - pub height: usize, - pub data: Vec, // RGBA, row-major -} - -impl RgbaImage { - /// Load a PNG from embedded bytes. - pub fn from_png_bytes(bytes: &[u8]) -> Self { - let img = image::load_from_memory_with_format(bytes, image::ImageFormat::Png) - .expect("Failed to decode PNG") - .to_rgba8(); - Self { - width: img.width() as usize, - height: img.height() as usize, - data: img.into_raw(), - } - } - - /// Create an empty (transparent) image. - pub fn empty() -> Self { - Self { - width: 0, - height: 0, - data: Vec::new(), - } - } } // ---- helpers ---- diff --git a/rust/crates/clean_flash_ui/src/widgets/checkbox.rs b/rust/crates/clean_flash_ui/src/widgets/checkbox.rs index 2409f96..407aedf 100644 --- a/rust/crates/clean_flash_ui/src/widgets/checkbox.rs +++ b/rust/crates/clean_flash_ui/src/widgets/checkbox.rs @@ -1,7 +1,7 @@ use super::Rect; -use crate::renderer::{Renderer, RgbaImage}; +use crate::renderer::Renderer; -/// An image-based checkbox matching the C# ImageCheckBox control. +/// A software-rendered checkbox with a gray gradient, black outline, and white checkmark. pub struct ImageCheckBox { pub rect: Rect, pub checked: bool, @@ -32,59 +32,34 @@ impl ImageCheckBox { } } - pub fn draw( - &self, - renderer: &mut Renderer, - checked_img: &RgbaImage, - unchecked_img: &RgbaImage, - ) { + pub fn draw(&self, renderer: &mut Renderer) { if !self.visible { return; } - let img = if self.checked { - checked_img - } else { - unchecked_img - }; - if img.width > 0 && img.height > 0 { - renderer.draw_image_scaled(self.rect.x, self.rect.y, self.rect.w, self.rect.h, img); - } else { - // Fallback: draw a simple square. - let bg = if self.checked { - Renderer::rgb(97, 147, 232) - } else { - Renderer::rgb(80, 80, 80) - }; - renderer.fill_rect(self.rect.x, self.rect.y, self.rect.w, self.rect.h, bg); - renderer.draw_rect( - self.rect.x, - self.rect.y, - self.rect.w, - self.rect.h, - Renderer::rgb(160, 160, 160), - ); - if self.checked { - // Draw a simple checkmark. - let cx = self.rect.x + 5; - let cy = self.rect.y + 10; - for i in 0..4 { - renderer.set_pixel(cx + i, cy + i, Renderer::rgb(255, 255, 255)); - renderer.set_pixel(cx + i, cy + i + 1, Renderer::rgb(255, 255, 255)); - } - for i in 0..8 { - renderer.set_pixel(cx + 3 + i, cy + 3 - i, Renderer::rgb(255, 255, 255)); - renderer.set_pixel(cx + 3 + i, cy + 4 - i, Renderer::rgb(255, 255, 255)); - } - } + + let r = self.rect; + + // Gray gradient background (matching button style). + let color1 = Renderer::rgb(118, 118, 118); + let color2 = Renderer::rgb(81, 81, 81); + renderer.fill_gradient_v(r.x, r.y, r.w, r.h, color1, color2); + + // Black 1px outline. + renderer.draw_rect(r.x, r.y, r.w, r.h, Renderer::rgb(0, 0, 0)); + + // White checkmark when checked. + if self.checked { + let white = Renderer::rgb(255, 255, 255); + Self::draw_checkmark(renderer, r.x, r.y, r.w, r.h, white); } if !self.enabled { // Dim overlay. - for dy in 0..self.rect.h { - for dx in 0..self.rect.w { + for dy in 0..r.h { + for dx in 0..r.w { renderer.blend_pixel( - self.rect.x + dx, - self.rect.y + dy, + r.x + dx, + r.y + dy, Renderer::rgb(50, 51, 51), 100, ); @@ -92,4 +67,72 @@ impl ImageCheckBox { } } } + + /// Draw a checkmark scaled to fit within the given box. + fn draw_checkmark(renderer: &mut Renderer, bx: i32, by: i32, bw: i32, bh: i32, color: u32) { + // Checkmark geometry defined in a normalised coordinate space. + // The check goes from bottom-left, down to a valley, then up to top-right. + // Key points (in fractions of size): + // start: (0.20, 0.50) + // valley: (0.40, 0.72) + // end: (0.80, 0.25) + // We draw two thick line segments between these points. + + let w = bw as f32; + let h = bh as f32; + + // Absolute coordinates of the three key points. + let x0 = bx as f32 + w * 0.20; + let y0 = by as f32 + h * 0.48; + let x1 = bx as f32 + w * 0.40; + let y1 = by as f32 + h * 0.72; + let x2 = bx as f32 + w * 0.80; + let y2 = by as f32 + h * 0.25; + + // Line thickness scales with checkbox size. + let thickness = (w * 0.14).max(1.5); + + draw_thick_line(renderer, x0, y0, x1, y1, thickness, color); + draw_thick_line(renderer, x1, y1, x2, y2, thickness, color); + } +} + +/// Draw a thick line between two points using filled circles along the path (round caps). +fn draw_thick_line( + renderer: &mut Renderer, + x0: f32, + y0: f32, + x1: f32, + y1: f32, + thickness: f32, + color: u32, +) { + let dx = x1 - x0; + let dy = y1 - y0; + let dist = (dx * dx + dy * dy).sqrt(); + let steps = (dist * 2.0).ceil() as i32; + let half = thickness / 2.0; + + for i in 0..=steps { + let t = i as f32 / steps.max(1) as f32; + let cx = x0 + dx * t; + let cy = y0 + dy * t; + + // Fill a small circle at (cx, cy). + let min_x = (cx - half).floor() as i32; + let max_x = (cx + half).ceil() as i32; + let min_y = (cy - half).floor() as i32; + let max_y = (cy + half).ceil() as i32; + let r_sq = half * half; + + for py in min_y..=max_y { + for px in min_x..=max_x { + let fdx = px as f32 + 0.5 - cx; + let fdy = py as f32 + 0.5 - cy; + if fdx * fdx + fdy * fdy <= r_sq { + renderer.set_pixel(px, py, color); + } + } + } + } } diff --git a/rust/crates/clean_flash_uninstaller/src/uninstall_form.rs b/rust/crates/clean_flash_uninstaller/src/uninstall_form.rs index 6da1644..ab5db7d 100644 --- a/rust/crates/clean_flash_uninstaller/src/uninstall_form.rs +++ b/rust/crates/clean_flash_uninstaller/src/uninstall_form.rs @@ -1,6 +1,6 @@ use clean_flash_common::{redirection, uninstaller, update_checker, ProgressCallback}; use clean_flash_ui::font::FontManager; -use clean_flash_ui::renderer::{Renderer, RgbaImage}; +use clean_flash_ui::renderer::Renderer; use clean_flash_ui::widgets::button::GradientButton; use clean_flash_ui::widgets::label::Label; use clean_flash_ui::widgets::progress_bar::ProgressBar; @@ -43,7 +43,7 @@ pub struct UninstallForm { panel: Panel, title_text: String, subtitle_text: String, - flash_logo: RgbaImage, + flash_logo_cache: clean_flash_ui::flash_logo::FlashLogoCache, prev_button: GradientButton, next_button: GradientButton, // Before uninstall @@ -79,7 +79,7 @@ impl UninstallForm { }; let version = update_checker::FLASH_VERSION; - let flash_logo = load_resource_image("flashLogo.png"); + let fonts = FontManager::new(); Self { @@ -87,7 +87,7 @@ impl UninstallForm { panel: Panel::BeforeInstall, title_text: "Clean Flash Player".into(), subtitle_text: format!("built from version {} (China)", version), - flash_logo, + flash_logo_cache: clean_flash_ui::flash_logo::FlashLogoCache::new(), prev_button: btn(90, 286, 138, 31, "QUIT"), next_button: btn(497, 286, 138, 31, "UNINSTALL"), before_label: lbl(PANEL_X + 3, PANEL_Y + 2, BEFORE_TEXT, 15.0), @@ -156,9 +156,9 @@ The following details could be useful. Press the Retry button to try again.", // Draw. renderer.clear(BG_COLOR); - let lw = (self.flash_logo.width as f32 * self.scale) as i32; - let lh = (self.flash_logo.height as f32 * self.scale) as i32; - renderer.draw_image_scaled(self.s(90), self.s(36), lw, lh, &self.flash_logo); + self.flash_logo_cache.draw( + renderer, self.s(90), self.s(36), self.s(109), self.s(107), + ); self.fonts .draw_text(renderer, self.s(233), self.s(54), &self.title_text, self.sf(32.0), FG_COLOR); @@ -288,10 +288,3 @@ impl ProgressCallback for ThreadProgressCallback { } } -fn load_resource_image(name: &str) -> RgbaImage { - let bytes: &[u8] = match name { - "flashLogo.png" => include_bytes!("../../../resources/flashLogo.png"), - _ => return RgbaImage::empty(), - }; - RgbaImage::from_png_bytes(bytes) -}