Правильное использование SetDevicegammaramp
Вопрос
Я хотел бы добавить возможность настраивать гамма экрана при запуске приложения и сбросить ее при выходе. Хотя спорно, следует ли вообще вмешиваться в гамма (личная, я нахожу это бесполезным и вредным), но, эй, некоторые люди ожидают, что смогут делать такие вещи.
Это просто один простой звонок API, так что все это просто, верно?
MSDN говорит: «Гамма -рампа указана в трех массивах из 256 элементов слов, каждый из которых [...] значения должны храниться в наиболее значимых битах каждого слова, чтобы повысить независимость DAC».. Анкет Это означает, в моем понимании, что -то вроде word_value = byte_value<<8
, что звучит довольно странно, но это то, как я это читал.
Исходный код DOOM3 содержит функцию, которая занимает три массива char
ценит и преобразует их в массив uint16_t
значения, которые имеют одинаковое значение байта оба В верхней и нижней половине. Другими словами word_value = (byte_value<<8)|byte_value
. Анкет Это одинаково странно, но что еще хуже не то же самое, что и выше.
Также существует несколько фрагментов кода в Интернете на различных сайтах программистов Hobby (по -видимому, один украден у другого, потому что они идентичны букве), которые делают некоторые неясные математические умножения, умножая линейный индекс со значением, смеется с 128, и зажимать до 65535. Я не совсем уверен, что это такое, но это похоже на полную чушь, и опять же, это не то же самое, что и любой из двух вышеупомянутых.
Что дает? Это должно быть четко определенным-не догадая-как должны выглядеть данные, которые вы поставляете? В конце концов, то, что можно будет прочитать исходные значения и позволить пользователю в любом случае направлять некоторые слайдеры (и, необязательно сохранить эту BLOB, чтобы диск с конфигурацией пользователя), но все же ... Чтобы изменить эти значения, нужно, чтобы нужно было Знайте, что они и что ожидают.
Кто -нибудь сделал (и проверял!) Это раньше и знает, какой из них прав?
Решение
Изучая способность программно изменять яркости экрана, я наткнулся на эту статью Изменение яркости экрана программирующим - с помощью API Gama Rampi.
Используя отладчик, я посмотрел на значения, предоставленные GetDeviceGamaRamp()
функция Выход - это двухмерный массив, определенный как что -то вроде WORD GammaArray[3][256];
и представляет собой таблицу из 256 значений для изменения красных, зеленых и синих значений отображаемых пикселей. Значения, которые я видел, начались со значением нуля (0) при индексе 0 и добавили значение 256 для вычисления следующего значения. Таким образом, последовательность 0, 256, 512, ..., 65024, 65280 для индексов 0, 1, 2, ..., 254, 255.
Насколько я понимаю, эти значения используются для изменения значения RGB для каждого пикселя. Изменив значение таблицы, вы можете изменить яркость дисплея. Однако эффективность этой техники может варьироваться в зависимости от оборудования для отображения.
Вы можете найти эту краткую статью, Гамма контроли, В интересах, поскольку он описывает уровни гамма -рампа, хотя с точки зрения Direct3D. В статье есть это, чтобы сказать о уровнях гамма -рампа.
В Direct3D термин гамма -рампа описывает набор значений, которые отображают уровень определенного цветового компонента - Red, зеленый, синий - для всех пикселей в буфере кадров на новые уровни, которые получены DAC для дисплея. Передача выполняется с помощью трех таблиц поиска, по одной для каждого цветового компонента.
Вот как это работает: Direct3D берет пиксель из кадриста и оценивает его индивидуальные компоненты красного, зеленого и синего цвета. Каждый компонент представлен значением от 0 до 65535. Direct3D принимает исходное значение и использует его для индексации массива 256 элементов (рампа), где каждый элемент содержит значение, которое заменяет исходное. Direct3D выполняет этот процесс поиска и замены для каждого цветового компонента каждого пикселя в буфере рамы, тем самым изменяя последние цвета для всех пикселей на экране.
Согласно онлайн -документации для GetDeviceGamaRamp()
а также SetDeviceGamaRamp()
Эти функции поддерживаются в API Windows, начиная с Professional Windows 2000.
Я использовал их источник, конденсированный к следующему примеру, вставленному в приложение 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 имеет настройки Gamma Page Windows Что может сказать о Microsoft Windows.
При переносе красного смещения в окна я столкнулся с неприятностями при установлении цветовой температуры ниже, чем около 4500K. Проблема заключается в том, что Windows устанавливает ограничения на то, какие правила гамма могут быть внесены, вероятно, в качестве средства защиты пользователя от злых программ, которые инвертируют цвета, блуждают дисплей или воспроизводят какой -то другой раздражающий трюк с гамма -рампами. Такое ограничение, возможно, понятно, но проблема заключается в полном отсутствии документации этой функции (SetDevicegammaramp на MSDN) Программа, которая пытается установить гамма -рампу, которая не разрешена, просто не пройдет с общей ошибкой, оставив программиста задуматься, что пошло не так.
Другие советы
Я не проверял это, но если бы мне пришлось догадаться, ранние видеокарты были нестандартными в их реализации SetDevicegammaramp (), когда Doom был написан, а иногда использовал Lobyte, а иногда использовал Hibyte из значения слова. Консенсус перешел на использование Hibyte, отсюда word_value = byte_value<<8
.
Вот еще один данных, из библиотеки психопии (в 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, предложившие управление гамма, - это интерфейс Graphics Device Windows (GDI) SetDeviceGammaramp и GetDevicegammaramp. Эти API работают с тремя массивами слов 256-входов, с каждым словом, кодирующим нуль до одного, представленным значениями слов 0 и 65535 предназначен для того, чтобы быть гибким. Эти API, в отличие от других, описанных позже в этом разделе, позволяют только небольшое отклонение от идентификационной функции. Фактически, любая запись в рампе должна быть в пределах 32768 от значения идентификации. Это ограничение означает, что ни одно приложение не может повернуть дисплей полностью черным или в какой -то другой нечитаемый цвет.
http://msdn.microsoft.com/en-us/library/windows/desktop/jj635732(v=vs.85).aspx