Манипуляции с цветом и некоторые другие возможности GDI+

В главе 21 вы уже встречались с описанием функций GdipDrawImageRectRect и GdipDrawImageRectRectI, которые копируют выделенную область изображения на указанное место растра. Особенностью этих функций является то, что в процессе рисования они используют объект ImageAttributes. В этом разделе мы рассмотрим, как с помощью этого объекта можно менять баланс цветов изображения.

Объект ImageAttributes

Создаётся объект ImageAttributes функцией GdipCreateImageAttributes. Вот её объявление:

  
 DECLARE Long GdipCreateImageAttributes IN Gdiplus.dll Long @ nativeImageAttributes
 

где nativeImageAttributes — возвращаемый дескриптор объекта ImageAttributes.

Функция GdipDisposeImageAttributes уничтожает этот объект. Вот её объявление:

 
 DECLARE Long GdipDisposeImageAttributes IN Gdiplus.dll Long nativeImageAttributes
 

где nativeImageAttributes — дескриптор объекта ImageAttributes.

Объект ImageAttributes позволяет выполнять множество операций над изображением, позволяя создавать многофункциональные графические редакторы. Наша же задача предельно проста: научиться изменять цветовую гамму и степень прозрачности для конкретного изображения. Для этого мы должны при помощи функции GdipSetImageAttributesColorMatrix передать этому объекту цветовую матрицу размером 5x5, представляющую собой массив, состоящий из пяти строк и пяти столбцов вещественных чисел. Структура матрицы показана на рис. 23.7.

Рис. 23.7. Матрица преобразования цветов

Каждый столбец матрицы (кроме последнего) определяет, как будет изменена цветовая компонента (Red, Green, Blue) или прозрачность (Alpha). Последний столбец выполняет служебные функции. Ячейки матрицы, в которых на рис. 23.7 указаны числовые значения (0 или 1), не могут содержать никаких других значений, кроме указанных. А вот ячейки, в которых написано слово Val, могут содержать различные значения (конечно, в допустимых пределах — но об этом чуть позже) и предназначены они для вычисления нового значения каждой цветовой компоненты.
В строках матрицы с первой по четвёртую значения Val определяют кратность изменения цвета; значение соответствующей цветовой компоненты умножается на значение ячейки (это значение не может быть отрицательным). Так, если вы хотите в два с половиной раза увеличить значение красной цветовой компоненты, не изменяя значения остальных компонент, то запишите в ячейку на пересечении первой строки и столбца Red значение 2.5, а в ячейки второй, третьей и четвёртой строки, там, где на рисунке указано «Val», — единицы. А вот ячейки в пятой строке матрицы (кроме ячейки дополнительного столбца) могут принимать вещественные значения в интервале ±1. Для понимания того, как используется пятая строка матрицы, нужно дать определение цветового вектора.
Значение каждой цветовой компоненты может изменяться в интервале от 0 до 255. Например, пиксель со значениями компонент (0, 128, 0, 255), где три первых числа соответствуют соответственно красному, зелёному и синему цветам, а последнее число указывает степень прозрачности, будет тёмно-зелёным и непрозрачным. Если мы применим относительное представление цветовых компонент, то параметры этого пикселя можно было бы записать так: (0, 0,5, 0, 1), где минимальное значение компоненты равно нулю, а максимальное — единице. Все остальные значения лежат внутри этого интервала.
Такое представление цвета и называется цветовым вектором. Значения из пятой строки цветовой матрицы (без учёта дополнительного столбца) суммируются с цветовым вектором каждого пикселя растра.
Следовательно, значения матрицы в строках с первой по четвёртую указывают, во сколько раз должно измениться значение компоненты, а значения в пятой строке — на сколько должно измениться значение компоненты.

Как вы полагаете, как изменится цветовая гамма изображения, если массив будет отображать следующую матрицу (рис. 23.8)?

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

А как изменится цветовая гамма после обработки вот такой цветовой матрицы (рис. 23.9)?

Рис. 21.9. Матрица, корректирующая цветовую гамму изображения

