LightPhotos

Two Rust photo apps on the Mac

The same test as last time, on the desktop. On the Mac, LightPhotos lets Apple decode the photos. LightCraft decodes every photo with its own Rust code.

The main difference: who decodes the pixels

On the desktop, both apps are usual Rust programs. Both use all CPU cores, draw with wgpu on Metal and read your folders in place. The important difference is where the pixels come from.

WHERE THE PIXELS COME FROM RAW file Screen Apple ImageIO part of macOS Own Rust decoders inside the app

LightPhotos: Apple decodes every JPEG, HEIC and RAW file. The decoders add 0 MB to the 15 MB app.

Select an app. LightPhotos uses the decoders that Preview and Photos use (see What ImageIO gives you free). The Mac build does not include the RAW library that the other builds use.

LightCraft also has many more finished features. It is a full Lightroom-style editor, with masks, healing, lens corrections, presets, history, HDR and panorama merges, and export to six formats. LightPhotos has a smaller job: you go through a folder fast, keep the good photos and make quick edits. Remember this for each number below.

LightPhotos LightCraft
Decoding Apple's ImageIO, and CoreImage's CIRAWFilter for full-size RAW Its own, in Rust, for every format
HEIC Yes Not yet
Canon CR3 Yes Embedded preview only
Your photos Folders, read in place. Each folder keeps its own part of the catalog. One central catalog. Files stay in place unless you copy them.
License MIT or Apache-2.0, with no copyleft libraries in the Mac app MIT or Apache-2.0

One catalog or one in each folder

LightCraft keeps one central library, as Lightroom does. Its catalog records every photo, so searches, albums and stacks can include all of them. Import can add a photo in place, or copy or move it into Originals/YYYY/YYYY-MM-DD/. Browse Folder… also records what it sees. It removes those records later if you did not change the photos.

LightPhotos does it differently. The app can open many folders, and each folder keeps its own small cache and index in the .lightphotos folder inside it. The catalog for a folder moves with the folder. You can move, copy, rename or delete a folder in Finder, and the app does not need to know, other than opening it again.

How I measured

I built both apps with their own release scripts. I ran them on one M4 Pro Mac with 48 GB of memory and macOS 26.3. For each run, I copied the same 20 Sony A7 II RAW files to a new folder, so no cache had seen them. Each app started with a new home folder and default settings.

Each window was 3840 × 2000 px on a 4K display. In a smaller window, the camera's embedded JPEG is large enough. Then neither app must develop the RAW data.

A script, tools/desktop-bench, starts the app, double-clicks the first photo and pushes the right arrow eight times. It captures the window every 150 ms. It records the first change, and the time when nothing changed for 3 s. Each number is the median of five runs. One capture takes about 0.34 s, so no result can be less than about 0.5 s.

The numbers

LightPhotos LightCraft
Download (.dmg) 7.4 MB 15.2 MB
App, installed 15 MB 43 MB
Launch to window 0.27 s 0.43 s
Launch to finished grid, 20 RAWs 0.85 s 1.37 s
Open the first photo: first change / screen settled 0.57 / 1.46 s 0.67 / 0.67 s
Next photo, each (median of 8): first change / screen settled 0.55 / 0.55 s 0.60 / 0.60 s
Memory afterwards 1.2 GB 1.4 GB

The runs agreed to within a few percent, with three exceptions. The LightPhotos first photo took 1.0 to 1.5 s. One LightCraft grid took 2.3 s. LightCraft's memory was 1.3 to 1.7 GB.

Explore the timing

What the measurement sees

Open first photo

Nothing prepared the first photo. The script records the first change and the time when the whole window stops changing. It cannot see when the photo becomes sharp.

LightPhotosWhole screen settled
First visible change
0.57 s
Whole screen settled
1.46 s
LightCraftWhole screen settled
First visible change
0.67 s
Whole screen settled
0.67 s

Next photo

Both apps prepare the photos on each side. The 0.55 s and 0.60 s results are at the lowest value that the script can measure. The difference is too small to see.

LightPhotosWhole screen settled
First visible change
0.55 s
Whole screen settled
0.55 s
LightCraftWhole screen settled
First visible change
0.60 s
Whole screen settled
0.60 s

Fixed 0–2 s scale. Medians of five runs, full screen on a 4K display. The capture method cannot measure less than about 0.5 s, so the next-photo difference is too small to see. These times are for the whole window, not for a sharp photo. Do not compare them with the browser test.

Why the next photo is fast

Both apps prepare the photos on each side of the current photo. When you push the arrow key, the next photo is already developed. The app only has to show it.

PHOTOS IN THE FOLDER on screen Ready Developing Not prepared

Photo 1 is open. Nothing prepared it, so the app develops it now.

Push Next photo slowly, then push it fast. If you move faster than a develop, you must wait. Develop time is shown as 0.6 s, about the time of one RAW develop at this window size.

LightPhotos develops the neighbours with ImageIO, at the window size, up to 4096 px. LightCraft uses its own code, up to 2560 px. Both times are at the limit of the measurement, so I call them equal. Both apps pay the same cost: CPU time and battery for photos that you possibly do not look at.

Nothing prepares the first photo. At this window size, the embedded JPEG (1616 px wide) is too small. LightPhotos shows the grid thumbnail first, then develops the RAW data in about 0.6 s. LightCraft shows the first photo in one step.

My script waits a few seconds on each photo, as a person does who looks at each one. If you hold the arrow key down, you can go faster than either app can prepare. I did not measure that.

For 100% zoom and export, LightPhotos uses CoreImage's CIRAWFilter. It uses the same Apple RAW engine, so the pixels agree to within 8-bit rounding. But it runs on the GPU and demosaics only at the size that you ask for. A full 24-megapixel decode took 185 ms, against 590 ms through ImageIO. (Median of the same 20 files, one at a time.)

Why the grid is faster and memory is lower

For a grid thumbnail, LightPhotos asks ImageIO for a small image. ImageIO reads the embedded JPEG in 12 to 22 ms per file. LightCraft also shows the embedded JPEGs first. Then it replaces them with thumbnails that it develops from the RAW data. Its grid is not finished until those thumbnails arrive.

For memory, each app keeps three photos ready: the current photo and its two neighbours. But the two apps keep different pixels.

MEMORY FOR ONE PHOTO = PIXELS × BYTES PER PIXEL 52 MB 4.4 million pixels (2560 × 1707) 12 bytes

LightCraft: 32-bit floating-point RGB. 2560 × 1707 × 12 bytes ≈ 52 MB a photo, 157 MB for three.

Select an app. The dashed outline is the other app. LightCraft keeps fewer pixels with more data in each. LightPhotos keeps more pixels with less data in each. Sizes are for a 3:2 photo at each app's largest size.

With 12 bytes for each pixel, LightCraft's sliders can use the full range of the sensor: highlights above white, and exposure changes without banding. LightPhotos gets finished 8-bit pixels from ImageIO. The totals are almost the same, and on screen the photos look the same.

The app size also comes from ImageIO. LightCraft includes its own decoders for RAW, JPEG, JPEG XL and more, and its own colour management. Its release build also skips link-time optimisation and keeps some debug information. The macOS decoders add nothing to LightPhotos.

What each choice costs

Wrapping up

On the Mac, LightPhotos relies on the operating system, and LightCraft relies on itself. LightPhotos is smaller, starts faster, fills its grid faster and uses a little less memory. Apple did that work, and a smaller feature set fits in a smaller app. Both apps prepare the photos on each side, so both are equally fast through a shoot. LightCraft looks the same everywhere and does much more when you start to edit.