Skip to content

fix(rle): return all pixels instead of only first row#57

Merged
rfuest merged 4 commits into
embedded-graphics:mainfrom
yanorei32:fix/rle-pixel-iterator-first-row
May 13, 2026
Merged

fix(rle): return all pixels instead of only first row#57
rfuest merged 4 commits into
embedded-graphics:mainfrom
yanorei32:fix/rle-pixel-iterator-first-row

Conversation

@yanorei32
Copy link
Copy Markdown
Contributor

  • Check that you've added passing tests and documentation
  • Add a CHANGELOG.md entry in the Unreleased section under the appropriate heading (Added, Fixed, etc) if your changes affect the public API
  • Run rustfmt on the project
  • Run just build (Linux/macOS only) and make sure it passes. If you use Windows, check that CI passes once you've opened the PR.

Problem

When iterating over pixels of an RLE4 or RLE8 compressed BMP image using Bmp::pixels(), the iterator seems to only return pixels from the first row instead of all pixels in the image. (fixes: #56)

For example, with a 640×480 RLE8 image:

  • Expected: PixelCount: 307200 (640 × 480)
  • Actual: PixelCount: 640 (only one row)

Root Cause

It looks like this was introduced in commit d61a220, which refactored the RLE decoder to use a start_of_row flag instead of tracking absolute pixel coordinates. There appear to be two issues:

  1. start_of_row initialized to false: Both Rle8Colors::new() and Rle4Colors::new() initialize start_of_row to false, but the flag is only set to true when start_row() is explicitly called. When using Bmp::pixels() (which doesn't call start_row()), the iterator starts with start_of_row = false.

  2. End-of-line escape handler returns None: When the decoder encounters an end-of-line marker (00 00), the code checks if !self.start_of_row { return None; }. Since start_of_row is false at the start, the iterator terminates early after processing the first row's end-of-line marker.

Proposed Fix

This PR attempts to fix the issue by:

  • Initializing start_of_row to true in both Rle8Colors::new() and Rle4Colors::new()
  • Setting start_of_row = false after returning each pixel (in both Absolute and Running modes)
  • Changing the end-of-line escape handler from return None to self.start_of_row = true to properly transition to the next row

Changes

  • src/raw_iter.rs:
    • Rle8Colors::new(): start_of_row: falsestart_of_row: true
    • Rle4Colors::new(): start_of_row: falsestart_of_row: true
    • Added self.start_of_row = false before returning pixels in Absolute mode (Rle8Colors, Rle4Colors)
    • Added self.start_of_row = false before returning pixels in Running mode (Rle8Colors, Rle4Colors)
    • Changed end-of-line handler: if !self.start_of_row { return None; }self.start_of_row = true (Rle8Colors, Rle4Colors)

`start_of_row` was initialized to `false` in both `Rle8Colors` and `Rle4Colors`. Additionally, the end-of-line escape handler (`00 00`) returned `None` if `start_of_row` was not set. This combination caused the iterator to terminate prematurely after processing the first row when using `Bmp::pixels()`.

Fix by:
- Initializing `start_of_row` to `true`.
- Setting `start_of_row = false` after yielding each pixel.
- Changing the end-of-line handler to set `start_of_row = true` instead of returning `None`.
Copy link
Copy Markdown
Member

@rfuest rfuest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks OK at first glance. But this needs to have a test to make sure it doesn't silently break again in the future.

This adds regression tests verifying that pixels().count() returns the correct total for indexed (1bpp, 4bpp, 8bpp),
RLE-compressed (RLE4, RLE8), and RGB formats (555, 565, 24bpp, 32bpp) ensuring the earlier start_of_row fix holds across all supported formats.
@yanorei32
Copy link
Copy Markdown
Contributor Author

Thank you for the feedback. I've added pixel iteration tests in commit ea128da using the existing logo test images that were already in the test suite.
Each test verifies that pixels().count() returns the expected WIDTH * HEIGHT count, which should help catch if this issue slips back in.

Copy link
Copy Markdown
Member

@rfuest rfuest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and thanks for also adding the tests.

@rfuest rfuest merged commit 1f057b1 into embedded-graphics:main May 13, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: RLE4/RLE8 pixel iterator returns only first row of pixels

2 participants