Skip to content

Commit c513b3a

Browse files
committed
add support for non-square pixels
1 parent 0afacca commit c513b3a

4 files changed

Lines changed: 48 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
## [Unreleased] - ReleaseDate
88

9+
### Added
10+
11+
- Added support for non-square pixels
12+
913
## [0.8.0] - 2025-10-10
1014

1115
### Added

src/display.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,15 @@ impl<C: PixelColor> SimulatorDisplay<C> {
102102
/// [`pixel_spacing`](OutputSettings::pixel_spacing) settings to determine
103103
/// the size of this display in output pixels.
104104
pub fn output_size(&self, output_settings: &OutputSettings) -> Size {
105-
self.size * output_settings.scale
106-
+ self.size.saturating_sub(Size::new_equal(1)) * output_settings.pixel_spacing
105+
let width = self.size.width.saturating_mul(output_settings.scale.width)
106+
+ self.size.width.saturating_sub(1) * output_settings.pixel_spacing;
107+
let height = self
108+
.size
109+
.height
110+
.saturating_mul(output_settings.scale.height)
111+
+ self.size.height.saturating_sub(1) * output_settings.pixel_spacing;
112+
113+
Size::new(width, height)
107114
}
108115
}
109116

src/output_image.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ where
6464
)
6565
.unwrap();
6666

67-
if output_settings.scale == 1 {
67+
if output_settings.scale == Size::new(1, 1) && output_settings.pixel_spacing == 0 {
6868
display
6969
.bounding_box()
7070
.points()
@@ -78,16 +78,19 @@ where
7878
.draw(self)
7979
.unwrap();
8080
} else {
81-
let pixel_pitch = (output_settings.scale + output_settings.pixel_spacing) as i32;
82-
let pixel_size = Size::new(output_settings.scale, output_settings.scale);
81+
let pitch_x = (output_settings.scale.width + output_settings.pixel_spacing) as i32;
82+
let pitch_y = (output_settings.scale.height + output_settings.pixel_spacing) as i32;
8383

8484
for p in display.bounding_box().points() {
8585
let raw_color = display.get_pixel(p).into();
8686
let themed_color = output_settings.theme.convert(raw_color);
8787
let output_color = C::from(themed_color);
8888

8989
self.fill_solid(
90-
&Rectangle::new(p * pixel_pitch + position, pixel_size),
90+
&Rectangle::new(
91+
Point::new(p.x * pitch_x, p.y * pitch_y) + position,
92+
output_settings.scale,
93+
),
9194
output_color,
9295
)
9396
.unwrap();

src/output_settings.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use embedded_graphics::prelude::*;
44
/// Output settings.
55
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
66
pub struct OutputSettings {
7-
/// Pixel scale.
8-
pub scale: u32,
7+
/// Pixel scale, allowing for non-square pixels.
8+
pub scale: Size,
99
/// Spacing between pixels.
1010
pub pixel_spacing: u32,
1111
/// Binary color theme.
@@ -16,12 +16,15 @@ pub struct OutputSettings {
1616
impl OutputSettings {
1717
/// Translates a output coordinate to the corresponding display coordinate.
1818
pub(crate) const fn output_to_display(&self, output_point: Point) -> Point {
19-
let pitch = self.pixel_pitch() as i32;
20-
Point::new(output_point.x / pitch, output_point.y / pitch)
19+
let pitch = self.pixel_pitch();
20+
Point::new(output_point.x / pitch.x, output_point.y / pitch.y)
2121
}
2222

23-
pub(crate) const fn pixel_pitch(&self) -> u32 {
24-
self.scale + self.pixel_spacing
23+
pub(crate) const fn pixel_pitch(&self) -> Point {
24+
Point::new(
25+
(self.scale.width + self.pixel_spacing) as i32,
26+
(self.scale.height + self.pixel_spacing) as i32,
27+
)
2528
}
2629
}
2730

@@ -34,7 +37,7 @@ impl Default for OutputSettings {
3437
/// Output settings builder.
3538
#[derive(Default)]
3639
pub struct OutputSettingsBuilder {
37-
scale: Option<u32>,
40+
scale: Option<Size>,
3841
pixel_spacing: Option<u32>,
3942
theme: BinaryColorTheme,
4043
}
@@ -55,7 +58,7 @@ impl OutputSettingsBuilder {
5558
pub fn scale(mut self, scale: u32) -> Self {
5659
assert!(scale > 0, "scale must be > 0");
5760

58-
self.scale = Some(scale);
61+
self.scale = Some(Size::new(scale, scale));
5962

6063
self
6164
}
@@ -77,7 +80,7 @@ impl OutputSettingsBuilder {
7780
pub fn theme(mut self, theme: BinaryColorTheme) -> Self {
7881
self.theme = theme;
7982

80-
self.scale.get_or_insert(3);
83+
self.scale.get_or_insert(Size::new(3, 3));
8184
self.pixel_spacing.get_or_insert(1);
8285

8386
self
@@ -94,10 +97,25 @@ impl OutputSettingsBuilder {
9497
self
9598
}
9699

100+
/// Sets the pixel scale to a non-square value. This is useful for displaying
101+
/// non-square pixels.
102+
///
103+
/// # Panics
104+
///
105+
/// Panics if `width` or `height` is `0`.
106+
pub fn scale_non_square(mut self, width: u32, height: u32) -> Self {
107+
assert!(width > 0, "width must be > 0");
108+
assert!(height > 0, "height must be > 0");
109+
110+
self.scale = Some(Size::new(width, height));
111+
112+
self
113+
}
114+
97115
/// Builds the output settings.
98116
pub fn build(self) -> OutputSettings {
99117
OutputSettings {
100-
scale: self.scale.unwrap_or(1),
118+
scale: self.scale.unwrap_or(Size::new(1, 1)),
101119
pixel_spacing: self.pixel_spacing.unwrap_or(0),
102120
theme: self.theme,
103121
}

0 commit comments

Comments
 (0)