Красивый способ определить темную тему оформления
У современного десктопа есть две основных темы оформления: темная и светлая. Темные и светлые темы есть и в Windows и в MacOS и в линуксах. Временами необходимо подстроить элементы оформления в своем софте под оформление в ОС. Но определить какая тема используется не так-то просто, поэтому рассказываю про один интересный вариант.
Проблема
Проблема не выдуманная, вы и сами наверняка неоднократно наблюдали различные визуальные артефакты — кусочки интерфейса в светлом стиле, при переключении на темную тему в ОС.
Конечно же у каждой ОС и каждого графического фреймворка есть свои способы получения названия темы оформления и ключевых цветов оформления.
Но во-первых это технически сложно и объемно, во-вторых хотелось-бы универсальное решение, без привязки к реализации.
Поэтому я решил включить голову и подумать.
Оригинальное решение
сделать скриншот экрана или рабочей области, перевести полученную картинку в двухцветный формат и посчитать количество черных и белых пикселей.
Если черных больше чем белых — тема оформления темная, если наоборот — тема светлая.
Реализация на Java и Swing, но легко можно адаптировать под любой язык и графический фреймворк.
public static synchronized boolean isBlackThemedDesktop() {
try {
// получаем изображение со скриншотом
final BufferedImage screenFullImage = createImage(),
// черно-белая копия
bw = new BufferedImage(
screenFullImage.getWidth(),
screenFullImage.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
final Graphics2D g = bw.createGraphics();
// переводим в черно-белую палитру
g.drawImage(screenFullImage, 0, 0, null);
int b = 0, // количество черных пикселей
w = 0; // количество белых
for (int y = 0; y < bw.getHeight(); y++) {
for (int x = 0; x < bw.getWidth(); x++) {
final int p = bw.getRGB(x, y);
// если пиксель черный
if ((p & 0x00FFFFFF) == 0)
b++; // увеличиваем счетчик количества черных
else
w++; // или белых
}
}
return b > w; // если черных пикселей больше чем светлых - тема темная
} catch (Exception e) {
return false;
}
}Теперь про получение скриншота.
К сожалению в MacOS есть специальная проверка на вызов API отвечающего за создание скриншота экрана или любого фрагмента интерфейса:
Чтобы не смущать пользователя таким диалогом, вылезающим без повода, мы пойдем другим путем:
Вместо того чтобы делать скриншот экрана или уже существующего графического элемента, мы такой элемент создадим и отрисуем его в картинку.
private static BufferedImage createImage() {
// создаем виртуальную кнопку
final JButton b = new JButton();
b.setPreferredSize(new Dimension(100, 100));
b.setSize(100, 100);
final BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
final Graphics2D g = bi.createGraphics();
// отрисовываем в картинку
b.print(g);
g.dispose();
return bi;
}Суть тут в том, что созданная кнопка унаследует системное оформление, в том числе ключевые цвета.
Естественно что при темном оформлении, большая часть такой картинки с кнопкой будет также темной, а при светлой — светлой.