Changelog archive
The 70 versions of Open Negative Initiative before 1.4.2, with the notes they shipped with. Each one is still downloadable from its release page. The 11 oldest notes are in French, as they were published.
- Versions here
- 0.0.1 to 1.4.1
- Newer
- The 6 most recent are on the changelog
- Downloads
- Every version, on the release pages
1.4.1
A quick fix for slides, and ONI now runs on Intel Macs as well as Apple Silicon.
- Slides: White point now takes the saturation the right way as it moves; Black point is unchanged.
- Intel Macs: one download for every Mac, Intel and Apple Silicon.
v1.4.1 on GitHub, with its download and its source
1.4.0
ONI, rebuilt from scratch: faster, steadier, and now on Windows too. Your photos, edits and rolls open as they are; each camera is matched once to the earlier version so colours look the same.
- Export up to 4× faster, beside the editor: the destination opens at once and a small card follows the progress.
- Instant Auto White Balance, read ahead when a photo opens, even on many frames at once.
- A steadier roll measure: a tinted frame no longer tints the whole roll, and the roll keeps its contrast.
- Slides, simply: positives decode at 5500 K and each slide gets its own levels through one window.
- Scanner fixes: slides no longer come out overexposed, and Compare's before shows the plain conversion.
- Make a roll from the sidebar, with a short guide; the film stock sets the matching dye separation and shows on each roll.
- A demo for every ?, smooth browsing with thousands of photos, project walking, and submenus that open on hover.
- Nothing gets lost: safer undo, file moves and saves; a crash leaves a trace in the log.
v1.4.0 on GitHub, with its download and its source
1.3.1
Render changes
This version moves some renders. Photos converted on the Scanner face can look different: its finishing now acts on them, the S look is gone, a Frontier roll whose green window is not 1.3 D prints with a slightly different contrast, and Scanner Emulation is folded into each photo's Curves and Color Density, within 0.04 of display values. Every other photo looks and exports as before but for sharpening and chroma denoise, now computed exactly: a pixel can move by up to 2 or 3 levels out of 255, too little to see.
- A simpler Scanner face, after your feedback. It now shares the Pro panel: the machine's screen sits where the histogram stands, and its keypad in the Color tab as three blocks that fold. D, C, M and Y move by half steps, W is named TEMP, and the S look and CMY CANCEL are gone. Contrast, Vignette and Chrome are five keys each, read on the screen, and Curves, Spectrogram and the saturation curve now act after the machine's render.
- ONI's own machine. Beside the Frontier, the Scanner face offers ONI's machine: Pro's conversion with ONI's look, its keys moving the picture by the Frontier's measured clicks. Photos converted before keep the Frontier.
- A new colour space: ProPhoto RGB. The widest of the export spaces, in 16-bit TIFF, it keeps the colours Adobe RGB clips.
- Shadows and Highlights reach ±0.50 in Lighting, the curve still rising at the ends. Values within ±0.25 render as before.
- Smoother everywhere. Sliders follow the hand at the display's rate, the live histogram no longer slows the canvas, a photo opens without freezing the window, and sharpening with chroma denoise costs about a third less on a full-resolution canvas.
- Thumbnails are kept in a folder macOS does not empty, so the gallery shows them at once and stops redrawing photos at every launch.
- Auto Exposure is removed. Auto White Balance stays.
- The archive moves nothing by hand. Photos and folders are no longer dragged between folders or rolls; projects keep their own rearranging, and New Roll stays in the menu.
- Prepare the Roll keeps each frame's own shape, the feedback form links to the public issues, and a new launch picture by fllauh.
- Gold seals mark what changed in the panels; hover one to read what is new.
v1.3.1 on GitHub, with its download and its source
1.3.0
Render unchanged
This version changes no render: every photo already adjusted looks and exports as before. With a paper profile as the working space, the canvas now shows the paper itself, its white and its ink, so it looks bluer and flatter on an OBA paper than it did: that is what the print will look like.
- The paper proof simulates the paper. With a printer or paper profile chosen as the working space, the canvas, the loupe, the thumbnails and the export previews show the paper's own white and its ink's black, as Lightroom's Simulate Paper & Ink does. On a pearl paper whose white is bluish, the canvas used to show that white as pure white; it now shows it as it prints. "Show only color variation" still shows the colours alone.
- Paper Correction. On a paper profile, a new block in the Color tab holds three gains, laid last on a color or a black and white print alike. Auto Paper Correction reads the paper's white off its profile, never the picture, and sets the gains that print a grey as grey. The gains belong to the photo and act on that paper alone: in sRGB, Display P3 or Adobe RGB they do nothing.
- A warm cast is gone from paper proofs. macOS read some paper profiles slightly warm, which tinted every grey of the proof; ONI now takes that reading error off. The files sent to the printer were never affected.
v1.3.0 on GitHub, with its download and its source
1.2.3
Render unchanged
This version changes no render: every photo already adjusted looks as before.
- Sliders no longer go dead. A drag interrupted by the system, by switching to another app, by Mission Control or by the Mac going to sleep, could leave every slider unresponsive until ONI was quit. ONI now notices within a second and lets go.
- The first right-click opens its menu in the gallery and the sidebar, and a photo in the sidebar offers the same menu as its tile in the grid.
- A sleeping Mac is no longer taken for a frozen app. The console log no longer records each sleep as a freeze, and reading a real freeze can no longer stall the app itself.
v1.2.3 on GitHub, with its download and its source
1.2.2
Render changes
This version changes one render of photos already adjusted: a slide left on the Scanner tab used to show Pro's render there, and now goes through the Scanner's own look, as a negative does. Every other photo renders as before.
- Folders open at once. Opening a folder no longer waits for a starred folder still being read, nor for a starred folder that holds it: the folder you open is always read first.
- A folder opened again shows what was added since, such as the scans your scanner wrote meanwhile: the grid shows what ONI already knew, then the folder is read again.
- A folder that could not be read, on a disk asleep or unplugged or with access refused, no longer stays empty afterwards: opening it again reads it again, and its photos keep their place in the library.
- A disk that stops answering no longer holds up the next folder you open.
- A dropped photo opens in the editor straight away, without waiting for every thumbnail of its folder.
- A scan read while it was still being written is read again once finished, thumbnail included.
- Right-click, then Open, now opens a roll or a folder holding no other folder.
- The console log now records what the gallery does, folders opened and read, thumbnails, moves, without any folder, file or disk name in it: a report tells more about what went wrong, never where your files are.
v1.2.2 on GitHub, with its download and its source
1.2.1
Render changes
This version changes the colours of photos already adjusted: Dye Separation now rests at 60 % instead of 18 %, so every photo left at the old value moves to it. Reds turn a touch richer and yellows a touch softer; overall saturation is unchanged. A value you set yourself stays where you put it.
- Browse your folders. The sidebar shows the folders on your disks. Click a folder to open it, star the ones you use often, and go up with Parent. Only the folder you open is read, so a huge disk never slows you down. Photos not converted yet show as scanned.
- Prepare the Roll, step by step. It opens in the editor, in smaller steps with a short video each. Choosing the frames and flagging the odd ones are separate steps, and a roll you leave halfway picks up where you stopped.
- Deleting is reversible. Delete hides a photo in the ONI Trash, in the sidebar, and Restore brings it back. Nothing on your disk is moved or erased.
- Projects follow your photos when you move them inside ONI.
- Smoother: switching between Pro and Scanner, dragging Temperature and Tint, and opening a folder no longer stutter. The Scanner tab now wears ONI's own look.
- The Chroma Decompression block is gone: it no longer acted on any measured roll.
v1.2.1 on GitHub, with its download and its source
1.1.0
Render changes
This version changes the rendering of photos already adjusted in Pro: Dye Separation no longer adds saturation, so every frame with a separation renders a little less saturated (about 5 % at the 18 % rest, 14 % at 60 %). If you took a strong separation back with Color Density, return Color Density to 0.
- Scans read outside the RAW engine keep their own channels. TIFF, JPEG, PNG and linear DNG files were converted to the working primaries before the inversion, which mixed their channels and cost a film scanner about 40 % of its colour. Rolls measured from this version on render with fuller colour; rolls measured before keep their look until you measure them again.
- RGB passes. A frame exposed three times, under red, green and blue light, is grouped, registered and read as one negative. Choose RGB Passes in Prepare the Roll: the pass order is read from the first triplet, and dragging the band chips corrects it.
- Scanner tab. A second edit for every photograph, rendered through a look measured on a lab scanner, with its own keypad: D, C, M and Y in clicks, then warmth (W) and skin (S). Pro and Scanner keep their own settings, so switching loses nothing.
- Reset to Default, in the gallery's Rolls menu, takes whole rolls back to unconverted, their framing, dust corrections and flat-field kept. A triplet of RGB passes parts into its three shots, each keeping the frame's crop.
- Before/after now compares against the frame at rest, with the roll's window, its flat-field and the resting exposure, instead of a bare inversion.
- Library: boxes are gone, dragging in the archive moves files on the disk, and a roll wears its stock as its icon.
- Prepare the Roll no longer decodes the scan again on every hover of the film-base loupe, and a frame whose decode came back with an empty channel is rendered again.
v1.1.0 on GitHub, with its download and its source
1.0.3
Render unchanged
This version does not change the rendering of photos already adjusted. A negative that starts from rest now opens at +1.5 EV: a new photo, a reset, or a roll prepared again.
- Exposure starts at +1.5 EV on negatives, colour and black and white. A roll's window has to hold its brightest frame, so most frames printed darker than they should at 0. Double-click the Exposure slider to return to 0. Slides still start at 0.
v1.0.3 on GitHub, with its download and its source
1.0.2
Render unchanged
This version does not change the rendering of photos already adjusted. What it adds acts when a roll is prepared again.
- Rolls digitised on an automatic mode. Prepare the Roll reads each frame's shutter speed, aperture and ISO, warns when frames were digitised with other settings than most of the roll, and marks them with a dot. Measuring brings each of them back to the roll's settings, exactly as if the whole roll had been shot in manual. A different aperture also changes the vignetting the flat-field measured: the warning suggests re-shooting those frames in manual. Rolls already measured keep their rendering until they are prepared again.
- Picker Size. The film base step has a slider for the size of the disc the base is read on, remembered from one roll to the next.
v1.0.2 on GitHub, with its download and its source
1.0.1
Render changes
This version changes the rendering of photos already adjusted: colour, Lighting and the balance were rebuilt around the roll, so a photo edited in a beta can open looking different. Opening a frame of a roll not yet measured now starts Prepare the Roll, which brings each frame's colour back to rest on the roll's window; crops and dust corrections are kept. If you would rather keep a beta's rendering for now, skip this update: every earlier version stays available.
1.0.1 fixes the crash at launch on macOS 13 Ventura, which stopped 1.0.0 and the betas before it on every Mac running that system, Intel included. The welcome screen shows once more.
The beta is over. Thank you to every tester who sent a scan, a bug or an idea.
- Prepare the Roll. Each roll is measured as a whole before its frames are edited, from the gallery's PREPARE ROLL key or on opening a frame not yet measured, in four steps: the film type and what digitised it, a flat-field taken from a frame of the empty light panel, the film base picked with a full-resolution loupe, and one measuring frame checked on every scan. Light leaks and extreme shots can be flagged so they take the roll's window without setting it.
- A Roll tab. The film type, flat-field, manual balance, dye separation and Balance strength belong to the roll: a change there reaches every frame measured with it, and one undo takes it back.
- Auto White Balance and Auto Exposure replace the former level keys. On a selection, each frame can be corrected on its own or all of them given the average.
- Temperature and Tint replace Cyan, Magenta and Yellow, and move colour alone, never how light the photo is.
- Lighting loses Mids, the per-channel points and the compensation slider; Contrast moves to Effects and turns on a middle grey. Black point and White point now keep the colour's saturation as they move.
- Black and white prints get wider Black point and White point travel and Contrast up to +1.
- Contact sheets are made for every roll measured and stand on the roll's window; their Auto White Balance and Auto Exposure average the roll's frames. Contact sheets made before keep their settings, but read their frames whole: make them again to give them the roll's measuring window.
- Paste carries the Color and Details tabs; Paste to Roll lays them on the whole roll. Crop is a tab again, with Copy, Paste and Paste to Roll for the framing.
- Both side panels can be put away, sliding back over the photo when the pointer nears their edge.
- A welcome screen, and a launch picture shown on the screen ONI opens on.
- The Latent Image window, an experiment, is gone.
v1.0.1 on GitHub, with its download and its source
1.0.0
Render changes
This version changes the rendering of photos already adjusted: colour, Lighting and the balance were rebuilt around the roll, so a photo edited in a beta can open looking different. Opening a frame of a roll not yet measured now starts Prepare the Roll, which brings each frame's colour back to rest on the roll's window; crops and dust corrections are kept. If you would rather keep a beta's rendering for now, skip this update: every earlier version stays available.
The beta is over. Thank you to every tester who sent a scan, a bug or an idea.
- Prepare the Roll. Each roll is measured as a whole before its frames are edited, from the gallery's PREPARE ROLL key or on opening a frame not yet measured, in four steps: the film type and what digitised it, a flat-field taken from a frame of the empty light panel, the film base picked with a full-resolution loupe, and one measuring frame checked on every scan. Light leaks and extreme shots can be flagged so they take the roll's window without setting it.
- A Roll tab. The film type, flat-field, manual balance, dye separation and Balance strength belong to the roll: a change there reaches every frame measured with it, and one undo takes it back.
- Auto White Balance and Auto Exposure replace the former level keys. On a selection, each frame can be corrected on its own or all of them given the average.
- Temperature and Tint replace Cyan, Magenta and Yellow, and move colour alone, never how light the photo is.
- Lighting loses Mids, the per-channel points and the compensation slider; Contrast moves to Effects and turns on a middle grey. Black point and White point now keep the colour's saturation as they move.
- Black and white prints get wider Black point and White point travel and Contrast up to +1.
- Contact sheets are made for every roll measured and stand on the roll's window; their Auto White Balance and Auto Exposure average the roll's frames. Contact sheets made before keep their settings, but read their frames whole: make them again to give them the roll's measuring window.
- Paste carries the Color and Details tabs; Paste to Roll lays them on the whole roll. Crop is a tab again, with Copy, Paste and Paste to Roll for the framing.
- Both side panels can be put away, sliding back over the photo when the pointer nears their edge.
- A welcome screen, and a launch picture shown on the screen ONI opens on.
- The Latent Image window, an experiment, is gone.
v1.0.0 on GitHub, with its download and its source
0.4.2
Render changes
This version changes the rendering of photos already adjusted: a frame balanced by a key in 0.4.0 or 0.4.1 now opens with Chroma Decompression at 50 % instead of 0 %, since at 0 % a dense, overexposed negative came out heavily oversaturated. The next balance key you press also sets Dye separation to 100 % and Chroma Decompression to 50 %, unless you moved them by hand.
- Chroma Decompression now rests at 50 %, and every balance key sets it there unless you moved it by hand.
- Dye separation rests at 100 % again. Frames keep their current dose until the next balance key.
- Slides and other positives always render their colour whole: Chroma Decompression no longer applies to them, and its block is hidden in positive mode.
- The Chroma Decompression handle follows its value again instead of freezing while the image changed.
- A double click resets every slider and handle reliably.
- The selected photo in the sidebar is marked by a plain white outline, as in the grid.
v0.4.2 on GitHub, with its download and its source
0.4.1
Render unchanged
No change to the rendering of photos already adjusted.
- The app opens onto its window again. Version 0.4.0 showed a launch picture that left the window hidden until the Dock icon was clicked a second time; the picture is off for now.
v0.4.1 on GitHub, with its download and its source
0.4.0
Render changes
This version changes the rendering of photos already adjusted: camera RAWs decode differently, linear DNGs from VueScan read their colours correctly, and a balance key now keeps the film's own colour. A RAW frame balanced before keeps the density axis its balance was placed on, and its colour, until a balance key is pressed again.
- Every camera decodes the same way: Apple's per-camera shadow bias, lens correction, moiré reduction, luminance noise reduction and highlight recovery are off, and the decoder version is pinned. Frames carrying dust corrections keep the lens correction, so their corrections stay on their specks; on other frames a crop can move by a few pixels.
- A camera RAW negative is read without the knee that made its balance depend on how bright the capture was: the same negative captured two stops apart now balances the same.
- New: Chroma Decompression, beside the per-channel levels. At 0 %, the default, the levels stretch the tones and keep the film's own colour; at 100 % the colour is stretched with them, as before. Every balance key sets it to 0 % unless you moved it by hand.
- A scan that declares no colour profile can be read as sRGB, Linear or Display P3, from the Settings tab.
- The density ceiling of a camera RAW now reaches 4.
- A photo never balanced opens with its orange mask at full strength until a balance key is pressed.
v0.4.0 on GitHub, with its download and its source
0.3.4
Render unchanged
No change to the rendering of photos already adjusted.
- Entering the editor, every key of the top bar answers at once: the keys at either end of the centre group no longer ignore clicks and hover until a while later.
- Switching between gallery and editor, the editor's keys appear or leave at once and the Pro / Scanner switch opens or closes in width between them.
- The thumbnail size keys leave the gallery's top bar for now; ⌘− and ⌘+ still resize the thumbnails.
v0.3.4 on GitHub, with its download and its source
0.3.3
Render unchanged
No change to the rendering of photos already adjusted.
- A right click in the library column works again after scrolling. On a photo it offers Edit and New Roll from Selection, beside Show in Finder.
- A double click on a photo in the library column opens it in the editor, from the gallery too.
v0.3.3 on GitHub, with its download and its source
0.3.2
Render unchanged
No change to the rendering of photos already adjusted.
Library column
- A reload key reads your folders again, for what you changed in the Finder.
- A target key brings the selected photo to the middle of the column, in the archive and in Projects. Changing the column's layout does the same.
- The folder field no longer says Root, shows in Projects too, and its menu is as wide as the column.
Measuring window
- A contact sheet never opens with the measuring window drawn, and when you draw one there it covers the whole sheet.
- Pasting settings that carry a white balance, or applying a preset that does, closes the window. The paste also brings the copied photo's window.
Also
- The header's EDITOR, GALLERY and RESET SCAN keys open at their right size.
- The Noritsu screen reads C M Y and plain numbers, like the others.
v0.3.2 on GitHub, with its download and its source
0.3.1
Render unchanged
No change to the rendering of photos already adjusted.
- A photo with no white balance yet opens with the custom measuring window drawn, so you can set where the balance reads first. Pressing a balance key closes it. It happens every time such a photo is opened, until it has a balance.
- The header's first key reads EDITOR or GALLERY instead of an icon.
v0.3.1 on GitHub, with its download and its source
0.3.0
Render changes
Photos already adjusted may look different in three cases. Zone saturation becomes the Saturation curve: its two sliders open as points on the curve and render almost exactly as before. Lighting's Contrast now runs from −0.50 to +0.50: a photo contrasted further opens at the end of the track. Contact sheets are rendered without sharpening and chroma denoise, their values kept.
Your library follows your disk
- Pick the folder that holds your scans: every image in it and in its subfolders is in the archive, with nothing to import. Pick it wide enough to hold every scan, but not your whole disk.
- The archive tree is that folder's own tree, in the Finder's order. Right-click a folder to make it a roll.
- New Roll from a selection makes a folder beside the photos, named after the earliest capture, and moves them in. ⌘Z in the gallery puts them back.
- Rename a roll and the folder is renamed on your disk. Its stock, date and camera are kept in the folder.
- A library made with an earlier version is shown, once, how to pick its folder and which photos no folder holds yet.
- The library column shows photos as names, two thumbnails a line, or one, and replaces the filmstrip.
Scanner
- A Scanner face beside Pro, switched from the centre of the header: ONI, Noritsu and Frontier keyboards with their own looks, colour and density keys, framing and flat-field.
- Chrome, a new Effects slider up to 150 %, greys the very ends and keeps colour in the middle. The scanner opens a photo at 50 %, ONI's at 100 %.
Colour
- The Saturation curve: five points from the black point to the white, placed freely, over the histogram. Brightness and hue never move.
- Pasting settings re-places each channel's black and white points with the balance key the copied photo last used, and carries its gains and middle points as they are, so a roll's look travels frame to frame.
- Automatic balance is now Auto Balance, marked START HERE.
Also
- Flat-field masks can be renamed, their folder opened, and a mask made from a photo of your library can move that photo out of it.
- The header's reset reads RESET SCAN.
- The app no longer ships presets; the ones it installed are moved to the Trash if you never changed them.
v0.3.0 on GitHub, with its download and its source
0.2.3
Render changes
Photos already adjusted may look different in three cases. Chroma denoise is now on by default (4 px, 20 %): a photo where it had never been touched opens with it on. Paper simulation is gone: a photo that used it loses it. Color cast becomes each channel's own black and white points, and lands very close to its former render.
Lighting
- New Mids slider, which lifts or lowers the middle of the curve.
- New Black point and White point sliders. They move the ends of the scan itself, as a darkroom black point does, on the RGB curve or on one channel. They replace Color cast.
- Every Lighting slider is finer near the middle and stronger toward its ends, with the same full range.
- New photos start with the black point lifted 6 %, so an automatic balance no longer crushes the deepest shadows. Photos already edited keep their black.
A simpler panel
- Three tabs: Settings (flat-field and dye separation), Color, and Details (sharpening, chroma denoise, texture). Frame and De-dust open from the header. Every photo opens on Color.
- Blocks fold with the chevron in their title row. Flat-field, Dye separation, Curves, Spectrogram finishing and Zone saturation start folded.
- Spectrogram finishing and Zone saturation now close the Color tab.
- The manual balance opens right under the automatic balance keys with the new SETTINGS key.
- Resets are small keys marked RESET.
Also
- Flat-field: load your own masks under the Custom tab.
- The measuring window can be copied and pasted onto another photo.
- The custom window key reads Apply window while you draw it.
- Gold seals mark what changed; Help › Show What's New Again brings them back.
v0.2.3 on GitHub, with its download and its source
0.2.2
Render changes
Photos already adjusted will look slightly different. Lighting replaces the former exposure, linked levels and finishing balance: each photo is converted to the new controls as it opens and lands very close to its former render, except a black or white point that clipped, which now stays on pure black or pure white. RAW files are decoded without the decoder's own sharpening and with stronger colour noise reduction, and sharpening now rests at 1.
Fixed
- Pressing any key in the app crashed it on every Mac but the one that built it, whenever key clicks were on. If 0.2.1 crashed for you, this is the fix.
Lighting
- One RGB curve shaped by six sliders — Exposure, Contrast, Highlights, Shadows, Whites, Blacks — and the same six on each channel's own curve, picked above the sliders.
- Colour holds as the light changes: a brighter or darker area keeps its saturation, and so does a vignetted corner.
- Blacks and Whites move one end of the curve behind a soft toe or shoulder, leaving the other end where it is.
- Film fade becomes Paper simulation: a paper's white and black, laid on Lighting's curve.
Grade and flat-field
- Color cast tints the blacks and the whites apart, one channel at a time, and never clips.
- The flat-field mask takes Temperature and Tint to match your light panel, and your last Amount, Temperature and Tint follow every new photo.
Also
- Contact sheets edit as smoothly as any photo.
- Opening a photo slides the panels in at once while the controls load.
- Medals are small metal discs; a gold seal marks what changed in this version, and Help › Show What's New Again brings the seals back.
- Presets list what they carry by tab, in the order of the panel.
v0.2.2 on GitHub, with its download and its source
0.2.1
Render changes
Photos already adjusted can look different: a dye separation left at its former 100 % rest now opens at 67 %, the new rest; a dose you chose yourself is kept. The editor now always shows the picture through the working space, Display P3 unless you pick another.
Much faster, everywhere
- Editing: a slider redraws only itself and the picture, at up to 120 frames a second.
- Library: the grid, the film and project trees and the filmstrip scroll at 120 frames a second, and thumbnails appear at launch without a scroll.
- Memory: opening a large RAW uses about half as much, full resolution is built once and only when the zoom needs it, and walking a roll never decodes the frames it crosses.
- Smoother on smaller Macs: the cache follows the machine's memory and is handed back when the system asks.
Colour management
- One working space for editing and export, changed from the chip at the top of the picture: sRGB, Display P3, Adobe RGB, or a Custom printer or paper profile, converted in relative colorimetric with black point compensation.
- Paper Profiles: official profiles from several paper makers, listed from their own pages and installed in one click; Load a Profile takes .icc, .icm or a maker's zip.
- A lime key in the bar stripes what this screen cannot show.
Also
- Presets: share one as a line of text, import, export, duplicate; delete and update ask first.
- Space opens a photo from the library again, and a held Space on the correction tab no longer beeps.
- A frame opened at a zoom that needs full resolution now loads it without another zoom.
v0.2.1 on GitHub, with its download and its source
0.2.0
Render changes
Photos already adjusted can look different: a dye separation left at its former 100 % rest now opens at 67 %, the new rest; a dose you chose yourself is kept. The editor now always shows the picture through the working space, Display P3 unless you pick another.
Much faster, everywhere
- Editing: a slider redraws only itself and the picture, at up to 120 frames a second.
- Library: the grid, the film and project trees and the filmstrip scroll at 120 frames a second, and thumbnails appear at launch without a scroll.
- Memory: opening a large RAW uses about half as much, full resolution is built once and only when the zoom needs it, and walking a roll never decodes the frames it crosses.
- Smoother on smaller Macs: the cache follows the machine's memory and is handed back when the system asks.
Colour management
- One working space for editing and export, changed from the chip at the top of the picture: sRGB, Display P3, Adobe RGB, or a Custom printer or paper profile, converted in relative colorimetric with black point compensation.
- Paper Profiles: official profiles from several paper makers, listed from their own pages and installed in one click; Load a Profile takes .icc, .icm or a maker's zip.
- A lime key in the bar stripes what this screen cannot show.
Also
- Presets: share one as a line of text, import, export, duplicate; delete and update ask first.
- Space opens a photo from the library again, and a held Space on the correction tab no longer beeps.
- A frame opened at a zoom that needs full resolution now loads it without another zoom.
v0.2.0 on GitHub, with its download and its source
0.1.9
Reading the library no longer blocks. The index pass, a whole rebuild as much as a repair, shows on the status bar with its counter, and the gallery stays usable while the originals are read.
- A member the pass could not read — an original on an unplugged disk, a moved file — made "Reading the library" appear on every medal, paste or reorder. It is now read again only when the library changes or on an explicit recheck.
v0.1.9 on GitHub, with its download and its source
0.1.8
The automatic balance on a contact sheet reads the roll, not its worst frame. Each frame's window is read on a copy fine enough to give it 24 rows of cells, and the black and white points are taken at the tenth across frames, so one blank or under-exposed frame no longer sets every other's black, and a speck in one frame no longer pulls one channel's white.
- A cropped contact sheet lost every frame window and read its black margins as picture, which put the black point on them; the sheet is now rebuilt from the crop and its frames kept.
- The block grid's cell is a fixed 19 px of the measuring copy: a sheet's frame no longer shrinks to 2 px cells whose extremes were single pixels.
- With the measuring window armed on a sheet, every frame's window and grid is drawn, cut exactly as the balance reads them.
v0.1.8 on GitHub, with its download and its source
0.1.7
The canvas now renders in your display's own colour space instead of sRGB, so saturated colours that used to clip on a wide-gamut screen now show. Exports and sidecars are unchanged, and View → Canvas Colour Space switches it back.
The automatic balance reads on blocks: the measuring window is cut into 48 rows of square cells, each read by its median, so dust and specks never set a point, and the black and white points are placed on each cell's own tails, so a small light keeps its value. The pixel reading and its threshold are gone; the grid is drawn while the custom measuring window is armed.
Exposure, in stops, is the first slider of the Lighting block: ±4 EV, hue held. What a stop adds or removes rolls into each pixel's distance to white, so a white stays a white in both directions and the mid-tones carry the stop: an under-exposed frame comes up without its highlights clipping, an over-exposed one comes down without greying. The colour density is compensated 20 % per stop both ways so colours keep their saturation. The luma gamma beside it is now named Midtones.
- The bar's reset keeps the flat-field mask and the dye family: they describe the rig and the film, not the look.
- The balance keys no longer preview on hover; the marks under the levels show the balance applied by the last click, and the click runs off the main thread.
- The dye separation can be shouldered for comparison with the launch switch ONI_SEPARATION_SHOULDER=1.
v0.1.7 on GitHub, with its download and its source
0.1.6
Render changes
Every photo you have already edited will render differently: dye separation is on at 100 % by default, and every thumbnail is regenerated on first launch.
Added dye separation, in the Colour block: a matrix that subtracts each dye's spill into the other two channels, so colours separate while greys and the automatic balance stay exactly where they are. Five dye families — Kodak C-41, Fuji C-41, Generic C-41, ECN-2 and E-6 — with a dose from 0 to 200 %; the family follows the mode until you pick one.
- Fixed a crash while rendering on some machines, caused by the memory instrumentation added in 0.1.4.
v0.1.6 on GitHub, with its download and its source
0.1.5
Fixed ⌘A in the editor's project filmstrip: it now selects the whole project instead of only the roll the current photo or selection sits in.
v0.1.5 on GitHub, with its download and its source
0.1.4
Fixed a memory leak while zooming and panning: every crossing of 100 % kept a full-resolution copy of the photo, reaching 6 GB within minutes on a scan with fifty corrections. The same photo now rests at 400 MB after the same gestures.
- Fixed the correction patches: each is now the size of its stroke instead of an 800 px tile, so fifty corrections weigh 30 MB instead of 500 and the patch cache 468 KB instead of 151 MB.
- Fixed a brief hitch on each crossing of 100 % on a photo carrying many corrections: 25 ms of GPU instead of 100.
v0.1.4 on GitHub, with its download and its source
0.1.3
Added a white balance measurement window: a cyan frame you place on the photo, and the automatic balance and the levels histogram read only what it holds. It follows the crop until you arm it, and travels with the framing copy and paste.
- Added a session memory of the last aspect ratio and portrait choice: the next photo's crop mode opens on them.
- Added copy and paste of the framing — crop, straightening, rotation, mirrors and measurement window — onto the whole selection.
- Added an Effects block in Color, holding Contrast, Vignette and Film fade.
- Added Return to validate framing and the measurement window.
- Changed the slider tracks: half as tall, recessed, with a keycap knob that lifts under the pointer.
- Changed the Frame panel: aspect ratio first, rotation and mirrors on one row, copy and paste beside the block's reset.
- Changed the automatic balance keys into one plate, with the measurement window keys and a crop reminder on it.
- Fixed the bar's reset erasing the framing: the crop, the straightening and the window now stay.
- Fixed a new preset carrying the photo's white balance unasked: the save sheet opens on Not carried, and every preset label says what it carries.
- Fixed the vertical mirror key turning the whole key instead of its glyph.
- Fixed a photo belonging to several projects: it sits in one, the most recent, and joining another moves it.
- Fixed a stutter when hovering rolls and boxes with many photos in the gallery sidebar.
v0.1.3 on GitHub, with its download and its source
0.1.2
Added a white balance measurement window: a cyan frame you place on the photo, and the automatic balance and the levels histogram read only what it holds. It follows the crop until you arm it, and travels with the framing copy and paste.
- Added copy and paste of the framing — crop, straightening, rotation, mirrors and measurement window — onto the whole selection.
- Added an Effects block in Color, holding Contrast, Vignette and Film fade.
- Added Return to validate framing and the measurement window.
- Changed the slider tracks: half as tall, recessed, with a keycap knob that lifts under the pointer.
- Changed the Frame panel: aspect ratio first, rotation and mirrors on one row, copy and paste beside the block's reset.
- Changed the automatic balance keys into one plate, with the measurement window keys and a crop reminder on it.
- Fixed the bar's reset erasing the framing: the crop, the straightening and the window now stay.
- Fixed a new preset carrying the photo's white balance unasked: the save sheet opens on Not carried, and every preset label says what it carries.
- Fixed the vertical mirror key turning the whole key instead of its glyph.
- Fixed a photo belonging to several projects: it sits in one, the most recent, and joining another moves it.
- Fixed a stutter when hovering rolls and boxes with many photos in the gallery sidebar.
v0.1.2 on GitHub, with its download and its source
0.1.1
Render changes
This version changes the rendering of photos that carry dust or scratch corrections: their patches are now copied pixel for pixel and come out as sharp as the area they were taken from, where they were slightly soft before, and a small correction now shows in full on the fitted preview. Nothing else moves on a photo you have already adjusted: the two new controls rest at zero until you touch them.
Corrections
A correction painted on a dust speck used to look blurred next to the grain around it, and a small one barely showed unless the photo was viewed at 100 %. Both are fixed: the patch is an exact copy of its source, and the fitted preview applies it fully whatever the brush size, cropped or turned frames included. The number of a correction now sits off the top-right of its ring instead of covering the pixels you are judging, and stays readable at any zoom. While the brush is over the picture, the system cursor hides and only the brush's circle remains.
Film fade
A new slider at the end of the Grade panel: the matte of a print that has aged. Blacks lift a little, whites come down, the highlights roll off into them, and the mid-tones stay exactly where your grade put them. It acts on the three channels alike, after the finishing balance, so very light tints set on the whites are compressed along with everything else up there.
Vignette
Also in Grade, in stops: darkens the corners of the print without shifting their colour, on an ellipse that follows your crop. Below zero it lightens them instead. The fade's floor bounds it, so a corner never falls under the faded black.
Automatic balance and flat-field
The automatic balance, the histogram under the levels and the marks shown on hover no longer see the flat-field mask: they read the frame before the correction, which is what you got by switching the mask off, clicking, and switching it back on. The picture and the output histogram keep the mask. A black point you place by hand on that histogram therefore describes the frame before the division, whose corners render a little lighter than the plot shows.
v0.1.1 on GitHub, with its download and its source
0.1.0
Render unchanged
Nothing in this version changes the rendering of a photo you have already adjusted. What changes is what an exported file can contain: a new HDR switch adds a gain map to a JPEG, and each frame now carries the EXIF you set for it. Both are off or empty until you touch them.
Open Negative Initiative leaves alpha
This is 0.1.0, the first beta. The orange "ONI is in Alpha" notice is gone from the card: the major defects reported through it have been fixed, and the export — the one part that still had to be reworked before saying so — has been rebuilt from the ground up. Bugs are still to be expected; please keep reporting them.
Export is a screen of its own
Export no longer opens a dialog. The photos about to be written take the whole card, one per row, and their settings sit in a panel on the right. Cancel and EXPORT are at the bottom right; Escape leaves, ⌘E confirms; a batch can be stopped between two files. The mode you came from — gallery or editor — is where you return.
Three presets — Instagram, Display, Print — set every row at once and lock none of them. The size is typed as width × height, linked by the frame's shape: the edge you type is the one the ceiling rides on every photo of the batch, so Instagram's "1440 px on the short edge" lands a landscape and a portrait alike. Exports never enlarge. Your export settings are remembered between launches; the default is now JPEG in sRGB, the space every reader — Instagram included — agrees on.
The HDR hack
A checkbox on JPEG exports, on in the Instagram preset. It changes no pixel: the file gets a flat gain map, so an HDR screen — a recent phone, an XDR Mac — shows the picture up to two stops above the page's white, while every other reader sees exactly the same picture as without it. It is written in the form Instagram, Threads and X keep through their re-encode: post the file uncropped, from a desktop browser at original ratio. Whether Instagram accepts a given file is Instagram's to decide, and not published; the file matches what is known to pass.
EXIF, frame by frame
Beside each preview sits the frame's own line: its file name, camera, lens, film (picked from the catalogue), ISO, date, artist and copyright. It opens on the scanner's own EXIF — the body, ISO and date of the camera or scanner you digitised with — so you can see these are not the photograph's, and replace them. What you type is kept with the frame for the next export. Nothing of the scanner is written unless you leave it there. The naming pattern is gone: the name is a field of the frame's line.
Also
- A roll's film stock can no longer be unpicked by clicking the active one again: a roll was shot on some film.
- Export previews render at 1600 px instead of 500, so the picture can be judged.
v0.1.0 on GitHub, with its download and its source
0.0.36
Render unchanged
Nothing in this version changes the rendering of a photo you have already adjusted. It is about the Projects tab, and about a few things that used to get stuck.
Projects: selection finally knows which project you meant
A photo that belongs to two projects shows up once under each. Clicking it used to light up every copy, in the grid and in the sidebar, and ⌘A then completed every project it belonged to. Now only the copy you clicked lights up, ⌘A completes the project you clicked in — or the one you selected in the sidebar — and a photo stays with the project it was picked in even as you ⌘-click your way into another one. Opening a photo from a project's grid opens it in that project, and clicking the same photo again under a different project unfolds that project in the sidebar.
Projects can be deleted
Delete Project sits in a project's context menu in the sidebar, behind a confirmation that says what stays untouched: the photos, their settings, and every other project or roll they belong to. Removing a project's last photo deletes the project on its own, and a box emptied of its last roll or project is pruned the same way.
Also
- Thumbnails no longer get stuck loading after a big import: a tile still on screen retries on its own instead of waiting for a quit and reopen.
- Clicking in the sidebar is faster with many rolls expanded: rows are no longer recut on every click, and the scroll that reveals a ringed row waits for the click to paint first.
- The Library tab is now called Archive.
- The project card's cover stack shows the project's real thumbnails instead of blank plates.
- Reading a photo's settings no longer touches the original file unless the sidecar needs migrating.
v0.0.36 on GitHub, with its download and its source
0.0.35
Render changes
Camera RAW decoding is more accurate now, and existing photos are affected too. Every RAW you've already edited has had its balance nudged automatically to compensate, so most will look the same or very close to before. If one still looks a touch off, a press of your usual balance button settles it.
Truer colour, especially on unusual film
The old decode assumed every colour negative sat behind an orange base and quietly corrected for it. Films that don't, Harman Phoenix among them, were fighting that assumption instead of benefiting from it. RAWs now decode neutrally for every file, and the app's own colour tools do the actual correcting, exactly as they always did.
- Scanner files (TIFF, JPEG, PNG, HEIC, linear DNG) were never affected by this.
- A preset carrying Source balance may need a quick re-save if it lands wrong on a RAW now.
Also
- A project's filmstrip now follows the same order as its grid, instead of silently regrouping a hand-picked, cross-roll order by roll.
v0.0.35 on GitHub, with its download and its source
0.0.34
The photo grid and the sidebar tree both got a serious speed pass this release. A library with hundreds of photos, dense grid columns, and every roll expanded in the sidebar used to slow scrolling and hovering to a crawl — both now stay smooth by only drawing what is actually on screen, instead of holding everything live at once.
Drag to reorder actually reorders now
Dragging a photo to a new position inside a scanned roll could silently do nothing, because scanned frames often share one capture time for the whole roll and the app had no other number to place them by. It now finds a real gap to drop into regardless, and undoing or redoing a reorder correctly updates the grid instead of leaving it showing the old order.
Projects get a real info panel
Selecting a project's photo used to leave the right panel showing nothing useful, or the wrong roll's details. It now shows the project itself: its name, a stacked preview of its first photo, every film stock among its photos, and an editable description. Anchoring on one of its photos from the grid also opens the right project in the sidebar now, even when it was collapsed.
Also
- Add to Project and Remove from Project, from the grid's own context menu, for a single photo or a whole selection.
- New icons for a project group and a project box.
- The info panel's own separators now reach the full width of the panel instead of stopping short of its edge.
v0.0.34 on GitHub, with its download and its source
0.0.33
Drag and drop got a proper pass this release: move a photo into any roll or day by dropping it directly there, including between two photos that belong to a different group — that used to fail silently. Import works the same way now too: drag files or a whole folder from Finder anywhere in the library window, no need to open the file picker.
A hand tool for the correction brush
Painting dust and scratches used to leave no way to pan a zoomed-in photo — the brush took every drag. Hold Space to pan instead, exactly like Photoshop's hand tool: an open hand while held, a closed hand while dragging, and the brush's own preview circle steps aside so it never looks like it is about to paint.
The preset deck stopped grabbing the bottom edge
It used to rise from far away and leave an invisible strip above its own peek that intercepted clicks — corrections and crop handles along the bottom of a zoomed-in photo could miss for no visible reason. It now answers only where it is actually shown.
Also
- A persistent status bar under the photo: name and pixel dimensions, or how many photos are selected, with three medal buttons that label the current photo or the whole selection at once.
- The mirror buttons in Geometry now survive leaving the photo — they used to silently reset.
- A new app icon.
v0.0.33 on GitHub, with its download and its source
0.0.32
Render changes
If you use Contrast and Colour (Temperature/Tint) together, their combined look shifts slightly in this version — Contrast now applies on its own, ahead of Colour, instead of being baked into the same table. Using only one of the two is unaffected.
Dust and scratch removal is rebuilt from the ground up: a classical, GPU-based search finds a matching patch elsewhere in the same photo — no neural network, nothing decided without a brush stroke. A manual curves editor also returns to the Color pane, five channels, drawn by hand.
- Fixed: right-clicking a thumbnail in the gallery only opened its menu over the right half of the image.
- Fixed: thumbnails reloaded on every launch instead of once.
v0.0.32 on GitHub, with its download and its source
0.0.31
Render unchanged
Nothing changes in how an already-adjusted photograph renders — exports and saved edits are pixel-identical to 0.0.30. This version gives a roll its own identity, adds seven film stocks, and fixes several selection, hover and comparison issues.
A roll can now carry its own film stock, shot date and camera body, editable from the info panel — the shot date is three plain fields (month, day, year) instead of a calendar picker, sized to match the toolbar's own buttons. Rolls and boxes can be reordered by dragging them, at the root or nested inside another box. An unassigned day is promoted to a real roll the moment it is imported, rather than staying a stand-in category.
Seven new film stocks: AgfaPhoto APX, Foma Fomapan 200, Fomapan 400, Fomapan 401, Lucky Color 200, Mira Color 400 and Mira Color 800.
- Fixed: selecting a roll or a box in the sidebar sometimes stayed marked after the ring moved to a photo selected elsewhere, showing two things selected at once.
- Fixed: hovering the gallery grid or the sidebar tree could land on the wrong row, or flicker, depending on exactly how the pointer crossed between cells.
- A box's rolls now show inside the gallery grid too, not only in the sidebar — as a larger title, never a separate background or an expand arrow, so it reads as a bigger heading rather than a different kind of thing.
- Fixed: the Before/After comparison measured against the bare, un-corrected negative — after dialling in white balance and levels, that comparison had nothing useful left to show. It now compares from the corrected image instead, and respects the frame's own negative/positive/monochrome mode, which it previously ignored.
v0.0.31 on GitHub, with its download and its source
0.0.30
Render unchanged
Nothing changes in how an already-adjusted photograph renders — exports and saved edits are pixel-identical to 0.0.29. This version refines the sidebar that shipped last time.
A small arrow now leads every roll, day and box row in the sidebar, separate from the rest of the row: click it to expand or collapse, click anywhere else to select — the two no longer do both at once. It sits flush against the sidebar's own left edge, no wasted margin before it.
- "Ungroup" now takes the whole selection at once, however mixed: a roll among the selected rows falls back to its own capture day, a box among them dissolves back into whatever held it — one command instead of picking through each row's own menu.
- Fixed: "All Photos" drew a faint line underneath it that no other row had.
v0.0.30 on GitHub, with its download and its source
0.0.29
Render unchanged
Nothing changes in how an already-adjusted photograph renders — exports and saved edits are pixel-identical to 0.0.28. This version is entirely new ground: organizing and finding photographs, not converting them.
A sidebar next to the gallery lists every roll and every capture day as its own row, mirroring exactly what the gallery already headers itself with. Click a row to see only that group; click "All Photos" to see everything again. Double-click any name — a roll or a bare day, in the sidebar or in the gallery's own heading — to rename it on the spot.
Rolls can now nest inside boxes — virtual containers, never real folders on disk, purely a way to arrange a growing library. Select several rolls or days and group them into a box from the sidebar's own menu, or drag one roll onto another to form one automatically. Drag a roll onto a box to move it in; drag a box onto another to nest it. "Unbox" dissolves a box back into whatever held it, keeping every roll inside it exactly where it was, one level up.
- A medal filter sits in the top bar in gallery mode, in the mode tab's own slot: one button cycling ALL → BRONZE → SILVER → GOLD → ALL, showing exactly that tier and no other.
- Negative/Positive, the framing button and the compare button no longer sit greyed out in gallery mode — they only ever did anything on an open photograph, so they are hidden there instead.
- Fixed: double-clicking a roll's name in the gallery to rename it usually did nothing, because the header under the pointer during a scroll was a decorative copy with no gesture of its own.
- Fixed: the sidebar's "All Photos" row drew a faint border no other row had; it was the only one built as a real button rather than a plain click target.
v0.0.29 on GitHub, with its download and its source
0.0.28
Render unchanged
Exports and saved edits render exactly as before. One thing changes on screen: while a slider is held past 100 % zoom, the canvas shows the stretched preview — soft during the gesture, sharp again the moment you release. That trade closes a serious latent leak.
The leak, first. Holding a Colour slider past 100 % zoom made the app file full-resolution working buffers on every notch and never re-use them — gigabytes within seconds, however much memory the machine has, and the less it has the sooner everything stops answering. Every version to date carried it. The preview-under-the-hand rule above removes the mechanism entirely; a twenty-second worst-case drag now holds flat where it used to take the whole machine.
Editing feel, measured on a real hand rather than a script. Recorded before and after over the same erratic session: seventeen freezes over 200 ms in fifteen seconds became one in a whole session; the worst five percent of frames went from 6 to 35 per second.
- Adjusting by trackpad scroll now counts as a held hand, as dragging always did — so the heavy work every control defers during a drag is deferred for the scroll too. This was the single biggest cause of stutter, and it had been there since the scroll gesture shipped.
- The histograms follow the hand at about sixty refreshes a second, and a finished measurement is never thrown away again — the plot used to only catch up after the gesture ended.
- Full-resolution drags stopped rebuilding their cache on every notch; the region is rebuilt once, when you release.
- Nothing a drag starts can outlive it and pile up any more — one measurement in flight at a time, the newest settings win.
Also in this version:
- Applying a crop happens in two beats — the cropped frame renders first, the panel travels next — so slower machines no longer take both on one breath.
- The Straighten slider now works from the frame the gesture started on: sweeping out and back returns exactly where you began, instead of ratcheting the crop tighter.
- Launch no longer re-reads the whole library's EXIF twice per photograph; a large library opens without the disk churn.
- While a photograph's first measurement is still running, the auto-balance plate says so instead of sitting grey unexplained.
- Walking a roll with the arrow keys no longer builds full-resolution frames for photographs you have already left — on scan libraries this reached nineteen gigabytes.
- The diagnostics console now stamps every watchdog line with the app's memory footprint, so a report tells the whole story on its own.
v0.0.28 on GitHub, with its download and its source
0.0.27
Render unchanged
Nothing here changes how a photograph is rendered or exported. This version only adds to what the app can say about itself when it stops responding.
Three explanations for the crop freeze have now been ruled out by measurement rather than argument: memory, a file on a network volume, and the canvas cache — squeezed to a quarter of what the affected machine has, it still behaved. The log from 0.0.26 dates a block but does not name what is inside it, and that is what this version adds.
- Past one second of being unresponsive, the app now reads its own main thread and writes the function it is stuck in, with the frames above it. This is what a system spindump does; it runs from a thread that is not the blocked one, so the reading survives a forced quit.
- One reading per block, six per session, forty frames deep. A log nobody can read answers nothing.
Same routine as before, and it is the last thing needed: Help → Show Console before
reproducing, work until it happens, then Copy — or send the file the window names. What matters this
time is the block of lines beginning stack ·.
v0.0.27 on GitHub, with its download and its source
0.0.26
Render unchanged
Nothing here changes how a photograph is rendered or exported. Frames you have already adjusted open and export exactly as they did, and no cached thumbnail is thrown away.
This version exists to find one fault rather than to fix it. Cropping a photograph, clicking to apply, and having the app stop responding has been reported twice and reproduced neither time — so the app now records what it was doing when it stops.
- Help → Show Console. Open it BEFORE reproducing the fault, work until it happens, then press Copy. The window is frozen while the app is, so it also names a file: everything it holds is written to disk as it happens, and a forced quit keeps all of it.
- A watchdog on its own thread records how long the app went unresponsive and what it was drawing at the time. It writes that line during the block, not afterwards.
- The log also states which volume a photograph lives on, and whether a file provider owns it — a file that looks local in the Finder is not always a file the disk can hand over quickly.
Two real faults on that same path are fixed on the way: applying a crop no longer reads the disk on the thread that draws, and the crop gesture now defers the work that follows it the way every slider already did.
If it happens again, two things settle it: the console log, and the report macOS writes by itself
in Console under Crash Reports, named for this app and ending in .hang.
v0.0.26 on GitHub, with its download and its source
0.0.25
Render unchanged
Nothing here changes how a photograph is exported. Frames you have already adjusted come out of the export bit for bit as they did. What can change is what the canvas shows while you work: on a Mac with less memory, the reduced preview is now held at zoom levels where the app used to decode real pixels. That is sharpness on screen, never in the file.
Three faults reported by testers turned out to be one. Past a certain zoom, or a crop tighter than about two thirds of a side, the canvas switches to the full-resolution frame — and that path asked the GPU for as much on a 16 GB laptop as on a 96 GB desktop, never handed the memory back, and said nothing at all when an allocation was refused.
- The canvas now reads what the machine can actually give and caps itself at 4 GB. A large Mac is handed what it was already using, so nothing there renders differently. A smaller one is handed less, which is the whole point.
- A refused frame falls back to the preview instead of going black. One tester saw photographs simply vanish above roughly half zoom; that was an allocation being refused and the refusal being swallowed.
- Memory is handed back when the system says it is short, rather than held until the app quits.
- Exporting no longer needs a restart to work again. A render refused for want of memory is retried once with the session caches dropped — which is exactly what relaunching the app used to do by hand.
If a crop or a deep zoom still stalls on your machine, the app can now say what it was drawing
when it happened: run it with --fps, work until it stutters, quit, and send
/tmp/oni-fps.txt. It names the source and the crop, which earlier reports could not.
v0.0.25 on GitHub, with its download and its source
0.0.24
Render unchanged
Nothing here changes how a photograph is rendered. Frames you have already adjusted open exactly as they did.
Installs are now counted. On the first launch after an update, the app sends its version number and nothing else; what is kept is that number and the country the request came from. No identifier, no address, nothing that singles anyone out.
v0.0.24 on GitHub, with its download and its source
0.0.23
Render changes
This version changes the rendering of photographs you have already adjusted in Positive mode. A slide or a scan set to Positive opened almost white until now, and it opens on a picture instead. If you graded a positive around that paleness, your handles are where you left them but the image under them has moved. Negative and B&W do not move at all — that was measured on a full-resolution negative, before and after, and every figure came back identical. Version 0.0.22 stays in the feed if you would rather not take this one.
Positive mode was leaving a logarithm in the picture
Converting a negative works in density, which means taking a logarithm. Positive mode gave up the inversion that follows it and kept the logarithm — correctly, because that is what keeps the sliders linear in stops. What it never did was undo that logarithm before showing you the result.
- The symptom was a frame with no blacks in it. On a 16-bit scan of a slide, the median pixel came out at 224 / 227 / 246 of display code where the file itself holds 113 / 122 / 198, and the darkest thousandth of the picture opened in mid-grey, at 159 instead of 10. Over the brightest decade the app was rendering a quarter of the contrast the file carried.
- No automatic button could fix it. The balance keys write the three per-channel levels and never the RGB set, which is the one carrying the gamma — so pressing Classic left the medians at 219 / 221 / 241, still white.
What a positive now rests on
- The three black points start on the film base rather than under it. A physical black opens on black instead of on a grey veil, and nothing is clipped to get there.
- The RGB midtone slider rests at 0.670 instead of 0.500. That is what undoes the encoding. The same scan now opens on 0.463 / 0.503 / 0.809 where it used to open on 0.747 / 0.769 / 0.919.
- The rest stops short of matching the file exactly, on purpose. Landing on it takes the midtone handle to the very end of its travel, leaving nothing to add contrast with. A positive is meant to open on a usable starting point, not on a finished picture.
What happens to a positive you already adjusted
Its settings file is read onto the new resting point, so the fix reaches frames already in your library and not only the next import. A handle you actually placed is left exactly where you put it: only the ones still sitting untouched are moved. A negative or a B&W frame is read through without a single key being altered.
Also in this version
- The film probe used for diagnostics now reports what the whole chain makes of a frame in Positive as well as in Negative, and reports quantiles alongside the extremes.
v0.0.23 on GitHub, with its download and its source
0.0.22
Render unchanged
Nothing in this version changes the rendering of a photo you have already adjusted. No control moved and no default changed. The only difference is what ships alongside the application.
The source code now ships with every release
- Every release from this one on carries its own source archive, named
OpenNegative-<version>-source.zip. It holds the Swift sources, the resources, the Metal kernels, the package manifest and the Makefile: what you need to build this exact version, and nothing from my own machine. - Do not confuse it with the "Source code (zip)" GitHub attaches on its own.
That one is an archive of the release repository, which holds binaries and an update feed,
and it contains no Swift at all. The file to take is the one with
-sourcein its name. - One piece is still missing, and it was missing before too. The keycap button component lives in a separate private repository, so the archive does not compile as it stands: replace it with a plain button first. That is about an hour of work, and it is spelled out on the site.
The licence has not changed, and neither has what it gives you. GPL-3.0 asks for the source that corresponds to the binary you were handed; until now that source existed but you had to ask me for it, which is not the same thing.
v0.0.22 on GitHub, with its download and its source
0.0.21
Render unchanged
Nothing in this version changes the rendering of a photo you have already adjusted. One fix, on the thumbnail cache alone. Your settings, your rolls and your presets are untouched.
Thumbnails survive an unplugged drive
- Launching with the originals' drive disconnected no longer empties the thumbnail cache. The tidying pass built its list of claimed files by reading each original, and silently dropped every one it could not reach — so a whole library on an external drive was read as files nobody wanted, and deleted. Measured on a 632-frame library: the 592 frames on the external drive lost their thumbnails, the 40 on the internal drive kept theirs.
- An unreachable original now keeps its files, claimed through the fingerprint the index holds, which survives the drive going away. And an index that does not yet account for every member of the library deletes nothing at all: without knowing who is a member, no file can be called an orphan.
- The tidying itself still works. A superseded thumbnail of an original that really was read is still removed, and so are the files of a photo taken out of the library. The fix is a rule about proof, not the housekeeping switched off.
Version 0.0.20 announced that thumbnails had stopped being thrown away. That was half true: the rebuild stopped inventing fingerprints, but the pass that sweeps unclaimed cache files kept reading an unreachable original as an unwanted one. This is the other half.
v0.0.21 on GitHub, with its download and its source
0.0.20
Render unchanged
Nothing in this version changes the rendering of a photo you have already adjusted. Contact sheets are new, so nothing existed to move; every other change is interface, speed or reliability.
Contact sheets
- Make a contact sheet from a selection. Frames are laid six to a row in one scene-linear TIFF, which is imported like any other photograph — so one balance, one set of curves and one export cover the whole roll.
- The automatic balance reads inside the frames only. A window is placed on each cell, well inside its edges, so the gaps and the film rebate never enter the measurement — which is what used to drag the whole sheet off colour.
- The gaps export black. A sheet reads as a sheet instead of arriving on a white page.
- Every step of the grind is named. A forty-frame sheet used to sit for ten seconds on a full progress bar with nothing to say — writing, adding and opening now each announce themselves.
Rolls
- Group frames into a roll with ⌘G, and name it. The gallery cuts on rolls instead of capture days, so a film shot over a week stops being scattered across it.
- Membership lives in the sidecar. Deleting the index or moving to another machine cannot lose a roll, and a paste can never move a photograph out of one.
Presets
- Five film presets ship with the app — Azure, Cinestill 800T, Gold 200, Portra 400, Redscale. They are laid down once, then they are yours: rename them, retune them, or throw them away and they stay away.
Framing
- A horizontal and a vertical mirror. Both act on the frame as you see it, so the axis means what it says whatever quarter turns are applied.
- Rotation turns clockwise, which is the direction the button was already claiming.
- An Apply button under the panel's reset. Committing a crop no longer means finding the gesture elsewhere.
The bar at the top
- Three groups instead of one row. Framing and comparison, then editing, then the two that commit — read left to right rather than scanned.
- Delete is red, reset is amber, new contact sheet is orange. A deliberate choice: the gestures you cannot casually undo are the ones that carry a colour.
Speed and reliability
- The library is read off the main thread. This version rebuilds its index at first launch, which costs one reading of each original; it now happens behind a progress sheet instead of an empty window.
- Each original is read once, not twice. The fingerprint and the capture date both wanted the same metadata and each asked for it — 12.93 ms per photograph instead of 25.19.
- A disconnected disk no longer poisons the library. What cannot be read is skipped rather than recorded with invented dates, and plugging the drive back in repairs it with no gesture. Thumbnails stop being thrown away, and frames stop piling onto one impossible day.
- The gallery draws only what is on screen. Landing on the six-hundredth frame of an import used to build six hundred cells; the count is now what a window holds.
- Column count replaces tile size, six or twelve, and ⌘− / ⌘+ walk it.
Smaller things
- Conversion mode applies to a whole selection, as does reset.
- Clicking a tab slides the panel instead of cutting to it, so the swipe the panel already supported is discoverable without being told about it.
v0.0.20 on GitHub, with its download and its source
0.0.19
Render unchanged
Your photographs render exactly as before. The new stage added here is skipped, bit for bit, until you move one of its points, so a conversion already made comes back identical. Nothing in this version needs a migration and nothing is lost by going back.
One habit does change on the first click. A photograph you have already worked on now opens on the Color panel instead of the framing view. A scan you have never touched still opens on framing, which is what a fresh negative wants.
Spectrogram finishing: the colour mixer, as a wheel
Photoshop and Lightroom put a colour mixer behind rows of sliders, where reading which colour you are steering means reading a label. It is the same control here, drawn as the thing it describes: eight points on a wheel, one per colour range, at the top of the Grade panel.
Each point carries three things. Its angle is that colour's hue, its distance from the centre its saturation, and a second point riding the same spoke its luminance. Click a point, then use the arrow keys — left and right turn the hue, up and down steer whichever point you are holding. Tab walks the wheel clockwise, Option-Tab the other way. Four keys under the graph do the same for a hand that would rather not leave the mouse, and a slider sets how far one press moves.
Double-clicking a point puts its own axes back to rest, and only its own: clearing a hue does not quietly undo the luminance the other point on that spoke is carrying.
What the wheel promises is that a band reaches its own colours and no others. Pushing red to the end of its travel leaves a blue pixel where it was, exactly — not nearly. The luminance point is a gain in stops, so a colour can be taken four times down without ever reaching black, and the hue and the saturation ratio come through it untouched.
Lighting, on black and white
The block offered two tabs, RGB and Luma. On a monochrome render that distinction has already collapsed — everything becomes one channel at the end of the chain — so the two were the same control under two different laws, one of them labelled RGB on a grey image, and their effects added up. Monochrome now offers the one set, and the tab bar goes away with the choice.
The Exposure handle also sat two thirds along its track while reading its resting value, on black and white only, which reads as already pushed. It rests at mid-travel now, in every mode. Only the handle moved: the stored value and the rendering did not.
Framing has a button
Cropping and straightening was a panel among others. It is now a key at the head of the toolbar, and while you are framing that key turns green and carries a check: press it and you are back where you were working, or on Color if you had not been anywhere yet. ⌘K does the same, and the gesture is in the View menu like every other one the bar carries.
The zoom follows you between photographs
Opening the next frame refitted the view, so walking a roll at 100 % to compare grain from one frame to the next was not possible. The zoom is now kept, and so is the fitted state if that is what you were on; only the pan is dropped, since it describes a picture you have left. The blurred stand-in shown while the next frame decodes is drawn at that same zoom instead of flashing back to fitted.
What it runs on
macOS 13 Ventura or newer, on Apple Silicon or Intel — one universal build for both.
v0.0.19 on GitHub, with its download and its source
0.0.18
Render changes
One thing moves the rendering of photographs you have already adjusted, and it is named first. Sharpening and chroma denoise are now dosed in pixels of the full-resolution scan instead of a fraction of its width. On a scan whose long side is 8368 px — what the old fraction was calibrated on — nothing moves at all. On any other size it does: measured on scans of 6000 to 6240 px, the dose lands 34 to 39 % higher than before. Everything else comes back identical.
Two consequences worth knowing before you install. Every thumbnail is rebuilt once, on the first import or launch, behind a progress step — after that they are never rebuilt again. And a photograph adjusted in this version opens read-only in 0.0.17 and below: going back loses nothing, but the older version will not let you move a handle. Every published version stays in the feed, so going back remains possible.
The gallery no longer freezes
Dragging the scroll bar froze the app for two to five seconds, and macOS reported it as not responding. The cause was the container itself: it filled contiguously, so reaching frame 600 built all 600 on the way, and it paid that cost again on every switch between the grid and the editor.
The grid is now computed rather than measured — every tile's rectangle and the document's height are arithmetic, and only the cells the visible band touches are drawn. Landing on the last frame of a 600-photograph day builds 78 cells instead of 600. The scroll bar can be dragged end to end, and the scroll bar itself is honest, because the height is computed rather than estimated.
Thumbnails are written once
They were regenerated when the app opened, when the gallery reopened, and when the window was resized. They are now written once, at a fixed size, kept in the app's own files, and rebuilt only after you edit the photograph. Deleting a photograph deletes its thumbnails with it.
What you see: a step with a progress bar the first time, then a gallery that opens immediately and stays that way.
The gallery groups by capture date
It grouped by import date, so re-importing or re-scanning part of a roll split it across two headings. It now reads the capture date from the file. A roll stays together whatever evening you scanned it.
Six columns, or twelve
A strip of film is cut into six frames, so a row is a strip; twelve is that strip doubled, for sorting a roll rather than judging one frame. ⌘− and ⌘+ walk between the two, and the change is crossed with a fade instead of photographs sliding to new places.
Both are fully responsive: the count is what you choose, and the tile is what takes the room. On a wide screen the tiles are large. There is no width at which the grid rearranges itself behind your back.
The conversion works in density
Inverting a negative by 1 − x on linear data crushes everything into the first few percent of the range, which is why the handles felt unusable at one end and violent at the other. The whole chain now works in density, where a stop is a stop.
What changes for you: the three per-channel level windows read a density with three decimals instead of a percentage, and their track runs from −0.35 to 3. A black point can be placed under zero, which is where a channel transmitting past 1 actually lands — previously unreachable. Your existing adjustments were converted exactly; the arithmetic is an identity, and it is verified pixel for pixel against the frozen previous version.
A new control: Density ceiling
Scans differ in what they left under zero. The top of the density axis was a fixed constant that suited eight measured films differently, so it became a control — resting exactly on the old constant, so nothing moves until you touch it.
Raising it buys separation in a burnt patch, at the cost of pulling up whatever the scanner left under zero. It is the one handle that reaches a channel piled flat against the floor, which no gain and no black point can separate.
Colour is now Temperature and Tint
Colour was a single gesture that was hard to aim. It is now two named sliders, in the order and the sense every other application uses: pushing right warms. They are shouldered, so the travel is fine near the middle and never runs into a wall at the end.
They stay a finishing gesture and are deliberately independent of the balance gains above them: a finishing move must not displace the conversion, nor the answer an automatic button just gave. Colour density now sits with them, under the same heading, since it belongs to the same decision.
Lighting gains Shadows and Highlights
Exposure and White moved the two ends, and one gamma moved everything between them. That single exponent cannot fold two problems at once: after the medians are aligned, crossed dye curves leave the quarter-tones and the three-quarter-tones apart.
Two sliders now steer those two zones directly, and the same pair was added to the per-channel level windows. The ends stay pinned, so a black and a white placed on data keep their meaning whatever the inner three carry. Everything rests where it did, so nothing moves until you move it.
Three more automatic balance buttons
None of them is right on every photograph, and that is the point — each wins films the others lose, in a measured way. Whites places the white point on a higher quantile than Highs. Body moves both ends together so the tenth and ninetieth quantiles land on green's. AVG is the average position of all five handles across the other five buttons.
AVG is first on nothing and last on nothing, which is what it is for: it is the one to press when you do not want to try five. The buttons that assume nothing about the scene's colour are tinted apart from the ones that align a statistic across the channels.
Sharpening and chroma denoise are dosed in pixels
Both radii were a fraction of the image's width, calibrated on one scanner's output. The same setting therefore meant a different real dose on a scan of another size, silently.
They are now full-resolution pixels: a slider reading 3 px puts 3 px in the export. This is what moves the rendering, and only on scans whose long side is not 8368 px. Their ranges were tightened to what a preview can actually show — the bottom of the sharpening track is now the smallest radius a fitted preview can display at all, so no part of the gesture is inert on screen while still reaching the export. Use the loupe to judge the real dose: a fitted preview cannot show it, whatever the unit.
Navigating the photograph
Dragging now follows the pointer instead of moving against it. The wheel zooms in sixteen steps across the range rather than the barely perceptible amount it moved before. A double click goes to 100 %, and 100 % now really shows the pixels at any window size — the readout used to say "100 % · preview" on a large display while showing a reduced copy.
Explanations moved into the panels
Notes under blocks are gone. A question mark now sits to the right of each section title and opens a bubble on hover, drawn above the panel and confined to the picture area, so it never covers the control it describes. Every sentence was rewritten to say what the control does for you rather than how it works.
Smaller things
A resized export no longer leaves a translucent rim around its edge.
The window can no longer be dragged narrower than its own contents, which used to cut the interface off on the right instead of refusing.
Lighting's Shadows and Highlights sliders lighten to the right, like Exposure and White beside them. Only the handle was reflected: the stored value, the sidecar and the rendering do not move.
What it runs on
macOS 13 Ventura or newer, on Apple Silicon or Intel — one universal build for both. The interface is dressed for recent macOS; on older systems it is the same app with a plainer toolbar.
v0.0.18 on GitHub, with its download and its source
0.0.17
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. One thing does not survive going back, and it is named first.
Presets are stored in a new form. Yours are read and converted on first launch, carrying exactly what they carried before. But a preset saved from this version is not readable by an earlier one: going back to 0.0.16 or below would show your presets carrying nothing. The photo settings themselves are untouched by this and read on any version.
A preset carries settings, not tabs
Saving a preset offered three tabs — Balance, Rendering, Detail — and each was all or nothing. It now offers the settings themselves, grouped and named as the panels name them: white balance, colour, lighting, flat-field, grade, detail. The box opens with exactly what you moved on that photograph ticked, so saving a look no longer drags every resting stage along with it.
Three settings could not be carried by any preset at all, because no tab named them: colour density, texture and the flat-field reference. They can now.
The white balance is one choice rather than two boxes, because manual and automatic write the same two settings. A preset can carry the values this photograph holds, or a method — Classic, Mids or Highs — which is measured on each photograph it is applied to rather than copied. Hovering such a preset shows the balance it will produce, not the preset without it.
Saving now happens in the app's own window instead of a system alert, and the card's colour is chosen there rather than afterwards.
Copying settings adds, and no longer strips
A copy now carries only what the source photograph actually moved. Pasting can lend a look to a frame; it can no longer take one away because the source happened to leave a stage at rest. In the same move, the conversion mode stopped travelling: pasting from a negative no longer flips a positive scan, which it did silently on a mixed roll.
Smaller things
The negative/positive selector acts on what is selected in the gallery. It used to stay bound to the last photograph opened, so it wrote to that one whatever you had selected — and stayed lit after leaving the editor when nothing was selected at all.
The gallery opens at the end of the library again, where the latest import sits.
The loupe rests at 150 % and says so. Above 1:1 the pixels are interpolated: the sharpening dose is still the one that will be written, the pixels are no longer exact.
Cropping no longer vibrates — there are no notches to feel on a frame's edges. Swiping between panels gives one tick at the point of no return instead of a run of them along the way.
v0.0.17 on GitHub, with its download and its source
0.0.16
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. This version is about the button holding the far end of the bar.
The gallery imports where the editor exports
That button now carries the gesture that finishes the surface you are on: importing in the gallery, exporting in the editor. Each face has its own fill, so the colour states which gesture the slot is holding rather than leaving you to read the label.
Exporting from the gallery has not gone anywhere. It stays on the File menu and on the shortcut, count of targeted photographs included, and the import button says so on hover — the bar is one of four places that gesture is reachable from, never the only one.
A waiting update still outranks both faces
When a new version is waiting, that same button offers it, in orange, on either surface. The gallery is where the app lands, so a face hidden there would be hidden altogether. It still installs nothing without a click.
v0.0.16 on GitHub, with its download and its source
0.0.15
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. This version settles what the app itself looks like.
The app no longer follows the system's light appearance
Nothing pinned the interface's appearance, so a Mac set to Light dressed the app in a theme that was only ever half built. The canvas and the photograph tiles are fixed dark values by design — a photograph has to be the brightest thing on screen — while the panels, the title bar and the alerts took whatever the system handed them. Measured, a light system ringed a canvas at 0.106 with panels at 0.588: a fivefold mismatch, and nothing in the app could correct it.
The app now sets its own appearance at launch, before the first window is drawn, so it looks the same whichever theme the system is on. Alerts, panels and the title bar follow, which the SwiftUI setting alone would have left behind on the system theme.
Under the hood
A check reads the launch code as text and fails if that pin is ever removed, so a later change cannot quietly hand the interface back to the system. The export sheet carried its own dark override, which existed only to survive the light theme; it goes with it.
v0.0.15 on GitHub, with its download and its source
0.0.14
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. This version is about the memory the app holds while you work.
Scans no longer pile up in memory
Decoding a linear DNG built its pixels in a buffer the system's allocator then kept resident even after the app released it. Opening one photograph after another climbed by more than a gigabyte each time and never came back down. Those pages are now returned the moment a photograph is closed.
Measured over four consecutive opens of a 78-megapixel scan: what stays held afterwards went from 6.5 GB to 24 MB. Browsing a roll of scans now sits under a gigabyte where it used to reach four.
One less render at every open
Every photograph opened ran a full-frame measurement whose result nothing read. It is gone. The full-resolution frame is still decoded when a photograph opens — it has to be, for the loupe and for 100 % zoom — but off the main thread, so the window never waits on it.
A warning that could fire on a healthy photograph
The "flat decode" remark read an empty render as a flat frame. A buffer that comes back exactly zero everywhere is a failed measurement, not a photograph with no contrast, and it no longer raises the notice.
Under the hood
Nothing measured this app's memory before, which is why the leak of the previous version reached a user before it reached us. Four instruments now do, and they run from the command line: one drives thousands of slider writes, one opens photograph after photograph, one builds the state a step at a time, and one sweeps a slider across its whole travel counting the frames actually presented. Each reports the footprint alongside what Metal has allocated.
That last one found something the others could not: a probe that launches the app without a window renders nothing at all, and had been reporting comfortable numbers for a canvas that never drew a pixel. Work on drag responsiveness continues with an instrument that can now see it.
v0.0.14 on GitHub, with its download and its source
0.0.13
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. This version fixes a memory leak that a tester hit at 19 GB.
Browsing no longer holds what it opened
Opening one photograph after another kept about a full-resolution frame each time, and never gave it back. On a machine with plenty of RAM it stayed invisible for a long while; on a smaller one the app grew until the system started swapping. This is the defect behind the slowdowns reported after a long session.
The cause was the preloading of neighbouring frames: the app decoded the previous and the next photograph in advance so an arrow key would cost nothing. Its reservation marker never actually stuck, so every open relaunched the same decodes, and the frames piled up.
The preloading is gone rather than patched. Measured over twenty consecutive opens, the footprint is now flat where it used to climb by about 1.9 GB per photograph. The price is stated plainly: an arrow key now decodes on demand instead of finding the frame ready, so moving along a roll is a little slower. A long session's memory comes before one key's comfort.
Under the hood
Nothing measured the app's memory before this, which is why the defect reached a user before it reached us. Two instruments now exist, and both run from the command line: one drives thousands of slider writes, the other opens photograph after photograph, and each reports the footprint alongside what Metal has allocated. A slider drag, measured over five thousand writes, holds nothing.
Two smaller changes ride along: the curve pass no longer builds a callback on every evaluation, and each drawn frame now releases its temporaries at its own end rather than at the end of the run loop's turn.
v0.0.13 on GitHub, with its download and its source
0.0.12
Render unchanged
Your photographs render exactly as before. No stage changed shape and no setting changed value: a conversion already made comes back identical, pixel for pixel. This version adds a third mode next to Negative and Positive.
A black-and-white mode
B&W joins Negative and Positive in the top bar, because it is the same kind of thing: what the frame is, not a treatment you dial. It inverts and rests exactly like a negative, because that is what it is — printed grey.
It adds no channel mixer, and that is deliberate. The three sliders in the Colour block already do that work: each places one point at the middle of its channel's curve, never touching the black or the white point. Push red and the sky darkens — that is the Tri-X yellow filter, reached with a control you already know. The projection to grey happens only at the very end, and does nothing but render what those curves prepared.
Put differently: all the colour work still happens. It is what decides which grey.
What the mode takes away
Anything that only shapes colour leaves the screen rather than sitting there doing nothing:
- The Grade tab — the finishing balance and zone saturation act on a chroma the last stage projects away regardless.
- The Mids and Highs buttons of the automatic balance: aligning medians or highlights across channels shapes a cast. What remains is Equalise, which places each channel's ends and gives a clean base.
- The Color density slider. Its value is kept and returns if you switch back to colour.
Cropping, the automatic balance, the three colours, the Lighting block, flat-field correction and the whole Detail tab all stay. The manual conversion is still there behind its door, called manual equalisation here.
Also
- A photo set to black and white and then opened by an earlier version opens as a negative instead of refusing to open at all. Its settings are intact; only the mode is ignored by a version that does not know it.
v0.0.12 on GitHub, with its download and its source
0.0.11
Render unchanged
Le rendu de vos photos ne bouge pas. Aucun étage du pipeline n'a changé, aucun réglage n'a changé de valeur : ce que vous exportez sort identique au pixel près.
L'application dit qu'elle est en alpha
Une bulle orange s'affiche en permanence sous la barre, dans l'éditeur comme dans la galerie : ONI is in Alpha, bugs are to be expected. Elle porte un lien qui ouvre directement le formulaire de signalement.
Elle est posée dans la bande que le rendu ne peut pas atteindre, donc elle ne couvre jamais un pixel de la photographie.
Elle remplace le relevé des moyennes du négatif brut, qui affichait les valeurs R, V et B lues dans le fichier. C'était un instrument de mise au point du traitement, pas une information utile pour convertir une photographie.
v0.0.11 on GitHub, with its download and its source
0.0.10
Render unchanged
Le rendu de vos photos ne bouge pas. Aucun étage du pipeline n'a changé de forme et aucun réglage n'a changé de valeur : ce que vous exportez aujourd'hui sort identique au pixel près. Cette version corrige ce que l'aperçu montrait de faux, et deux détails de la fenêtre.
Le liseré autour de l'aperçu
Un cheveu clair bordait l'image à l'écran, présent depuis toujours, et la réduction de bruit chroma le transformait en cadre coloré. Il n'a jamais touché le fichier exporté ni la vue à 100 % — c'était un défaut de l'aperçu seul, et il avait trois causes empilées, toutes corrigées.
- Le décodage réduit assombrissait sa rangée et sa colonne extérieures. Le rééchantillonnage y couvre moins d'un pixel de la source : jusqu'à 10 % d'écart avec la ligne voisine, mesuré. Inversé, cet écart de densité ressort en clair.
- Réduire l'image pour la faire tenir dans la fenêtre laissait son pixel de bord à moitié couvert. À un ajustement de 0,73, il n'était couvert qu'à 7 % : il se mélangeait donc au fond de la carte, et ce mélange dessinait le trait.
- Et surtout, le recadrage. Le cadre est calé sur la grille des pixels de la pleine résolution, pour que l'écran et le fichier décrivent exactement le même rectangle — on n'exporte pas un demi-pixel. Mais un cadre entier à 8368 px tombe forcément entre les pixels d'un aperçu de 2000, et son bord sortait alors à 67 % de couverture. Les étages qui lisent un voisinage — réduction de bruit, netteté, texture — recevaient là une couleur faussée et la portaient vers l'intérieur sur la largeur de leur rayon. D'où une bande colorée, et non un simple trait.
Le bord est désormais reconstruit depuis la ligne juste à l'intérieur, uniquement sur les copies réduites. À pleine résolution le cadre tombe sur des entiers, donc rien n'y est touché : le fichier exporté garde son propre bord, tel que la pellicule le donne.
La fenêtre
- En plein écran, la barre du haut reprenait le matériau du système et se dotait d'un filet. Elle reste maintenant plate et sans filet, et le redevient à chaque passage en plein écran — macOS y remet sa parure à chaque bascule.
- La carte de l'aperçu est à fleur des panneaux dans l'éditeur. La gouttière qu'elle gardait sur ses côtés arrêtait les séparateurs du panneau de gauche avant l'image, et donnait à la colonne de droite une marge plus large d'un côté que de l'autre. Elle ne sert qu'à la galerie, où l'image serait sinon collée aux deux bords.
Aussi
- Les vignettes se régénèrent une fois : celles en cache portaient encore le liseré.
v0.0.10 on GitHub, with its download and its source
0.0.9
Render changes
Le rendu change si vous aviez réglé la réduction de bruit chroma à la main : l'étage a changé de place dans la chaîne. Il n'agit plus sur le négatif avant inversion mais sur l'image finie, et il fait enfin ce qu'on lui demande. Les photos dont vous n'aviez pas touché ce réglage ne bougent pas.
Le bleu fluo : la cause est trouvée
La version précédente désactivait la réduction de bruit chroma faute de comprendre pourquoi elle teintait les contours. C'est compris, et mesuré.
L'étage remplaçait la couleur d'un pixel par celle de son voisinage, exprimée en valeur absolue. Or il agissait sur le négatif, avant l'inversion — c'est-à-dire avant un logarithme. Prendre la couleur d'un voisinage clair pour la poser sur un pixel sombre pouvait retirer au canal bleu davantage que ce canal ne contenait. Le résultat passait sous le plancher, et le logarithme le renvoyait saturé : un liseré bleu du côté sombre de chaque contour.
Deux choses expliquent que ça se voyait surtout sur les scans en DNG ou en TIFF. Leur canal bleu part beaucoup plus bas — entre 0,04 et 0,10 quand le rouge est à 0,45 — parce que le masque orange du film l'écrase et que ces fichiers n'ont reçu aucune balance au décodage. Il n'avait donc presque aucune marge avant le plancher. Et l'effet se concentrait sur les contours, là où la couleur d'un pixel diffère le plus de celle de ses voisins : d'où cette impression d'accentuation colorée plutôt que de lissage.
L'étage rejoint la netteté et la texture, à la fin
Il agit désormais après l'inversion, en tête du groupe de finition. Trois conséquences :
- Il débruite pour de bon. Mesuré sur l'image telle qu'on la voit, il retire la majeure partie du bruit de couleur ; à son ancienne place il en ajoutait sur les fichiers les plus touchés, tout en paraissant bien travailler dans l'espace où on le mesurait.
- Il ne peut plus produire de bleu saturé. Sans logarithme en aval, un débordement devient au pire un point sombre, écrêté comme n'importe quel autre.
- On lisse la couleur qu'on voit, et non une couleur que les courbes, la balance de finition et la saturation par zone vont ensuite redéformer.
Les deux curseurs restent à zéro au repos. L'étage fonctionne, mais c'est à vous de le doser : la loupe de l'onglet Detail montre son effet à l'échelle réelle du fichier.
Aussi
- Le contrôle automatique qui surveillait cet étage mesurait la bonne grandeur dans le mauvais espace, et restait vert pendant tout le défaut. Il mesure désormais après l'inversion, et son contre-exemple est l'ancien traitement reconstruit à l'identique.
v0.0.9 on GitHub, with its download and its source
0.0.8
La réduction de bruit chroma est désactivée, sur les photos déjà importées comme sur les nouvelles. Elle teintait les contours en bleu au lieu de lisser la couleur, et d'autant plus que la résolution était basse. Si vous l'aviez réglée à la main, votre réglage est conservé et continue de s'appliquer — c'est seulement la dose que personne n'avait choisie qui cesse d'agir.
Ce qui se passait
L'étage était censé lisser la couleur en laissant le grain intact. Sur certaines images il faisait l'inverse : au lieu de fondre les détails, il les dessinait, en bleu. Le défaut se voyait surtout sur les fichiers déjà réduits — scans en DNG linéaire, TIFF — et il empirait à mesure que la résolution baissait. Sur un RAW à pleine résolution il fallait pousser les deux curseurs au maximum pour le déclencher.
La cause n'est pas encore établie. Plutôt que de livrer une correction devinée, l'étage cesse d'agir tant qu'on ne le lui demande pas : les deux curseurs partent de zéro, et un double clic y revient. Il reste entièrement disponible, à la main, pour qui veut l'essayer.
Pourquoi vos photos déjà traitées sont concernées
Mettre un réglage par défaut à zéro ne change rien aux photographies déjà importées : leur sidecar porte la valeur qu'avait la version où elles ont été ouvertes, et il la garde. Elles auraient donc continué de bleuir.
Cette version reconnaît donc exactement les deux valeurs de repos que les versions précédentes posaient, et les relit à zéro. Toute autre valeur — celle que vous avez posée vous-même en déplaçant un curseur — est un choix, et elle survit intacte. Aucun autre réglage n'est touché.
Aussi
- Le format des sidecars passe en version 2. Les fichiers écrits par cette version restent lisibles par les précédentes, qui ignoreront simplement la mise à zéro.
v0.0.8 on GitHub, with its download and its source
0.0.7
Render changes
Le rendu de vos photos change. Trois étages du pipeline ont été corrigés, et les conversions déjà faites ne ressortiront pas identiques : la texture a changé de forme, la netteté et la réduction de bruit avaient des rayons trop petits pour agir, et les DNG linéaires étaient réduits d'une façon qui fabriquait du bruit couleur. Aucun réglage n'est perdu — vos sidecars se relisent tous — mais rouvrez une photo déjà traitée avant d'exporter.
Cette version refond aussi l'organisation des panneaux de fond en comble. C'est la mise à jour la plus large depuis le début.
Le panneau est réorganisé par usage, plus par ordre de traitement
Quatre onglets au lieu de trois, et ils suivent maintenant la façon dont on juge une photographie plutôt que l'ordre dans lequel la machine calcule :
- Frame — le cadrage, d'abord, pour que la balance automatique et l'histogramme ne comptent que les pixels gardés.
- Color — arriver à une image juste : balance automatique, couleur, densité, lumière.
- Grade — prendre parti sur une image juste : balance de finition et saturation par zone.
- Detail — réduction de bruit, netteté et texture.
Les courbes sont devenues des curseurs. Trois couleurs et un contraste, là où il fallait poser des points à la main. Le contraste rejoint les niveaux dans un bloc Lighting, parce qu'il se juge contre l'exposition qu'il façonne et non tout seul. Ses libellés disent enfin ce qu'ils font : Exposure, Black point, White point, et pousser vers la droite éclaircit dans les trois cas.
La conversion manuelle passe à la fin, derrière une porte. Le chemin court vient en premier ; la balance de source et les niveaux par canal restent accessibles d'un clic, dans une boîte sombre qui dit qu'on est ailleurs. La correction de flat-field en sort, puisqu'elle corrige l'éclairage du banc de numérisation et non la photographie.
Color density, un réglage neuf
Un curseur qui écarte les trois canaux les uns des autres sans toucher à la saturation. Le gris est son point fixe : une zone vraiment neutre ne bouge pas, et tout ce qui s'en écartait s'en écarte davantage, proportionnellement à ce qu'il en était déjà loin. Une couleur ressort alors plus claire que le gris avec lequel elle était à égalité — ce sont les aplats qui gagnent en présence, pas la chroma qui monte.
Detail : une loupe, et une texture qui ne moutonne plus
Une loupe remplace l'histogramme dans cet onglet. La réduction de bruit et la netteté agissent sur un rayon de deux pixels du fichier : aucun aperçu réduit ne peut les montrer, l'information n'y est pas. La loupe affiche la zone au centre de la vue à l'échelle réelle du fichier, 1:1 ou 2:1, avec exactement le dosage qui sera exporté. L'histogramme de sortie, lui, n'apprenait rien ici — aucun de ces trois étages ne déplace visiblement la distribution.
Texture est un contraste de bande médiane : ce que la netteté ne peut pas atteindre et ce que la clarté déborde. Elle a été entièrement refaite depuis sa première version, qui posait des plaques au lieu de dessiner. Elle repose maintenant sur une base qui suit les contours, ce qui divise le halo par cinq à l'endroit où il se voyait, et elle s'affiche dès l'aperçu au lieu d'exiger le zoom à 100 %.
La netteté perd son seuil, qui restait à zéro sans que rien ne prouve qu'il servait. Son rayon est ancré au milieu de sa course, là où le geste se fait réellement sur un scan de film.
Trois réglages qui ne faisaient presque rien
- La netteté et la réduction de bruit chroma étaient trop faibles pour agir. Leur rayon est une fraction de la taille de l'image, et il était descendu sous le seuil où un flou gaussien rend son entrée inchangée. Sur un fichier de 8368 pixels la réduction de bruit travaillait sur 0,84 pixel ; elle en couvre 8,4 maintenant.
- Le rayon suivait la largeur, pas le grand côté. Un scan en portrait recevait jusqu'à trois fois et demie moins de dose que le même scan en paysage.
- La texture était purement sautée sur l'aperçu. Le curseur se réglait à l'aveugle : il n'agissait qu'à 100 % de zoom et dans le fichier exporté.
Les DNG linéaires : un bruit couleur qui n'existait pas
Un DNG linéaire — un scan à trois canaux, non mosaïqué — était réduit en prenant un pixel sur n, sans moyenner. L'aperçu portait ainsi près d'une fois et demie l'énergie fine du fichier réel, et près du double en couleur : le bruit chroma qu'on cherchait à retirer était en partie fabriqué par cette réduction. Les vignettes et la mesure que lit la balance automatique étaient les plus touchées. Elles moyennent désormais toute la zone qu'elles remplacent.
La barre et les gestes
- Le avant/après devient une touche de la barre.
- Un bouton coupe et rend le son des touches.
- Nouvelle icône d'application.
- Le quart de tour, le son et le avant/après ont des icônes qui nomment le geste et non l'état.
Aussi
- La balance automatique lisait une mesure qui portait déjà la densité couleur et la texture : elle se posait donc sur une image qu'elle avait elle-même modifiée.
- Un export par lot demande confirmation avant de remplacer des fichiers existants, comme le faisait déjà l'export d'une seule photo.
- Plus aucun chemin du disque de développement dans le binaire livré.
v0.0.7 on GitHub, with its download and its source
0.0.6
Render unchanged
Le rendu de vos photos ne bouge pas. Aucune constante, aucun étage du pipeline n'a changé : les conversions déjà faites ressortent identiques au pixel près.
La galerie défile enfin correctement
Faire défiler la grille ou la pellicule saccadait, et d'autant plus que le pointeur passait sur les vignettes. Trois causes, aucune dans le traitement d'image :
- Rien ne limitait le travail de fond. Chaque vignette qui apparaissait lançait sa propre tâche : trente-six cellules à l'écran, c'était trente-six décodages de RAW en même temps. Ils sont maintenant mis en attente, et surtout servis en commençant par les dernières demandées — c'est-à-dire ce que vous regardez, au lieu de ce que vous venez de dépasser.
- Une vignette qui arrivait faisait redessiner toute la galerie, deux fois. Elle ne redessine plus que sa propre case.
- Les images étaient reconstruites à chaque affichage. Elles sont décodées une fois, quand elles sont produites.
Les vignettes sont aussi demandées à la taille où elles sont affichées, au lieu de toujours la plus grande : trois fois moins de pixels à la taille par défaut.
Aussi
- Le survol d'une vignette ne fait plus travailler ses trente-cinq voisines.
- L'app ne peut plus être lancée sous Rosetta par erreur sur un Mac Apple Silicon.
Si vous êtes sur macOS Ventura : toujours vrai, vous êtes les premiers à y lancer l'app et rien n'y a été testé ici. Signalez ce qui cloche, même un détail.
v0.0.6 on GitHub, with its download and its source
0.0.5
Render unchanged
Le rendu de vos photos ne bouge pas. Aucune constante, aucun étage du pipeline n'a changé : les conversions déjà faites ressortent identiques au pixel près.
Le retour vers la galerie ne bloque plus
En 0.0.4, fermer une photo pouvait figer l'app : l'image restait au centre de l'écran, floutée, les deux panneaux disparaissaient et la galerie n'apparaissait jamais. Il fallait quitter et relancer.
La photo était animée d'un mouvement qui l'emmenait de sa vignette au canevas à l'ouverture, et refaisait le chemin inverse à la fermeture. C'est ce retour qui pouvait rester en l'air. Ce mouvement est supprimé — la bascule est maintenant immédiate, et seuls les deux panneaux latéraux s'animent, à l'ouverture comme à la fermeture.
C'est un choix, pas un pansement : le mouvement était beau et compliqué, il valait mille lignes, et il produisait un blocage complet. La bascule instantanée ne peut pas rester en l'air.
Si vous êtes sur macOS Ventura
Rien de nouveau depuis la 0.0.4 sur ce point, mais ça reste vrai : vous êtes les premiers à y lancer l'app, et rien n'a jamais été testé sur Ventura ici. Signalez ce qui cloche, même un détail d'affichage.
v0.0.5 on GitHub, with its download and its source
0.0.4
Render unchanged
Le rendu de vos photos ne bouge pas. Aucune constante, aucun étage du pipeline n'a changé : les conversions déjà faites ressortent identiques au pixel près.
macOS Ventura suffit désormais
L'app demandait Sonoma (14) ; elle demande maintenant Ventura (13). C'est deux versions de macOS de moins que la première publication, et ça vise une machine précise : un Mac qui ne peut pas monter plus haut.
Une cinquantaine d'endroits du code utilisaient des fonctions apparues après Ventura. Elles ont été réécrites avec des moyens plus anciens qui font la même chose — et partout, pas seulement sur les vieux systèmes : une fonctionnalité écrite deux fois est une fonctionnalité vérifiée une seule fois. Les animations, notamment, ne sont plus demandées au système mais calculées ; l'équivalence a été mesurée au seizième chiffre après la virgule, et les mouvements sont identiques.
Ce que ça implique si vous êtes sur Ventura : vous êtes la première personne à y lancer l'app. Elle compile et passe ses 967 contrôles, mais aucun d'eux n'a tourné sur Ventura — personne n'en a sous la main ici. Signalez ce qui cloche, même un détail d'affichage.
Le paquet de courbes s'ouvre sur le contraste
Les six presets de contraste passent en première page et les six d'exposition en seconde. Les courbes elles-mêmes sont inchangées.
Un défaut d'affichage corrigé
Dans la galerie, les vignettes pouvaient rester sur un rouet indéfiniment et les tuiles ne réagissaient plus au survol — jusqu'à ce qu'un clic débloque tout d'un coup. Une optimisation de la 0.0.3 faisait considérer la grille comme inchangée alors qu'elle avait de quoi se redessiner.
v0.0.4 on GitHub, with its download and its source
0.0.3
Render unchanged
Le rendu de vos photos ne bouge pas. Aucune constante, aucun étage du pipeline n'a changé : les conversions déjà faites ressortent identiques au pixel près.
L'app tourne beaucoup plus vite
Sur un négatif de 448 Mo, manier un curseur coûtait 29 ms par image — 34 images par seconde, et une image sur sept dépassait le seuil où l'œil voit une saccade. C'est maintenant 4 à 5 ms, soit environ 230 images par seconde. Le geste est fluide, et l'histogramme suit la main au lieu de l'attendre.
Trois causes, aucune dans le traitement d'image : les mesures d'histogramme se relançaient à chaque cran, l'historique d'annulation s'enregistrait à chaque cran, et la pellicule se redessinait entièrement alors qu'elle n'affiche que des vignettes.
Elle tourne sur plus de Mac
- Mac Intel : l'app est désormais universelle. Elle ne démarrait pas du tout sur ces machines.
- macOS Sonoma (14) au lieu de Sequoia (15).
Aussi
- Un badge signale une source 8 bits sous l'histogramme : ces scans n'ont que 256 valeurs par canal, ce qui donne un tracé en peigne. Ce n'est pas un défaut de l'app, et le badge est là pour que ça se lise comme tel.
- L'app vérifie les mises à jour toutes les douze heures au lieu de vingt-quatre.
Si vous avez la 0.0.1, elle ne démarrait sur aucune machine sauf celle qui l'a compilée — retéléchargez plutôt que d'attendre une mise à jour, elle ne peut pas vous parvenir.
v0.0.3 on GitHub, with its download and its source
0.0.2
Render unchanged
Correctif d'urgence. Le rendu de vos photos ne bouge pas : cette version ne change aucun réglage, aucune constante, aucun étage du pipeline. Les conversions déjà faites ressortent identiques.
La 0.0.1 ne démarrait pas, sur aucune machine sauf celle qui l'avait compilée. Elle cherchait ses icônes dans un dossier qui n'existe que sur l'ordinateur du développeur, et s'arrêtait net quand elle ne le trouvait pas — d'où une fenêtre de plantage sans le moindre rapport lisible. Si vous avez tenté la 0.0.1 et abandonné, c'était ça, et ce n'était pas votre installation.
Aussi dans cette version
- Les kernels graphiques étaient compilés pour une version de macOS plus récente que celle que l'app annonce supporter. Sous macOS 26, tous les étages de traitement disparaissaient en silence : l'image s'affichait sans conversion. Corrigé, et un contrôle refuse désormais de construire une version qui recommencerait.
- Le lecteur de fichiers TIFF et DNG ne vérifiait pas ce qu'il lisait : certains fichiers pouvaient faire disparaître l'app, y compris en faisant simplement défiler la galerie. Il borne maintenant tout ce qu'un fichier lui annonce.
- Un export par lot pouvait, dans un cas précis, écrire par-dessus le scan d'origine. C'est désormais refusé avant que quoi que ce soit soit écrit.
Merci à celles et ceux qui ont signalé le plantage : c'est exactement à ça que sert une alpha.
v0.0.2 on GitHub, with its download and its source
0.0.1
Render unchanged
Première version, et c'est une alpha. Elle ne déplace le rendu d'aucune photo déjà réglée, parce qu'il n'y en a pas encore : il n'existe aucune version antérieure à celle-ci.
Le numéro dit ce que c'est : 0.0.1. L'app est utilisable de bout en bout — on importe, on convertit, on exporte — mais elle est calibrée sur les pellicules d'une seule personne, et c'est précisément ce que cette alpha cherche à corriger. Les retours sur ce qui sort faux chez vous valent plus que les retours sur ce qui manque.
Cette ligne est en tête parce que toutes les suivantes le seront aussi. La règle de ce projet est de ne pas geler le rendu — l'app existe pour être calibrée sur du vrai film, et une constante mal choisie ne se voit que sur les négatifs de quelqu'un d'autre — mais de geler la surprise. Toute version qui déplacera une conversion déjà enregistrée le dira ici, avant l'installation, et vous pourrez la refuser.
Ce que fait cette version
- Conversion de négatifs couleur C-41 photographiés au boîtier, à partir du RAW. L'inversion se fait en densité, donc les curseurs se comportent linéairement en stops.
- Gains par canal, niveaux par canal et RVB, courbes, balance de finition, saturation par zone, débruitage chroma, netteté, recadrage et redressement.
- Trois boutons de balance automatique, qui proposent des positions : le survol les dessine sur l'histogramme, et rien ne s'applique sans un clic.
- Presets, galerie, labels, export TIFF 16 bits ou JPEG.
- Tout reste en flottant du RAW au fichier écrit, sans aucun tampon intermédiaire quantifié. C'est vérifié à chaque build, pas espéré.
Ce qu'il faut savoir avant de commencer
- C'est un alpha. Le rendu peut bouger d'une version à l'autre — voir la première ligne.
- Vos originaux ne sont jamais touchés. L'app importe par lien et ne fait que les lire. Vos réglages vivent dans un petit fichier à côté de chaque RAW.
- macOS 15 ou plus, Apple Silicon.
- L'app cherche ses mises à jour seule et n'en installe jamais une d'elle-même : elle vous montre ces notes et attend.
Un défaut à signaler ? La version se lit dans la fenêtre « À propos », et si c'est un problème de décodage ou de couleur, joignez le RAW — une capture montre le symptôme, le fichier le reproduit.
v0.0.1 on GitHub, with its download and its source
Where to go from here.
The newest notes, the download and the source. Every version stays downloadable from its release page.