Правильное использование SetDeviceGammaRamp

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

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

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

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

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

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

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

2 ответа

Решение

Исследуя возможность программного изменения яркости экрана, я наткнулся на эту статью. Изменение яркости экрана программным способом - с помощью 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() эти функции поддерживаются в Windows API начиная с 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). Программа, которая пытается установить недопустимое гамма-изменение, просто потерпит неудачу с общей ошибкой, оставляя программиста в недоумении, что пошло не так.

Я не проверял это, но если бы мне пришлось угадывать, ранние видеокарты были нестандартными в их реализации 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

Другие вопросы по тегам