Add polarity option ✨
This commit is contained in:
parent
f7d6ec8f1d
commit
6a706cba69
4 changed files with 40 additions and 21 deletions
|
|
@ -55,9 +55,12 @@ a NixOS module; how to do this is shown in the example above.
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# A colorscheme will be chosen automatically based on your wallpaper
|
||||
# A colorscheme will be chosen automatically based on your wallpaper.
|
||||
stylix.image = ./wallpaper.png;
|
||||
|
||||
# Use this option to force a light or dark theme.
|
||||
stylix.polarity = "light";
|
||||
|
||||
# Select your preferred fonts, or use these defaults:
|
||||
stylix.fonts = {
|
||||
serif = {
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ import Text.JSON ( encode )
|
|||
|
||||
-- | Run the genetic algorithm to generate a palette from the given image.
|
||||
selectColours :: (Floating a, Real a)
|
||||
=> V.Vector (LAB a) -- ^ Colours of the source image
|
||||
=> String -- ^ Scheme type: "either", "light" or "dark"
|
||||
-> V.Vector (LAB a) -- ^ Colours of the source image
|
||||
-> V.Vector (LAB a) -- ^ Generated palette
|
||||
selectColours image
|
||||
= snd $ evolve image (EvolutionConfig 1000 100 0.5 150) (mkStdGen 0)
|
||||
selectColours polarity image
|
||||
= snd $ evolve (polarity, image) (EvolutionConfig 1000 100 0.5 150) (mkStdGen 0)
|
||||
|
||||
-- | Convert a 'DynamicImage' to a simple 'V.Vector' of colours.
|
||||
unpackImage :: (Num a) => DynamicImage -> V.Vector (RGB a)
|
||||
|
|
@ -30,22 +31,23 @@ loadImage :: String -- ^ Path to the file
|
|||
-> IO DynamicImage
|
||||
loadImage input = either error id <$> readImage input
|
||||
|
||||
mainProcess :: (String, String) -> IO ()
|
||||
mainProcess (input, output) = do
|
||||
mainProcess :: (String, String, String) -> IO ()
|
||||
mainProcess (polarity, input, output) = do
|
||||
putStrLn $ "Processing " ++ input
|
||||
image <- loadImage input
|
||||
let outputTable = makeOutputTable
|
||||
$ V.map lab2rgb
|
||||
$ selectColours
|
||||
$ selectColours polarity
|
||||
$ V.map rgb2lab
|
||||
$ unpackImage image
|
||||
writeFile output $ encode outputTable
|
||||
putStrLn $ "Saved to " ++ output
|
||||
|
||||
parseArguments :: [String] -> Either String (String, String)
|
||||
parseArguments [input, output] = Right (input, output)
|
||||
parseArguments [_] = Left "Please specify an output file"
|
||||
parseArguments [] = Left "Please specify an image"
|
||||
parseArguments :: [String] -> Either String (String, String, String)
|
||||
parseArguments [polarity, input, output] = Right (polarity, input, output)
|
||||
parseArguments [_, _] = Left "Please specify an output file"
|
||||
parseArguments [_] = Left "Please specify an image"
|
||||
parseArguments [] = Left "Please specify a polarity: either, light or dark"
|
||||
parseArguments _ = Left "Too many arguments"
|
||||
|
||||
main :: IO ()
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ randomFromVector generator vector
|
|||
= let (index, generator') = randomR (0, V.length vector - 1) generator
|
||||
in (vector ! index, generator')
|
||||
|
||||
instance (Floating a, Real a) => Species (V.Vector (LAB a)) (V.Vector (LAB a)) where
|
||||
instance (Floating a, Real a) => Species (String, (V.Vector (LAB a))) (V.Vector (LAB a)) where
|
||||
{- |
|
||||
Palettes in the initial population are created by randomly
|
||||
sampling 16 colours from the source image.
|
||||
-}
|
||||
generate image = generateColour 16
|
||||
generate (_, image) = generateColour 16
|
||||
where generateColour 0 generator = (generator, V.empty)
|
||||
generateColour n generator
|
||||
= let (colour, generator') = randomFromVector generator image
|
||||
|
|
@ -51,17 +51,13 @@ instance (Floating a, Real a) => Species (V.Vector (LAB a)) (V.Vector (LAB a)) w
|
|||
Mutation is done by replacing a random slot in the palette with
|
||||
a new colour, which is randomly sampled from the source image.
|
||||
-}
|
||||
mutate image generator palette
|
||||
mutate (_, image) generator palette
|
||||
= let (index, generator') = randomR (0, 15) generator
|
||||
(colour, generator'') = randomFromVector generator' image
|
||||
in (generator'', palette // [(index, colour)])
|
||||
|
||||
fitness _ palette
|
||||
= realToFrac $
|
||||
accentDifference -
|
||||
-- Either light schemes or dark themes are allowed.
|
||||
-- We try to converge on whichever theme we are closer to.
|
||||
min lightScheme darkScheme
|
||||
fitness (polarity, _) palette
|
||||
= realToFrac $ accentDifference - scheme
|
||||
where
|
||||
-- The accent colours should be as different as possible.
|
||||
accentDifference = minimum $ do
|
||||
|
|
@ -79,6 +75,12 @@ instance (Floating a, Real a) => Species (V.Vector (LAB a)) (V.Vector (LAB a)) w
|
|||
-- The accent colours should all have the given lightness.
|
||||
+ sum (V.map (difference accentValue) $ accent lightnesses)
|
||||
|
||||
scheme = case polarity of
|
||||
"either" -> min lightScheme darkScheme
|
||||
"light" -> lightScheme
|
||||
"dark" -> darkScheme
|
||||
_ -> error ("Invalid polarity: " ++ polarity)
|
||||
|
||||
{-
|
||||
For light themes, the background is bright and the text is dark.
|
||||
The accent colours are slightly darker.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ let
|
|||
cfg = config.stylix;
|
||||
|
||||
paletteJSON = pkgs.runCommand "palette.json" { } ''
|
||||
${palette-generator}/bin/palette-generator ${cfg.image} $out
|
||||
${palette-generator}/bin/palette-generator ${cfg.polarity} ${cfg.image} $out
|
||||
'';
|
||||
|
||||
palette = importJSON paletteJSON // {
|
||||
|
|
@ -18,6 +18,18 @@ let
|
|||
|
||||
in {
|
||||
options.stylix = {
|
||||
polarity = mkOption {
|
||||
type = types.enum [ "either" "light" "dark" ];
|
||||
default = "either";
|
||||
description = ''
|
||||
Use this option to force a light or dark theme.
|
||||
|
||||
By default we will select whichever is ranked better by the genetic
|
||||
algorithm. This aims to get good contrast between the foreground and
|
||||
background, as well as some variety in the highlight colours.
|
||||
'';
|
||||
};
|
||||
|
||||
image = mkOption {
|
||||
type = types.coercedTo types.package toString types.path;
|
||||
description = ''
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue