Skip to content

Commit 1be0284

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

File tree

4 files changed

+41
-15
lines changed

4 files changed

+41
-15
lines changed

CHANGELOG.md

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

77
## [Unreleased] - ReleaseDate
88

9+
### Added
10+
11+
- **(breaking)** [#71](https://github.com/embedded-graphics/simulator/pull/71) Added support for non-square pixels.
12+
13+
### Fixed
14+
15+
- [#71](https://github.com/embedded-graphics/simulator/pull/71) Fixed pixel spacing for unscaled outputs.
16+
917
## [0.8.0] - 2025-10-10
1018

1119
### Added

src/display.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ 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
105+
self.size.component_mul(output_settings.scale)
106106
+ self.size.saturating_sub(Size::new_equal(1)) * output_settings.pixel_spacing
107107
}
108108
}

src/output_image.rs

Lines changed: 5 additions & 5 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,16 @@ 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);
83-
8481
for p in display.bounding_box().points() {
8582
let raw_color = display.get_pixel(p).into();
8683
let themed_color = output_settings.theme.convert(raw_color);
8784
let output_color = C::from(themed_color);
8885

8986
self.fill_solid(
90-
&Rectangle::new(p * pixel_pitch + position, pixel_size),
87+
&Rectangle::new(
88+
p.component_mul(output_settings.pixel_pitch()) + position,
89+
output_settings.scale,
90+
),
9191
output_color,
9292
)
9393
.unwrap();

src/output_settings.rs

Lines changed: 27 additions & 9 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,14 @@ 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+
output_point.component_div(self.pixel_pitch())
2120
}
2221

23-
pub(crate) const fn pixel_pitch(&self) -> u32 {
24-
self.scale + self.pixel_spacing
22+
pub(crate) const fn pixel_pitch(&self) -> Point {
23+
Point::new(
24+
(self.scale.width + self.pixel_spacing) as i32,
25+
(self.scale.height + self.pixel_spacing) as i32,
26+
)
2527
}
2628
}
2729

@@ -34,7 +36,7 @@ impl Default for OutputSettings {
3436
/// Output settings builder.
3537
#[derive(Default)]
3638
pub struct OutputSettingsBuilder {
37-
scale: Option<u32>,
39+
scale: Option<Size>,
3840
pixel_spacing: Option<u32>,
3941
theme: BinaryColorTheme,
4042
}
@@ -55,6 +57,22 @@ impl OutputSettingsBuilder {
5557
pub fn scale(mut self, scale: u32) -> Self {
5658
assert!(scale > 0, "scale must be > 0");
5759

60+
self.scale = Some(Size::new(scale, scale));
61+
62+
self
63+
}
64+
65+
/// Sets a non-square pixel scale.
66+
///
67+
/// This is useful for simulating a display with a non-square pixel aspect ratio.
68+
///
69+
/// # Panics
70+
///
71+
/// Panics if `width` or `height` is `0`.
72+
pub fn scale_non_square(mut self, scale: Size) -> Self {
73+
assert!(scale.width > 0, "width must be > 0");
74+
assert!(scale.height > 0, "height must be > 0");
75+
5876
self.scale = Some(scale);
5977

6078
self
@@ -77,7 +95,7 @@ impl OutputSettingsBuilder {
7795
pub fn theme(mut self, theme: BinaryColorTheme) -> Self {
7896
self.theme = theme;
7997

80-
self.scale.get_or_insert(3);
98+
self.scale.get_or_insert(Size::new_equal(3));
8199
self.pixel_spacing.get_or_insert(1);
82100

83101
self
@@ -97,7 +115,7 @@ impl OutputSettingsBuilder {
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_equal(1)),
101119
pixel_spacing: self.pixel_spacing.unwrap_or(0),
102120
theme: self.theme,
103121
}

0 commit comments

Comments
 (0)