Сначала вычисления выполняются над первыми четырьмя строками матрицы, в результате чего значение красной цветовой компоненты удваивается (но оно не может быть более чем 255), значения цветов остальных компонент и прозрачность остаются без изменения.
При обработке пятой строки матрицы:

  • красная компонента цветового вектора увеличивается на 0,2
  • зелёная компонента так же увеличивается на 0,2
  • синяя компонента так же увеличивается на 0,2
  • прозрачность пикселя не изменяется

Как применить всё вышеизложенное на практике? Нужно создать объект ImageAttributes и при помощи функции GdipSetImageAttributesColorMatrix передать ему массив, содержащий цветовую матрицу.
Вот объявление функции GdipSetImageAttributesColorMatrix:

 
 DECLARE Long GdipSetImageAttributesColorMatrix IN Gdiplus.dll ;
         Long nativeImageAttributes, Long type, Long enable, String colorMatrix, ;
         String grayMatrix, Long flags 
 

Передаваемые функции параметры:

  • nativeImageAttributes — дескриптор объекта ImageAttributes

  • type — этот параметр при работе с изображениями равен 1.

  • enable — если функции передаётся цветовая матрица, параметр равен 1; иначе - ноль.

  • colorMatrix — указатель на массив, содержащий цветовую матрицу

  • grayMatrix — указатель на массив, содержащий матрицу оттёнков серого (полутона). Если не используется, то должен быть NULL

  • flags — параметр, определяющий типы изображений и цветов, на которые будут воздействовать цветовые и полутоновые установки. Его значения приведены в таблице 23.4.

Таблица 23.4. Значения параметра flags функции GdipSetImageAttributesColorMatrix

Значение flags Описание
0 Полное преобразование
1 Цвета корректируются, но оттенки серого не корректируются. Оттенком серого является любой цвет, цветовые компоненты которого имеют одинаковые значения
2 Цвета корректируются одной матрицей (colorMatrix), а оттёнки серого корректируются другой матрицей (grayMatrix)

Пример корректировки цветовой гаммы изображения

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

Листинг 23.28. Пример корректировки цветовой гаммы изображения

 
 DECLARE Long GdipDrawImageRectRectI IN Gdiplus.dll Long, Long, Long, Long, Long, Long, ;
         Long, Long, Long, Long, Long, Long, Long, Long
 DECLARE Long GdipGetImagePixelFormat IN Gdiplus.dll Long, Long @
 DECLARE Long GdipCreateImageAttributes IN Gdiplus.dll Long @
 DECLARE Long GdipSetImageAttributesColorMatrix IN Gdiplus.dll ;
         Long nativeImageAttributes, Long, Long, String, String, Long
 DECLARE Long GdipDisposeImageAttributes IN Gdiplus.dll Long
 DECLARE Long GdipGetImageWidth IN Gdiplus.dll Long, Long @
 DECLARE Long GdipGetImageHeight IN Gdiplus.dll Long, Long @
 DECLARE Long GdipDeleteGraphics IN Gdiplus.dll Long 
 * Получаем размеры исходного изображения
 nSrcX = 0
 nSrcY = 0
 nSrcWidth = 0
 nSrcHeight = 0
 = GdipGetImageWidth(nativeImage, @nSrcWidth)
 = GdipGetImageHeight(nativeImage, @nSrcHeight)
 * Размеры конечного изображения должны быть равны
 * размерам исходного изображения
 nDstX = nSrcX
 nDstY = nSrcY
 nDstWidth = nSrcWidth
 nDstHeight = nSrcHeight
 * Создаём объект Graphics, связанный с исходным изображением
 nativeGraphics = 0
 GdipGetImagePixelFormat(nativeImage, @nativeGraphics)
 * Создаём массив, содержащий цветовую матрицу. 
 DIMENSION aColorMatrix[5,5]
 STORE 0 TO aColorMatrix
 aColorMatrix[1,1] = 1 && Кратность для цветов не меняется
 aColorMatrix[2,2] = 1
 aColorMatrix[3,3] = 1
 aColorMatrix[4,4] = 1
 aColorMatrix[5,5] = 1
 * Установка приращений для цветов
 aColorMatrix[5,1] = -0.2 && Уменьшаем интенсивность красного на 20%
 aColorMatrix[5,2] = 0 && Зелёный цвет не изменяем
 aColorMatrix[5,3] = 0.25 && Увеличиваем интенсивность синего на 25% 
 aColorMatrix[5,4] = 1 && Растр полностью непрозрачный
 * Заносим массив в строку
 cColorMatrix = ''
 FOR i = 1 TO 25
    cColorMatrix = cColorMatrix + BINTOC(aColorMatrix[i], 'F')
 ENDFOR
 * Создаём объект ImageAttributes
 nativeImageAttributes = 0
 GdipCreateImageAttributes(@nativeImageAttributes)
 * Передаём объекту цветовую матрицу
 GdipSetImageAttributesColorMatrix(nativeImageAttributes, 1, 1, cColorMatrix, 0, 0)
 * Теперь можно рисовать
 GdipDrawImageRectRectI(nativeGraphics, nativeImage, nDstX, nDstY, nDstWidth, nDstHeight, ;
                        nSrcX, nSrcY, nSrcWidth, nSrcHeight, 0, cColorMatrix, 0, 0)
 * Убираем "мусор"
 GdipDisposeImageAttributes(nativeImageAttributes)
 GdipDeleteGraphics(nativeGraphics)
 

