Управление яркостью в Windows на программном уровне

Возможно, подобный вопрос уже присутствует на сайте, но я много искал и не нашел подходящего решения, поэтому я публикую его здесь.

Я делаю приложение Night Light, которое имеет два варианта:

  1. Уменьшить яркость ПК

  2. Примените маску фильтра синего света поверх экрана.

Я делаю это приложение кроссплатформенным, поэтому я уже нашел решение для систем Linux, где я использовал утилиту xrandr для настройки яркости и гаммы на программном уровне, и мое приложение работает безупречно.

Основная проблема связана с системами Windows, где функция яркости доступна только для портативных экранов, таких как ноутбуки. Я не могу найти никакого решения для этого. Я использовал Qt5 для создания полупрозрачного окна приложения, которое хорошо работает, но не соответствует требованиям, потому что элементы, отображаемые на уровне ядра, не маскируются, например курсор, панель задач, меню «Пуск», центр действий и многое другое.

Я много и много искал, включая Microsoft Developer Network, где документация включала Win32 API, где присутствовала функция яркости, но у меня это не сработало, так как у меня был настольный ПК.

Итак, моя главная проблема заключается в том, как настроить яркость всех ПК с Windows, включая ноутбуки, настольные компьютеры и все остальные.

Я работаю над Python с модулем ctypes. Я не очень хорошо знаком с VC+ и даже не могу позволить себе установить его в своей системе, так как он занимает слишком много памяти и ресурсов.

В первую очередь я хочу изменить вывод, поступающий на физический монитор, то есть изменить значения гаммы, чтобы получить соответствующую яркость и желтый оттенок.

У меня есть что-то под названием gdi32.dll, которое занимается выводом на экраны, но я не могу найти выход, так как в Интернете все рядом с C++.

Кроме того, я даже не могу предоставить свой пробный код, так как я не очень хорошо знаком с кодированием типа C в Python.

Кроме того, то, что я хочу сделать, Intel Graphics Command Center уже делает это на моем рабочем столе. Если это можно сделать на программном уровне, то я знаю, что это возможно и программно.

Может ли кто-нибудь сказать, возможно ли это, о чем я думаю, и если да, то как я могу этого добиться?
Мне не нужен исходный код, мне просто нужен выход для этого.

Возможно, можно использовать GammaRamp из API Gdi32, но я не знаю, с чего начать.

Это тема, которая на самом деле спрашивала об этом, но я не получил здесь ответа, а новичкам запрещено комментировать, поэтому У меня не было другого выбора, кроме как опубликовать этот вопрос здесь.


person Chiku1022    schedule 03.01.2021    source источник


Ответы (2)


Я нашел путь к проблеме.

Мы можем использовать GetDeviceGammaRamp и SetDeviceGammaRamp из библиотеки gdi32.dll в ОС Windows, чтобы установить уровень яркости.

Чтобы вызвать эти функции через Python, мы можем использовать модуль ctypes. Ниже приведен пример кода, который может установить яркость в Windows 10 с помощью Python.

import ctypes


def displayGammaValues(lpRamp):
    """
    Displays the GammaArray of 256 values of R,G,B individually
    :param lpRamp: GammaArray
    :return: None
    """
    print("R values: ", end=' ')
    for j in range(256):
        print(lpRamp[0][j], end=' ')
    print()

    print("G values: ", end=' ')
    for j in range(256):
        print(lpRamp[0][j], end=' ')
    print()

    print("B values: ", end=' ')
    for j in range(256):
        print(lpRamp[0][j], end=' ')
    print(), print()


def changeGammaValues(lpRamp, brightness):
    """
    Modifies the Gamma Values array according to specified 'Brightness' value
    To reset the gamma values to default, call this method with 'Brightness' as 128
    :param lpRamp: GammaArray
    :param brightness: Value of brightness between 0-255
    :return: Modified GammaValue Array
    """
    for i in range(256):
        iValue = i * (brightness + 128)
        if iValue > 65535: iValue = 65535
        lpRamp[0][i] = lpRamp[1][i] = lpRamp[2][i] = iValue
    return lpRamp


