From 88755feac43963c31919d4dfc45e0c4515c21897 Mon Sep 17 00:00:00 2001 From: Mike Lynch <m.lynch@sydney.edu.au> Date: Sat, 15 Mar 2025 13:47:03 +1100 Subject: [PATCH 1/2] Writing my own colour name picker --- package-lock.json | 20 ++++++++++++++------ package.json | 2 +- poptimal.js | 17 ++++++++--------- src/components/palettes.js | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e6b89a..9051999 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,9 @@ "@resvg/resvg-js": "^2.6.2", "d3": "^7.9.0", "d3-color": "^3.1.0", + "d3-color-difference": "^0.1.3", "d3-dsv": "^3.0.1", "d3-time-format": "^4.1.0", - "hex-color-to-color-name": "^1.0.2", "jsdom": "^26.0.0", "lodash.shuffle": "^4.2.0", "random": "^5.1.1", @@ -1766,6 +1766,19 @@ "node": ">=12" } }, + "node_modules/d3-color-difference": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/d3-color-difference/-/d3-color-difference-0.1.3.tgz", + "integrity": "sha512-yAGiVdTZR/wpI66n85xvkTvjxFth0IuGrEeX/anl1Q5rzNc2/V7oOjoJdqQnahOuS+SgbAR0zu8T0SYY7hGTtw==", + "dependencies": { + "d3-color": "^1.1.0" + } + }, + "node_modules/d3-color-difference/node_modules/d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + }, "node_modules/d3-contour": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", @@ -2482,11 +2495,6 @@ "he": "bin/he" } }, - "node_modules/hex-color-to-color-name": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hex-color-to-color-name/-/hex-color-to-color-name-1.0.2.tgz", - "integrity": "sha512-YKPBFTSbYIHH8YKcJB4Q5PV+Tr+kvDXpV60BcPMUu5CSZUcc/qOOx7lkr7luk6MSXKd5A82yfPGZTgedIdQ+aA==" - }, "node_modules/highlight.js": { "version": "11.11.1", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", diff --git a/package.json b/package.json index 58600cf..3fb1144 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "@resvg/resvg-js": "^2.6.2", "d3": "^7.9.0", "d3-color": "^3.1.0", + "d3-color-difference": "^0.1.3", "d3-dsv": "^3.0.1", "d3-time-format": "^4.1.0", - "hex-color-to-color-name": "^1.0.2", "jsdom": "^26.0.0", "lodash.shuffle": "^4.2.0", "random": "^5.1.1", diff --git a/poptimal.js b/poptimal.js index 187517c..a98fcf1 100644 --- a/poptimal.js +++ b/poptimal.js @@ -12,9 +12,7 @@ const xlinkns = "http://www.w3.org/1999/xlink"; const svgns = "http://www.w3.org/2000/svg"; import {RADIUS_OPTS, DotMaker} from './src/components/dots.js'; -import {PALETTES} from './src/components/palettes.js'; - -import { GetColorName } from "hex-color-to-color-name"; +import {PALETTES, colour_to_text} from './src/components/palettes.js'; const CELL = 10; const MAG = 2; @@ -40,12 +38,6 @@ function randomise_params() { } } -function colour_to_text(d3color) { - const rawname = GetColorName(d3color.formatHex()).toLowerCase(); - // some return values are things like "cyan / aqua": take the first - const parts = rawname.split(/\//); - return parts[0].trim(); -} function image_description(params) { const bgc = colour_to_text(params.background); @@ -138,6 +130,13 @@ async function main() { .default('s', 1200) .default('c', 'config.json').argv; + if( argv.t ) { + const blue = d3.rgb(0, 0, 255); + const name = await colour_to_text(blue, "./rgb.txt"); + console.log(name); + process.exit(); + } + const cfjson = await promises.readFile(argv.c); const cf = JSON.parse(cfjson); diff --git a/src/components/palettes.js b/src/components/palettes.js index 7d01ac5..3b0db99 100644 --- a/src/components/palettes.js +++ b/src/components/palettes.js @@ -2,6 +2,9 @@ import * as d3 from "d3-color"; import shuffle from "lodash.shuffle"; import random from "random"; +import { promises } from "fs"; + +import * as d3cd from "d3-color-difference"; const PALETTES = new Map([ [ "random RGB", palette_random ], @@ -75,4 +78,33 @@ function palette_cmy() { return shuffle(cols); } -export { PALETTES } +async function parse_colours(colourfile) { + const colourBuff = await promises.readFile(colourfile); + const colours = colourBuff.toString(); + const colmap = new Map(); + const seen = new Set(); + colours.split(/\n/).map((l) => { + const m = l.match(/(\d+)\s+(\d+)\s+(\d+)\s+(.*)/); + if( m ) { + const sig = `${m[1]},${m[2]},${m[3]}`; + if( !seen.has(sig) ) { + colmap.set(m[4], d3.rgb(m[1], m[2], m[3])); + seen.add(sig); + } + } + }); + return colmap; +} + +async function colour_to_text(d3color, colourfile) { + const colours = await parse_colours(colourfile); + const diffs = [] + for( const [ name, colour] of colours) { + diffs.push({name: name, dist: d3cd.differenceCie76(colour, d3color)}); + } + diffs.sort((a, b) => a.dist - b.dist); + return diffs[0].name; +} + + +export { PALETTES, colour_to_text } From 469de3c94db840b3064a9431ad4c6663dffce14c Mon Sep 17 00:00:00 2001 From: Mike Lynch <m.lynch@sydney.edu.au> Date: Sun, 16 Mar 2025 14:46:34 +1100 Subject: [PATCH 2/2] Added my own colour name code to palettes.js --- poptimal.js | 21 ++--- rgb.txt | 169 +++++++++++++++++++++++++++++++++++++ src/components/palettes.js | 53 ++++++------ 3 files changed, 206 insertions(+), 37 deletions(-) create mode 100644 rgb.txt diff --git a/poptimal.js b/poptimal.js index a98fcf1..462e19a 100644 --- a/poptimal.js +++ b/poptimal.js @@ -12,7 +12,7 @@ const xlinkns = "http://www.w3.org/1999/xlink"; const svgns = "http://www.w3.org/2000/svg"; import {RADIUS_OPTS, DotMaker} from './src/components/dots.js'; -import {PALETTES, colour_to_text} from './src/components/palettes.js'; +import {PALETTES, ColourNamer} from './src/components/palettes.js'; const CELL = 10; const MAG = 2; @@ -39,9 +39,9 @@ function randomise_params() { } -function image_description(params) { - const bgc = colour_to_text(params.background); - const dotc = params.patterns.map((p) => colour_to_text(p.colour)); +function image_description(namer, params) { + const bgc = namer.colour_to_text(params.background); + const dotc = params.patterns.map((p) => namer.colour_to_text(p.colour)); const a = bgc.match(/^[aeiou]/) ? 'an' : 'a'; return `A pattern of ${dotc[0]} and ${dotc[1]} dots on ${a} ${bgc} background`; @@ -130,22 +130,19 @@ async function main() { .default('s', 1200) .default('c', 'config.json').argv; - if( argv.t ) { - const blue = d3.rgb(0, 0, 255); - const name = await colour_to_text(blue, "./rgb.txt"); - console.log(name); - process.exit(); - } - const cfjson = await promises.readFile(argv.c); const cf = JSON.parse(cfjson); + const namer = new ColourNamer(); + await namer.load_colours(cf['colours']); + + const fn = argv.o || String(Date.now()) + '.png'; const imgfile = cf['working_dir'] + '/' + fn; const params = randomise_params(); - const alt_text = image_description(params); + const alt_text = image_description(namer, params); const svg = poptimal_svg(params); const opts = { diff --git a/rgb.txt b/rgb.txt new file mode 100644 index 0000000..7af8368 --- /dev/null +++ b/rgb.txt @@ -0,0 +1,169 @@ +255 250 250 snow +248 248 255 ghost white +245 245 245 white smoke +220 220 220 gainsboro +255 250 240 floral white +253 245 230 old lace +250 240 230 linen +250 235 215 antique white +255 239 213 papaya whip +255 235 205 blanched almond +255 228 196 bisque +255 218 185 peach puff +255 222 173 navajo white +255 228 181 moccasin +255 248 220 cornsilk +255 255 240 ivory +255 250 205 lemon chiffon +255 245 238 seashell +240 255 240 honeydew +245 255 250 mint cream +240 255 255 azure +240 248 255 alice blue +230 230 250 lavender +255 240 245 lavender blush +255 228 225 misty rose +255 255 255 white +105 105 105 dim grey +112 128 144 slate grey +119 136 153 light slate grey +190 190 190 grey +211 211 211 light grey +100 149 237 cornflower blue +106 90 205 slate blue +123 104 238 medium slate blue +132 112 255 light slate blue +135 206 235 sky blue +135 206 250 light sky blue +176 196 222 light steel blue +173 216 230 light blue +176 224 230 powder blue +175 238 238 pale turquoise +224 255 255 light cyan +102 205 170 medium aquamarine +127 255 212 aquamarine +143 188 143 dark sea green +152 251 152 pale green +124 252 0 lawn green +127 255 0 chartreuse +173 255 47 green yellow +154 205 50 yellow green +107 142 35 olive drab +189 183 107 dark khaki +240 230 140 khaki +238 232 170 pale goldenrod +250 250 210 light goldenrod yellow +255 255 224 light yellow +255 255 0 yellow +255 215 0 gold +238 221 130 light goldenrod +218 165 32 goldenrod +184 134 11 dark goldenrod +188 143 143 rosy brown +205 92 92 indian red +139 69 19 saddle brown +160 82 45 sienna +205 133 63 peru +222 184 135 burlywood +245 245 220 beige +245 222 179 wheat +244 164 96 sandy brown +210 180 140 tan +210 105 30 chocolate +178 34 34 firebrick +165 42 42 brown +233 150 122 dark salmon +250 128 114 salmon +255 160 122 light salmon +255 165 0 orange +255 140 0 dark orange +255 127 80 coral +240 128 128 light coral +255 99 71 tomato +255 69 0 orange red +255 0 0 red +255 105 180 hot pink +255 20 147 deep pink +255 192 203 pink +255 182 193 light pink +219 112 147 pale violet red +176 48 96 maroon +199 21 133 medium violet red +208 32 144 violet red +255 0 255 magenta +238 130 238 violet +221 160 221 plum +218 112 214 orchid +186 85 211 medium orchid +153 50 204 dark orchid +148 0 211 dark violet +138 43 226 blue violet +160 32 240 purple +147 112 219 medium purple +216 191 216 thistle +102 102 102 60% grey +105 105 105 59% grey +107 107 107 58% grey +110 110 110 57% grey +112 112 112 56% grey +115 115 115 55% grey +117 117 117 54% grey +120 120 120 53% grey +122 122 122 52% grey +125 125 125 51% grey +127 127 127 50% grey +130 130 130 49% grey +133 133 133 48% grey +135 135 135 47% grey +138 138 138 46% grey +140 140 140 45% grey +143 143 143 44% grey +145 145 145 43% grey +148 148 148 42% grey +150 150 150 41% grey +153 153 153 40% grey +156 156 156 39% grey +158 158 158 38% grey +161 161 161 37% grey +163 163 163 36% grey +166 166 166 35% grey +168 168 168 34% grey +171 171 171 33% grey +173 173 173 32% grey +176 176 176 31% grey +179 179 179 30% grey +181 181 181 29% grey +184 184 184 28% grey +186 186 186 27% grey +189 189 189 26% grey +191 191 191 25% grey +194 194 194 24% grey +196 196 196 23% grey +199 199 199 22% grey +201 201 201 21% grey +204 204 204 20% grey +207 207 207 19% grey +209 209 209 18% grey +212 212 212 17% grey +214 214 214 16% grey +217 217 217 15% grey +219 219 219 14% grey +222 222 222 13% grey +224 224 224 12% grey +227 227 227 11% grey +229 229 229 10% grey +232 232 232 9% grey +235 235 235 8% grey +237 237 237 7% grey +240 240 240 6% grey +242 242 242 5% grey +245 245 245 4% grey +247 247 247 3% grey +250 250 250 2% grey +252 252 252 1% grey +169 169 169 dark grey +0 0 139 dark blue +0 139 139 dark cyan +139 0 139 dark magenta +139 0 0 dark red +144 238 144 light green diff --git a/src/components/palettes.js b/src/components/palettes.js index 3b0db99..e9a2c27 100644 --- a/src/components/palettes.js +++ b/src/components/palettes.js @@ -78,33 +78,36 @@ function palette_cmy() { return shuffle(cols); } -async function parse_colours(colourfile) { - const colourBuff = await promises.readFile(colourfile); - const colours = colourBuff.toString(); - const colmap = new Map(); - const seen = new Set(); - colours.split(/\n/).map((l) => { - const m = l.match(/(\d+)\s+(\d+)\s+(\d+)\s+(.*)/); - if( m ) { - const sig = `${m[1]},${m[2]},${m[3]}`; - if( !seen.has(sig) ) { - colmap.set(m[4], d3.rgb(m[1], m[2], m[3])); - seen.add(sig); +class ColourNamer { + constructor() { + this.colmap = new Map(); + } + + async load_colours(colourfile) { + const colourBuff = await promises.readFile(colourfile); + const colours = colourBuff.toString(); + const seen = new Set(); + colours.split(/\n/).map((l) => { + const m = l.match(/(\d+)\s+(\d+)\s+(\d+)\s+(.*)/); + if( m ) { + const sig = `${m[1]},${m[2]},${m[3]}`; + if( !seen.has(sig) ) { + this.colmap.set(m[4], d3.rgb(m[1], m[2], m[3])); + seen.add(sig); + } } + }); + } + + colour_to_text(d3color) { + const diffs = [] + for( const [ name, colour] of this.colmap) { + diffs.push({name: name, dist: d3cd.differenceCie76(colour, d3color)}); } - }); - return colmap; + diffs.sort((a, b) => a.dist - b.dist); + return diffs[0].name; + } } -async function colour_to_text(d3color, colourfile) { - const colours = await parse_colours(colourfile); - const diffs = [] - for( const [ name, colour] of colours) { - diffs.push({name: name, dist: d3cd.differenceCie76(colour, d3color)}); - } - diffs.sort((a, b) => a.dist - b.dist); - return diffs[0].name; -} - -export { PALETTES, colour_to_text } +export { PALETTES, ColourNamer }