Ещё несколько функций GDIPlus…

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

  • создать перо, рисующее кистью
  • изменить форму начала или конца линии (например, нарисовать стрелку)
  • получать и изменять цвет отдельного пикселя растра

Перо, рисующее кистью

До сих пор мы рассматривали перо как инструмент для рисования линий. Возможность рисовать линии кистью позволяет получить очень интересные эффекты. Например, представьте себе перо, рисующее градиентной кистью. Нарисованные им линии будут переливаться всеми цветами радуги!
Создаётся такое перо функцией GdipCreatePen2. Вот её объявление в Visual FoxPro:

 
 DECLARE Long GdipCreatePen2 IN diplus.dll ;
         Long nativeBrush, Single width, Long unit, Long @ nativePen
 

Передаваемые функции параметры:

  • nativeBrush — дескриптор кисти
  • width — толщина пера
  • unit — код используемой единицы измерения; как обычно, равен нулю
  • nativePen — передаваемый по ссылке параметр, в который записывается дескриптор созданного пера

Изменение вида начала или конца линии

Функция GdipSetPenStartCap «пририсовывает» элемент к началу линии, а функция GdipSetPenEndCap — к концу. Вот их объявление в Visual FoxPro:

 
 DECLARE Long GdipSetPenStartCap IN Gdiplus.dll Long nativePen, Long startCap
 DECLARE Long GdipSetPenEndCap IN Gdiplus.dll Long nativePen, Long endCap
 

Передаваемые функциям параметры:

  • nativePen — дескриптор пера
  • startCap и endCap — вид «наконечника». Возможные значения параметров приведены в таблице 23.5.

Таблица 23.5. Виды «наконечников» линий
 

Значения
 startCap, endCap
Описание
3 Начало (конец) линии заостряется в виде треугольника
17 К началу (концу) линии пририсовывается прямоугольник
18 К началу (концу) линии пририсовывается окружность
19 К началу (концу) линии пририсовывается ромб
20 Начало (конец) линии заканчиваются стрелкой

 
Замечание
Для того, чтобы эффект проявился, перо должно иметь достаточную толщину (по крайней мере, больше одного пикселя)

Получение и установка цвета пикселей

Возвращает цвет пикселя функция GdipBitmapGetPixel, а устанавливает — функция GdipBitmapSetPixel. Вот их объявление в Visual FoxPro:

 
 DECLARE Long GdipBitmapGetPixel IN Gdiplus.dll 
         Long nativeImage, Long x, Long y, Long @ color
 DECLARE Long GdipBitmapSetPixel IN Gdiplus.dll ;
         Long nativeImage, Long x, Long y, Long color
 

Параметры функций:

  • nativeImage — указатель на область памяти, в которую загружен растр
  • x, y — координаты пикселя в растре
  • color — получает или передает значение цвета и прозрачности пикселя