Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*.build
*.changes

.idea
.venv
dist
build
pick.egg-info
debian/pick/
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
recursive-include pick/assets *
46 changes: 36 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,43 @@ snap install pick-colour-picker

### Source

You'll need the following dependencies:
You'll need the dependencies listed in `pyproject.toml`
Doing the steps in the **Setup** section below will install them for you.

* `gir1.2-dee-1.0`
* `gir1.2-gdkpixbuf-2.0`
* `gir1.2-glib-2.0`
* `gir1.2-gtk-3.0`
* `gir1.2-unity-5.0`
* `python3-cairo`
* `python3-gi`
* `python3-gi-cairo`
**For development with a virtual environment:**
```bash
# Remove old venv if it exists
rm -rf .venv

# Create venv and activate it
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
```

#### Setup
```bash
./setup.sh
```

#### Running Pick
```bash
python3 -m pick
```

## Packaging

Pick can be run from the checkout with `python3 -m pick`.
Both Flatpak and Snap packages use the shared `assets` directory located at the project root (`/assets`). Ensure any asset updates are made in this directory.

## Distribution
Create a build of the project using the following:

```bash
sudo python3 setup.py install
```
A `setup.py` is present, so `python3 setup.py install` is possible, but beware that [uninstalling setup.py-installed apps is not as easy as it should be](https://github.com/stuartlangridge/ColourPicker/issues/62) and prepare accordingly if you plan to use this install method.

#### (Experimental) Building a Wheel or Source Distribution
```bash
pip install build
python -m build
```
3 changes: 3 additions & 0 deletions flatpak/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- name: assets
src: ../assets
dest: /app/share/colourpicker/assets
106 changes: 17 additions & 89 deletions pick/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,92 +6,21 @@
from gi.repository import Unity
except:
Unity = False
import cairo, math, json, os, codecs, time, subprocess, sys, base64, colorsys

__VERSION__ = "1.60.178"

if "--snark" in sys.argv:
from .snark import COLOUR_NAMES
else:
from .colours import COLOUR_NAMES

import cairo, math, json, os, codecs, time, subprocess, sys, base64, colorsys
from .converters import rgb_to_lab, rgb_to_oklch, deltaE, LAB_COLOUR_NAMES

def rgb_to_lab(r, g, b):
"""Convert RGB colours to LAB colours
thank you Roman Nazarkin, http://stackoverflow.com/a/16020102/1418014"""
inputColor = [r, g, b]
num = 0
RGB = [0, 0, 0]
for value in inputColor:
value = float(value) / 255
if value > 0.04045:
value = ((value + 0.055) / 1.055) ** 2.4
else:
value = value / 12.92
RGB[num] = value * 100
num = num + 1
XYZ = [0, 0, 0]
X = RGB[0] * 0.4124 + RGB[1] * 0.3576 + RGB[2] * 0.1805
Y = RGB[0] * 0.2126 + RGB[1] * 0.7152 + RGB[2] * 0.0722
Z = RGB[0] * 0.0193 + RGB[1] * 0.1192 + RGB[2] * 0.9505
XYZ[0] = round(X, 4)
XYZ[1] = round(Y, 4)
XYZ[2] = round(Z, 4)

XYZ[0] = float(XYZ[0]) / 95.047 # ref_X = 95.047
# XYZ[0]: Observer= 2deg, Illuminant= D65
XYZ[1] = float(XYZ[1]) / 100.0 # ref_Y = 100.000
XYZ[2] = float(XYZ[2]) / 108.883 # ref_Z = 108.883

num = 0
for value in XYZ:
if value > 0.008856:
value = value ** (0.3333333333333333)
else:
value = (7.787 * value) + (16 / 116)
XYZ[num] = value
num = num + 1

Lab = [0, 0, 0]
L = (116 * XYZ[1]) - 16
a = 500 * (XYZ[0] - XYZ[1])
b = 200 * (XYZ[1] - XYZ[2])

Lab[0] = round(L, 4)
Lab[1] = round(a, 4)
Lab[2] = round(b, 4)

return Lab


def deltaE(labA, labB):
"""deltaE is the standard way to compare two colours
for how visibly alike they are"""
deltaL = labA[0] - labB[0]
deltaA = labA[1] - labB[1]
deltaB = labA[2] - labB[2]
c1 = math.sqrt(labA[1] * labA[1] + labA[2] * labA[2])
c2 = math.sqrt(labB[1] * labB[1] + labB[2] * labB[2])
deltaC = c1 - c2
deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC
if deltaH < 0:
deltaH = 0
else:
deltaH = math.sqrt(deltaH)
sc = 1.0 + 0.045 * c1
sh = 1.0 + 0.015 * c1
deltaLKlsl = deltaL / (1.0)
deltaCkcsc = deltaC / (sc)
deltaHkhsh = deltaH / (sh)
i = (deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc +
deltaHkhsh * deltaHkhsh)
if i < 0:
return 0
else:
return math.sqrt(i)
from importlib.resources import files, as_file
from importlib.metadata import version

# Resources (PEP 621 safe)
icons_dir = files("pick").joinpath("assets/icons")

LAB_COLOUR_NAMES = [(rgb_to_lab(x[0], x[1], x[2]), x[3]) for x in COLOUR_NAMES]
# Version (from pyproject)
try:
__VERSION__ = version("pick-colour-picker")
except Exception:
__VERSION__ = "dev"


class Main(object):
Expand Down Expand Up @@ -228,11 +157,10 @@ def start_everything_first_time(self, on_window_map=None):
else:
# not in the theme, so we're probably running locally;
# use the local one
snap_icon = os.path.join(os.path.split(__file__)[0], "..",
"data", "icons", "scalable", "apps",
"pick-colour-picker-symbolic.svg")
snap_icon = str(icons_dir.joinpath("hicolor", "scalable", "apps",
"pick-colour-picker-symbolic.svg"))
flatpak_icon = ("/app/share/icons/hicolor/scalable/apps/"
"org.kryogenix.Pick-symbolic.svg")
"org.kryogenix.Pick-symbolic.svg")
if os.path.isfile(snap_icon):
image = Gtk.Image.new_from_file(snap_icon)
elif os.path.isfile(flatpak_icon):
Expand Down Expand Up @@ -271,6 +199,7 @@ def start_everything_first_time(self, on_window_map=None):
colorsys.rgb_to_hls(r/255.0, g/255.0, b/255.0)[0] * 360,
colorsys.rgb_to_hls(r/255.0, g/255.0, b/255.0)[2] * 100,
colorsys.rgb_to_hls(r/255.0, g/255.0, b/255.0)[1] * 100),
"CSS oklch": lambda r, g, b: "oklch({:.4f} {:.4f} {:.2f});".format(*rgb_to_oklch(r, g, b)),
"GDK.RGBA": lambda r, g, b: "Gdk.RGBA(%.3f, %.3f, %.3f, 1.0)" % (
r/255.0, g/255.0, b/255.0),
"QML Qt.rgba": lambda r, g, b: "Qt.rgba(%.3f, %.3f, %.3f, 1.0)" % (
Expand Down Expand Up @@ -330,9 +259,8 @@ def start_everything_first_time(self, on_window_map=None):
image = None
# not in the theme, so we're probably running locally;
# use the local one
licon = os.path.join(
os.path.split(__file__)[0], "..",
"data", "icons", "48x48", "apps", "pick-colour-picker.png")
licon = str(icons_dir.joinpath(
"hicolor", "48x48", "apps", "pick-colour-picker.png"))
if os.path.exists(licon):
# print("Using local icon", licon)
image = Gtk.Image.new_from_file(licon)
Expand Down
File renamed without changes.
File renamed without changes
90 changes: 90 additions & 0 deletions pick/converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import math
import numpy as np
import sys
from colour.models import sRGB_to_XYZ, XYZ_to_Oklab

if "--snark" in sys.argv:
from .snark import COLOUR_NAMES
else:
from .colours import COLOUR_NAMES

def rgb_to_lab(r, g, b):
"""Convert RGB colours to LAB colours."""
inputColor = [r, g, b]
num = 0
RGB = [0, 0, 0]
for value in inputColor:
value = float(value) / 255
if value > 0.04045:
value = ((value + 0.055) / 1.055) ** 2.4
else:
value = value / 12.92
RGB[num] = value * 100
num = num + 1
XYZ = [0, 0, 0]
X = RGB[0] * 0.4124 + RGB[1] * 0.3576 + RGB[2] * 0.1805
Y = RGB[0] * 0.2126 + RGB[1] * 0.7152 + RGB[2] * 0.0722
Z = RGB[0] * 0.0193 + RGB[1] * 0.1192 + RGB[2] * 0.9505
XYZ[0] = round(X, 4)
XYZ[1] = round(Y, 4)
XYZ[2] = round(Z, 4)

XYZ[0] = float(XYZ[0]) / 95.047 # ref_X = 95.047
XYZ[1] = float(XYZ[1]) / 100.0 # ref_Y = 100.000
XYZ[2] = float(XYZ[2]) / 108.883 # ref_Z = 108.883

num = 0
for value in XYZ:
if value > 0.008856:
value = value ** (0.3333333333333333)
else:
value = (7.787 * value) + (16 / 116)
XYZ[num] = value
num = num + 1

Lab = [0, 0, 0]
L = (116 * XYZ[1]) - 16
a = 500 * (XYZ[0] - XYZ[1])
b = 200 * (XYZ[1] - XYZ[2])

Lab[0] = round(L, 4)
Lab[1] = round(a, 4)
Lab[2] = round(b, 4)

return Lab

def rgb_to_oklch(r, g, b):
"""Convert RGB (0-255) to OKLCH color space, output L and C in [0,1], H in degrees."""
rgb_normalized = np.array([r / 255.0, g / 255.0, b / 255.0])
xyz = sRGB_to_XYZ(rgb_normalized)
oklab = XYZ_to_Oklab(xyz)
L, a, b_val = oklab
C = np.sqrt(a**2 + b_val**2)
H = np.degrees(np.arctan2(b_val, a)) % 360
return (L, C, H)

def deltaE(labA, labB):
"""deltaE is the standard way to compare two colours for how visibly alike they are"""
deltaL = labA[0] - labB[0]
deltaA = labA[1] - labB[1]
deltaB = labA[2] - labB[2]
c1 = math.sqrt(labA[1] * labA[1] + labA[2] * labA[2])
c2 = math.sqrt(labB[1] * labB[1] + labB[2] * labB[2])
deltaC = c1 - c2
deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC
if deltaH < 0:
deltaH = 0
else:
deltaH = math.sqrt(deltaH)
sc = 1.0 + 0.045 * c1
sh = 1.0 + 0.015 * c1
deltaLKlsl = deltaL / (1.0)
deltaCkcsc = deltaC / (sc)
deltaHkhsh = deltaH / (sh)
i = (deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh)
if i < 0:
return 0
else:
return math.sqrt(i)

LAB_COLOUR_NAMES = [(rgb_to_lab(x[0], x[1], x[2]), x[3]) for x in COLOUR_NAMES]
55 changes: 55 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "pick-colour-picker"
version = "1.61.0"
description = "A colour picker that remembers where you picked colours from"
readme = "README.md"
license = { text = "MIT" }

authors = [
{ name = "Stuart Langridge", email = "sil@kryogenix.org" }
]

keywords = ["pick", "colour", "colour picker", "color", "color picker"]

classifiers = [
"Programming Language :: Python",
"Environment :: X11 Applications :: GTK",
"Development Status :: 4 - Beta",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX :: Linux",
"Topic :: Multimedia :: Graphics"
]

dependencies = [
"colour-science",
]

[tool.system-dependencies]
system-dependencies = [
"gir1.2-dee-1.0",
"gir1.2-gdkpixbuf-2.0",
"gir1.2-glib-2.0",
"gir1.2-gtk-3.0",
"gir1.2-unity-7.0",
"python3-cairo",
"python3-gi",
"python3-gi-cairo",
]

[project.urls]
Homepage = "https://kryogenix.org/code/pick"

[project.gui-scripts]
pick-colour-picker = "pick.__main__:main"

[tool.setuptools]
include-package-data = true

[tool.setuptools.packages.find]
where = ["."]

4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from setuptools import setup

icons = []
for dirpath, dirnames, filenames in os.walk("data/icons/"):
relpath = dirpath[len("data/icons/"):]
for dirpath, dirnames, filenames in os.walk("pick/assets/icons/"):
relpath = dirpath[len("pick/assets/icons/"):]
if relpath and filenames:
icons.append((sys.prefix+"/share/icons/hicolor/"+relpath, [os.path.join(dirpath, x) for x in filenames]))

Expand Down
Loading