if __name__ == '__main__':
    brightness = 100    # can be aby value in 0-255 (as per my system)
    GetDC = ctypes.windll.user32.GetDC
    ReleaseDC = ctypes.windll.user32.ReleaseDC
    SetDeviceGammaRamp = ctypes.windll.gdi32.SetDeviceGammaRamp
    GetDeviceGammaRamp = ctypes.windll.gdi32.GetDeviceGammaRamp

    hdc = ctypes.wintypes.HDC(GetDC(None))
    if hdc:
        GammaArray = ((ctypes.wintypes.WORD * 256) * 3)()
        if GetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)):
            print("Current Gamma Ramp Values are:")
            displayGammaValues(GammaArray)

            GammaArray = changeGammaValues(GammaArray, brightness)

            print("New Current Gamma Ramp Values are:")
            displayGammaValues(GammaArray)

            if SetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)): print("Values set successfully!")
            else: print("Unable to set GammaRamp")
        if ReleaseDC(hdc): print("HDC released")
    else: print("HDC not found")

Это устанавливает значение яркости в диапазоне 0-255. Значения могут различаться в разных системах, поэтому предпочтительным диапазоном яркости является 0–128, где 128 — яркость по умолчанию.

person Chiku1022    schedule 09.01.2021

FYI Windows уже имеет встроенный синий оттенок/изменение цвета монитора. Уменьшение яркости выходов внешнего монитора на рабочем столе, скорее всего, невозможно.

Вам нужно будет каким-то образом подключиться к Windows API, чтобы управлять функциями Windows. Есть некоторая документация о настройке цветовой температуры (сделав ее теплее, вы, по сути, добавит фильтр синего света на экран на веб-сайте Microsoft.

https://docs.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-setmonitorcolortemperature.

Что касается выполнения небольшого CPP-скрипта, который на самом деле может взаимодействовать с Windows, вы можете написать небольшую CPP-программу, затем скомпилировать ее и выполнить из python с помощью (слегка измененной из этот вопрос)

import os
import subprocess

for filename in os.listdir(os.getcwd()):   
    proc = subprocess.Popen(["./prog", filename])
    proc.wait()

Однако, если у вас нет места для установки инструментов компиляции Visual Studio, вы не сможете локально скомпилировать небольшой сценарий CPP. Однако есть несколько онлайн-сервисов, которые могут сделать это за вас.

person Todd Rylaarsdam    schedule 03.01.2021
comment
Большое спасибо, но предложенное вами решение работает не со всеми мониторами. Проблема в том, что если монитор его поддерживает, то только он будет выставлять температуру и яркость. Я хочу сделать это для всех ПК, поэтому это должно быть что-то программно-ориентированное, то есть изменить вывод Windows GammaRamp, который в итоге выглядит тусклым и желтоватым на мониторе. Но проблема в том, что я не знаю, как это сделать, так как я не знаю C++ в стиле VC++. - person Chiku1022; 03.01.2021
comment
Яркость да, но ночной свет, как называет Windows, работает со всеми мониторами. howtogeek.com/302186/how-to -enable-night-light-on-windows-10. Вы должны иметь возможность переключать это из сценария CPP. - person Todd Rylaarsdam; 03.01.2021
comment
Но это работает только для Windows 10 Fall Creators Update и выше. Потому что это переключит уже встроенный ночной свет. Я хочу собрать его для использования со старыми версиями Windows 10 и 8 и, если возможно, с 7. Вот почему я хочу создать его с нуля. - person Chiku1022; 03.01.2021
comment
Ах. В таком случае я не уверен. Если вызов Windows API не работает, не знаю, что вы можете сделать, чтобы изменить вывод монитора. Надеюсь, кто-то, у кого больше опыта работы с Windows API и более старыми версиями, придет. - person Todd Rylaarsdam; 03.01.2021