Skip to content

Conversation

@itsmeow
Copy link
Contributor

@itsmeow itsmeow commented Jul 30, 2025

Breaking Changes

(minor) breaking API change, Icon::load now requires Read + Seek rather than just Read to be implemented on its reader. BufReader and File both implement Seek, though, so it's unlikely anything will have an issue with this.

Changes

load_meta

Icon::load spends a lot of time calling image::load_from_memory_with_format and parsing IDAT chunks.

This PR adds Icon::load_meta and RawDmi::load_meta, which skip over any chunks that aren't the PNG header, IHDR, or zTXt. This makes it suitable for pure metadata (e.g. only reading the icon states, width, height, or DMI version) without spending any time doing image data parsing.

Direct PNG Decoding

By converting from image::load_from_memory_with_format to a raw buffer decode with PngDecoder, the MTPC of Icon::load is reduced from 32.447ms to 21.175ms, making it significantly faster. The major savings are in crop_imm calls, which are now directly loaded from decoded PNG data by indexing, which is significantly faster.

DMI Handling Improvements

looping = 0 was found in at least one DMI I tested (I tested this on every BeeStation dmi file in the repository) so I made it correctly convert this to Indefinitely

It also appears a decent volume of DMIs did not have a width or height, so I made them optional fields and they default to 32x32 because that appears to be what BYOND does.

Fixes icon states that have names containing quotes or backslashes being parsed incorrectly. They will now be loaded and saved with escape characters handled automatically.

Also satisfies clippy by converting format strings to use templating. help.

Performance

As you can see here almost all of load's time is spent doing image parsing. We can just skip this!

image

Here's load after replacing the PNG decoder.

image

Here's load_meta

image

after replacing split_terminator with parse_dmi_line (I'm pretty sure it's almost faster despite handling quite a few more cases)

image

You can see that load_meta is ~75x faster (particularly for large icon files, smaller files it's only about 10x faster):

Icon::load_meta bench
---
Num calls: 68850
Total Call Duration (μs): 18896089
MTPC (μs): 274

Icon::load bench
---
Num calls: 1377
Total Call Duration (μs): 29158782
MTPC (μs): 21175

Testing

I tested this on literally every image on TG and Bee, and it can load them just fine. I also added additional test images to cover edge cases (greyscale + alpha icons, extremely small icons that are well compressed)

@itsmeow itsmeow changed the title Add load_meta for reading only IHDR and zTXt Add load_meta for reading only IHDR and zTXt, better DMI field handling Jul 30, 2025
@itsmeow itsmeow changed the title Add load_meta for reading only IHDR and zTXt, better DMI field handling Add load_meta for reading only IHDR and zTXt, better DMI field handling, parsing optimizations Aug 1, 2025
@itsmeow itsmeow changed the title Add load_meta for reading only IHDR and zTXt, better DMI field handling, parsing optimizations Add load_meta for faster metadata, improve DMI field handling, parsing optimizations Aug 1, 2025
@ZeWaka ZeWaka merged commit 03fcf1a into spacestation13:master Aug 25, 2025
3 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.

2 participants