#!/usr/bin/env python3 """ # Script ob-colors ## Metadata **Kind**: #obsidian/ob-script **Language**: #python **Parent**:: [[Obsidian Chore Scripts]], [[Executable Markdown File]] ## Synopsis Dump palettes saved in macOS color picker. Example:: [[Palette - Obsidian]] ## References - JXA Cookbook Authors. (2017). _[Using Objective C (ObjC) with JXA](https://github.com/JXA-Cookbook/JXA-Cookbook/wiki/Using-Objective-C-(ObjC)-with-JXA)_. GitHub. - Apple Developer Authors. (2019). _[NSColorList](https://developer.apple.com/documentation/appkit/nscolorlist?language=objc)_. Apple Developer Documentation. - [[Wikipedia Authors - Luma (Video) (Highlights)]] ## Script ```python # """ import filecmp import json import os import re import subprocess import tempfile from pathlib import Path JXA_SCRIPT = ''' ObjC.import("AppKit"); function hex(nsfloat) { return Math.round(ObjC.unwrap(nsfloat) * 255).toString(16).toUpperCase().padStart(2, '0'); } function rgba(nscolor) { const r = hex(nscolor.redComponent); const g = hex(nscolor.greenComponent); const b = hex(nscolor.blueComponent); const a = hex(nscolor.alphaComponent); return `${r}${g}${b}${a == 'FF' ? '' : a}`; } let palettesJSON = {}; for (const palette of ObjC.unwrap($.NSColorList.availableColorLists)) { const name = ObjC.unwrap(palette.name); const keys = ObjC.unwrap(palette.allKeys); let paletteJSON = {}; for (const key of keys) { const color = palette.colorWithKey(key).colorUsingColorSpace($.NSColorSpace.genericRGBColorSpace); paletteJSON[ObjC.unwrap(key).replace('\\x00', '')] = rgba(color); } palettesJSON[name] = paletteJSON; } JSON.stringify(palettesJSON, null, 2) ''' INVALID_CHARS_RE = re.compile(r'[\[\]\'?*#:||,\\/:" ~]+') ESCAPE_MD_RE = re.compile(r'[#]') def safe_palette_name(name): return INVALID_CHARS_RE.sub(' ', name).strip() def safe_color_name(name): return ESCAPE_MD_RE.sub(r'\\\g<0>', name) def auto_color(rgba): r = int(rgba[0:2], 16) g = int(rgba[2:4], 16) b = int(rgba[4:6], 16) brightness = 0.2126 * r + 0.7152 * g + 0.0722 * b if len(rgba) == 8: brightness = brightness * int(rgba[6:8], 16) / 255 if brightness > 144: return 'black' return 'white' palettes = json.loads( subprocess.check_output( ['osascript', '-l', 'JavaScript', '-e', JXA_SCRIPT], stderr=subprocess.DEVNULL, encoding='utf-8' ) ) export_dir = Path.home() / 'Dropbox' / 'Brain' / 'robot' / 'Color Palettes' for name, palette in palettes.items(): name = safe_palette_name(name) tmp_md_fd, tmp_md_path = tempfile.mkstemp(suffix='.md', text=True) with os.fdopen(tmp_md_fd, 'w') as md_io: print(f'# Palette - {name}\n\n', file=md_io) print('**Kind**:: #color-palette', file=md_io) print('**Source**:: #from/macos-colors', file=md_io) print('**Generated by**:: [[ob-colors]]', file=md_io) print('\n| Name | Color |\n| --- | --- |', file=md_io) for color_name, color in palette.items(): colorized_rgb = f'<code style="color:{auto_color(color)}; background:#{color}"> {color} </code>' print( f'| {safe_color_name(color_name)} | {colorized_rgb} |', file=md_io) md_file = export_dir / f'Palette - {name}.md' tmp_md_path = Path(tmp_md_path) if not md_file.exists() or not filecmp.cmp(tmp_md_path, md_file, shallow=False): if name != "System" or not md_file.exists(): print('New: {}'.format(md_file.name)) os.replace(tmp_md_path, md_file) else: # print('Same: {}'.format(md_file.name)) tmp_md_path.unlink() """ # vim: ft=python ``` """