#!/usr/bin/perl
use strict; use warnings; use utf8;
+use autodie;
+use Math::Trig;
+use File::Basename qw(basename dirname);
+use File::Temp qw(tempfile);
sub hexTuple {
my ($r, $g, $b) = @_;
# https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
sub hslHex {
my ($hue, $sat, $lig ) = @_;
- my $h = ($hue * 6);
+ $hue = $hue / 360.0;
+ my $h = ($hue * 6.0);
my $c = (1 - abs(2.0*$lig - 1)) * $sat;
- my $h_mod_2 = $h - 2*int($h/2);
+ my $h_mod_2 = $h - 2.0*int($h/2);
my $x = $c * (1 - abs($h_mod_2 - 1));
my ($r, $g, $b);
my $m = $lig - $c / 2.0;
return $max;
}
+sub hexToRGB {
+ my $hexTriplet = shift;
+
+ my @d = $hexTriplet =~ /^#?(.)(.)(.)(.)(.)(.)/;
+
+ return (16 * $hexValue{$d[0]} + $hexValue{$d[1]},
+ 16 * $hexValue{$d[2]} + $hexValue{$d[3]},
+ 16 * $hexValue{$d[4]} + $hexValue{$d[5]});
+}
+
sub hexToHSL {
my $hexTriplet = shift;
- my ( $r,$g,$b ) = $hexTriplet =~ /^#?(..)(..)(..)/;
- for ($r,$g,$b) {
- my @d = split(//);
- $_ = 16 * $hexValue{$d[0]} + $hexValue{$d[1]};
- }
+ my ($r,$g,$b) = hexToRGB($hexTriplet);
warn "$hexTriplet -> $r:$g:$b";
for ($r, $g, $b ) { $_ = $_ / 255.0 }
my $baseColorHSV = [ hexToHSL('#935ff2') ];
my $baseColorHue = $baseColorHSV->[0];
-warn sprintf( 'H:%1.4f S:%1.4f L:%1.4f', @$baseColorHSV );
+warn sprintf( 'H:%1.4f S:%1.4f V:%1.4f', @$baseColorHSV );
warn sprintf( 'H:%1.4f S:%1.4f L:%1.4f', hexToHSL('#3e148c') );
+my @target = hexToRGB('#935ff2');
+my ($best, $min_dist);
+for (my $s = 0.50; $s < 0.90; $s += 0.001) {
+ for ( my $l = 0.50; $l <= 0.80; $l += 0.001 ) {
+ my $hexColor = hslHex($baseColorHue, $s, $l);
+ my ($r,$g,$b) = hexToRGB( $hexColor );
+ my $dist = abs($r-$target[0])
+ + abs($g-$target[1])
+ + abs($b-$target[2]);
+ if (not defined($best) or $dist < $min_dist) {
+ $best = [ $s, $l, $hexColor ];
+ $min_dist = $dist;
+ }
+ }
+}
+warn sprintf( 's%1.3f, l%1.3f -> %s',
+ @$best );
my $baseTheme = "AppTheme.NoActionBar";
+use constant STEP_DEGREES => 5;
+
# # hsb
-# for( my $hue = 0; $hue < 360; $hue += 15 ) {
-# printf "<style name=\"%s.%d\" parent=\"%s\">\n",
+# for( my $hue = 0; $hue < 360; $hue += STEP_DEGREES ) {
+# printf "<style name=\"%s.%03d\" parent=\"%s\">\n",
# $baseTheme, $hue, $baseTheme;
# printf " <item name=\"colorPrimary\">#%s</item>\n",
# hsvHex($hue/360.0, 0.61, 0.95);
# }
# HSL
-hslStyleForHue($baseColorHue);
-for( my $hue = 0; $hue < 360; $hue += 15 ) {
- hslStyleForHue($hue, $baseTheme);
+sub outputThemes {
+ my $out = shift;
+ my $baseIndent = shift;
+ $out->print(hslStyleForHue($baseColorHue, undef, $baseIndent));
+ for( my $hue = 0; $hue < 360; $hue += STEP_DEGREES ) {
+ $out->print("\n");
+ $out->print(hslStyleForHue($hue, $baseTheme, $baseIndent));
+ }
}
sub hslStyleForHue {
my $hue = shift;
my $base = shift;
+ my $baseIndent = shift // '';
+
+ my $blueL = 0.665;
+ my $yellowL = 0.350;
+
+ my $blueL2 = 0.350;
+ my $yellowL2 = 0.500;
+
+ # $y == 0 for yellow
+ my $y = $hue - 60;
+ $y += 360 if $y < 0;
+ # $q == 0 for yellow, 1 for blue
+ my $q = cos(deg2rad(abs($y-180)/2.0));
+ my $l1 = $yellowL + ($blueL - $yellowL) * $q;
+ my $l2 = 0.250 + 0.250 * $q;
+ my $l3 = 0.950;
+ my $l4 = 0.980;
+
+ my $result = "";
+ my $indent = "$baseIndent ";
if ($base) {
- printf "<style name=\"%s.%d\" parent=\"%s\">\n",
- $baseTheme, $hue, $baseTheme;
- }
- else {
- printf "<style name=\"%s\">\n",
- $baseTheme;
- printf " <item name=\"windowActionBar\">false</item>\n";
- printf " <item name=\"windowNoTitle\">true</item>\n";
- printf " <item name=\"textColor\">#d0000000</item>\n";
+ $result .= sprintf "$baseIndent<style name=\"%s.%03d\" parent=\"%s\">\n",
+ $baseTheme, $hue, $baseTheme;
+ }
+ else {
+ $result .= sprintf "$baseIndent<style name=\"%s\">\n",
+ $baseTheme;
+ $result .= "$indent<item name=\"windowActionBar\">false</item>\n";
+ $result .= "$indent<item name=\"windowNoTitle\">true</item>\n";
+ $result .= "$indent<item name=\"textColor\">#757575</item>\n";
+ }
+ my $S = 0.845;
+ $result .= sprintf "$indent<item name=\"colorPrimary\">#%s</item>\n",
+ hslHex($hue, $S, $l1);
+ $result .= sprintf "$indent<item name=\"colorPrimaryTransparent\">#00%s</item>\n",
+ hslHex($hue, $S, $l1);
+ $result .= sprintf "$indent<item name=\"colorAccent\">#%s</item>\n",
+ hslHex($hue, $S, $l2);
+ $result .= "$indent<item name=\"drawer_background\">#ffffffff</item>\n";
+ $result .= sprintf "$indent<item name=\"table_row_dark_bg\">#%s</item>\n",
+ hslHex($hue, $S, $l3);
+ $result .= sprintf "$indent<item name=\"table_row_light_bg\">#%s</item>\n",
+ hslHex($hue, $S, $l4);
+ $result .= "$baseIndent</style>\n";
+
+ return $result;
+}
+
+my $xml = shift;
+
+if ($xml) {
+ my $start_marker = '<!-- theme list start -->';
+ my $end_marker = '<!-- theme list end -->';
+ my ($fh, $filename) = tempfile(basename($0).'.XXXXXXXX', DIR => dirname($xml));
+ open(my $in, '<', $xml);
+ my $base_indent = '';
+ my $state = 'waiting-for-start-marker';
+ while (<$in>) {
+ if ( $state eq 'waiting-for-start-marker' ) {
+ print $fh $_;
+ $state = 'skipping-styles', $base_indent = $1
+ if /^(\s*)\Q$start_marker\E/;
+ next;
+ }
+ if ( $state eq 'skipping-styles' ) {
+ next unless /^\s*\Q$end_marker\E/;
+ outputThemes($fh, $base_indent);
+ print $fh $_;
+ $state = 'copying-the-rest';
+ next;
+ }
+ if ( $state eq 'copying-the-rest') {
+ print $fh $_;
+ next;
+ }
+
+ die "Unexpected state '$state'";
}
- printf " <item name=\"colorPrimary\">#%s</item>\n",
- hslHex($hue/360.0, 0.60, 0.60);
- printf " <item name=\"colorPrimaryTransparent\">#00%s</item>\n",
- hslHex($hue/360.0, 0.60, 0.60);
- printf " <item name=\"colorAccent\">#%s</item>\n",
- hslHex($hue/360.0, 0.85, 0.50);
- printf " <item name=\"drawer_background\">#ffffffff</item>\n";
- printf " <item name=\"table_row_dark_bg\">#%s</item>\n",
- hslHex($hue/360.0, 0.85, 0.95);
- printf " <item name=\"table_row_light_bg\">#%s</item>\n",
- hslHex($hue/360.0, 0.85, 0.98);
- printf "</style>\n";
+
+ close($fh);
+ close($in);
+
+ rename($filename, $xml);
+}
+else {
+ outputThemes(\*STDOUT);
}