Правильное использование SetDeviceGammaRamp - PullRequest
8 голосов
/ 02 декабря 2011

Я хотел бы добавить возможность настройки гаммы экрана при запуске приложения и сброса при выходе. Хотя это спорный вопрос, должен ли один подделать гамма вообще (личное, я считаю бесполезным и вредным), но эй, некоторые люди ожидают, что в состоянии сделать такую ​​вещь.

Это всего лишь один простой вызов API, так что все просто, верно?

MSDN говорит: "Гамма-аппроксимация указывается в трех массивах из 256 элементов WORD, для каждого значения должны быть [...] сохранены в старших битах каждого WORD, чтобы увеличить независимость ЦАП." . В моем понимании это означает что-то вроде word_value = byte_value<<8, что звучит довольно странно, но именно так я и читаю.

Исходный код Doom3 содержит функцию, которая принимает три массива значений char и преобразует их в массив значений uint16_t, имеющих одинаковые байтовые значения и в верхней и нижней половине. Другими словами что-то вроде word_value = (byte_value<<8)|byte_value. Это в равной степени странно, но, что хуже, это не то же самое, что и выше .

Также есть несколько фрагментов кода в Интернете на различных сайтах программистов-хобби (очевидно, один украден у другого, потому что они идентичны букве), которые делают некоторую неясную математику, умножая линейный индекс на значение, смещая с 128 и зажимом до 65535. Я не совсем уверен, о чем идет речь, но для меня это выглядит полной чепухой, и опять же, это не то же самое, что любой из вышеперечисленных.

Что дает? Он должен быть четко определен - без догадок - как должны выглядеть данные, которые вы предоставляете? В конце концов, то, что нужно сделать, это прочитать исходные значения и позволить пользователю в любом случае настроить некоторые ползунки (и при желании сохранить этот большой двоичный объект на диск с помощью пользовательской конфигурации), но все же ... для изменения этих значений необходимо знать, что они и что ожидается.

Кто-нибудь делал (и проверял!) Это раньше и знает, какой из них прав?

Ответы [ 2 ]

7 голосов
/ 21 октября 2015

Исследуя возможность программного изменения яркости экрана, я наткнулся на эту статью Программирование изменения яркости экрана - с помощью Gama Ramp API .

Используя отладчик, я взглянул на значения, предоставляемые функцией GetDeviceGamaRamp(). Выходными данными является двумерный массив, определенный как что-то вроде WORD GammaArray[3][256];, и таблица из 256 значений для изменения значений красного, зеленого и синего отображаемых пикселей. Значения, которые я увидел, начинаются со значения ноль (0) с индекса 0 и добавления значения 256 для вычисления следующего значения. Таким образом, последовательность составляет 0, 256, 512, ..., 65024, 65280 для индексов 0, 1, 2, ..., 254, 255.

Насколько я понимаю, эти значения используются для изменения значения RGB для каждого пикселя. Изменяя значение таблицы, вы можете изменить яркость дисплея. Однако эффективность этого метода может варьироваться в зависимости от аппаратного обеспечения дисплея.

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

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

Вот как это работает: Direct3D берет пиксель из буфера кадра и оценивает отдельные компоненты красного, зеленого и синего цвета. каждый Компонент представлен значением от 0 до 65535. Direct3D занимает исходное значение и использует его для индексации массива из 256 элементов ( рампа), где каждый элемент содержит значение, которое заменяет исходный один. Direct3D выполняет этот поиск и заменяет процесс для каждого цвета компонент каждого пикселя в буфере кадра, тем самым изменяя окончательные цвета для всех пикселей на экране.

В соответствии с онлайн-документацией для GetDeviceGamaRamp() и SetDeviceGamaRamp() эти функции поддерживаются в API Windows, начиная с Windows 2000 Professional.

Я использовал их источник, сжатый до следующего примера, вставленного в приложение Windows, чтобы проверить эффект, используя значения из указанной статьи. Мое тестирование было проведено с Windows 7 и графическим адаптером AMD Radeon HD 7450.

При этом тесте оба моих дисплея, у меня есть два дисплея, были затронуты.

//Generate the 256-colors array for the specified wBrightness value.
WORD  GammaArray[3][256];
HDC   hGammaDC = ::GetDC(NULL);
WORD  wBrightness;

::GetDeviceGammaRamp (hGammaDC, GammaArray);

wBrightness = 64;     // reduce the brightness
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

wBrightness = 128;    // set the brightness back to normal
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

::ReleaseDC(NULL, hGammaDC);

В качестве дополнительного примечания я внес небольшое изменение в приведенный выше источник, чтобы вместо одинакового изменения каждого из значений RGB я закомментировал первые два назначения, чтобы было изменено только GammaArray[2][ik]. Результатом стал желтоватый оттенок на дисплее.

