-
-
Notifications
You must be signed in to change notification settings - Fork 9
Inverted 1bpp #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inverted 1bpp #19
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great if we could also support 8bpp images with color tables.
Thanks for the review! I agree with your comments; I'll find some time to refactor the header parsing to do it properly. Should we change the information in the publicly exposed |
I think this depends on whether we want Some fields in the One refactoring I had previously considered was to remove all fields from struct Header<'a> {
data: &'a [u8],
}
impl Header {
fn width(&self) -> i32 {
i32::from_le_bytes(self.data[0x12..0x12+4].try_into().unwrap())
}
} Writing the getters would be some effort and not as nice as using nom, but we could add getters without any RAM overhead. The constructor for the |
A good question, and one I don't really have a solid answer to. My best response is I want this crate to be "useful", so in that vein I think exposing more header data is probably the way to go (but not for this PR).
Good points, but for this PR, I think we should keep the public API the same and refactor the header parsing as you suggest, even if we discard most of what we parse. This lays the groundwork for changing the API in the future as well as keeping the scope of this PR to its original purpose. That's an interesting idea for the getter-based API. I do like the cleanliness of getting a big struct of everything though, and the fields are very well defined so we know what to return without having to add breaking changes in the future. We could consider a hybrid approach and have getters for individual header structs instead of fields. |
Agreed, let's keep this PR focused on the original problem. |
src/raw_pixels.rs
Outdated
} else { | ||
// No color mapping - use value directly | ||
pixel_value[0] = *byte | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure there's a better way to do these indexing operations, but I'm pretty tired at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned before, I would not mix the color table lookup and the RawPixels
iter. Instead RawPixels
would always return the raw image data, which would be the index into the color table for images with a pallete. The iterator could then be mapped to the actual color values by looking up the index in the color table. This step would be optional and shouldn't be used for true color images to improve performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. Are you expecting the colour table logic to go into the Pixels
iterator impl? I'm unsure how we'd be able to make the iterator zero cost for images without a colour table. Did you have a particular impl in mind?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The color table logic would need to go into the Pixels
iterator impl and it couldn't be zero cost in this instance.
But we don't need to use the Pixels
iterator in the ImageDrawable
implementation. RawBmp::draw
could use RawPixels
instead of Pixels
and have different code paths for image with or without a color table, like this pseudo code:
pub(crate) fn draw<D>(&self, target: &mut D) -> Result<(), D::Error>
where
D: DrawTarget,
D::Color: From<<D::Color as PixelColor>::Raw>,
{
if has_color_table {
target.fill_contiguous(
&Rectangle::new(Point::zero(), self.size()),
self.pixels().map(|Pixel(_, color)| do_color_mapping(color)),
)
} else {
target.fill_contiguous(
&Rectangle::new(Point::zero(), self.size()),
self.pixels().map(|Pixel(_, color)| D::Color::Raw::from_u32(color).into()),
)
}
}
Header parsing has been refactored to handle different DIB types better, although it ignores most fields from them. Thank you also for showing me |
src/raw_pixels.rs
Outdated
} else { | ||
// No color mapping - use value directly | ||
pixel_value[0] = *byte | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned before, I would not mix the color table lookup and the RawPixels
iter. Instead RawPixels
would always return the raw image data, which would be the index into the color table for images with a pallete. The iterator could then be mapped to the actual color values by looking up the index in the color table. This step would be optional and shouldn't be used for true color images to improve performance.
It is, I only recently discovered it myself. Really unfortunate that the BMP format makes it harder to use by including the length bytes in the data size. |
Co-authored-by: Ralf Fuest <mail@rfuest.de>
Rust Edit: see #21 (comment) |
I think I've fixed the 1.40 build issue, although I'm on macOS so can't test locally. I'd like to at least release this PR before we bump to 2021.
Let's just abort for now. As for this PR, let's limit the scope creep and call it done if you're happy with the public API. Internals can be refactored later :) |
The problem is that is also kind of broken, e.g. that |
I would be OK with merging this now, but IMO we should fix some issues before the next release. |
Agreed. I didn't realise |
If we want to do one non breaking release before the change to a newer Rust version I would suggest to leave |
Ok, that sounds like a good approach :) |
Hmm, this is even more broken than I noticed before. The color table is always stored as New plan: We remove all user visible references to the new color table code and perhaps disable some of the additional checks. Then we ship one last non breaking version that only fixes the original issue. After the release we make the new code accessible to the user and clean up the rest. |
33b1d8f
to
94f14c9
Compare
I'm sorry this is 15 days late. It's been 15 days of "I don't feel like programming today, I'll do it tomorrow"... I've pushed a change that un-pubs What checks should we walk back? The ones in the header parse, or the ones that check the bit depth in |
I hope this wasn't caused by my constant nagging about issues with this PR. But unfortunately this PR uncovered some existing issues that weren't directly related to your contribution in this PR.
I would suggest to leave the tests in the
After taking another look at the checks I believe we can keep them. But the changelog should mention that 1 BPP and 8 BPP images are now required to have a color table. |
Ah, no, sorry if it came across that way. I was grumbling about my lack of motivation, not being driven away :). The points you've raised so far are all valid so are all reasonable. I've added a TODO and tweaked the changelog entry a bit. Let me know if there's anything else. |
Did you notice this comment https://github.com/embedded-graphics/tinybmp/pull/19/files#r835934583? I would prefer to ignore I also noticed that you reordered some of the |
Thanks for reminding me. I've pushed some changes to completely ignore
I prefer to clump all imports together with no separating lines, but I've pushed a commit to make this PR's diff smaller in regard to imports. I don't want to bikeshed this too much but I'm happy to accept a PR in the future that unifies the style across |
Let's just assume the tests are perfect ;)
I don't like to mix |
Thanks for the reviews! |
Shall I release 0.3.2 as a new patch release? |
SGTM. How do we want to continue after that release? Do you want to work on fixing the color issues for the next breaking release? |
That, and adding better error handling as per #20 would be good. I'm focussing on other things at the moment so don't have much time to work on |
OK, I'll try to implement these changes if I have some time. It would be good if you could take a look at embedded-graphics/tinytga#16, because the changes to |
The tinytga PR is on my todo list :). I had a quick skim and it looks good so far. I'll take a closer look when I've got a moment. |
Thank you for helping out with tinybmp development! Please:
CHANGELOG.md
entry in the Unreleased section under the appropriate heading (Added, Fixed, etc) if your changes affect the public APIrustfmt
on the projectjust build
(Linux/macOS only) and make sure it passes. If you use Windows, check that CI passes once you've opened the PR.PR description
Closes #18.
I wrote this pretty late, so my interpretation of the BMP format might be incorrect. I'd also gladly accept suggestions for improvements in the commented-on areas (see files tab) for performance and cleanliness reasons.