Skip to content

Instantly share code, notes, and snippets.

@aminnj
Created January 23, 2022 03:07
Show Gist options
  • Save aminnj/0f1b18420108ea248fcfa9f856e27949 to your computer and use it in GitHub Desktop.
Save aminnj/0f1b18420108ea248fcfa9f856e27949 to your computer and use it in GitHub Desktop.
Get color palette of image on the clipboard
# requires
# numpy, PIL (and IPython, if you keep in the HTML repr stuff)
import itertools
import numpy as np
def _image_from_clipboard(algo="png"):
if algo == "jpeg":
from PIL import ImageGrab
im = ImageGrab.grabclipboard().convert("RGB")
elif algo == "png":
# adapted from https://pillow.readthedocs.io/en/stable/_modules/PIL/ImageGrab.html#grabclipboard
import sys
import os
import tempfile
import subprocess
from PIL import Image
fh, filepath = tempfile.mkstemp(".png")
os.close(fh)
commands = [
'try',
f' write (the clipboard as «class PNGf») to (open for access "{filepath}" with write permission)',
'end try',
]
script = ["osascript"]
for command in commands:
script += ["-e", command]
subprocess.call(script)
im = None
if os.stat(filepath).st_size != 0:
im = Image.open(filepath)
im.load()
os.unlink(filepath)
return im
def colors_from_clipboard(algo="png"):
"""
This returns a nice HTML repr of the common colors and their hexadecimal
representation from the picture in the system clipboard. Useful for
getting a hexadecimal color palette given a plot.
"""
from PIL import ImageGrab
from IPython.display import HTML
img = _image_from_clipboard(algo=algo)
arr = np.array(img)
arr = np.array(img)[:,:,(0,1,2)]
r = arr[:,:,0].flatten().astype(np.uint32)
g = arr[:,:,1].flatten().astype(np.uint32)
b = arr[:,:,2].flatten().astype(np.uint32)
sel = ((r > 230) & (g > 230) & (b > 230)) | ((r < 20) & (g < 20) & (b < 20))
r = r[~sel]
g = g[~sel]
b = b[~sel]
all_rgb = (r << 16) | (g << 8) | b
unique_rgb, counts = np.unique(all_rgb, return_counts=True)
top_rgb = unique_rgb[np.argsort(counts)[-12:]][::-1] # most to least common
def dist_rgb(rgb1, rgb2):
r1 = (rgb1 >> 16) & 0xff
g1 = (rgb1 >> 8) & 0xff
b1 = (rgb1 >> 0) & 0xff
r2 = (rgb2 >> 16) & 0xff
g2 = (rgb2 >> 8) & 0xff
b2 = (rgb2 >> 0) & 0xff
return ((r1-r2)**2 + (b1-b2)**2 + (g1-g2)**2)**0.5
if len(top_rgb) > 1:
deduped_rgb = [top_rgb[0]]
for i,rgb in enumerate(top_rgb[1:],1):
closest = min([dist_rgb(rgb,v) for v in top_rgb[:i]])
if closest > 6:
deduped_rgb.append(rgb)
top_rgb = deduped_rgb
def rgb_to_hex(v):
r = (v >> 16) & 0xff
g = (v >> 8) & 0xff
b = (v >> 0) & 0xff
return f"{r:02x}{g:02x}{b:02x}".upper()
from IPython.display import HTML
hex_values = list(map(rgb_to_hex,top_rgb))
body = "<table>"
for hv in hex_values:
body += f'<tr style="background:white;"><td><svg width="40" height="10"><rect width="40" height="10" style="fill:#{hv};stroke-width:0;"/></svg></td><td><pre>#{hv}</pre></td></tr>\n'
body += "</table>"
return HTML(body)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment