Hello,
Maybe someone can help me with this specific task.
I’m wondering how can I convert a hex color to a slice of integers.
input: #ffffff
output: 255,255,255
I need to do it in a template file (html), not in a SCSS file.
I need it to compare colors and decide if a color is suitable or not.
Any help would be appreciated.
I am not aware of a way to perform such a conversion directly in Hugo.
1 Like
Grob
October 30, 2020, 5:12pm
3
1 Like
That would be an option, but would be my last resort.
Anyway, now I have this partial:
{{ $c := . }}
{{ $conv := slice "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f" }}
{{ $val := 0 }}
{{ $out := slice }}
{{ range $i, $c := ( slice (substr $c 1 1) (substr $c 2 1) (substr $c 3 1) (substr $c 4 1) (substr $c 5 1) (substr $c 6 1) ) }}
{{ $mod := mod $i 2 }}
{{ $dec := 0 }}
{{ range $j, $v := $conv }}
{{ if eq $v $c }}{{$dec = $j}}{{ end }}
{{ end }}
{{ $dec }}
{{ $val = add $val ( mul $dec ( cond (eq $mod 0) 16 1 ) ) }}
{{ if $mod }}{{ $out = $out | append $val}}{{ $val = 0}}{{end}}
{{ end }}
{{ return $out }}
And this is how I use it:
{{ partial "color/hex-to-rgb" "#bbbbbb" }}
But I don’t like this solution. I’m hoping someone can help me find a better one. Or at least make mine better.
2 Likes
Why ? It works, no ?
And I’ll borrow this, nice partial for my use case. Thanks.
It’s slow - if you run it 2000 times it will increase your build by near a second.
But you can use partialCached if your use case benefits from it.
But yes, it works.
I’m glad you liked it!
pamubay
October 30, 2020, 10:22pm
7
you could directly split
the string, and use after
to exclude the #
character.
--{{ $c := . }}
{{ $conv := slice "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f" }}
{{ $val := 0 }}
{{ $out := slice }}
++{{ range $i, $c := after 1 (split . "") }}
--{{ range $i, $c := ( slice (substr $c 1 1) (substr $c 2 1) (substr $c 3 1) (substr $c 4 1) (substr $c 5 1) (substr $c 6 1) ) }}
{{ $mod := mod $i 2 }}
{{ $dec := 0 }}
{{ range $j, $v := $conv }}
{{ if eq $v $c }}{{$dec = $j}}{{ end }}
{{ end }}
{{ $dec }}
{{ $val = add $val ( mul $dec ( cond (eq $mod 1) 16 1 ) ) }}
{{ if $mod }}{{ $out = $out | append $val}}{{ $val = 0}}{{end}}
{{ end }}
{{ return $out }}
i dont know it’s going to improve the speed or not.
1 Like
What you’re doing is probably the best approach today. I would definitely use partialCached
for this.
Would it be helpful if we added a hexDecode
function? {{ $r := hexDecode "c0" }}
As shown by the OP there is a need for such a function. So +1.
pamubay:
split . "
The speed is almost the same, but it’s cleaner and works for colors with alpha like #ffffffff
But using a map in the conversion improved the performance.
Here is the updated version and thanks for the suggestion!
{{ $convMap := dict "0" 0 "1" 1 "2" 2 "3" 3 "4" 4 "5" 5 "6" 6 "7" 7 "8" 8 "9" 9 "a" 10 "b" 11 "c" 12 "d" 13 "e" 14 "f" 15 }}
{{ $val := 0 }}
{{ $out := slice }}
{{ range $i, $c := split (substr . 1) "" }}
{{ $mod := mod $i 2 }}
{{ $dec := index $convMap $c }}
{{ $val = add $val ( mul $dec ( cond (eq $mod 0) 16 1 ) ) }}
{{ if $mod }}{{ $out = $out | append $val}}{{ $val = 0}}{{end}}
{{ end }}
{{ return $out }}
3 Likes
Thanks for your help.
Yes, the function hexDecode would help! So +1 for that.
But I’m wondering if a more specialized function, related to colors - would also be interesting.
My use case is very specific, I’m not sure if this would create unnecessary noise.
Let me explain my use case:
I’m using Bootstrap in my theme. An editor can change the Bootstrap primary color variable in a Data file (theme.yaml).
Some sections of my website use the primary or secondary color as background. I want to know if it’s safe to use a btn-primary, btn-secondary or btn-danger in a specific section. If not, I want to decide which class would be better to use as a fallback, btn-light or btn-dark.
The logic is the same of this Bootstrap SCSS function:
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
$r: red($color);
$g: green($color);
$b: blue($color);
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
@if ($yiq >= $yiq-contrasted-threshold) {
@return $dark;
} @else {
@return $light;
}
}
Adding color-specific template functions is a bit of a stretch. Let’s stick with hex encoding enhancements for now.
I have a working implementation in a dev branch, and I’m seeing about a 10x improvement in speed versus your partial above. I’ll try to get a PR submitted in the few days.
PS - Your partial has a bug. Use (eq $mod 0)
instead of (eq $mod 1)
.
1 Like
adrinux
November 5, 2020, 9:38am
13
In my efforts to learn Go I worked on a colour palette generator app a couple of years ago - the code is horrible but it’s here - Palegen
It relies on the go-colorful library which may be worth a look if you want to manipulate colours in Go.
(Wish I’d had the time and energy to push on and polish it, but it’s getting eclipsed by improvements in CSS and now it seems Hugo as well :))
solopx
September 17, 2023, 2:06pm
14
Hi,
regarding you project PALEGEN
do you think that could help doing something like this:
{{- $hexColor := "#FF5733" -}}
{{- $hslColor := hexToHSL $hexColor -}}
<div>
<div style="background-color: {{ $hexColor }};">
Hex: {{ $hexColor }}<br>
HSL: {{ $hslColor }}
</div>
</div>
directly in hugo?
obvious by adding some special fuction
solopx
September 17, 2023, 2:10pm
15
I’m using something like here in order to run SCSS calculation:
colors.scss
{{ partial "scratching/images.html" . }}
{{ $colors := $.Scratch.Get "_colors" }}
@mixin text-contrast($n) {
$color-brightness: round((red($n) * 299) + (green($n) * 587) + (blue($n) * 114) / 1000);
$light-color: round((red(#ffffff) * 299) + (green(#ffffff) * 587) + (blue(#ffffff) * 114) / 1000);
@if abs($color-brightness) < ($light-color/2){
--fg: white;
}
@else {
--fg: black;
}
}
body {
--test: {{ $colors }};
{{ range first 1 $colors }}
@include text-contrast({{ . }});
--bg: {{ . }};
{{ end }}
}
then in template:
{{ $scssTemplate := resources.Get "scss/colors.scss" }}
{{ $vars := $scssTemplate | resources.ExecuteAsTemplate "var.colors.scss" . | toCSS | minify | fingerprint }}
<style data-colors>
{{ $vars.Content | safeCSS }}
</style>
are you on the same page?
adrinux
September 18, 2023, 9:07am
16
Not Palegen, no. But Palegen uses go-colorful to manipulate colours and that might be helpful for what you are trying to do. But I have no idea how you would call an external library.
Sass (as you have) or PostCSS seem better suited to the task and are already working in Hugo.
ryanm
March 14, 2024, 7:14am
17
I have no idea about the performance implications, but I find converting to rgb values quite easy in Hugo using the int function and some printf
/substr
fidgeting:
{{ $hex := "#f5f5f5" }}
{{ $rgb := printf "rgb(%d,%d,%d)" (printf "0x%s" (substr $hex 1 2) | int) (printf "0x%s" (substr $hex 1 2) | int) (printf "0x%s" (substr $hex 1 2) | int) }}
gives you rgb(245,245,245)
. A hexadecimal number is just a number, right?
Am I missing something or doing something really silly here? (Better software engineers than me: have at it!)
This approach is fine, but you need to change the substr args.
{{ $rgb := printf "rgb(%d,%d,%d)" (printf "0x%s" (substr $hex 1 2) | int) (printf "0x%s" (substr $hex 3 2) | int) (printf "0x%s" (substr $hex 5 2) | int) }}
Note that performance isn’t great. To compare…
4M iterations of the above: 22s
4M iterations of a single printf
statement: 4s
If this were a common need (which it isn’t) we’d probably want to implement a few functions in a colors namespace (e.g., colors.ToRGB, colors.ToRGBA, colors.IsLight, colors.IsDark, etc.).
1 Like