Насыщенность — это второй важный параметр в теории цвета, наравне с яркостью. Определяет степень отличия чистого хроматического цвета от аналогичного ему по яркости ахроматического цвета. Ахроматический цвет — это оттенки серого, который мы получили в предыдущей статье.
Цитатник
Несколько цитат для более широкого освещения вопроса. Рекомендую почитать, что там под ссылками LookColor и Jotto. По-моему, очень толково расписано.
Насыщенный цвет можно назвать «сочным», «глубоким», менее насыщенный — «приглушённым», приближённым к серому. Полностью ненасыщенный цвет будет оттенком серого. Насыщенность (saturation) — одна из трёх координат в цветовых пространствах HSL и HSV.
WIKI
Насыщенность цвета (интенсивность) – это степень выраженности определенного тона. Понятие идет следующим после яркости.
LookColor
Насыщенность — одна из трёх основных характеристик цвета в живописи и цветоведении (теории цвета), вместе с цветовым тоном и светлотой. Это степень отличия хроматического (цветного, принадлежащего цветовому спектру) цвета от равного ему по светлоте ахроматического (бесцветного серого).
Jotto
Перейдем непосредственно к эффекту.
Эффект Saturation
Используется для изменения насыщенности изображения. Является специализированным вариантом цветовой матрицы.
Минимальные требования: Windows 8 и обновление платформы для Windows 7. Из чего следует, что делать расширенную версию функции эффекта, как, например, для Grayscale эффекта, не требуется. Но матрицу обязательно рассмотрим.
Снова используем модуль Winapi.D2DMissing. Причины детально описаны ранее.
CLSID для эффекта Saturation:
1 2 |
const CLSID_D2D1Saturation: TGUID = '{5cb2d9cf-327d-459f-a0ce-40c0b2086bf7}'; |
Эффект имеет единственное свойство.
1 2 3 4 5 6 7 8 9 |
// The enumeration of the Saturation effect's top level properties. // Effect description: Alters the saturation of the bitmap based on the user // specified saturation value. TD2D1_SATURATION_PROP = ( // Property Name: "Saturation" // Property Type: FLOAT D2D1_SATURATION_PROP_SATURATION = 0, D2D1_SATURATION_PROP_FORCE_DWORD = $ffffffff ); |
D2D1_SATURATION_PROP_SATURATION |
Насыщенность изображения. Информация из MSDN. Она не совсем точная. Поэтому курсивом. Значение насыщенности имеет диапазон от 0 до 1. При значении 1, выходное изображение будет полностью насыщенным. Если значение установлено в 0, выходное изображение будет монохромным. Значение по умолчанию: 0.5f Тип: FLOAT |
Значение насыщенности на самом деле изменяется от 0 до 2.
Значение по умолчанию равно 1.0.
Таким образом, функция для эффекта предлагается следующая.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function GetSaturationEffect(AContext: ID2D1DeviceContext; AImage: ID2D1Image; const ASaturation: Single; out AEffect: ID2D1Effect): Boolean; var hr: HRESULT; begin Result := Assigned(AContext) and Succeeded(AContext.CreateEffect( CLSID_D2D1Saturation, AEffect)); if not Result then Exit; AEffect.SetInput(0, AImage); hr := AEffect.SetValue(Cardinal(D2D1_SATURATION_PROP_SATURATION), D2D1_PROPERTY_TYPE_FLOAT, @ASaturation, SizeOf(ASaturation)); Result := Result and Succeeded(hr); end; |
Цветовая матрица эффекта
Если снова обратимся к MSDN увидим следующую запись.

Рис.1. Матричное уравнение насыщенности. MSDN.
Как показали предыдущие статьи, Microsoft очень не любит писать толковую документацию, но в этот раз с уравнением все в порядке. Даже про альфа-канал не забыли.
Модифицируем код из статьи про ColorMatrix, добавим в контекстное меню пункт Saturation и поле для ввода значения насыщенности.

После выбора пункта контекстного меню Saturation внизу появится поле ввода, куда внесем максимальное значение 200. У нас пока целочисленные спины в интерфейсе, поэтому принимаем за истинные значения умноженные на 100.

Проверим непосредственно эффектом Saturation.

