From 1e73c018456714c9485d2187fbbdbe3fb5b007b0 Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 8 Mar 2024 17:40:17 +0100 Subject: [PATCH] Switch to sRGBA everywhere --- showbits-common/src/color.rs | 26 ++++++++++++------------- showbits-common/src/tree.rs | 13 +++++++------ showbits-common/src/view.rs | 26 ++++++++++++++++--------- showbits-common/src/widgets/text.rs | 10 +++++----- showbits-thermal-printer/src/drawer.rs | 5 ++--- showbits-thermal-printer/src/printer.rs | 16 +++++++-------- 6 files changed, 52 insertions(+), 44 deletions(-) diff --git a/showbits-common/src/color.rs b/showbits-common/src/color.rs index 8a59ec4..b6de01e 100644 --- a/showbits-common/src/color.rs +++ b/showbits-common/src/color.rs @@ -1,21 +1,21 @@ -use palette::Srgb; +use palette::Srgba; -pub fn from_image_rgb(color: image::Rgb) -> Srgb { - let [r, g, b] = color.0; - Srgb::new(r, g, b).into_format() +pub fn from_image_color(color: image::Rgba) -> Srgba { + let [r, g, b, a] = color.0; + Srgba::new(r, g, b, a).into_format() } -pub fn to_image_rgb(color: Srgb) -> image::Rgb { - let color = color.into_format::(); - image::Rgb([color.red, color.green, color.blue]) +pub fn to_image_color(color: Srgba) -> image::Rgba { + let color = color.into_format::(); + image::Rgba([color.red, color.green, color.blue, color.alpha]) } -pub fn from_text_color(color: cosmic_text::Color) -> Srgb { - let [r, g, b, _] = color.as_rgba(); - Srgb::new(r, g, b).into_format() +pub fn from_text_color(color: cosmic_text::Color) -> Srgba { + let [r, g, b, a] = color.as_rgba(); + Srgba::new(r, g, b, a).into_format() } -pub fn to_text_color(color: Srgb) -> cosmic_text::Color { - let color = color.into_format::(); - cosmic_text::Color::rgb(color.red, color.green, color.blue) +pub fn to_text_color(color: Srgba) -> cosmic_text::Color { + let color = color.into_format::(); + cosmic_text::Color::rgba(color.red, color.green, color.blue, color.alpha) } diff --git a/showbits-common/src/tree.rs b/showbits-common/src/tree.rs index ba09055..7799fcd 100644 --- a/showbits-common/src/tree.rs +++ b/showbits-common/src/tree.rs @@ -1,5 +1,5 @@ -use image::RgbImage; -use palette::Srgb; +use image::RgbaImage; +use palette::Srgba; use taffy::{AvailableSpace, NodeId, Point, Size, TaffyResult, TaffyTree}; use crate::{color, BoxedWidget, Rect, Vec2, View}; @@ -14,11 +14,11 @@ fn size_to_vec2(size: Size) -> Vec2 { pub struct Tree { tree: TaffyTree>, - background: Srgb, + background: Srgba, } impl Tree { - pub fn new(background: Srgb) -> Self { + pub fn new(background: Srgba) -> Self { Self { tree: TaffyTree::new(), background, @@ -88,7 +88,7 @@ impl Tree { ctx: &mut C, root: NodeId, available: Size, - ) -> anyhow::Result { + ) -> anyhow::Result { self.layout(ctx, root, available)?; let layout = self.tree.layout(root)?; @@ -97,7 +97,8 @@ impl Tree { // TODO Check how taffy treats the border? let (width, height) = size_to_vec2(layout.size).to_u32(); - let mut image = RgbImage::from_pixel(width, height, color::to_image_rgb(self.background)); + let mut image = + RgbaImage::from_pixel(width, height, color::to_image_color(self.background)); self.render_to_view(ctx, root, &mut View::new(&mut image))?; Ok(image) diff --git a/showbits-common/src/view.rs b/showbits-common/src/view.rs index 8113c9b..6bfd009 100644 --- a/showbits-common/src/view.rs +++ b/showbits-common/src/view.rs @@ -1,15 +1,15 @@ -use image::RgbImage; -use palette::Srgb; +use image::RgbaImage; +use palette::{blend::Compose, Srgba}; use crate::{color, Rect, Vec2}; pub struct View<'a> { area: Rect, - buffer: &'a mut RgbImage, + buffer: &'a mut RgbaImage, } impl<'a> View<'a> { - pub fn new(buffer: &'a mut RgbImage) -> Self { + pub fn new(buffer: &'a mut RgbaImage) -> Self { let size = Vec2::from_u32(buffer.width(), buffer.height()); let area = Rect::from_nw(Vec2::ZERO, size); Self { area, buffer } @@ -35,22 +35,30 @@ impl<'a> View<'a> { pos + self.area.corner_nw() } - pub fn get(&self, pos: Vec2) -> Option { + pub fn get(&self, pos: Vec2) -> Option { let (x, y) = self.pos_to_buffer_pos(pos).to_u32(); let pixel = self.buffer.get_pixel_checked(x, y)?; - Some(color::from_image_rgb(*pixel)) + Some(color::from_image_color(*pixel)) } - pub fn set(&mut self, pos: Vec2, color: Srgb) { + pub fn set(&mut self, pos: Vec2, color: Srgba) { let (x, y) = self.pos_to_buffer_pos(pos).to_u32(); if let Some(pixel) = self.buffer.get_pixel_mut_checked(x, y) { - *pixel = color::to_image_rgb(color); + let below = color::from_image_color(*pixel); + *pixel = color::to_image_color(color.atop(below)); + } + } + + pub fn replace(&mut self, pos: Vec2, color: Srgba) { + let (x, y) = self.pos_to_buffer_pos(pos).to_u32(); + if let Some(pixel) = self.buffer.get_pixel_mut_checked(x, y) { + *pixel = color::to_image_color(color); } } // More complicated drawing primitives - pub fn rect(&mut self, area: Rect, color: Srgb) { + pub fn rect(&mut self, area: Rect, color: Srgba) { let nw = area.corner_nw(); let se = area.corner_se(); for y in nw.y..=se.y { diff --git a/showbits-common/src/widgets/text.rs b/showbits-common/src/widgets/text.rs index ea4445c..21f215f 100644 --- a/showbits-common/src/widgets/text.rs +++ b/showbits-common/src/widgets/text.rs @@ -1,5 +1,5 @@ -use cosmic_text::{Attrs, Buffer, Color, FontSystem, Metrics, Shaping, SwashCache}; -use palette::Srgb; +use cosmic_text::{Attrs, Buffer, FontSystem, Metrics, Shaping, SwashCache}; +use palette::Srgba; use taffy::prelude::{AvailableSpace, Size}; use crate::{color, Rect, Vec2, View, Widget}; @@ -32,12 +32,12 @@ pub trait HasFontStuff { pub struct Text { buffer: Buffer, - color: Srgb, + color: Srgba, } impl Text { /// Default text color. - const COLOR: Srgb = Srgb::new(0.0, 0.0, 0.0); + const COLOR: Srgba = Srgba::new(0.0, 0.0, 0.0, 1.0); // Default shaping strategy. const SHAPING: Shaping = Shaping::Advanced; @@ -81,7 +81,7 @@ impl Text { } } - pub fn color(mut self, color: Srgb) -> Self { + pub fn color(mut self, color: Srgba) -> Self { self.color = color; self } diff --git a/showbits-thermal-printer/src/drawer.rs b/showbits-thermal-printer/src/drawer.rs index 255ff4d..b2a61f1 100644 --- a/showbits-thermal-printer/src/drawer.rs +++ b/showbits-thermal-printer/src/drawer.rs @@ -1,7 +1,6 @@ use cosmic_text::{Attrs, Metrics}; -use palette::Srgb; +use palette::Srgba; use showbits_common::{ - color, widgets::{FontStuff, HasFontStuff, Text}, Tree, WidgetExt, }; @@ -67,7 +66,7 @@ impl Drawer { } fn on_test(&mut self) -> anyhow::Result<()> { - let mut tree = Tree::::new(Srgb::new(1.0, 1.0, 1.0)); + let mut tree = Tree::::new(Srgba::new(1.0, 1.0, 1.0, 1.0)); let root = Text::simple( &mut self.ctx.font_stuff, diff --git a/showbits-thermal-printer/src/printer.rs b/showbits-thermal-printer/src/printer.rs index b98f832..530c763 100644 --- a/showbits-thermal-printer/src/printer.rs +++ b/showbits-thermal-printer/src/printer.rs @@ -5,8 +5,8 @@ use escpos::{ printer::Printer as EPrinter, utils::{PageCode, Protocol, GS}, }; -use image::{Rgb, RgbImage}; -use showbits_common::Tree; +use image::{Rgba, RgbaImage}; +use showbits_common::{color, Tree}; use taffy::{AvailableSpace, NodeId, Size}; pub struct Printer { @@ -91,7 +91,7 @@ impl Printer { /// https://download4.epson.biz/sec_pubs/pos/reference_en/escpos/gs_lv_0.html fn print_image_to_printer( printer: &mut EPrinter, - image: &RgbImage, + image: &RgbaImage, ) -> anyhow::Result<()> { assert_eq!(Self::WIDTH % 8, 0); assert_eq!(image.width(), Self::WIDTH); @@ -122,7 +122,7 @@ impl Printer { Ok(()) } - fn get_horizontal_byte_starting_at(image: &RgbImage, x: u32, y: u32) -> u8 { + fn get_horizontal_byte_starting_at(image: &RgbaImage, x: u32, y: u32) -> u8 { let p7 = Self::pixel_to_bit(*image.get_pixel(x, y)); let p6 = Self::pixel_to_bit(*image.get_pixel(x + 1, y)); let p5 = Self::pixel_to_bit(*image.get_pixel(x + 2, y)); @@ -148,9 +148,9 @@ impl Printer { /// /// Instead of doing the physically accurate thing, I do what makes the most /// sense visually. - fn pixel_to_bit(pixel: Rgb) -> bool { - let [r, g, b] = pixel.0; - let sum = (r as u32) + (g as u32) + (b as u32); - sum <= 3 * 255 / 2 // true == black + fn pixel_to_bit(pixel: Rgba) -> bool { + let color = color::from_image_color(pixel); + let avg = (color.red + color.green + color.blue) / 3.0; + avg < 0.5 // true == black } }