v0.2.4 is out. The headline change is a rewritten grain kernel that runs 3.8× faster on ARM processors — Apple Silicon and aarch64 Linux both benefit. For most images this brings grain rendering from the longest step in the pipeline to one of the shortest.

Here are the numbers on an M3 MacBook Pro, 24MP TIFF input, portra400 profile, averaged over 20 runs:

v0.2.0   grain: 1,840 ms   total: 2,210 ms
v0.2.4   grain:   484 ms   total:   860 ms

On x86_64 the improvement is smaller (~1.6×) because the previous implementation already used AVX2. The ARM path had no SIMD at all — I hadn't gotten around to writing NEON intrinsics and the auto-vectorizer wasn't picking it up reliably. The rewrite targets ARM's SVE2 where available and falls back to NEON on older chips.

WebP input

BergCraft can now read WebP files. I resisted this for a while — WebP is lossy by default, and applying analogue grain on top of DCT artifacts is a bit like putting a nice frame around a slightly blurry print. But enough people asked for it (mostly because their phone exports are WebP) that it made sense to add.

If you feed BergCraft a lossy WebP, it will warn you:

warning: input is lossy-compressed WebP (quality ~82). Consider using the
  original JPEG or a lossless source for best grain results.

You can suppress this with --no-lossy-warning if you know what you're doing.

Error messages

The previous error output for unsupported colour spaces was spectacularly unhelpful:

error: decode failed: unsupported

This has been a known embarrassment since v0.1. It's fixed. You'll now get something like:

error: unsupported colour space in photo.tiff: CMYK
  BergCraft currently supports sRGB and AdobeRGB (converted to sRGB on load).
  Convert your image to sRGB in Lightroom or with ImageMagick:
    convert photo.tiff -colorspace sRGB photo-srgb.tiff

Same for EXIF orientation — previously images shot in portrait mode came out sideways. Now BergCraft reads the orientation tag and rotates before processing.

Bug fixes

  • Fixed a panic when processing 1-channel (greyscale) TIFFs with hp5plus
  • Fixed halation bleeding outside image bounds on images with odd-pixel dimensions
  • Fixed --out-dir not creating intermediate directories on Windows
  • bergcraft profiles show now prints all parameters, not just the first group

Upgrading

curl -fsSL https://bergcraft.icu/install.sh | sh

or grab the binary from the release page. No config migration needed — the profile format hasn't changed since v0.2.0.

What's next

The main thing I want to tackle in v0.3 is custom curve support — right now the only way to use a custom profile is the TOML file format, which requires you to encode your curves as a lookup table by hand. I'd like to be able to import curves from Lightroom's XMP preset format, or from a simple CSV of input/output pairs measured from a scan. If you have opinions about this, open an issue.

I'm also slowly working on adding a fourth profile — Kodak Ektar 100. Getting the cyan response right is taking time. It'll be in v0.3 if it's ready, v0.4 otherwise.

Thanks to everyone who reported the greyscale panic and the Windows path bug. The halation bounds issue was found by @fischler_dev with a very minimal repro — that kind of report makes fixing things fast.