From 6642b97ec8d0cf8dae1e22134c027bc4a7be8b9e Mon Sep 17 00:00:00 2001 From: Angel Wang Date: Sat, 20 Jun 2026 13:29:12 -0600 Subject: [PATCH] feat: rewrite in zx, store data in cache file instead of directories --- grade.mjs | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ grade.sh | 85 ------------------------------------------- 2 files changed, 107 insertions(+), 85 deletions(-) create mode 100755 grade.mjs delete mode 100755 grade.sh diff --git a/grade.mjs b/grade.mjs new file mode 100755 index 0000000..71336cc --- /dev/null +++ b/grade.mjs @@ -0,0 +1,107 @@ +#!/usr/bin/env zx +import "fs"; + +await $`rm -f cache.json`; +// await $`lutgen apply -p catppuccin-latte -l 8 -L 0.001 -P -r 21.5 ./orig/* -o ./graded`; +cd("./graded"); + +const files = await fs.promises.opendir("."); + +let json = {}; + +// set up the data storage +let lightnessData = []; +for (var i = 0; i < 10; i += 2) { + lightnessData.push({ lightness: i / 10, paths: [] }); +} + +let chromaData = []; +for (var i = 0; i < 10; i += 2) { + chromaData.push({ chroma: i / 100, paths: [] }); +} + +let hueData = []; +for (var i = 0; i < 360; i += 90) { + hueData.push({ hue: i, paths: [] }); +} + +// analyze the files +for await (const file of files) { + const stat = await fs.promises.stat(file.name); + if (stat.isFile()) { + let output = + await $`magick ${file.name} -colorspace Oklch -kmeans 10 -format "%c" histogram:info:`.then( + (s) => + s.stdout + .split("\n") + .map((substr) => substr.trim()) + .filter((n) => n), + ); + + if (output.length < 5) { + // do it again but with more violence + console.log( + `-kmeans 10 of ${file.name} didn't give enough colours, trying again with a higher value...`, + ); + output = + await $`magick ${file.name} -colorspace Oklch -kmeans 40 -format "%c" histogram:info:`.then( + (s) => + s.stdout + .split("\n") + .map((substr) => substr.trim()) + .filter((n) => n), + ); + } + + let colours = output.map((entry) => { + let arr = entry.split(" "); + arr.pop(); + // [# of pixels, oklab colour, hex code] + return [parseInt(arr[0]), arr[1].replace(/[()]/g, "").split(","), arr[2]]; + }); + + colours.sort((a, b) => b[0] - a[0]); + + const dominantColour = colours[0][1]; + console.log( + `Got oklch(${dominantColour}) as dominant colour of ${file.name}!`, + ); + const lightness = dominantColour[0]; + const chroma = dominantColour[1]; + const hue = dominantColour[2]; + + lightnessData.forEach((n) => { + let targetLightness = Math.floor(lightness * 5) / 5; + if (n.lightness == targetLightness) { + n.paths.push(file.name); + return; + } + }); + + chromaData.forEach((n) => { + let targetChroma = Math.floor(chroma * 50) / 50; + if (n.chroma == targetChroma) { + n.paths.push(file.name); + return; + } + }); + + hueData.forEach((n) => { + let targetHue = Math.floor(hue / 90) * 90; + if (n.hue == targetHue) { + n.paths.push(file.name); + return; + } + }); + + json["lightnessData"] = lightnessData; + json["chromaData"] = chromaData; + json["hueData"] = hueData; + + fs.writeFile("./cache.json", JSON.stringify(json), err => {}) + + // past 0.3, the image is way too dark to have any discernable colour + } +} + + diff --git a/grade.sh b/grade.sh deleted file mode 100755 index 96b0379..0000000 --- a/grade.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env bash - -# RULES: -# Eliminate golden first, it's the outlier -# LAB -> a greater than 50: golden -# The rest of the categories: -# LAB -> l less than 45: night -# LAB -> l less than 60: day -# LAB -> l all other: noon -# Clear/overcast -# HSI -> s less than 10: overcast -# HSI -> l else: clear - -rm -r graded && mkdir -p graded/{night,golden,day,noon}/{clear,overcast} - -lutgen apply -p catppuccin-latte -l 8 -L 0.001 -P -r 21.5 ./orig/* -o ./graded - -cd graded - - -for file in *; do - if [ -f "$file" ]; then - l=$(magick $file -colorspace Oklch -channel 0 -separate +channel -format "%[fx:100*u.mean]\n" info:) - # c=$(magick $file -colorspace Oklch -channel 1 -separate +channel -format "%[fx:100*u.mean]\n" info:) - # h=$(magick $file -colorspace Oklch -channel b -separate +channel -format "%[fx:u.mean]\n" info:) - - echo $l - - # if (( $(echo "$h > 285" | bc -l) )) || (( $(echo "$h < 90" | bc -l) )) ; then - # echo $h - # mv $file golden/$file - # fi - fi -done - - - -# for file in *; do -# if [ -f "$file" ]; then -# b=$(magick $file -colorspace LAB -channel b -separate +channel -format "%[fx:100*u.mean]\n" info:) -# # l=$(magick $file -colorspace LAB -channel r -separate +channel -format "%[fx:100*u.mean]\n" info:) -# # && (( $(echo "$l > 50" | bc -l) )) -# a=$(magick $file -colorspace LAB -channel g -separate +channel -format "%[fx:100*u.mean]\n" info:) - -# if (( $(echo "$a > 51" | bc -l) )) && (( $(echo "$b > 47" | bc -l) )) ; then -# mv $file golden/$file -# fi - -# # for file in golden/*; do -# # if [ -f "$file" ]; then -# # if (( $(echo "$a < 55" | bc -l) )) && (( $(echo "$b < 55" | bc -l) )); then -# # mv $file ${file%/*}/overcast/${file#*/} -# # else -# # mv $file ${file%/*}/clear/${file#*/} -# # fi -# # fi -# # done - -# fi -# done - -# for file in *; do -# if [ -f "$file" ]; then -# l=$(magick $file -colorspace LAB -channel r -separate +channel -format "%[fx:100*u.mean]\n" info:) -# if (( $(echo "$l < 50" | bc -l) )); then -# mv $file night/$file -# elif (( $(echo "$l < 60" | bc -l) )); then -# mv $file day/$file -# else -# mv $file noon/$file -# fi -# fi -# done - -# for file in */*; do -# if [ -f "$file" ]; then -# s=$(magick $file -colorspace HSI -channel g -separate +channel -format "%[fx:100*u.mean]\n" info:) - -# if (( $(echo "$s < 15" | bc -l) )); then -# mv $file ${file%/*}/overcast/${file#*/} -# else -# mv $file ${file%/*}/clear/${file#*/} -# fi -# fi -# done -- 2.51.2