Красивый способ определить темную тему оформления
У современного десктопа есть две основных темы оформления: темная и светлая. Темные и светлые темы есть и в 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; }
Суть тут в том, что созданная кнопка унаследует системное оформление, в том числе ключевые цвета.
Естественно что при темном оформлении, большая часть такой картинки с кнопкой будет также темной, а при светлой — светлой.