diff --git a/assets/weather-icons/svg/wi-cloudy.svg b/assets/weather-icons/svg/wi-cloudy.svg new file mode 100644 index 00000000..c3eaf41d --- /dev/null +++ b/assets/weather-icons/svg/wi-cloudy.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-day-cloudy.svg b/assets/weather-icons/svg/wi-day-cloudy.svg new file mode 100644 index 00000000..cf63543a --- /dev/null +++ b/assets/weather-icons/svg/wi-day-cloudy.svg @@ -0,0 +1,26 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-day-sunny.svg b/assets/weather-icons/svg/wi-day-sunny.svg new file mode 100644 index 00000000..eafcd77d --- /dev/null +++ b/assets/weather-icons/svg/wi-day-sunny.svg @@ -0,0 +1,27 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-fog.svg b/assets/weather-icons/svg/wi-fog.svg new file mode 100644 index 00000000..cf06f8f8 --- /dev/null +++ b/assets/weather-icons/svg/wi-fog.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-night-alt-cloudy.svg b/assets/weather-icons/svg/wi-night-alt-cloudy.svg new file mode 100644 index 00000000..fcd1496d --- /dev/null +++ b/assets/weather-icons/svg/wi-night-alt-cloudy.svg @@ -0,0 +1,19 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-night-clear.svg b/assets/weather-icons/svg/wi-night-clear.svg new file mode 100644 index 00000000..053b2de9 --- /dev/null +++ b/assets/weather-icons/svg/wi-night-clear.svg @@ -0,0 +1,13 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-rain.svg b/assets/weather-icons/svg/wi-rain.svg new file mode 100644 index 00000000..7ecef3fe --- /dev/null +++ b/assets/weather-icons/svg/wi-rain.svg @@ -0,0 +1,23 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-snow.svg b/assets/weather-icons/svg/wi-snow.svg new file mode 100644 index 00000000..56afebf9 --- /dev/null +++ b/assets/weather-icons/svg/wi-snow.svg @@ -0,0 +1,27 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-sprinkle.svg b/assets/weather-icons/svg/wi-sprinkle.svg new file mode 100644 index 00000000..c26b2075 --- /dev/null +++ b/assets/weather-icons/svg/wi-sprinkle.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/assets/weather-icons/svg/wi-thunderstorm.svg b/assets/weather-icons/svg/wi-thunderstorm.svg new file mode 100644 index 00000000..52555ec7 --- /dev/null +++ b/assets/weather-icons/svg/wi-thunderstorm.svg @@ -0,0 +1,21 @@ + + + + + diff --git a/lib/Weather/WeatherIcons48.h b/lib/Weather/WeatherIcons48.h index b92bc221..d7e5f349 100644 --- a/lib/Weather/WeatherIcons48.h +++ b/lib/Weather/WeatherIcons48.h @@ -1,215 +1,196 @@ #pragma once #include -// Generated from erikflowers/weather-icons (font + css mappings) -// 48x48, 1-bit, MSB-first, row-major, rotated for device orientation +// Generated from erikflowers/weather-icons SVGs. +// 48x48, 1-bit, MSB-first, row-major. +// Regenerate with: python scripts/generate_weather_icons.py --fetch static const uint8_t WI48_CLEAR_DAY[] = { - 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFE, 0x7F, 0xF8, 0x7F, 0xFC, 0x7F, - 0xFC, 0x3F, 0xFC, 0xFF, 0xF8, 0x3F, 0xFC, 0x1F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFE, 0x0F, 0xFF, 0xFF, - 0xC0, 0x7F, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0x8F, - 0xC0, 0x0F, 0xC3, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xC0, 0x7F, 0xFF, 0xFF, 0xF8, 0x3F, 0xF0, - 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xE0, - 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFE, 0x1F, 0xFF, 0x00, 0xE1, 0xFF, 0xFE, 0x1F, 0x00, - 0x00, 0xE1, 0xFF, 0xFE, 0x1F, 0x00, 0x00, 0xE1, 0xFF, 0xFE, 0x1F, 0x00, 0x81, 0xE1, 0xFF, 0xFE, - 0x1F, 0x81, 0xFF, 0xE0, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xF0, - 0x7F, 0xF8, 0x3F, 0xFF, 0xFF, 0xF0, 0x3F, 0xF0, 0x3F, 0xFF, 0xFF, 0xF8, 0x1F, 0xE0, 0x7F, 0xFF, - 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x03, - 0xFF, 0xFF, 0xFF, 0xCF, 0xC0, 0x0F, 0xE7, 0xFF, 0xFF, 0x8F, 0xF0, 0x3F, 0xC3, 0xFF, 0xFF, 0x0F, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, - 0xFC, 0x1F, 0xFC, 0xFF, 0xF0, 0x3F, 0xFC, 0x3F, 0xF8, 0x7F, 0xFC, 0x3F, 0xFE, 0x7F, 0xF8, 0x7F, - 0xFE, 0x7F, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFE, 0x1F, 0xFE, 0x7F, 0xF8, 0xFF, + 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC1, 0xFF, + 0xFF, 0xC3, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xE7, 0xF8, 0x1F, 0xE7, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xF0, 0x7F, 0xFF, + 0xFF, 0xFC, 0x1F, 0xF8, 0x3F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFC, 0x3F, 0xFF, 0xFF, 0xF8, 0x7F, 0xFE, 0x3F, 0xFF, + 0xFF, 0xF8, 0x7F, 0xFE, 0x1F, 0xFF, 0xC0, 0xF8, 0xFF, 0xFF, 0x1F, 0x03, 0x80, 0x78, 0xFF, 0xFF, 0x1E, 0x01, + 0x80, 0x78, 0xFF, 0xFF, 0x1E, 0x01, 0xC0, 0xF8, 0xFF, 0xFF, 0x1F, 0x03, 0xFF, 0xF8, 0x7F, 0xFE, 0x1F, 0xFF, + 0xFF, 0xF8, 0x7F, 0xFE, 0x1F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFC, 0x3F, 0xFF, 0xFF, 0xFC, 0x1F, 0xF8, 0x3F, 0xFF, + 0xFF, 0xFE, 0x0F, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xE7, 0xF0, 0x0F, 0xE7, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC3, 0xFF, + 0xFF, 0x83, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0x7F, + 0xFE, 0x1F, 0xFE, 0x7F, 0xF8, 0x7F, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_CLEAR_NIGHT[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, - 0xF0, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0xFE, 0x07, 0xFF, - 0xFF, 0xFF, 0xE1, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, - 0xC1, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xC1, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xE0, 0xFF, 0xFF, 0x00, - 0x0F, 0xFF, 0xE0, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF0, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, - 0xF0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0x07, - 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC1, 0xFF, - 0xFF, 0x81, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x7F, 0xFE, - 0x07, 0xFF, 0xFF, 0xE0, 0x1F, 0xF8, 0x0F, 0xFF, 0xFF, 0xF0, 0x03, 0x80, 0x1F, 0xFF, 0xFF, 0xFC, - 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFF, + 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0xFF, + 0xFF, 0xC0, 0x03, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0x07, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x07, 0xFF, 0xFF, + 0xFE, 0x01, 0xFF, 0x03, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0x83, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0x83, 0xFF, 0xFF, + 0xF8, 0x1F, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, + 0xE0, 0x7F, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, 0x7F, 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, + 0xC0, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0x00, 0x01, + 0xC1, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xC1, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0x81, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, + 0x81, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, + 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0x03, 0xE0, 0x7F, 0xFF, 0xFF, 0xFE, 0x07, + 0xE0, 0x3F, 0xFF, 0xFF, 0xFE, 0x07, 0xF0, 0x1F, 0xFF, 0xFF, 0xFC, 0x0F, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x0F, + 0xF8, 0x0F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFC, 0x07, 0xFF, 0xFF, 0xE0, 0x1F, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x3F, + 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_PARTLY_CLOUDY_DAY[] = { - 0xFE, 0x3F, 0xFC, 0x3F, 0xFE, 0x3F, 0xFE, 0x1F, 0xFE, 0x7F, 0xFC, 0x3F, 0xFE, 0x0F, 0xFF, 0xFF, - 0xF8, 0x3F, 0xFE, 0x07, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0x83, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x01, 0xE3, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x07, 0xE0, - 0x00, 0x0F, 0xFF, 0xFC, 0x1F, 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x3F, 0xE0, 0x7F, 0x03, 0xFF, 0xF8, - 0x7F, 0xC0, 0xFF, 0x81, 0xFF, 0xF0, 0x7F, 0xC1, 0xFF, 0xC1, 0xFF, 0xF0, 0x7F, 0x83, 0xFF, 0xE0, - 0x00, 0x70, 0xFF, 0x83, 0xFF, 0xE0, 0x00, 0x70, 0xFF, 0x87, 0xFF, 0xF0, 0x00, 0x70, 0xFF, 0x87, - 0xFF, 0xF0, 0x80, 0xF0, 0xFF, 0x87, 0xFF, 0xF0, 0xFF, 0xF0, 0x7C, 0x07, 0xFF, 0xF0, 0xFF, 0xF0, - 0x78, 0x07, 0xFF, 0xF0, 0xFF, 0xF8, 0x30, 0x07, 0xFF, 0xF0, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0xF0, - 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x07, 0xFF, - 0xFF, 0xF0, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, - 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0x9E, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0x0E, 0x1F, 0xFF, 0xFF, 0xF0, - 0xFE, 0x0E, 0x1F, 0xFF, 0xFF, 0xF0, 0xFE, 0x1E, 0x1F, 0xFF, 0xFF, 0xF0, 0xFE, 0x1E, 0x1F, 0xFF, - 0xFF, 0xF0, 0xFF, 0x3E, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, - 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF0, - 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xE0, 0x0F, - 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xF0, 0xFF, 0xFF, - 0xFE, 0x07, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xE0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xF3, 0xFF, 0x7F, + 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x9F, 0xFF, 0xF8, 0x7F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, + 0xFF, 0xF8, 0x00, 0x1C, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x7F, 0x0F, 0xFF, 0xFF, 0xC1, 0xF0, 0x7F, 0x87, 0xFF, + 0xFF, 0x87, 0xFC, 0x3F, 0xC7, 0xFF, 0xFF, 0x8F, 0xFE, 0x3F, 0xE7, 0xFF, 0xFF, 0x1F, 0xFF, 0x1F, 0xE7, 0x83, + 0xFF, 0x1F, 0xFF, 0x1F, 0xE3, 0x81, 0xFE, 0x3F, 0xFF, 0x83, 0xE7, 0x83, 0xF8, 0x3F, 0xFF, 0x80, 0xE7, 0xFF, + 0xF0, 0x3F, 0xFF, 0x80, 0x07, 0xFF, 0xE1, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xC7, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, + 0x8F, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 0xCE, 0x7F, 0x8F, 0xFF, 0xFF, 0xFF, 0x8C, 0x3F, + 0xC7, 0xFF, 0xFF, 0xFF, 0x8E, 0x3F, 0xC7, 0xFF, 0xFF, 0xFF, 0x1F, 0x7F, 0xE1, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_PARTLY_CLOUDY_NIGHT[] = { - 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x60, - 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x08, 0x00, 0x01, 0xFF, 0xFF, 0xFC, - 0x0C, 0x00, 0x00, 0xFF, 0xFC, 0x60, 0x1C, 0x0F, 0xE0, 0x7F, 0xF8, 0x00, 0x38, 0x1F, 0xF0, 0x3F, - 0xF8, 0x00, 0x78, 0x3F, 0xF8, 0x3F, 0xF8, 0x01, 0xF0, 0x7F, 0xFC, 0x1F, 0xF8, 0x0F, 0xF0, 0x7F, - 0xFC, 0x1F, 0xF8, 0x7F, 0xF0, 0xFF, 0xFE, 0x1F, 0xF8, 0x7F, 0xF0, 0xFF, 0xFE, 0x1F, 0xF8, 0x3F, - 0xF0, 0xFF, 0xFE, 0x1F, 0xF8, 0x3F, 0x80, 0xFF, 0xFE, 0x1F, 0xFC, 0x1F, 0x00, 0xFF, 0xFE, 0x1F, - 0xFC, 0x1E, 0x00, 0xFF, 0xFE, 0x1F, 0xFE, 0x04, 0x03, 0xFF, 0xFE, 0x1F, 0xFE, 0x00, 0x1F, 0xFF, - 0xFE, 0x1F, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0x80, 0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xE0, - 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC1, 0xFF, 0xFF, 0xFE, 0x1F, - 0xFF, 0xC1, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xFF, - 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC1, - 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xC1, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0xFE, 0x1F, - 0xFF, 0xE0, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xE0, 0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, - 0xFE, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x01, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, - 0x00, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFE, 0x1F, - 0xFF, 0xFF, 0xF0, 0x7F, 0xFC, 0x1F, 0xFF, 0xFF, 0xF8, 0x7F, 0xFC, 0x1F, 0xFF, 0xFF, 0xF8, 0x3F, - 0xF8, 0x3F, 0xFF, 0xFF, 0xF8, 0x1F, 0xF0, 0x3F, 0xFF, 0xFF, 0xFC, 0x07, 0xC0, 0x7F, 0xFF, 0xFF, - 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF8, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0xF8, 0xFF, + 0xFF, 0xFE, 0x00, 0x03, 0xF8, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xF8, 0xFF, 0xFF, 0xF0, 0x3F, 0x03, 0xF8, 0x7F, + 0xFF, 0xF0, 0xFF, 0xC1, 0xFC, 0x3F, 0xFF, 0xE1, 0xFF, 0xF0, 0xFC, 0x1F, 0xFF, 0xC3, 0xFF, 0xF8, 0x7E, 0x07, + 0xFF, 0xC3, 0xFF, 0xF8, 0x7F, 0x01, 0xFF, 0xC7, 0xFF, 0xFC, 0x7F, 0x83, 0xFF, 0x87, 0xFF, 0xFC, 0x07, 0xC3, + 0xFE, 0x0F, 0xFF, 0xFC, 0x01, 0xC3, 0xF8, 0x0F, 0xFF, 0xFC, 0x00, 0x07, 0xF0, 0x0F, 0xFF, 0xFE, 0x80, 0x07, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, + 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, + 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, + 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, 0xF0, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xFE, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_OVERCAST[] = { - 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, - 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC1, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFE, - 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xF8, 0xFF, 0xFF, - 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xF0, 0x7F, 0xFF, 0xFF, 0xC0, 0x3F, 0x80, - 0x0F, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0xFF, 0xFF, 0x87, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0x0F, - 0xFC, 0x1F, 0x81, 0xFF, 0xFF, 0x1F, 0xFC, 0x3F, 0xE1, 0xFF, 0xFE, 0x1F, 0xF8, 0x7F, 0xF0, 0xFF, - 0xFE, 0x3F, 0xF8, 0x7F, 0xF0, 0xFF, 0xFE, 0x3F, 0xF8, 0xFF, 0xF8, 0xFF, 0xFE, 0x3F, 0xF8, 0xFF, - 0xF8, 0xFF, 0xFE, 0x3F, 0xF8, 0xFF, 0xF8, 0xFF, 0xFE, 0x1F, 0xC0, 0xFF, 0xF8, 0xFF, 0xFE, 0x1F, - 0x80, 0xFF, 0xF8, 0xFF, 0xFF, 0x0E, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0x06, 0x0F, 0xFF, 0xF8, 0xFF, - 0xFF, 0x8C, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0x88, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, - 0xF8, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, - 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xF8, 0xFF, - 0xFF, 0xF1, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, - 0xF8, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC, - 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xF8, 0xFF, - 0xFF, 0xFF, 0x80, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, - 0xF0, 0xFF, 0xFF, 0xFF, 0xF8, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xE1, 0xFF, 0xFF, 0xFF, - 0xFC, 0x1F, 0xC1, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, + 0xFF, 0xFF, 0xFE, 0x1F, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xC7, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE3, 0xFF, + 0xFF, 0xF0, 0x00, 0xFF, 0xE3, 0xFF, 0xFF, 0xE0, 0x60, 0x7F, 0xF0, 0xFF, 0xFF, 0xC3, 0xFC, 0x3F, 0xF0, 0x1F, + 0xFF, 0x87, 0xFE, 0x1F, 0xF0, 0x0F, 0xFF, 0x8F, 0xFF, 0x0F, 0xFF, 0x87, 0xFF, 0x1F, 0xFF, 0x8F, 0xFF, 0xE3, + 0xFF, 0x1F, 0xFF, 0x8F, 0xFF, 0xE3, 0xFC, 0x1F, 0xFF, 0xC0, 0x7F, 0xF1, 0xF8, 0x3F, 0xFF, 0xC0, 0x3F, 0xF1, + 0xE0, 0x7F, 0xFF, 0xFC, 0x1F, 0xF1, 0xE3, 0xFF, 0xFF, 0xFF, 0x0F, 0xF1, 0xC7, 0xFF, 0xFF, 0xFF, 0xC7, 0xE3, + 0xC7, 0xFF, 0xFF, 0xFF, 0xC7, 0xE3, 0x8F, 0xFF, 0xFF, 0xFF, 0xE3, 0x87, 0x8F, 0xFF, 0xFF, 0xFF, 0xE2, 0x0F, + 0x8F, 0xFF, 0xFF, 0xFF, 0xE2, 0x1F, 0x8F, 0xFF, 0xFF, 0xFF, 0xE3, 0x7F, 0x8F, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, + 0xC7, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, + 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_FOG[] = { - 0xFF, 0xFF, 0xFD, 0xE7, 0xFF, 0x0F, 0xFF, 0xFF, 0xE1, 0xC3, 0xFF, 0x0F, 0xFF, 0xFF, 0xC1, 0xC3, - 0xFF, 0x0F, 0xFF, 0xFF, 0x81, 0xC3, 0xFF, 0x0F, 0xFF, 0xFF, 0x01, 0xC3, 0xFF, 0x0F, 0xFF, 0xFE, - 0x07, 0xC3, 0xFF, 0x0F, 0xFF, 0xFE, 0x0F, 0xC3, 0xCF, 0x0F, 0xFF, 0xFC, 0x1F, 0xC3, 0x87, 0x0F, - 0xFF, 0xFC, 0x1F, 0xC3, 0x87, 0x0F, 0xFF, 0xFC, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xFC, 0x3F, 0xC3, - 0x87, 0x0F, 0xFF, 0xFC, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xF0, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xC0, - 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0x80, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0x00, 0x3F, 0xC3, 0x87, 0x0F, - 0xFE, 0x07, 0xFF, 0xC3, 0x87, 0x0F, 0xFC, 0x0F, 0xFF, 0xC3, 0x87, 0x0F, 0xFC, 0x1F, 0xFF, 0xC3, - 0x87, 0x0F, 0xF8, 0x3F, 0xFF, 0xC3, 0x87, 0x0F, 0xF8, 0x7F, 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0x7F, - 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0x7F, 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0xFF, 0xFF, 0xC3, 0x87, 0x0F, - 0xF0, 0xFF, 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0xFF, 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0xFF, 0xFF, 0xC3, - 0x87, 0x0F, 0xF0, 0xFF, 0xFF, 0xC3, 0x87, 0x0F, 0xF0, 0x7F, 0xFF, 0xC3, 0x87, 0x0F, 0xF8, 0x7F, - 0xFF, 0xC3, 0x87, 0x0F, 0xF8, 0x3F, 0xFF, 0xC3, 0x87, 0x0F, 0xF8, 0x3F, 0xFF, 0xC3, 0x87, 0x0F, - 0xFC, 0x1F, 0xFF, 0xC3, 0x87, 0x0F, 0xFE, 0x07, 0xFF, 0xC3, 0x87, 0x0F, 0xFE, 0x00, 0xFF, 0xC3, - 0x87, 0x0F, 0xFF, 0x00, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xC0, 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xE0, - 0x3F, 0xC3, 0x87, 0x0F, 0xFF, 0xFC, 0x1F, 0xC3, 0x87, 0x0F, 0xFF, 0xFC, 0x1F, 0xC3, 0x87, 0x0F, - 0xFF, 0xFE, 0x0F, 0xC3, 0x87, 0x0F, 0xFF, 0xFE, 0x07, 0xC3, 0x87, 0x0F, 0xFF, 0xFF, 0x03, 0xC3, - 0x87, 0x1F, 0xFF, 0xFF, 0x81, 0xC3, 0x87, 0xFF, 0xFF, 0xFF, 0xC1, 0xC3, 0x87, 0xFF, 0xFF, 0xFF, - 0xE1, 0xC3, 0x87, 0xFF, 0xFF, 0xFF, 0xF9, 0xC7, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC1, 0xFF, 0xFF, + 0xFF, 0xFE, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xF8, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFC, 0x7F, 0xFF, + 0xFF, 0xF8, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFE, 0x01, 0xFF, + 0xFF, 0x80, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0x1F, 0xFF, 0xFF, 0xFC, 0x3F, + 0xFE, 0x3F, 0xFF, 0xFF, 0xFE, 0x1F, 0xFE, 0x3F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, 0xFF, + 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_DRIZZLE[] = { - 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0x03, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x07, 0xFC, 0x0F, 0xFF, 0xFF, 0xFE, 0x0F, 0xFE, 0x0F, 0xFF, - 0xFF, 0xFC, 0x1F, 0xFF, 0x07, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0x07, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, - 0x87, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0x87, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, - 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xC0, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, - 0x00, 0x7F, 0xF8, 0x3F, 0xFF, 0xFE, 0x00, 0x3F, 0xF8, 0x3F, 0xE1, 0xFC, 0x00, 0x3F, 0xF0, 0x7F, - 0xC0, 0xF8, 0x00, 0x3F, 0xF0, 0x7F, 0xC0, 0xF0, 0x00, 0x3F, 0xF0, 0xFF, 0xE1, 0xF8, 0x00, 0x3F, - 0xF0, 0xFF, 0xFF, 0xFC, 0x00, 0x3F, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, - 0x80, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xF0, 0x7F, 0xFF, 0x83, 0xFF, 0xFF, 0xF0, 0x7F, - 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x7F, 0xFC, 0x01, 0xFF, 0xFF, 0xF8, 0x3F, 0xFC, 0x01, 0xFF, 0xFF, - 0xF8, 0x1F, 0xFE, 0x03, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x83, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xEF, - 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x87, 0xFF, 0xFF, 0xC0, - 0x3F, 0xFF, 0x87, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0x87, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0x07, 0xFF, - 0xFF, 0xFC, 0x1F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFE, 0x0F, 0xFE, 0x0F, 0xFF, 0xFF, 0xFE, 0x07, 0xFC, - 0x1F, 0xFF, 0xFF, 0xFF, 0x01, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, - 0xC0, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0xF8, 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, + 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, + 0xFF, 0xC7, 0xFF, 0xFF, 0x03, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x3F, + 0xF0, 0x07, 0xFF, 0xFF, 0x00, 0x0F, 0xF0, 0x7F, 0xFF, 0x9F, 0xFE, 0x0F, 0xE1, 0xFF, 0xFF, 0x8F, 0xFF, 0x87, + 0xC3, 0xFF, 0xFF, 0x0F, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0x0F, 0xFF, 0xC3, 0xC7, 0xFF, 0xBF, 0x9F, 0xFF, 0xE3, + 0x87, 0xFF, 0x1F, 0xFF, 0xFF, 0xE1, 0x87, 0xFE, 0x1F, 0xFF, 0xFF, 0xE1, 0x87, 0xFE, 0x0F, 0xFF, 0xFF, 0xE1, + 0x87, 0xFC, 0x0F, 0xFF, 0xFF, 0xE1, 0xC7, 0xFC, 0x0F, 0xFF, 0xFF, 0xE3, 0xC3, 0xFE, 0x0F, 0x9F, 0xFF, 0xC3, + 0xC3, 0xFF, 0x1F, 0x0F, 0xFF, 0xC3, 0xE1, 0xFF, 0xFE, 0x07, 0xFF, 0x87, 0xF0, 0x7F, 0xFE, 0x07, 0xFE, 0x0F, + 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x0F, 0xFC, 0x03, 0xF0, 0x3F, 0xFE, 0x0F, 0xF8, 0x01, 0xF0, 0x7F, + 0xFF, 0xCF, 0xF8, 0x01, 0xF3, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_RAIN[] = { - 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, - 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, - 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFC, - 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, - 0xFE, 0x07, 0xFF, 0xFF, 0xFE, 0x01, 0xFE, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x0F, 0xFF, - 0xF0, 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0xF0, 0x3F, 0xFF, 0xE0, 0x00, 0xFF, 0xE0, 0xFF, 0xFF, 0xFE, - 0x00, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, - 0xFE, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0x87, 0xFF, 0xFE, 0x00, 0x07, 0xFF, - 0x87, 0xFF, 0xFF, 0x80, 0x00, 0x7F, 0x87, 0xFF, 0xFF, 0xF8, 0x00, 0x0F, 0x87, 0xFF, 0xFF, 0xFF, - 0x00, 0x01, 0x87, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0x83, 0xFF, 0xFE, 0x1F, 0xFE, 0x01, 0x83, 0xFF, - 0xFE, 0x01, 0xFF, 0xE3, 0xC3, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC1, 0xFF, 0xFE, 0x00, 0x03, 0xFF, - 0xC0, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x00, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, - 0x80, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xF1, 0xFF, 0xFC, 0x01, 0xFF, 0xFC, 0x3F, 0xFF, 0xFE, 0x01, - 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x81, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, - 0xFF, 0xE0, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, - 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0xF8, 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, + 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, + 0xFF, 0x87, 0xFF, 0xFF, 0x03, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x3F, + 0xF0, 0x07, 0xFF, 0xFF, 0x00, 0x0F, 0xF0, 0x7F, 0xFF, 0xFF, 0xFE, 0x0F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, + 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, + 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x87, 0xFF, 0xDF, 0x9F, 0x3F, 0xE1, + 0x87, 0xFF, 0x8F, 0x1F, 0x1F, 0xE1, 0xC7, 0xFF, 0x8F, 0x0E, 0x1F, 0xE3, 0xC3, 0xFF, 0x0F, 0x1E, 0x1F, 0xC3, + 0xC1, 0xFF, 0x0E, 0x1E, 0x3F, 0x83, 0xE0, 0xFF, 0x1E, 0x1C, 0x3F, 0x87, 0xF0, 0x7E, 0x1E, 0x3C, 0x3E, 0x0F, + 0xF8, 0x0E, 0x1E, 0x3C, 0x70, 0x1F, 0xFC, 0x0E, 0x3C, 0x3C, 0x70, 0x3F, 0xFE, 0x0E, 0x3C, 0x38, 0x70, 0x7F, + 0xFF, 0xEC, 0x3C, 0x78, 0x7F, 0xFF, 0xFF, 0xFC, 0x38, 0x78, 0xFF, 0xFF, 0xFF, 0xFC, 0x78, 0x70, 0xFF, 0xFF, + 0xFF, 0xF8, 0x78, 0xF0, 0xFF, 0xFF, 0xFF, 0xF8, 0x78, 0xF1, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0xF1, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_SNOW[] = { - 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, - 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, - 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, - 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFC, - 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFC, 0x3C, 0x3F, - 0xF0, 0x0F, 0xFF, 0xFC, 0x3C, 0x3F, 0xF0, 0x3F, 0xFF, 0xFC, 0x3C, 0x3F, 0xE0, 0xFF, 0xFF, 0xFE, - 0x7E, 0x7F, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xE7, 0xE7, 0xF3, 0x87, 0xFF, 0xFF, 0xC3, 0xC3, 0xE1, - 0x87, 0xFF, 0xFF, 0xC3, 0xC3, 0xE1, 0x87, 0xFF, 0xFF, 0xC3, 0xC3, 0xE1, 0x87, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x83, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x3C, 0x3F, 0xC1, 0xFF, 0xFF, 0xFC, 0x3C, 0x3F, - 0xC0, 0xFF, 0xFF, 0xFC, 0x3C, 0x3F, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFC, 0x3F, 0xFF, 0xFE, 0x01, - 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x81, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, - 0xFF, 0xE0, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, - 0x7F, 0xFF, 0xFF, 0xF8, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, - 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0xF8, 0x3F, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x7F, 0xFF, + 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, + 0xFF, 0x87, 0xFF, 0xFF, 0x03, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x3F, + 0xF0, 0x07, 0xFF, 0xFF, 0x00, 0x1F, 0xF0, 0x7F, 0xFF, 0xFF, 0xFE, 0x0F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, + 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, + 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, + 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, + 0xC3, 0xFF, 0xFE, 0x3F, 0xFF, 0x83, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0x07, 0xF0, 0x7F, 0xFE, 0x7F, 0xFE, 0x0F, + 0xF0, 0x0F, 0x3F, 0xFC, 0xF0, 0x1F, 0xFC, 0x0E, 0x1F, 0xF8, 0x70, 0x3F, 0xFE, 0x0F, 0x1F, 0xFC, 0x70, 0x7F, + 0xFF, 0xEF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFC, 0xFF, 0xFF, + 0xFF, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; static const uint8_t WI48_THUNDERSTORM[] = { - 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, - 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, - 0x3F, 0x81, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xFF, - 0xFF, 0xC1, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xC1, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xC3, 0xFF, 0xF8, - 0x7F, 0xFF, 0xFF, 0xC3, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xC3, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0x03, - 0xFC, 0x0F, 0xFF, 0xFF, 0xFC, 0x03, 0xFC, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFC, 0x00, 0x0F, 0xFF, - 0xE0, 0x1F, 0xFE, 0x00, 0x03, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xC1, 0xFF, 0xFF, 0xFE, - 0x01, 0xFF, 0x83, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0x83, 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0x07, 0xFF, - 0xFC, 0x07, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x0F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, - 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0x0F, 0xFF, 0xFF, 0xFF, - 0x00, 0x03, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x03, 0x07, 0xFF, 0xFD, 0xFF, 0xFF, 0x03, 0x07, 0xFF, - 0xFC, 0x7F, 0x9F, 0xFF, 0x87, 0xFF, 0xFC, 0x1F, 0x8F, 0xFF, 0x83, 0xFF, 0xFC, 0x07, 0x83, 0xFF, - 0x81, 0xFF, 0xFC, 0x01, 0x81, 0xFF, 0xC0, 0xFF, 0xFC, 0x00, 0x80, 0x7F, 0xE0, 0x7F, 0xFC, 0x00, - 0x00, 0x3F, 0xF0, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x03, 0xFE, 0x00, 0x04, 0x07, 0xFC, 0x03, - 0xFF, 0xC0, 0x07, 0xC1, 0xFF, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xC1, 0xFF, 0xF0, 0x07, 0xFF, - 0xFF, 0xE1, 0xFF, 0xF0, 0xC7, 0xFF, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xE0, 0x7F, 0xC1, - 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, - 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xC0, 0xFF, 0xFF, + 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0xE0, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, + 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x01, 0xFF, + 0xFE, 0x07, 0xFF, 0xFF, 0x00, 0x7F, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x1F, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x0F, + 0xE0, 0x7F, 0xFF, 0xFF, 0xFE, 0x07, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, + 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, + 0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0x87, 0xF8, 0x0F, 0x9F, 0xBF, 0xE1, 0x87, 0xF8, 0x1F, 0x0F, 0x1F, 0xE1, + 0xC7, 0xF0, 0x1F, 0x1E, 0x1F, 0xE3, 0xC3, 0xF0, 0x3F, 0x1E, 0x1F, 0xC3, 0xC1, 0xE0, 0x3E, 0x1E, 0x3F, 0x83, + 0xE0, 0xE0, 0x7E, 0x1E, 0x3F, 0x07, 0xF0, 0x60, 0x7E, 0x3C, 0x3E, 0x0F, 0xF8, 0x00, 0xFE, 0x3C, 0x30, 0x1F, + 0xFC, 0x00, 0xFC, 0x3C, 0x70, 0x3F, 0xFF, 0x01, 0xFC, 0x3C, 0x70, 0x7F, 0xFF, 0x81, 0xFC, 0x78, 0x7F, 0xFF, + 0xFF, 0x80, 0x1C, 0x78, 0x7F, 0xFF, 0xFF, 0x00, 0x18, 0x78, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x78, 0xFF, 0xFF, + 0xFF, 0xF0, 0x78, 0xF0, 0xFF, 0xFF, 0xFF, 0xF8, 0x78, 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF1, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xF1, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE7, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; diff --git a/scripts/convert_icon.py b/scripts/convert_icon.py index 56ea7d4b..81585636 100644 --- a/scripts/convert_icon.py +++ b/scripts/convert_icon.py @@ -3,36 +3,113 @@ import os from PIL import Image import cairosvg import io +import xml.etree.ElementTree as ET threshold = 128 + +def parse_svg_intrinsic_size(svg_data): + try: + root = ET.fromstring(svg_data) + except ET.ParseError: + return None, None + + viewbox = root.get("viewBox") or root.get("viewbox") + if viewbox: + parts = viewbox.replace(",", " ").split() + if len(parts) == 4: + try: + vb_w = float(parts[2]) + vb_h = float(parts[3]) + if vb_w > 0 and vb_h > 0: + return vb_w, vb_h + except ValueError: + pass + + def parse_len(value): + if not value: + return None + cleaned = "".join(ch for ch in value if ch.isdigit() or ch in ".-") + if not cleaned: + return None + try: + parsed = float(cleaned) + return parsed if parsed > 0 else None + except ValueError: + return None + + w = parse_len(root.get("width")) + h = parse_len(root.get("height")) + return w, h + + +def fit_inside_canvas(src_w, src_h, dst_w, dst_h): + if src_w <= 0 or src_h <= 0 or dst_w <= 0 or dst_h <= 0: + return dst_w, dst_h + + src_ratio = src_w / src_h + dst_ratio = dst_w / dst_h + + if src_ratio >= dst_ratio: + fit_w = dst_w + fit_h = max(1, int(round(fit_w / src_ratio))) + else: + fit_h = dst_h + fit_w = max(1, int(round(fit_h * src_ratio))) + + return fit_w, fit_h + + def svg_to_png_bytes(svg_path, width, height): - with open(svg_path, 'rb') as f: + with open(svg_path, "rb") as f: svg_data = f.read() - png_bytes = cairosvg.svg2png(bytestring=svg_data, output_width=width, output_height=height) + + src_w, src_h = parse_svg_intrinsic_size(svg_data) + render_w, render_h = fit_inside_canvas( + src_w or width, src_h or height, width, height + ) + + png_bytes = cairosvg.svg2png( + bytestring=svg_data, output_width=render_w, output_height=render_h + ) return png_bytes + +def center_on_canvas(img, width, height): + if img.mode != "RGBA": + img = img.convert("RGBA") + canvas = Image.new("RGBA", (width, height), (255, 255, 255, 255)) + x = (width - img.width) // 2 + y = (height - img.height) // 2 + canvas.paste(img, (x, y), img) + return canvas + + def load_image(path, width, height): ext = os.path.splitext(path)[1].lower() - if ext == '.svg': + if ext == ".svg": png_bytes = svg_to_png_bytes(path, width, height) - img = Image.open(io.BytesIO(png_bytes)) + img = Image.open(io.BytesIO(png_bytes)).convert("RGBA") + img = center_on_canvas(img, width, height) else: - img = Image.open(path) - img = img.convert('RGBA') - img = img.resize((width, height), Image.LANCZOS) + img = Image.open(path).convert("RGBA") + # Keep source aspect ratio and fit inside requested canvas. + fit = img.copy() + fit.thumbnail((width, height), Image.LANCZOS) + img = center_on_canvas(fit, width, height) # Flatten alpha: paste on white background - background = Image.new('RGBA', img.size, (255, 255, 255, 255)) + background = Image.new("RGBA", img.size, (255, 255, 255, 255)) background.paste(img, mask=img.split()[3]) img = background # Rotate 90 degrees counterclockwise img = img.rotate(90, expand=True) return img + def image_to_c_array(img, array_name): # Convert to grayscale, then threshold to get white=1, black=0 # Convert to grayscale - img = img.convert('L') + img = img.convert("L") width, height = img.size pixels = list(img.getdata()) packed = [] @@ -44,37 +121,39 @@ def image_to_c_array(img, array_name): v = pixels[y * width + x + b] # 1 for white, 0 for black bit = 1 if v >= threshold else 0 - byte |= (bit << (7 - b)) + byte |= bit << (7 - b) packed.append(byte) # Format as C array - c = f'#pragma once\n#include \n\n' - c += f'// size: {width}x{height}\n' - c += f'static const uint8_t {array_name}[] = {{\n ' + c = f"#pragma once\n#include \n\n" + c += f"// size: {width}x{height}\n" + c += f"static const uint8_t {array_name}[] = {{\n " for i, v in enumerate(packed): - c += f'0x{v:02X}, ' + c += f"0x{v:02X}, " if (i + 1) % 16 == 0: - c += '\n ' - c = c.rstrip(', \n') + '\n};\n' + c += "\n " + c = c.rstrip(", \n") + "\n};\n" return c + def main(): if len(sys.argv) < 5: - print('Usage: python convert_image.py input.png output_name width height') + print("Usage: python convert_image.py input.png output_name width height") sys.exit(1) input_path, output_name, width, height = sys.argv[1:5] - array_name = output_name.capitalize() + 'Icon' + array_name = output_name.capitalize() + "Icon" width, height = int(width), int(height) img = load_image(input_path, width, height) c_array = image_to_c_array(img, array_name) # Always save to src/components/icons/[output_name].h relative to project root project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - output_dir = os.path.join(project_root, 'src', 'components', 'icons') + output_dir = os.path.join(project_root, "src", "components", "icons") os.makedirs(output_dir, exist_ok=True) - output_path = os.path.join(output_dir, f'{output_name}.h') - with open(output_path, 'w') as f: + output_path = os.path.join(output_dir, f"{output_name}.h") + with open(output_path, "w") as f: f.write(c_array) - print(f'Wrote {output_path}') + print(f"Wrote {output_path}") -if __name__ == '__main__': - main() \ No newline at end of file + +if __name__ == "__main__": + main() diff --git a/scripts/generate_weather_icons.py b/scripts/generate_weather_icons.py new file mode 100644 index 00000000..c1ef2cb0 --- /dev/null +++ b/scripts/generate_weather_icons.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python3 +""" +Generate lib/Weather/WeatherIcons48.h from SVG sources. + +By default, this script loads SVG files from assets/weather-icons/svg. +Use --fetch to download missing files from erikflowers/weather-icons. +""" + +import argparse +import io +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import urllib.request +import xml.etree.ElementTree as ET +import zipfile + +from PIL import Image + +try: + import cairosvg # type: ignore +except Exception: + cairosvg = None + + +SIZE = 48 +THRESHOLD = 128 +CONTENT_MARGIN = 1 +PROJECT_ROOT = Path(__file__).resolve().parent.parent +DEFAULT_SVG_DIR = PROJECT_ROOT / "assets" / "weather-icons" / "svg" +DEFAULT_OUT = PROJECT_ROOT / "lib" / "Weather" / "WeatherIcons48.h" +UPSTREAM_BASE = "https://raw.githubusercontent.com/erikflowers/weather-icons/master/svg" +RESVG_ZIP_URL = ( + "https://github.com/linebender/resvg/releases/latest/download/resvg-win64.zip" +) +RESVG_EXE = PROJECT_ROOT / ".cache" / "resvg" / "resvg.exe" + +ICON_SOURCES = { + "WI48_CLEAR_DAY": "wi-day-sunny.svg", + "WI48_CLEAR_NIGHT": "wi-night-clear.svg", + "WI48_PARTLY_CLOUDY_DAY": "wi-day-cloudy.svg", + "WI48_PARTLY_CLOUDY_NIGHT": "wi-night-alt-cloudy.svg", + "WI48_OVERCAST": "wi-cloudy.svg", + "WI48_FOG": "wi-fog.svg", + "WI48_DRIZZLE": "wi-sprinkle.svg", + "WI48_RAIN": "wi-rain.svg", + "WI48_SNOW": "wi-snow.svg", + "WI48_THUNDERSTORM": "wi-thunderstorm.svg", +} + + +def parse_svg_intrinsic_size(svg_data): + try: + root = ET.fromstring(svg_data) + except ET.ParseError: + return None, None + + viewbox = root.get("viewBox") or root.get("viewbox") + if viewbox: + parts = viewbox.replace(",", " ").split() + if len(parts) == 4: + try: + vb_w = float(parts[2]) + vb_h = float(parts[3]) + if vb_w > 0 and vb_h > 0: + return vb_w, vb_h + except ValueError: + pass + + def parse_len(value): + if not value: + return None + cleaned = "".join(ch for ch in value if ch.isdigit() or ch in ".-") + if not cleaned: + return None + try: + parsed = float(cleaned) + return parsed if parsed > 0 else None + except ValueError: + return None + + return parse_len(root.get("width")), parse_len(root.get("height")) + + +def fit_inside_canvas(src_w, src_h, dst_w, dst_h): + if src_w <= 0 or src_h <= 0: + return dst_w, dst_h + + src_ratio = src_w / src_h + dst_ratio = dst_w / dst_h + if src_ratio >= dst_ratio: + fit_w = dst_w + fit_h = max(1, int(round(fit_w / src_ratio))) + else: + fit_h = dst_h + fit_w = max(1, int(round(fit_h * src_ratio))) + return fit_w, fit_h + + +def ensure_resvg_binary(): + if shutil.which("resvg"): + return Path(shutil.which("resvg")) + + if RESVG_EXE.exists(): + return RESVG_EXE + + RESVG_EXE.parent.mkdir(parents=True, exist_ok=True) + archive_path = RESVG_EXE.parent / "resvg.zip" + with urllib.request.urlopen(RESVG_ZIP_URL) as response: + archive_path.write_bytes(response.read()) + + with zipfile.ZipFile(archive_path, "r") as zf: + zf.extractall(RESVG_EXE.parent) + + found = list(RESVG_EXE.parent.rglob("resvg.exe")) + if not found: + raise RuntimeError("resvg.exe not found after extraction") + + if found[0] != RESVG_EXE: + RESVG_EXE.write_bytes(found[0].read_bytes()) + + return RESVG_EXE + + +def render_svg_with_resvg(svg_data, render_w, render_h): + exe = ensure_resvg_binary() + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + in_svg = tmp_path / "icon.svg" + out_png = tmp_path / "icon.png" + in_svg.write_bytes(svg_data) + + cmd = [ + str(exe), + "--width", + str(render_w), + "--height", + str(render_h), + str(in_svg), + str(out_png), + ] + subprocess.run(cmd, check=True, capture_output=True) + return out_png.read_bytes() + + +def render_svg_contain(svg_data, width, height): + src_w, src_h = parse_svg_intrinsic_size(svg_data) + render_w, render_h = fit_inside_canvas( + src_w or width, src_h or height, width, height + ) + + # Render larger first so trimming and re-fit preserve detail quality. + oversample = 4 + render_w *= oversample + render_h *= oversample + + if cairosvg is not None: + png_bytes = cairosvg.svg2png( + bytestring=svg_data, output_width=render_w, output_height=render_h + ) + else: + png_bytes = render_svg_with_resvg(svg_data, render_w, render_h) + + icon = Image.open(io.BytesIO(png_bytes)).convert("RGBA") + + # Trim transparent/empty margins so symbols use available icon area better. + alpha_bbox = icon.split()[3].getbbox() + if alpha_bbox is not None: + icon = icon.crop(alpha_bbox) + + max_w = max(1, width - 2 * CONTENT_MARGIN) + max_h = max(1, height - 2 * CONTENT_MARGIN) + icon.thumbnail((max_w, max_h), Image.Resampling.LANCZOS) + + canvas = Image.new("RGBA", (width, height), (255, 255, 255, 255)) + off_x = (width - icon.width) // 2 + off_y = (height - icon.height) // 2 + canvas.paste(icon, (off_x, off_y), icon) + + # Flatten alpha on white and convert to monochrome-friendly grayscale. + flat = Image.new("RGBA", canvas.size, (255, 255, 255, 255)) + flat.paste(canvas, mask=canvas.split()[3]) + return flat.convert("L") + + +def image_to_packed_bits(img): + width, height = img.size + pixels = img.tobytes() + packed = [] + for y in range(height): + for x in range(0, width, 8): + out = 0 + for b in range(8): + px = x + b + lum = pixels[y * width + px] if px < width else 255 + # 1-bit means white/clear (not drawn), 0-bit means black/drawn. + bit = 1 if lum >= THRESHOLD else 0 + out |= bit << (7 - b) + packed.append(out) + return packed + + +def format_array(name, data): + lines = [] + per_line = 16 + for i in range(0, len(data), per_line): + chunk = data[i : i + per_line] + lines.append(" " + ", ".join(f"0x{v:02X}" for v in chunk) + ",") + body = "\n".join(lines) + return f"static const uint8_t {name}[] = {{\n{body}\n}};\n" + + +def ensure_svg(path, fetch): + if path.exists(): + return + if not fetch: + raise FileNotFoundError(f"Missing SVG: {path}") + + path.parent.mkdir(parents=True, exist_ok=True) + url = f"{UPSTREAM_BASE}/{path.name}" + with urllib.request.urlopen(url) as response: + data = response.read() + path.write_bytes(data) + + +def generate(svg_dir, output_path, fetch): + arrays = [] + for symbol, filename in ICON_SOURCES.items(): + svg_path = svg_dir / filename + ensure_svg(svg_path, fetch) + svg_data = svg_path.read_bytes() + img = render_svg_contain(svg_data, SIZE, SIZE) + packed = image_to_packed_bits(img) + arrays.append(format_array(symbol, packed)) + + header = [ + "#pragma once", + "#include ", + "", + "// Generated from erikflowers/weather-icons SVGs.", + "// 48x48, 1-bit, MSB-first, row-major.", + "// Regenerate with: python scripts/generate_weather_icons.py --fetch", + "", + ] + header.extend(arrays) + + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text("\n".join(header) + "\n", encoding="utf-8") + + +def main(): + parser = argparse.ArgumentParser( + description="Generate WeatherIcons48.h from SVG files" + ) + parser.add_argument( + "--svg-dir", + type=Path, + default=DEFAULT_SVG_DIR, + help="Directory containing source SVG files", + ) + parser.add_argument( + "--output", type=Path, default=DEFAULT_OUT, help="Output header path" + ) + parser.add_argument( + "--fetch", action="store_true", help="Fetch missing SVG files from upstream" + ) + args = parser.parse_args() + + generate(args.svg_dir, args.output, args.fetch) + rel_out = os.path.relpath(args.output, PROJECT_ROOT) + print(f"Wrote {rel_out}") + + +if __name__ == "__main__": + main() diff --git a/src/activities/weather/WeatherActivity.cpp b/src/activities/weather/WeatherActivity.cpp index d5183b36..5c4502cb 100644 --- a/src/activities/weather/WeatherActivity.cpp +++ b/src/activities/weather/WeatherActivity.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -29,79 +28,18 @@ inline bool getBitmapBit(const uint8_t* bitmap, const int size, const int x, con return (bitmap[idx] & mask) != 0; } -inline void setBitmapBit(uint8_t* bitmap, const int size, const int x, const int y, const bool value) { - const int rowBytes = size / 8; - const int idx = y * rowBytes + (x / 8); - const uint8_t mask = static_cast(0x80 >> (x % 8)); - if (value) { - bitmap[idx] |= mask; - } else { - bitmap[idx] &= static_cast(~mask); - } -} - void drawWeatherIconWithOrientation(const GfxRenderer& renderer, const uint8_t* icon, const int x, const int y, const int size) { - // Weather activity uses LandscapeClockwise; rotate icon pixels 90deg so - // directional glyphs align with the landscape-oriented UI. - if (renderer.getOrientation() != GfxRenderer::Orientation::LandscapeClockwise) { - renderer.drawImage(icon, x, y, size, size); - return; - } - - constexpr int kLargeIconBytes = (WEATHER_ICON_LARGE * WEATHER_ICON_LARGE) / 8; - std::array rotatedRaw{}; - rotatedRaw.fill(0xFF); - for (int srcY = 0; srcY < size; srcY++) { for (int srcX = 0; srcX < size; srcX++) { - // 90deg counter-clockwise: (x, y) -> (y, size - 1 - x) - const int dstX = srcY; - const int dstY = size - 1 - srcX; - setBitmapBit(rotatedRaw.data(), size, dstX, dstY, getBitmapBit(icon, size, srcX, srcY)); - } - } - - // Re-center rotated icon by its painted-pixel bounds to avoid asymmetric - // source padding appearing as left-side clipping after rotation. - int minX = size, minY = size, maxX = -1, maxY = -1; - for (int py = 0; py < size; py++) { - for (int px = 0; px < size; px++) { - if (!getBitmapBit(rotatedRaw.data(), size, px, py)) { - minX = std::min(minX, px); - minY = std::min(minY, py); - maxX = std::max(maxX, px); - maxY = std::max(maxY, py); - } - } - } - - if (maxX < minX || maxY < minY) { - renderer.drawImage(rotatedRaw.data(), x, y, size, size); - return; - } - - const int bboxW = maxX - minX + 1; - const int bboxH = maxY - minY + 1; - const int targetMinX = (size - bboxW) / 2; - const int targetMinY = (size - bboxH) / 2; - const int shiftX = targetMinX - minX; - const int shiftY = targetMinY - minY; - - std::array rotatedCentered{}; - rotatedCentered.fill(0xFF); - for (int py = 0; py < size; py++) { - for (int px = 0; px < size; px++) { - const int dstX = px + shiftX; - const int dstY = py + shiftY; - if (dstX < 0 || dstX >= size || dstY < 0 || dstY >= size) { + // 0 bits are black (drawn) in these icon bitmaps. + if (getBitmapBit(icon, size, srcX, srcY)) { continue; } - setBitmapBit(rotatedCentered.data(), size, dstX, dstY, getBitmapBit(rotatedRaw.data(), size, px, py)); + + renderer.drawPixel(x + srcX, y + srcY); } } - - renderer.drawImage(rotatedCentered.data(), x, y, size, size); } StrId getWeatherDescriptionStrId(const int wmoCode) { @@ -193,6 +131,8 @@ void WeatherActivity::onExit() { } void WeatherActivity::loadAndDisplay() { + constexpr long CACHE_REFRESH_AGE_SECONDS = 30L * 60L; + if (!WEATHER_SETTINGS.hasLocation()) { state = State::ERROR; errorMessage = tr(STR_WEATHER_NO_LOCATION); @@ -203,23 +143,23 @@ void WeatherActivity::loadAndDisplay() { // Try cache first WeatherData cached = WeatherClient::getWeather(WEATHER_SETTINGS, forceRefresh); if (cached.valid) { - const bool shouldRefresh = forceRefresh; - if (!shouldRefresh) { - const time_t now = time(nullptr); - const long age = (cached.fetchedAt > 0) ? static_cast(now - cached.fetchedAt) : -1; - if (age >= 0 && age > 30L * 60L) { - LOG_DBG("WEA", "Displayed stale cache (age=%ld s); scheduling refresh", age); - } else { - LOG_DBG("WEA", "Displayed cache (age=%ld s)", age); - } + const time_t now = time(nullptr); + const long age = (cached.fetchedAt > 0) ? static_cast(now - cached.fetchedAt) : -1; + const bool cacheIsStale = (age >= 0 && age > CACHE_REFRESH_AGE_SECONDS) || age < 0; + const bool shouldBackgroundRefresh = forceRefresh || cacheIsStale; + + if (cacheIsStale) { + LOG_DBG("WEA", "Displayed stale cache (age=%ld s); scheduling refresh", age); + } else { + LOG_DBG("WEA", "Displayed fresh cache (age=%ld s); skip auto-refresh", age); } weatherData = std::move(cached); state = State::WEATHER_DISPLAY; requestUpdate(); - // After first paint, refresh stale/non-forced data via WiFi-gated path. - if (!forceRefresh) { + // Refresh only when forced or when cache is stale. + if (shouldBackgroundRefresh) { checkAndConnectWifi(); } return; @@ -300,6 +240,7 @@ void WeatherActivity::loop() { if (state == State::ERROR) { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { // Open weather settings (useful when no location is configured) + renderer.setOrientation(GfxRenderer::Orientation::Portrait); startActivityForResult(std::make_unique(renderer, mappedInput), [this](const ActivityResult&) { renderer.setOrientation(GfxRenderer::Orientation::LandscapeClockwise); @@ -359,6 +300,7 @@ void WeatherActivity::loop() { onGoHome(); } else if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { // Open weather settings + renderer.setOrientation(GfxRenderer::Orientation::Portrait); startActivityForResult(std::make_unique(renderer, mappedInput), [this](const ActivityResult&) { // Re-apply landscape after returning from settings