Я также попытался поместить вышеуказанный источник в цикл, чтобы проверить, как изменился дисплей, и это было довольно большой разницей от wBrightness=0 до wBrightness=128.

for (wBrightness = 0; wBrightness <= 128; wBrightness += 16) {
    for (int ik = 0; ik < 256; ik++) {
        int iArrayValue = ik * (wBrightness + 128);
        if (iArrayValue > 0xffff) iArrayValue = 0xffff;
        GammaArray[0][ik] = (WORD)iArrayValue;
        GammaArray[1][ik] = (WORD)iArrayValue;
        GammaArray[2][ik] = (WORD)iArrayValue;
    }

    ::SetDeviceGammaRamp (hGammaDC, GammaArray);
    Sleep (3000);
}

Microsoft предоставляет онлайновую статью MSDN, Использование гамма-коррекции , которая является частью документации Direct3D, которая описывает основы гаммы следующим образом:

В конце графического конвейера, именно там, где изображение покидает компьютер, чтобы совершить путешествие по кабелю монитора, есть небольшой аппаратное обеспечение, которое может преобразовывать значения пикселей на лету. это аппаратное обеспечение обычно использует таблицу поиска для преобразования пикселей. это Аппаратное обеспечение использует красные, зеленые и синие значения, которые поступают из поверхность для отображения значений гамма-коррекции в таблице а затем отправляет исправленные значения на монитор вместо фактические значения поверхности. Итак, эта справочная таблица дает возможность заменить любой цвет на любой другой цвет. В то время как таблица имеет этот уровень власти, типичное использование заключается в тонкой настройке изображений, чтобы компенсировать за различия в ответе монитора. Ответ монитора функция, которая связывает числовое значение красного, зеленого и синий скомпоненты пикселя с отображаемой яркостью этого пикселя.

Кроме того, в программном приложении Redshift имеется страница настроек гаммы Windows , в которой говорится это о Microsoft Windows.

При портировании Redshift на Windows у меня возникли проблемы при установке цветовой температуры ниже примерно 4500K.Проблема заключается в том, что Windows устанавливает ограничения на то, какие виды гамма-коррекции могут быть сделаны, вероятно, как средство защиты пользователя от злых программ, которые инвертируют цвета, очищают экран или играют какую-то другую надоедливую хитрость с гамма-рампами.Ограничения такого рода, возможно, понятны, но проблема заключается в полном отсутствии документации этой функции ( SetDeviceGammaRamp на MSDN ).Программа, которая пытается установить недопустимую гамма-диаграмму, просто потерпит неудачу с общей ошибкой, оставляя программиста в недоумении, что пошло не так.

2 голосов
/ 23 января 2014

Я не проверял это, но если бы мне пришлось угадывать, ранние видеокарты были нестандартными в своей реализации SetDeviceGammaRamp (), когда Doom был написан, а иногда использовал LOBYTE, а иногда использовал HIBYTE значения WORD. Консенсус был перенесен только на использование HIBYTE, поэтому word_value = byte_value<<8.

Вот еще одна точка данных из библиотеки PsychoPy (на python), которая просто меняет LOBYTE и HIBYTE:

 """Sets the hardware look-up table, using platform-specific ctypes functions. 
 For use with pyglet windows only (pygame has its own routines for this). 
 Ramp should be provided as 3x256 or 3x1024 array in range 0:1.0 
 """ 
if sys.platform=='win32':   
    newRamp= (255*newRamp).astype(numpy.uint16) 
    newRamp.byteswap(True)#necessary, according to pyglet post from Martin Spacek 
    success = windll.gdi32.SetDeviceGammaRamp(pygletWindow._dc, newRamp.ctypes) 
    if not success: raise AssertionError, 'SetDeviceGammaRamp failed' 

Похоже, что Windows не поддерживает все настройки гаммы, см. http://jonls.dk/2010/09/windows-gamma-adjustments/

Обновление:

Первыми API-интерфейсами Windows, которые предлагают управление гаммой, являются SetDeviceGammaRamp и GetDeviceGammaRamp интерфейса графических устройств Windows (GDI). Эти API работают с тремя массивами WORD с 256 записями, причем каждое WORD кодирует от нуля до единицы, представленное значениями WORD 0 и 65535. Дополнительная точность WORD обычно недоступна в реальных таблицах поиска оборудования, но эти API предназначен быть гибким. Эти API, в отличие от других, описанных далее в этом разделе, допускают лишь небольшое отклонение от функции идентичности. Фактически, любая запись в рампе должна быть в пределах 32768 от значения идентификатора. Это ограничение означает, что ни одно приложение не может сделать дисплей полностью черным или другим нечитаемым цветом.

http://msdn.microsoft.com/en-us/library/windows/desktop/jj635732(v=vs.85).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...