Разницы никакой. Цветовая матрица для эффекта насыщенности рабочая. MSDN опять дал правильные данные. Это даже удивляет.
Функция расчета насыщенности
Функция инициализации матрицы для изменения насыщенности.
1 2 3 4 5 6 7 8 9 10 |
function GetSaturationColorMatrix(const s: Single): TD2D_MATRIX_5X4_F; begin Result.Init( 0.213 + 0.787 * s, 0.213 - 0.213 * s, 0.213 - 0.213 * s, 0, 0.715 - 0.715 * s, 0.715 + 0.285 * s, 0.715 - 0.715 * s, 0, 0.072 - 0.072 * s, 0.072 - 0.072 * s, 0.072 + 0.928 * s, 0, 0,0,0,1, 0,0,0,0 ); end; |
Если внимательно приглядеться, увидим, что коэффициенты ровно те же, что мы использовали для расчета изображения в оттенках серого в рамках Grayscale HDTV. Все та же восприимчивость человеческого глаза к синему и зеленому. А не любопытно было бы попробовать коэффициенты из первого набора? Того, который мы используем сейчас по умолчанию для оттенков серого.
1 2 3 4 5 6 7 8 9 10 |
function GetSaturationColorMatrixTwo(const s: Single): TD2D_MATRIX_5X4_F; begin Result.Init( 0.299 + 0.701 * s, 0.299 - 0.299 * s, 0.299 - 0.299 * s, 0, 0.587 - 0.587 * s, 0.587 + 0.413 * s, 0.587 - 0.587 * s, 0, 0.114 - 0.114 * s, 0.114 - 0.114 * s, 0.114 + 0.886 * s, 0, 0,0,0,1, 0,0,0,0 ); end; |
Насыщенность прекрасно считается, но результаты по сравнению с эффектом чуть-чуть отличаются. Оставлю тут «другую» матрицу для смелых экспериментаторов. Хочу заметить, что значения коэффициентов по диагонали в сумме должны дать 1. Сумма всех коэффициентов для R, G, B также должна дать 1.
То есть 0.299 + 0.701 = 1. И сумма всех коэффициентов 0.299 + 0.587 + 0.114 = 1.
Давайте напишем функцию изменения насыщенности цвета. Полезно при работе с цветовой гаммой интерфейса, чтобы не возникало аляповатостей. Предлагаю такой код.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// Изменить насыщенность цвета // AValue = 0..1 - Усиление насыщенности // AValue = -1..0 - Ослабление насыщенности до ахроматического (-1) function SaturationColor(const AColor: TColor; const AValue: Single = 0.0): TColor; function Get(const v: single): Byte; begin if v < 0 then Result := 0 else if v > 255 then Result := 255 else Result := Trunc(v); end; var r,g,b: single; r1,g1,b1: single; s, s1: Single; begin r := GetRValue(AColor)/255; g := GetGValue(AColor)/255; b := GetBValue(AColor)/255; s := AValue+1; s1 := 1 - s; r1 := r*(0.213 + 0.787 * s) + g * (0.715 * s1) + b * (0.072 * s1); g1 := r*(0.213 * s1) + g * (0.715 + 0.285 * s) + b * (0.072 * s1); b1 := r*(0.213 * s1) + g * (0.715 * s1) + b * (0.072 + 0.928 * s); Result := RGB (Get(r1*255),Get(g1*255),Get(b1*255)); end; |
Функция работает шустро. Попытки оптимизировать, а математически это очень даже возможно, приводили к незначительному замедлению работы. Поэтому остановился на этом компромиссном варианте — понятен алгоритм, скорость приемлемая.

В исходниках по ссылке ниже функция располагается в модуле IP76.DrawUtils. Там же находится и функция для яркости. Однако, так как сам грешу тем, что копирую прямо у себя же со страницы, привожу функции и для яркости.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// Lighten AColor by APercent percent function Lighter(AColor:TColor; const APercent:Byte): TColor; var r,g,b: Byte; begin AColor := ColorToRGB(AColor); r := GetRValue(AColor); g := GetGValue(AColor); b := GetBValue(AColor); r := r + muldiv(255-r, APercent, 100); g := g + muldiv(255-g, APercent, 100); b := b + muldiv(255-b, APercent, 100); Result := RGB(r, g, b); end; // Darken AColor by APercent percent function Darker(AColor:TColor; const APercent:Byte): TColor; var r,g,b: Byte; begin AColor := ColorToRGB(AColor); r := GetRValue(AColor); g := GetGValue(AColor); b := GetBValue(AColor); r := r - muldiv(r, APercent, 100); g := g - muldiv(g, APercent, 100); b := b - muldiv(b, APercent, 100); Result := RGB(r, g, b); end; // Change the brightness of a color linearly // AValue = 0..1 - Lighter // AValue = -1..0 - Darker function BrightnessColor(const AColor: TColor; const AValue: Single = 0.0): TColor; begin if AValue > 0 then Result := Lighter(AColor, trunc(AValue * 100)) else Result := Darker(AColor, trunc(-AValue * 100)) end; |
Скачать
Исходники (Delphi XE 7-10) 1.09 Mб
Перед тем, как открыть проект, необходимо установить шрифт Font Awesome 5 Free-Solid-900.otf. Он находится в архиве в подпапке Fonts.
Исполняемый файл D2DEffects 0.4 (zip) 1.82 Мб