Add harmonize utils

This commit is contained in:
Schluffe
2026-10-01 00:04:46 +02:00
parent 3b72cd5723
commit f9fee06d37
7 changed files with 1243 additions and 79 deletions
+84 -11
View File
@@ -31,7 +31,9 @@ cargo run --release -- /path/to/screenshot.png
## Color grouping and mapping
**Group similar colors** is enabled by default in the **Palette**. Nearby shades
**Group similar colors** is enabled by default in the **Palette**. The default
**Edited** view shows the resulting colors. Switch to **Source / map** to select
original colors for replacement. Nearby shades
from scaling or compression share a row showing their combined percentage and
shade count. Adjust **Tolerance** (default 8, range 0–32) to control the maximum
difference in each RGB channel from the group's most frequent color. Groups do
@@ -39,7 +41,8 @@ not chain together through intermediate shades. Turn grouping off or set toleran
to zero for the exact palette. Hover a row to highlight its pixels in magenta in
the crop preview; this temporary highlight is never exported.
Freeze a capture or import an image, then click **Map** beside a palette row.
Freeze a capture or import an image, choose **Source / map**, then click **Map**
beside a palette row.
In **Color mapping**, click its replacement swatch to choose another color or enter
RGB values. Every original shade in that group maps to the chosen replacement.
Add multiple mappings to try a new palette. Each mapping keeps its original group
@@ -54,13 +57,68 @@ changes, pause during live capture, and return when frozen again. Opening a new
image or choosing a new capture source clears them.
Mappings apply before the preview adjustments or vision filter. Source preview,
analysis, copied pixel values, and **Save crop PNG** still use the original.
copied pixel values, and **Save crop PNG** still use the original. Color analysis
and the vision check use the edited selection.
**Save mapped crop PNG** exports the crop with replacements, preserving alpha
and excluding preview adjustments and filters.
## Automatic harmony
Freeze a capture or import an image, open **Harmonize**, and enable **Preview
harmony**. Choose **Monochromatic**, **Analogous**, **Complementary**,
**Split-Complementary**, or **Triadic**. The app fits that rule to the crop automatically, then moves its hue families toward the
chosen harmony while preserving shading. **Strength** blends from the input
at 0% to the full transformation at 100%. **Rotation**, or dragging the color
wheel, changes the palette's direction. White dots on the wheel mark input hue
families; colored spokes mark target hues. The wheel shows targets at full
strength. **Auto fit** resets rotation and fits the current crop again.
**Protect neutrals** is enabled by default: gray and near-gray colors stay
unchanged, with a gradual transition into chromatic colors. **Reset harmony**
turns harmony off and restores its defaults. Disabling **Preview harmony** lets
you compare with the input (including any enabled manual mappings). Settings
pause during live capture, resume when frozen, and reset for a new image or
capture source. Changing the crop or manual mappings refits the harmony while
retaining your rotation and strength.
Harmony works in OKLCH: it holds perceptual lightness and chroma while shifting
hue, reducing chroma when needed to fit sRGB. It retains small hue variations
within a family and compresses broad families into bands around target hues.
Monochromatic instead converges to a single hue at full strength, retaining
lightness and chroma variations (with neutral protection still applied).
The offsets are 0° for monochromatic, −30°/0°/+30° for analogous, 0°/180° for
complementary, 0°/150°/210° for split-complementary, and 0°/120°/240° for triadic,
on the **OKLCH** wheel. These angles do not produce
identical color pairs to HSV or traditional artist color wheels.
The fit uses a circular hue histogram, finds hue families, and searches for the
orientation requiring the least weighted squared hue movement. Counts are
square-root weighted after hue binning so a large background has less influence
and compression-generated near-duplicates don't each get a separate vote. This
is an experimental palette heuristic: it does not recognize objects, protect
skin or gameplay indicators automatically, or guarantee that every target hue
is used. Families may merge, and family boundaries can still affect subtle hue
ramps. Start with moderate strength and compare the result in context.
The processing order is **source → manual mappings → harmony → preview filter
or adjustments**. The source preview and copied pixel values remain original; color analysis and
the vision check use the edited selection. **Save harmonized crop PNG** includes enabled mappings and harmony,
preserving transparency, without hover highlights, preview filters, or
adjustments. **Save mapped crop PNG** still saves only manual replacements;
**Save crop PNG** still saves the original.
The conversion uses [Björn Ottosson's Oklab transforms](https://bottosson.github.io/posts/oklab/).
## Color analysis and vision checks
The **Color analysis** tab has four distributions:
The **Color analysis** tab uses the edited selection after active mappings,
harmony, and the selected filter or adjustments. Histograms, means, neutral
counts, distinct-color weighting, and the **Edited** palette all update together.
Merged colors count once for distinct-color weighting. Diagnostic simulation
previews and hover highlights are excluded, just as in the vision check.
**Source / map** keeps the original palette available for choosing replacements.
The tab has four distributions:
- **Hue**: HSV hue in 36 ten-degree bins; saturation below 5% counts as neutral.
- **Saturation**: HSV saturation, from neutral to fully saturated.
@@ -80,8 +138,8 @@ tritanopia, or grayscale directly to the crop preview, or select **Original**
to use the live color adjustment sliders. The first three use the
Machado–Oliveira–Fernandes full-severity model, applied in linear RGB and then
encoded back to sRGB. Grayscale uses relative luminance and tests removal of color
cues; it does not model all aspects of achromatopsia. Preview mode does not change
histograms, copied pixel values, or the exported PNG: those always use the original.
cues; it does not model all aspects of achromatopsia. The selected filter updates color analysis and the vision check. Copied pixel
values and **Save crop PNG** still use the original.
**Invert** replaces each RGB channel with its complement (255 minus the channel).
With **Original** selected, adjust **Hue shift** (−180° to +180°), **Saturation**
@@ -94,12 +152,24 @@ while another filter is selected and applied again when returning to Original.
Filters preserve alpha and always start from source pixels, so edits do not
accumulate rounding errors.
**Vision check** automatically checks all four scenarios. It flags pairs whose
OKLab distance falls from at least 0.08 to at most 0.04, losing at least 50% of the
original separation. These are project-specific screening heuristics, not
validated visibility thresholds or WCAG criteria. Each scenario shows original
**Vision check** automatically checks all four scenarios against the **edited
selection**, after enabled group/manual mappings, harmony, and the selected
filter or adjustments. It updates when these edits or the crop change. Palette
grouping alone only organizes colors; mapping a group changes the checked pixels.
Colors that merge through editing count as one color, and opaque-pixel coverage
is recalculated from the result. Color distributions and the edited palette use
those same pixels; **Source / map** remains available for mapping input colors.
The report's **Preview** buttons add a separate simulation of those edited
pixels. They do not change the selected filter or feed simulated pixels back into
the report. Use **Return to edited preview** to remove this simulation. Temporary
palette hover highlights are also excluded from the check.
The check flags pairs whose OKLab distance falls from at least 0.08 to at most 0.04, losing at least 50% of the
separation in the edited image. These are project-specific screening heuristics, not
validated visibility thresholds or WCAG criteria. Each scenario shows edited
and simulated swatches, numeric hex values, and up to six closest candidate pairs.
The preview button opens the corresponding simulation for the current crop.
The preview button opens the corresponding simulation for the edited crop.
The check is bounded to the 64 most frequent **opaque** colors and reports both
color and pixel coverage. Partially/fully transparent pixels have no known
@@ -156,6 +226,9 @@ repeated portal requests during/after capture. The portal regression test requir
bus and does not open desktop dialogs. Color tests cover histogram endpoints and
weighting, sRGB gamma, simulation reference colors, alpha handling, warning
positives/negatives, palette coverage, and preserving source pixels.
Harmony tests cover color-space reference values, gamut reduction, circular hue
fitting, neutral protection, shading, alpha, preset rendering, crop and capture
lifecycle, and exported PNG pixels.
Actual portal capture requires a running
Wayland desktop and permission through KDE's picker.