Skip to main content

Crate hyprforge_image

Crate hyprforge_image 

Source
Expand description

What a picture is, before anything draws it.

Measure it without decoding it, work out what may safely be decoded, decode that much, and turn it the right way up. No iced, no Wayland, no async runtime, nothing Hyprland-shaped — so a viewer, a preview pane and a test without a window can all ask the same questions.

§The finding this crate exists for

iced decodes an image handle at full resolution with no cap, and applies EXIF orientation — but only for two of its three handle kinds. In iced_graphics-0.14.0/src/image.rs, Handle::Path and Handle::Bytes go through image::open / load_from_memory and are then rotated per exif::Tag::Orientation. Handle::Rgba is a pure passthrough of the pixels it is given.

For a wallpaper or a thumbnail that is fine. For a viewer it is not: a 36-megapixel photograph decodes to 144MB and peaks near 300MB once the renderer has its own premultiplied copy — the allocation profile that already cost this suite a lock screen, where a failure inside iced_tiny_skia caches as “no entry” and panics on the next frame.

So a viewer must hand the renderer Handle::Rgba built from pixels it decoded within a budget of its own — and the moment it does, it takes on the orientation work too. Two halves, and getting either one alone is a bug: skip orientation and every portrait phone photograph is sideways; apply it here and use a path handle elsewhere and the same picture is turned twice.

§Where to start

measure first, always — it allocates nothing and everything else depends on its answer. Then budget, which is pure arithmetic and the only place a cap lives. Then decode::decode_to_fit.

§Honest about what the budget bounds

What is retained is capped by the viewport: 56MB for a 36-megapixel photograph in a 2560x1600 window, against 137MB uncapped. What is transient cannot be capped here, because image 0.25 has no DCT-scaled decode — a JPEG is decoded whole and then scaled down, and the peak belongs to the source.

That peak was measured rather than assumed, and measuring it changed the code: it began at 509MB and is 214MB, because the obvious downscaler turned out to cost more than the decode it followed. The table and the reasoning are in budget, the line itself in decode.

It also corrected something this doc used to claim: image’s own Limits does not bound that peak — the measurement is identical with and without it.

Re-exports§

pub use budget::Budget;
pub use budget::DecodePixels;
pub use budget::ViewportPixels;
pub use camera::Camera;
pub use decode::decode_to_fit;
pub use decode::Decoded;
pub use error::ImageError;
pub use measure::measure;
pub use measure::Measured;
pub use measure::SourcePixels;
pub use orientation::Orientation;

Modules§

budget
How many pixels it is safe to keep, and how that number is reached.
camera
What the camera wrote down: body, lens, exposure, when and where.
decode
Turning a file into pixels a renderer can take, within a budget.
error
What can go wrong, kept apart.
format
Which formats this build can decode.
measure
How big a picture is, and which way up — without decoding it.
orientation
Which way up a picture is, according to its EXIF.