Home (All Topics) → Technology → Software → AI-Created Software
The following is AI-generated (aka vibe-coded) software. The software is specific to my needs and my system and may not work for you or your system. Support is limited, but if you report a bug I'll certainly look into it. All code is provided in a zip file for you to review should you choose.
A single-file desktop app for checking the colors in a photo against physically based and measured references. Click the sky, foliage, skin, snow, clouds, pale rock or whitewater, and the app shows how far each one sits from what it should look like, then tells you which adjustments in darktable’s color calibration and color equalizer modules would bring it closer. It can also apply those corrections to the whole photo, show the result side by side with the original, and save it.
It never changes your original photo: a corrected version is only written when you save it, under a new name.
pip install pillow numpy
Tkinter comes with the python.org installers for Windows and macOS.
Elsewhere:
| System | Command |
|---|---|
| Debian, Ubuntu | sudo apt install python3-tk |
| Fedora | sudo dnf install python3-tkinter |
| macOS with Homebrew Python | brew install python-tk |
Optional extras:
pip install rawpy # camera RAW files (CR2, CR3, NEF, ARW, DNG, RAF, ORF, RW2 and more)
Keep image-color-checker.ico in the same folder as the script: it is the app’s icon. Without it, the app runs with Tk’s standard icon.
python image-color-checker.py # open the app
python image-color-checker.py --photo-file-path photo.jpg # open the app with a photo loaded
See Command line for the options.
The icon shows the measured blue sky, foliage and light skin patches and a neutral gray, the kind of colors the app checks, with a sample ring over them from 32 pixels up. It appears in the title bar, on the taskbar and in Alt+Tab, and on the app’s dialogs. It is the file image-color-checker.ico beside the script, which holds it in every size from 16 to 256 pixels; on Windows, the title bar and the taskbar each take the size they need from it.
Desktop shortcut on Windows. To start the app from a shortcut with its icon:
pythonw.exe followed by the script’s full path in quotes, for example pythonw.exe "D:\tools\image-color-checker.py".pythonw starts the app without a console window.Image Color Checker and choose Finish.image-color-checker.ico beside the script, for example D:\tools\image-color-checker.ico.The shortcut can then be copied to the Start menu or pinned to the taskbar; see Limitations for how a pinned shortcut behaves.
| Keys | Action |
|---|---|
| Ctrl+O (Cmd+O on macOS) | Open a photo |
| Ctrl+V (Cmd+V on macOS) | Paste an image from the clipboard |
| Ctrl+S (Cmd+S on macOS) | Save the corrected photo |
\ (backslash) |
Switch between the original and the corrected photo |
| Delete or Backspace | Remove the selected sample (in the sample list) |
| Click a pin on the photo | Select that sample (the pointer becomes a hand over a pin) |
| Right-click a pin on the photo (Ctrl+click on macOS also works) | Remove that sample |
| Arrow keys | Move the sampled position on the sky panorama |
The Ctrl, Cmd and backslash shortcuts don’t act while you’re typing in a field, where Ctrl+V pastes text as usual, or while a dialog such as Export LUT is open. They work with Caps Lock on too.
python image-color-checker.py [options]
| Option | What it does |
|---|---|
--photo-file-path PHOTO |
A photo to open when the app starts. |
--layout auto, standard or wide |
The panel layout (see Layout and screen size). The default, auto, picks wide for wide windows. |
--working-folder-path FOLDER |
The folder for the settings file and temporary files, created if needed. The default is shown by --help; see Settings and working folder. |
--selftest TRUE |
Check the app’s calculations and exit (see below). |
--help (or -h) |
Show the usage, and the default working folder on this computer, and exit. |
The command line is read with Python’s argparse, and every option is named, so script launchers that read argparse options (such as Scriptary) find them all, and offer the values of --layout and --selftest as buttons; nothing is positional. Options can come in any order, written --name VALUE or --name=VALUE, in full (shortened names aren’t accepted), each at most once. Every option takes a value, so yes/no options are written TRUE or FALSE (also 1/0, YES/NO or ON/OFF). A mistake, such as an unknown option, a missing value, an option given twice or a folder that can’t be created, is reported with “Use –help for usage.” and exit status 2.
Started with pythonw.exe, which has no console, the app shows the mistake in a message box instead.
For example:
python image-color-checker.py --selftest TRUE
python image-color-checker.py --photo-file-path photo.jpg --layout wide
python image-color-checker.py --working-folder-path D:\tools\icc-data
The self-test verifies the color-difference math against published test data, checks the color conversions, compares the sky model with a measured reference, checks the correction, the LUT export and the darktable models against darktable 5.6.1’s output, converts an Adobe RGB test image to sRGB and saves it (it matched the published matrices within 0.4 levels), checks the icon file beside the script, and reports whether RAW and Tkinter support are available. It prints one line per check, ending in ok or FAIL, and exits with 0 when every check passes.
--photo-file-path.Click any row in the sample list, or a sample’s pin on the photo, to see and adjust that sample. The app guesses each sample’s material from its color, brightness and position in the frame; correct it with the Sky, Foliage, Skin and Should be neutral buttons if it guesses wrong. To remove a sample, right-click its pin on the photo, or select it in the list and press Remove.
Sample size sets how many pixels each click averages, from a single point up to 51 × 51. Larger sizes smooth out grain, leaf texture and noise. Choose evenly lit areas away from highlights and deep shadow.
Each sample is compared with a reference for its material.
Physical sky model. For daylight skies the reference comes from the Preetham analytic daylight model, which predicts sky color from:
Presets cover clear midday, clear mid-morning, hazy mid-morning, hazy midday and late afternoon. The sliders fine-tune them. Sun height and haze apply to the whole photo; the sampled position is set for each sample.
As a check, the model’s clear-midday zenith is within ΔE 3.7 of the measured ColorChecker blue-sky patch.
Looks. The model is unreliable with the sun below about 10°, and it cannot describe cloud. For golden hour, civil twilight, blue hour, overcast and storm skies, the app offers illustrative gradients instead. You can pick which band of the gradient you sampled, or let the app choose the closest. These are plausible values, not measurements.
The default reference is the foliage patch of the X-Rite ColorChecker Classic (CIELAB D50, post-2014 formulation), a chart color made to match typical green leaves in neutral daylight. It is the right target for accurate color.
Sixteen illustrative looks cover specific plants, seasons and light, such as sunlit meadow grass, evergreen needles, early autumn and golden-hour foliage. They are plausible values, not measurements. Real foliage varies a lot by species, so treat differences under about ΔE 5 as normal.
Two measured references come from the X-Rite ColorChecker Classic: the light skin and dark skin patches (CIELAB D50, post-2014 formulation), chart colors made to match typical light and dark skin in neutral daylight.
Typical skin tones cover nine ancestry groups: Northern European, Southern European, Middle Eastern, East Asian, Southeast Asian, South Asian, Latin American, African American and Sub-Saharan African. Each comes at four tan levels: no tan, light tan, medium tan and heavy tan. Each step darkens the skin and makes it more yellow. Deeper skin changes less, so its steps are smaller. Every tone shows its individual typology angle (ITA°) and ITA skin category, from very light to dark.
These tones are illustrative typical values within the ranges reported by skin colorimetry studies, not measurements. Skin varies more within any group than between groups, so pick the tone that looks closest to the person, not the one that matches their background. The picker lists the three closest tones, lightness included. The first skin sample starts on the closest reference; after you choose one, later skin samples use your choice.
Makeup, flushing and the light all shift skin color, so treat differences under about ΔE 5 as normal and trust the direction of the hue more than the exact numbers. Skin sits close to the skin-tone line on the vectorscope.
Neutral surfaces are the most direct check of white balance: any color they carry is a cast. Choose what you sampled.
| Reference | What it is | Keep in mind |
|---|---|---|
| Neutral surface | A gray card, concrete, or anything else that should have no color | |
| Sunlit snow | Fresh snow in direct sun reflects roughly 85 to 90% of visible light, almost equally at every wavelength, so it should be a bright neutral white, about L* 94 in a normal exposure | Only snow in direct sun is neutral. Shaded snow is lit by blue skylight and should look blue; old or dirty snow is darker and slightly warm |
| Sunlit cloud | The bright tops of daytime cumulus scatter all wavelengths about equally | Near sunrise and sunset clouds take on the color of the light. Shaded cloud bases can lean slightly blue |
| Pale rock | Limestone, granite and pale weathered stone | Rarely perfectly neutral; a slight warm lean is normal. When rock disagrees with snow or clouds, trust the snow or clouds |
| Whitewater | Foam, breaking surf and rapids: the bubbles scatter all wavelengths about equally | Like clouds, it takes on the color of the light at low sun and leans blue in shade. Foam on peaty or muddy water can be tinted yellow or brown |
Bright, weakly colored areas are usually recognized as snow (low in the frame) or cloud (high in the frame) automatically, even under a warm cast. A cloud with a strong blue cast may be taken for sky; switch it to Should be neutral.
With Compare color only turned off, sunlit snow is also checked for brightness against L* 94. This catches the common metering error that renders snow gray.
Each comparison is scored with CIEDE2000, the standard measure of how different two colors look.
| ΔE 2000 | Meaning |
|---|---|
| under 1 | Indistinguishable |
| 1 to 2 | Visible only side by side |
| 2 to 5 | Noticeable, within normal natural variation |
| 5 to 10 | Obvious mismatch |
| over 10 | A different color |
Each sample lists the adjustments that would move it toward its reference:
Amounts are in Lab units, not slider units. For slider values, use darktable… (see Settings for darktable).
On by default. How bright the sky or a leaf records depends on your exposure and on shade, so each reference is shown at your sample’s brightness and only color is compared. Turn it off to include brightness. That is most useful for sunlit snow, which has a predictable brightness.
The summary under All samples looks at every sample together:
If any channel of a sample is at its maximum, the true color there is lost. The sample is flagged as clipped and left out of the summary.
Recover highlights, or sample a slightly darker area.
The scope shows every pixel of the photo as a colored cloud, either as a BT.709 vectorscope or as a CIELAB a*b* plot, at 1×, 2× or 4× zoom.
Your samples appear as numbered rings, with a dashed line to each one’s reference; a sample beyond the outer ring is drawn at its edge as a triangle pointing outward, and the caption under the scope says so.
Small squares mark the measured skin, foliage and blue-sky patches. The dashed diagonal on the vectorscope is the skin-tone line. The scope is 300 pixels across (at 100% display scaling) when there’s room. In a short window it shrinks, down to 200 pixels, so the sample list below keeps at least three rows in view; in a tall one it grows to fill the width of its column once the list has room for six rows. Widen the right column to enlarge it.
The readout shows the color under the cursor, or of the selected sample, as hex, RGB, RGB %, HSV, L*a*b* D50, LCh and vectorscope position. RGB %, HSV, Lab and LCh are among the formats darktable’s color picker shows; Lab is D50 in both.
The app can apply its corrections to the whole photo, so that each sample matches its reference.
The toolbar above the photo switches between four views:
To flip between before and after without moving the pointer, click Corrected repeatedly: each click switches between the corrected photo and the original. Split and Changes work the same way. You can also press \ (backslash).
How it corrects. Choose one of two corrections next to the views:
How much each reference is trusted: measured ColorChecker patches and neutral surfaces fully, the sky model a little less, and illustrative looks and typical skin tones half as much.
Neutral samples also count double, so a gray card or sunlit snow is matched most closely of all.
The color step judges how similar two colors are mostly by hue and saturation, and by lightness at half weight. Correcting a bright sky therefore changes a dark blue shadow much less. Each sample’s reach adapts to your other samples: a sample on its own reaches further, and samples close together in color reach less, so they don’t fight.
Amount sets how much of the correction to apply, from 0% (the original photo) to 100% (each sample on its reference).
References are typical values, so a partial correction often looks more natural; the app remembers the amount and the kind of correction between sessions. Compare, the preview and the saved photo all use the amount.
While you drag Amount, or the sky’s sun height and haze (which change the correction too), the photo follows at once with a quick, lower-resolution preview, and shows the full-resolution result once the slider has rested for 0.4 seconds.
The correction uses the same samples as the summary, leaving out any too far from their reference to compare and any that are clipped; the toolbar says how many it uses. With Compare color only turned on, lightness is left alone and only color changes. Turn it off to correct brightness too, for example to lift gray snow toward L* 94.
Conflicting samples. Sometimes two samples have similar colors but need very different corrections, for example snow in shade marked as neutral next to a blue sky. Any correction by color moves similar colors alike, so it cannot give both. When the corrections differ by more than three quarters of the difference between the colors, and by at least 2, a bold warning under the correction’s summary, just above the photo, says so, both samples get a ⚠ in the sample list, and Compare explains the conflict for each. Usually one sample has the wrong material or reference: snow in shade is lit by blue skylight and is not neutral. Fix or remove it.
When both samples are right, for example sky and a blue lake below it that need different corrections, the app can separate conflicting samples by position. A checkbox for this appears beside the correction’s summary when there is a conflict; it is on by default and remembered. Each conflicting sample then owns the part of the photo nearer to it than to the other conflicting samples, and its correction applies everywhere except in the parts owned by the samples it conflicts with. The parts blend into each other across a narrow band.
Samples without conflicts, and typed values, which have no position, still apply everywhere by color alone, and samples that agree, such as two sky samples, cover the same parts, so large areas are corrected evenly. The Changes view outlines the parts in white.
The parts are drawn by nearness alone, so a border can cut through an object: for example, a corner of the sky that is nearer to a snow sample than to the sky sample. Add another sample on that object beyond the border, and the parts follow it. With the checkbox off, the correction compromises between conflicting samples instead.
For the selected sample, Compare shows its color in the corrected photo and its ΔE from the reference: normally 0 to 0.5 with Exact, and up to about 2 with Balanced.
Samples and the readout always read the original photo, even while the corrected one is shown.
Saving. Save corrected… opens in the photo’s own folder with the name <photo>-corrected and the same file type (TIFF for RAW files), and can save JPEG (quality 95), PNG, TIFF or WebP. The correction is applied to the full-resolution photo, not the preview, so large photos take a few seconds; the status bar shows progress. The saved photo is 8-bit sRGB with an embedded sRGB profile, and keeps the original’s EXIF data where the format allows. Saving over the original photo asks for confirmation first.
Exporting a LUT. Export LUT… saves the correction as a .cube 3D lookup table, so you can apply it in darktable to the original photo at its full bit depth and gamut, instead of using the 8-bit corrected file. It opens in the photo’s folder with the name <photo>-correction.cube, and records in its header what it was made from. The LUT carries the current correction at the current Amount, as a table over sRGB values. Before saving, the app asks for its size, and shows how closely each size reproduces the correction on your photo:
-65.cube.The app remembers your choice.
To apply it in darktable:
darktable stores only the LUT’s path in the edit, so keep the file where it is for as long as the edit uses it.
A LUT knows only colors, not where they are in the photo, so it cannot separate conflicting samples by position. When separation is on, the export dialog says so, and the LUT uses the compromise between them instead, as with separation turned off; its header notes this too.
Treat the corrected photo as a starting point for your own edit rather than the final word.
Most corrections are made once, for one photo, so rather than a file to import and later remove, darktable… (next to Export LUT) translates the correction into slider settings for two modules in darktable 5.6: color calibration for the white balance, and color equalizer for individual colors. Both work on the scene-referred data, before tone mapping, which is where darktable recommends making these changes.
The window stays open and updates as you add samples, change references, or change the correction or its amount:
Then export a JPEG from darktable and open it in the app. When the new photo has the same shape as the last one, the app offers to keep the samples at the same places, with their references, and measures them again. The window then shows further changes to add to the ones you made, and prefills the illuminant’s hue and chroma with the values it last suggested. One or two rounds are usually enough.
Tone mapping. Choose the tone mapper you use in darktable at the top of the window: AgX, sigmoid or other. It starts on AgX, and remembers your choice. The settings are worked out through models of darktable’s own modules: dt UCS 22 and the color equalizer’s node curves, color calibration’s CAT16 adaptation, and the tone mapper. With AgX or sigmoid, the app works out what each sample was before tone mapping and solves the settings there. AgX is modeled at the AgX workflow’s scene-referred default, with Blender-like primaries, and sigmoid at its default settings. Changes to the tone mapper’s settings (other than exposure) make the first round less exact; the second round takes care of it. With other (filmic, for example), the app treats the modules as if they acted on the exported photo, which gets most of the way in the first round and needs another to finish.
What to expect. Tested with darktable-cli 5.6.1 on a photo with a strong warm cast (samples 4.4 to 6.0 ΔE from their references), using AgX at its scene-referred default and the Balanced correction: after the first round, foliage, skin and sky were within ΔE 0.2 to 0.9 of the correction, and after the second within 0.6. Picking a snow sample made it exactly neutral. Sigmoid gave much the same, and a cool cast too. Without the AgX model, the first round had left skin 3.2 from the correction. The window gives the expected result for the first round.
Limits.
| Format | Support |
|---|---|
| JPEG, PNG, TIFF, WebP, BMP | Built in |
| Camera RAW | With rawpy |
| Clipboard images | Built in; on Linux needs xclip or wl-clipboard |
Embedded color profiles are honored. Photos in Adobe RGB, Display P3, ProPhoto RGB or CMYK are converted to sRGB with LittleCMS before any reading is taken, so the numbers match what darktable shows. In testing, a Display P3 image read within ΔE 0.4 of its true colors; ignoring its profile would have produced errors up to ΔE 3.4. Files without a profile are treated as sRGB. The line above the photo shows the photo’s name and size and which of these applied; it stays there while the status bar at the bottom reports other things.
RAW files are decoded with the camera’s white balance and a default rendering, not your edit. Use them as a starting point; to check an edit, export it as a JPEG or TIFF.
Photos larger than 6000 pixels on the long side are downscaled for sampling.
Export CSV… saves one row per sample with:
The file is UTF-8 with a byte-order mark and Windows line ends, so Excel opens it with symbols such as ° and ΔE intact. It is written through a temporary file, so an export that fails never leaves half a file in place of an earlier one.
The app arranges its panels in one of two layouts, chosen from the window’s width and shape:
The layout switches as you resize or maximize the window. It switches back to standard only below 1700 pixels wide or 1.5 times as wide as tall, so a window near the threshold doesn’t flip back and forth. To always use one layout, start the app with --layout standard or --layout wide.
Dividers, each shown as a faint line, can be dragged to resize the panels; the pointer changes to a double arrow over each one. Each panel keeps a minimum size, so none can be dragged shut. When the window is resized, the photo takes up the change and the other columns keep their width. Each layout remembers its own divider positions.
The Export LUT dialog and the darktable settings window open where you last closed them, also the next time the app starts. A place on a monitor that is no longer connected is ignored.
In a narrow reference picker, the reference buttons move into fewer columns so their names are never cut off. When the picker is taller than its panel, as the foliage and skin pickers can be in a small window, a scrollbar appears beside it, and the mouse wheel scrolls it while the pointer is over it. The directions in Compare get a scrollbar in the same way when they are longer than their panel. When the photo’s panel is narrow, the correction’s settings move to a second row of its toolbar, and the Save, Export LUT and darktable buttons to a row of their own if they don’t fit beside the views.
Smallest window. The window can be made as small as 1200 × 890 pixels (at 100% display scaling). Every button, label and reference fits at that size, at 100% and at 150%, and the sample list keeps at least three rows in view.
High-resolution screens. Everything is drawn to match the display scaling set in Windows or Linux, not only the text: dividers, pins, swatches, list rows, the scope, spacing and the minimum panel sizes. At 150% they are all half as large again as at 100%. On macOS the system handles this itself.
The app remembers its window size, position and maximized state, where you left each divider in each layout, the sample size, the scope’s mode and zoom, the correction’s mode, Amount, whether conflicting samples are separated by position, the LUT size, and the tone mapper chosen in the darktable window. They are saved when you close the app and restored the next time you open it. A window saved on a monitor that is no longer connected opens at its default position instead.
Settings and temporary files are kept in a working folder, created if needed:
| System | Default working folder |
|---|---|
| Windows | %APPDATA%\image-color-checker |
| macOS | ~/Library/Application Support/image-color-checker |
| Linux and others | $XDG_CONFIG_HOME/image-color-checker, or ~/.config/image-color-checker |
Use --working-folder-path FOLDER to choose a different folder, for example to keep the app and its settings together on a USB drive, or to keep separate setups:
python image-color-checker.py --working-folder-path D:\tools\icc-data
Settings are stored in image-color-checker.ini, a plain text file, and temporary files go in the folder’s tmp folder. A value in the settings file that can’t be used, for example after editing it by hand, is ignored and its default used instead; a settings file that can’t be read at all is ignored. Delete image-color-checker.ini to go back to the defaults. If the settings can’t be saved when the app closes, for example because the folder was removed or is read-only, a message says so and the app closes anyway.
Settings from earlier versions. Earlier versions kept their settings in settings.json in the same folder, and took the folder as --workdir. The first time this version runs in a folder with no image-color-checker.ini, it carries the settings over from settings.json; after that, settings.json is no longer read and can be deleted.
The default folder hasn’t changed. A shortcut or script that passes --workdir needs --working-folder-path instead; the app says so rather than starting.
The app checks itself in three ways. None of them touches your photos or your settings.
python image-color-checker.py --selftest TRUE checks the app’s calculations and exits (see Command line for what it covers). It takes under a second, prints one line per check ending in ok or FAIL, and exits with 0 when every check passes. Run it first if the app seems to give wrong numbers.python -m pytest, run from the app’s folder, runs 37 tests (it needs pytest: pip install pytest). Twenty-eight open the real app on a generated test photo and check sampling, the views, saving, the quick preview while Amount, sun height or haze move, conflicts, LUT export, the darktable window, that the LUT dialog and the darktable window open where they were closed, the icon, settings (saved, hand-edited, carried over from settings.json, and a failed save shown in a message box), starting from the command line, a photo that fails to open, keyboard shortcuts, the interface’s neutral grays, that buttons, fields, drop-downs and switches are all one height, that closing leaves nothing running, the main buttons clicked as a user would (with the CSV export’s byte-order mark and line ends), the switch between layouts and the dividers’ minimum sizes, that no button, label or reference is cut off or out of reach in the smallest windows and the sample list keeps three rows in view, that the picker’s images don’t pile up, that text drawn on the photo, the sky panorama and the scope stays inside them, and that the scope marks off-scale samples by shape. Eight need no window: the self-test, the named options, command-line mistakes and --help, choices written out, the icon file, and reading old settings. One more opens a camera RAW file, when RAW_TEST_FILE names one (it needs rawpy); otherwise it is skipped. They take about 31 seconds at 100% display scaling and 36 at 150%, without a RAW file. At 100% they all pass. At 150% under Xvfb with a Linux container’s fonts, test_picker_scrolls fails because the foliage picker fits its pane there and needs no scrollbar; the others pass. The window tests need a display; on Linux without one, the tests start Xvfb themselves, and without either they are skipped.python -m pytest -m "not gui" runs only the eight that open no window, python -m pytest -k amount only the tests whose names contain “amount”, and APP_SCRIPT=path/to/copy.py tests another copy of the script.python tools/make_icon.py --check TRUE checks that image-color-checker.ico matches the drawing in tools/make_icon.py. The tests run this check too.tests/darktable/ checks the darktable models against darktable-cli 5.6 itself and runs the darktable workflow end to end. It needs a darktable 5.6 AppImage; see tests/darktable/dtx.py for getting one.
| Problem | What to do |
|---|---|
Nothing happens when the app is started from a shortcut with pythonw.exe |
Run the same command with python.exe in a command prompt, which shows any error. A mistake in the shortcut’s options is shown in a message box. |
| “This app needs Pillow and NumPy” | pip install pillow numpy, using the same Python that runs the app. |
| “Tkinter is not available” | Install Tkinter for that Python (see Requirements). |
| “Error: unrecognized arguments: –workdir” | The option is now --working-folder-path (see Settings and working folder). |
| “Error: argument –selftest: expected one argument” | Every option takes a value: --selftest TRUE. |
| “Opening camera RAW files needs rawpy” | pip install rawpy, or export the photo from darktable as an sRGB JPEG, PNG or TIFF. |
| A HEIC or HEIF photo won’t open | The app doesn’t read HEIC. Export the photo as a JPEG, PNG or TIFF. |
| Paste says it could not read the clipboard, on Linux | Install xclip (X11) or wl-clipboard (Wayland). |
| The window has Tk’s standard icon instead of the app’s | Keep image-color-checker.ico in the same folder as the script. |
| “Could not save the settings” when closing | The working folder was removed, or can’t be written to. Start the app with --working-folder-path set to a folder you can write to. |
| The window or its dividers are laid out oddly | Close the app and delete image-color-checker.ini in the working folder to go back to the defaults. --help shows where the folder is. |
| A photo won’t open, and the previous one stays on screen | That’s deliberate, so its samples aren’t lost. The message says why the new photo couldn’t be read. |
| The numbers differ from darktable’s color picker | Check the line above the photo: it says whether the photo’s color profile was converted. Export from darktable in sRGB, and compare in darktable’s Lab readout, which uses the same D50 white. |
| The darktable settings don’t land where the window said | Check that the tone mapper chosen in the window matches darktable’s, and that no module between the color equalizer and tone mapping changes colors. Then do a second round (see Settings for darktable). |
The self-test reports FAIL |
Note the failing lines and the Python, Pillow and NumPy versions (pip list); the app’s numbers may be wrong on that setup. |
The reference data sits near the top of the file in plain Python lists.
Sky model presets use sun height in degrees and turbidity (2 to 7):
Sky looks take four (label, hex) stops from top to bottom, plus their positions in percent:
("golden", "Golden hour", "Sun about 5° high",
[("Zenith", "#28418C"), ("Upper sky", "#7864AA"), ("Horizon", "#FF9146"), ("Solar glow", "#FFD28C")], (0, 45, 85, 100)),
Foliage looks take (name, condition, hex):
Natural neutrals take an id, a name, a description, an expected L* in a normal exposure (or None if it varies too much to predict), and a caveat shown with every comparison:
NaturalNeutral("snow", "Sunlit snow", "Fresh snow in direct sun ...", 94.0,
"Only snow in direct sun is neutral. ..."),
Skin tones take an id, a name and the L*, a*, b* of untanned skin (CIELAB D50). The four tan levels are worked out from it using TAN_STEP, the change in L*, a* and b* for each level:
Anything added appears in the reference picker automatically. Give every entry a unique id.
tools/make_icon.py draws it with Pillow from the app’s reference colors, at four times each size and reduced, in 9 sizes from 16 to 256 pixels, and saves them all in image-color-checker.ico (about 37 KB); --check TRUE checks the saved file against the drawing. On Windows the app sets the file as the icon of every window with Tk’s iconbitmap, so the title bar and the taskbar each take the size they need; elsewhere it hands every size to Tk’s iconphoto. The 16 to 24 pixel sizes leave out the sample ring and use larger patches, so the colors stay apart; from 32 pixels up, the ring’s white line is at least 1.5 pixels wide, so it stays white. On Windows, the app sets its own AppUserModelID (infolific.image-color-checker) before opening its window; without one, Windows groups it with Python on the taskbar and shows Python’s icon.infolific/app-templates, recorded in templates.ini), marked in the script with copied from lines.winfo fpixels 1i ÷ 96, rounded to a quarter and never below 1). Divider positions are saved as fractions or in 96-dpi pixels, so they carry over when the scaling changes..cube format, red changing fastest). The accuracy shown when exporting compares the correction with a trilinear lookup in the LUT, as darktable’s LUT 3D module can, on a sample of up to 40,000 of the photo’s pixels, before rounding to 8 bits. The self-test checks both steps, the soft fit’s behavior with conflicting, near-miss, differently trusted and dark samples, the conflict warning, separation by position, LUT export, the amount, the darktable models against darktable 5.6.1’s output, and the settings for a photo with a cast.


Leave a Reply