Введение в GDI+

Тема в разделе "WASM.GDI+", создана пользователем Mikl___, 5 янв 2025.

  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896
    Основные понятия
    В Windows приложения не имеют непосредственного доступа к устройствам отображения, таким как монитор или принтер. Вместо этого они обращаются к интерфейсу графического устройства Windows, а он, в свою очередь, транслирует эти обращения к драйверам устройств отображения, обеспечивая аппаратную независимость приложений.
    Интерфейс графического устройства (Graphics Device Interface, GDI) – часть Windows API, которая представляет собой библиотеку функций, обеспечивающих графический вывод на различные устройства отображения.
    С выходом Windows XP появилась библиотека GDI+, призванная заменить устаревшую библиотеку GDI. Библиотека GDI+ содержит в себе все возможности GDI предшественника и предоставляет множество новых. В новых версиях Windows приложения, использующие GDI, выполняются, но при создании приложений рекомендуется использовать GDI+.
    В библиотеке GDI+ используется объектно-ориентированный подход к работе с графическими объектами. Библиотека GDI+ содержит около 40 классов. Документация по классам GDI+ в Platform Software Development Kit (Platform SDK).

    Обработка ошибок в GDI+

    Большинство функций и методов классов GDI+ после выполнения возвращают одно из значений перечисляемого типа Status, определенного в заголовочном файле gdiplustypes.h. В случае успешного выполнения возвращается значение Ok. Остальные значения типа Status указывают на причину возникновения ошибки. Подробное описание значений перечисляемого типа Status в документации Platform SDK.
    Большинство классов GDI+ содержат метод GetLastStatus, который возвращает значение, указывающее причину возникновения ошибки (или ее отсутствие) в последнем вызове одного из методов этих классов.
    При создании объектов одного из классов GDI+ можно вызвать метод GetLastStatus этого объекта, для того чтобы определить успешно или нет был создан объект. В случае успешного создания метод GetLastStatus возвращает значение Ok. При создании объектов некоторых классов GDI+ в случае возникновения ошибки метод GetLastStatus независимо от ее причины может вернуть значение OutOfMemory, указывающее на нехватку памяти для создания объекта.
    Цвет в GDI+
    31​
    ...​
    24​
    23​
    ...​
    16​
    15​
    ...​
    08​
    07​
    ...​
    00​
    альфа-фактор
    (alpha-value)
    красный (red)
    зеленый (green)
    синий (blue)
    Параметры цвета могут принимать 28=256 значений, от 255 (максимальная яркость) до 0 (отсутствие цвета). Параметр прозрачности от 255 (отсутствие прозрачности) до 0 (полная прозрачность)
    Методы класса Color
    МетодОписание
    BYTE GetAlpha, BYTE GetAВозвращает значение альфа-фактора
    BYTE GetBlue, BYTE GetBВозвращает значение синего компонента цвета
    BYTE GetGreen, BYTE GetGВозвращает значение зеленого компонента цвета
    BYTE GetRed, BYTE GetRВозвращает значение красного компонента цвета
    ARGB GetValueВозвращает значение цвета в формате ARGB
    MakeARGB(BYTE a, BYTE r, BYTE g, BYTE b)Собирает значения альфа-фактора и компонентов цвета в одно значение цвета в формате ARGB
    SetFromCOLORREF(COLORREF rgb)Задает значение цвета в формате COLORREF
    SetValue(ARGB argb)Задает значение цвета в формате ARGB
    Классы GDI+ для работы с координатами и размерами
    КлассПоляОписание
    PointX, YПара целых чисел, представляющих собой координаты точки
    PointFX, YПара вещественных чисел, представляющих собой координаты точки
    SizeWidth, HeightПара целых чисел, представляющих собой ширину и высоту
    SizeFWidth, HeightПара вещественных чисел, представляющих собой ширину и высоту
    RectX, Y, Width, HeightНабор из четырех целых чисел, определяющих расположение и размер прямоугольника
    RectFX, Y, Width, HeightНабор из четырех вещественных чисел, определяющих расположение и размер прямоугольника
    Point и PointF
    Классы Point и PointF используются для представления координат точек в двумерной прямоугольной системе координат. В классе Point у полей X и Y тип int, в классе PointF – float. В остальном классы Point и PointF идентичны.
    Size и SizeF
    Классы Size и SizeF используются для представления пары чисел, которые определяют ширину и высоту. В классе Size у полей Width и Height тип int, в классе SizeF – float. В остальном классы Size и SizeF идентичны.
    Rect и RectF
    Классы Rect и RectF используются для представления прямоугольников. Классы Rect и RectF в основном идентичны, в классе Rect поля X, Y, Width и Height имеют тип int, в классе RectF – float.
    Методы класса Rect
    МетодОписание
    Rect* CloneКлонирует текущий объект класса Rect.
    Возвращает указатель на созданный объект класса Rect, который должен быть удален вызовом оператора delete после того как станет не нужен
    BOOL Contains(Point &pt)
    BOOL Contains(INT x, INT y)
    Возвращает TRUE, если прямоугольник, представленный текущим объектом класса Rect, включает указанную точку, и FALSE – в противном случае
    BOOL Contains(Rect &rect)Возвращает TRUE, если прямоугольник, представленный текущим объектом класса Rect, включает прямоугольник, указанный параметром rect, и FALSE – в противном случае
    BOOL Equals(Rect &rect)Возвращает TRUE, если прямоугольник, представленный текущим объектом класса Rect, равен прямоугольнику, указанному параметром rect, и FALSE – в противном случае
    INT GetBottom()Возвращает координату по оси Y нижней стороны прямоугольника
    void GetBounds(Rect *rect)Возвращает прямоугольник, представленный текущим объектом класса Rect. Результат сохраняется в объекте класса Rect, на который указывает параметр rect
    INT GetLeft()Возвращает координату по оси X левой стороны прямоугольника
    void GetLocation(Point *point)Возвращает расположение прямоугольника, представленного текущим объектом класса Rect. Результат сохраняется в объекте класса Point, на который указывает параметр point
    INT GetRight()Возвращает координату по оси X правой стороны прямоугольника
    void GetSize(Size *size)Возвращает размер прямоугольника, представленного текущим объектом класса Rect. Результат сохраняется в объекте класса Size, на который указывает параметр size
    void Inflate(INT dx, INT dy)Расширяет прямоугольник, представленный текущим объектом класса Rect, на значение dx c левой и правой стороны и dy с верхней и нижней стороны
    void Inflate(Point &point)Расширяет прямоугольник, представленный текущим объектом класса Rect, на значение point.X c левой и правой стороны и point.Y с верхней и нижней стороны
    BOOL Intersect(Rect &c, Rect &a, Rect &b)Находит пересечение прямоугольников, указанных параметрами a и b. Результат сохраняется в объекте класса Rect, на который указывает параметр c.
    Возвращаемое значение равно TRUE, если пересечение найдено, и FALSE – в противном случае
    BOOL Intersect(Rect &rect)Находит пересечение прямоугольника, представленного текущим объектом класса Rect, и прямоугольника, указанного параметром rect. Результат сохраняется в текущем объекте класса Rect.
    Возвращаемое значение равно TRUE, если пересечение найдено, и FALSE – в противном случае
    BOOL IntersectsWith(Rect &rect)Возвращает TRUE, если прямоугольник, представленный текущим объектом класса Rect, пересекается с прямоугольником, указанным параметром rect, и FALSE – в противном случае
    BOOL IsEmptyArea()Возвращает TRUE, если поля Width и Height текущего объекта класса Rect меньше или равны нулю, и FALSE – в противном случае
    void Offset(INT dx, INT dy)Перемещает прямоугольник, представленный текущим объектом класса Rect, на значение dx по горизонтали и dy по вертикали
    void Offset(Point &point)Перемещает прямоугольник, представленный текущим объектом класса Rect, на значение point.X по горизонтали и point.Y по вертикали
    BOOL Union(Rect &c, Rect &a,
    Rect &b)
    Находит объединение прямоугольников, указанных параметрами a и b. Результат сохраняется в объекте класса Rect, на который указывает параметр c. Возвращаемое значение равно TRUE, если объединение найдено, и FALSE – в противном случае
     
    Последнее редактирование: 10 янв 2025
    Thetrik и MaKsIm нравится это.
  2. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Графические объекты GDI+

    Библиотека GDI+ содержит набор графических объектов, обеспечивающих выполнение различных графических операций. К таким объектам относятся кисти, перья, шрифты и изображения.

    Кисти

    Замкнутая фигура (например, такая как окружность или многоугольник) закрашивается с помощью кисти (brush). В GDI+ имеется несколько классов для работы кистями, каждый из которых является производным от класса Brush.
    Большинство классов GDI+ для работы кистями (включая класс Brush) определено в заголовочном файле gdiplusbrush.h.

    Сплошные кисти

    Сплошная кисть используется для заполнения замкнутой фигуры однородным цветом.
    Класс SolidBrush имеет следующий конструктор:
    SolidBrush(Color &color);
    Конструктор создает объект класса SolidBrush на основе объекта класса Color, который задает цвет сплошной кисти.
    В классе SolidBrush определены два метода – GetColor и SetColor, которые работают с цветом кисти. Эти методы имеют следующие прототипы:
    GetColor(Color *color)
    SetColor(Color &color);
    Метод GetColor сохраняет текущее значение цвета кисти в объект класса Color, на который указывает параметр color, метод SetColor задает новое значение цвета кисти.
    Цвет кисти можно задать как в конструкторе класса SolidBrush, так и позднее, для уже созданного объекта класса SolidBrush

    Штриховые кисти

    Штриховая кисть (класс HatchBrush) позволяет заполнять замкнутую фигуру с использованием определенного узора.
    Класс HatchBrush имеет следующий конструктор:
    HatchBrush(HatchStyle hatchStyle, Color &foreColor, Color &backColor = Color());
    Этот конструктор создает объект класса HatchBrush на основе предопределенного стиля штриховой кисти, который задает его первый параметр – hatchStyle. Этот параметр должен принимать одно из значений перечисляемого типа HatchStyle, приведенных в таблице. Второй параметр, foreColor, задает цвет, который используется при отображении линий узора штриховой кисти, третий параметр, backColor, задает цвет фона штриховой кисти

    Значения параметра hatchStyle


    ЗначениеhexУзор
    HatchStyle05Percent6
    HatchStyle10Percent7
    HatchStyle20Percent8
    HatchStyle25Percent9
    HatchStyle30PercentA
    HatchStyle40PercentB
    HatchStyle50PercentC
    HatchStyle60PercentD
    HatchStyle70PercentE
    HatchStyle75PercentF
    HatchStyle80Percent10
    HatchStyle90Percent11
    HatchStyleBackwardDiagonal3
    HatchStyleCross4
    HatchStyleDarkDownwardDiagonal5
    HatchStyleDarkHorizontal1D
    HatchStyleDarkUpwardDiagonal15
    HatchStyleDarkVertical1C
    HatchStyleDashedDownwardDiagonal
    HatchStyleDashedHorizontal
    HatchStyleDashedUpwardDiagonal
    HatchStyleDashedVertical
    HatchStyleDiagonalBrick
    HatchStyleDiagonalCross
    HatchStyleDivot
    HatchStyleDottedDiamond
    HatchStyleDottedGrid
    HatchStyleForwardDiagonal
    HatchStyleHorizontal
    HatchStyleHorizontalBrick
    HatchStyleLargeCheckerBoard
    HatchStyleLargeConfetti
    HatchStyleLightDownwardDiagonal
    HatchStyleLightHorizontal
    HatchStyleLightUpwardDiagonal
    HatchStyleLightVertical
    HatchStyleNarrowHorizontal
    HatchStyleNarrowVertical
    HatchStyleOutlinedDiamond
    HatchStylePlaid
    HatchStyleShingle
    HatchStyleSmallCheckerBoard
    HatchStyleSmallConfetti
    HatchStyleSmallGrid
    HatchStyleSolidDiamond
    HatchStyleSphere
    HatchStyleTrellis
    HatchStyleVertical
    HatchStyleWave
    HatchStyleWeave
    HatchStyleWideDownwardDiagonal
    HatchStyleWideUpwardDiagonal
    HatchStyleZigZag

    Методы класса HatchBrush

    В таблице перечислены методы класса HatchBrush, которые могут быть полезны при работе с объектами этого класса.
    МетодОписание
    GetBackgroundColor( Color *color)Возвращает цвет, который используется при отображении узора штриховой кисти.
    Результат сохраняется в объект класса Color, на который указывает параметр color
    GetForegroundColor( Color *color)Возвращает цвет фона штриховой кисти. Результат сохраняется в объект класса Color, на который указывает параметр color
    HatchStyle GetHatchStyle()Возвращает стиль штриховой кисти

    Текстурные кисти

    Текстурная кисть (TextureBrush) позволяет заполнять замкнутую фигуру с использованием изображения.
    Класс TextureBrush имеет следующие конструкторы:
    TextureBrush(Image *image, WrapMode wrapMode = WrapModeTile);
    TextureBrush(Image *image, WrapMode wrapMode, RectF &dstRect);
    TextureBrush(Image *image, WrapMode wrapMode, RectF &dstRect, ImageAttributes *imageAttributes = NULL);
    TextureBrush(Image *image, WrapMode wrapMode, Rect &dstRect, ImageAttributes *imageAttributes = NULL);
    TextureBrush(Image *image, WrapMode wrapMode, Rect &dstRect);
    TextureBrush(Image *image, WrapMode wrapMode, REAL dstX, REAL dstY, REAL dstWidth, REAL dstHeight);
    TextureBrush(Image *image, WrapMode wrapMode, INT dstX, INT dstY, INT dstWidth, INT dstHeight);
    Все эти конструкторы создают объект класса TextureBrush на основе объекта класса Image, на который указывает параметр image. Объект класса Image, который в GDI+ используется для работы с изображениями, содержит изображение, используемое для создания текстурной кисти.
    00.png
    Параметр wrapMode задает режим заполнения, когда изображение меньше заполняемой области. Этот параметр должен принимать одно из значений перечисляемого типа WrapMode:
    WrapModehexОписание
    WrapModeTile0мозаичное заполнение 01.png
    WrapModeTileFlipX1мозаичное заполнение с зеркальным отображением изображения по горизонтали 02.png
    WrapModeTileFlipY2мозаичное заполнение с зеркальным отображением изображения по вертикали 00.png
    WrapModeTileFlipXY3мозаичное заполнение с зеркальным отображением изображения по горизонтали и вертикали 03.png
    WrapModeClamp4заполнение не производится
    Параметр dstRect, а также параметры dstX, dstY, dstWidth и dstHeight, определяют часть изображения, которая будет использоваться для создания кисти.
    Параметр imageAttributes, указывает на объект класса ImageAttributes, задающий свойства изображения. Этот параметр может быть установлен в NULL.
    В классе TextureBrush определено несколько методов, которые могут быть полезны при работе с объектами этого класса. Основные методы этого класса перечислены в таблице

    Методы класса TextureBrush


    МетодОписание
    Image* GetImage()Возвращает указатель на объект класса Image, который использовался при создании текстурной кисти
    WrapMode GetWrapMode()Возвращает режим заполнения
    SetWrapMode( WrapMode wrapMode)Задает режим заполнения
    Полный перечень методов класса TextureBrush, а также их описание, можно найти в документации Platform SDK.

    Кисти линейного градиента

    Кисть линейного градиента (класс LinearGradientBrush) используется для заполнения замкнутой фигуры цветовым градиентом, в котором цвет меняется параллельно некоторой линии.
    Класс LinearGradientBrush имеет следующие конструкторы:
    LinearGradientBrush(PointF &point1, PointF &point2, Color &color1, Color &color2);
    LinearGradientBrush(Point &point1, Point &point2, Color &color1, Color &color2);
    LinearGradientBrush(RectF &rect, Color &color1, Color &color2, LinearGradientMode mode);
    LinearGradientBrush(Rect &rect, Color &color1, Color &color2, LinearGradientMode mode);
    LinearGradientBrush(RectF &rect, Color &color1, Color &color2, REAL angle, BOOL isAngleScalable = FALSE);
    LinearGradientBrush(Rect &rect, Color &color1, Color &color2, REAL angle, BOOL isAngleScalable = FALSE);
    Все эти конструкторы создают объект класса LinearGradientBrush на основе двух объектов класса Color, которые задают начальный и конечный цвет в линейном градиенте (соответственно параметры color1 и color2).
    00.png
    В первом и втором конструкторах класса LinearGradientBrush параметры point1 и point2 задают, соответственно, начальную и конечную точку линейного градиента, которые образуют вектор. Как видно на рисунке, длина этого вектора определяет плавность градиента, а его направление – направление градиента
    В третьем и четвертом конструкторах класса LinearGradientBrush параметр rect задает прямоугольник, в котором определены начальная и конечная точки линейного градиента. При этом на определение этих точек влияет параметр mode, который должен принимать одно из значений перечисляемого типа LinearGradientMode:
    LinearGradientModehex
    LinearGradientModeHorizontal0начальная точка линейного градиента расположена в левом верхнем углу заданного прямоугольника, а конечная – в правом верхнем 00.png
    LinearGradientModeVertical1начальная точка линейного градиента расположена в левом верхнем углу заданного прямоугольника, а конечная – в левом нижнем 01.png
    LinearGradientModeForwardDiagonal2начальная точка линейного градиента расположена в левом верхнем углу заданного прямоугольника, а конечная – в правом нижнем 03.png
    LinearGradientModeBackwardDiagonal3начальная точка линейного градиента расположена в правом верхнем углу заданного прямоугольника, а конечная – в левом нижнем 02.png
    На рисунке показаны возможные варианты расположения начальной и конечной точки линейного градиента, определяемого прямоугольником.
    В пятом и шестом конструкторах класса LinearGradientBrush параметр rect задает прямоугольник, в верхнем левом углу которого находится начальная точка линейного градиента, а в правом нижнем углу – конечная точка. Параметр angle задает угол (в градусах) по часовой стрелке от верхней границы заданного прямоугольника. При этом если параметр isAngleScalable принимает значение равное FALSE, параметр angle задает угол, определяющий направление градиента. Если же параметр isAngleScalable принимает значение равное TRUE, параметр angle задает базовый угол, из которого рассчитывается угол, определяющий направление градиента, по следующей формуле:
    [math]\beta =\operatorname{arctg}\left (\frac{\displaystyle width}{\displaystyle height}\times\operatorname{tg}(\alpha)\right )[/math] где [math]\beta[/math]– угол, определяющий направление градиента; [math]width[/math] и [math]heigth[/math] – ширина и высота прямоугольника; [math]\alpha[/math] – базовый угол. Формула справедлива если [math]\alpha<90^{o}[/math].
     
    Последнее редактирование: 19 янв 2025
    Thetrik и MaKsIm нравится это.
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896
    Кисть линейного градиента, определяемая прямоугольником и углом, который задается (а) или вычисляется из базового угла (б)
    00.png 01.png
    Для изменения начального и конечного цвета линейного градиента в классе LinearGradientBrush определен метод SetLinearColors:
    SetLinearColors(Color &color1, Color &color2);
    Параметры color1 и color2 задают начальный и конечный цвет линейного градиента.
    В классе LinearGradientBrush имеется метод GetLinear.Colors, который возвращает начальный и конечный цвет градиента:
    GetLinearColors(Color *colors)
    Параметр colors указывает на массив из двух объектов класса Color, в которые будут сохранены значения начального и конечного цвета линейного градиента.
    цвет в линейном градиенте может меняться не только между двумя цветами. В классе LinearGradientBrush есть метод SetInterpolationColors, позволяющий задать несколько цветов интерполяции, между которыми будет изменяться цвет в линейном градиенте.
    SetInterpolationColors(Color *presetColors, REAL *blendPositions, INT count);
    Первый параметр, presetColors, указывает на массив объектов класса Color, каждый из которых хранит значение цветов интерполяции в линейном градиенте.
    Второй параметр, blendPositions, указывает на массив значений типа float, которые задают положение цвета в градиенте. Значение каждого элемента этого массива находится в диапазоне от 0 до 1.0, 0 указывает начало градиента, 1.0 – окончание градиента. В массиве, на который указывает параметр blendPositions, должно быть, по крайней мере, два элемента: начало градиента и его окончание.
    Третий параметр, count, задает количество элементов в массиве presetColors. Количество элементов в массиве presetColors должно быть таким же, как и в массиве blendPositions.
    Создание градиентной кисти, определяемой тремя цветами
    Код (C):
    1.  // создаем кисть линейного градиента
    2. LinearGradientBrush linGrBrush(Rect(0, 0, 200, 200), Color::White, Color::Black, 45.f);
    3. // изменяем параметры кисти линейного градиента...
    4. Color colors[3] = { Color(255, 255, 0, 0), // красный цвет
    5. Color(255, 0, 0, 255), // синий цвет
    6. Color(255, 0, 255, 0)}; // зеленый цвет
    7. float pos[3] = {0.0f, // начало градиента
    8.  0.3f, // 30% от начала градиента до его конца
    9.  1.0f}; // конец градиента
    10. linGrBrush.SetInterpolationColors(colors, pos, 3);
    00.png
    Линейный градиент, определяемый тремя цветами​
    Определить количество установленных цветов интерполяции в линейном градиенте можно с помощью метода GetInterpolationColorCount, а получить значения этих цветов и их позиции в градиенте можно с помощью метода GetInterpolationColors.
    INT GetInterpolationColorCount()
    GetInterpolationColors(Color *presetColors, REAL *blendPositions, INT count)
    Первый параметр, presetColors, указывает на массив объектов класса Color, в который будут сохранены значения цветов интерполяции в линейном градиенте.
    Второй параметр, blendPositions, указывает на массив типа float, в который будут сохранены позиции цветов в градиенте.
    Третий параметр, count, задает количество элементов в массиве presetColors. При этом количество элементов в массиве presetColors должно быть таким же, как и в массиве blendPositions.
    По умолчанию цвет в линейном градиенте меняется однородным образом. Однако можно настроить линейный градиент так, чтобы изменение цвета осуществлялось неоднородным образом. В классе LinearGradientBrush есть метод SetBlend, который позволяет настраивать способ градиентного изменения цвета при движении от начала до конца градиента.
    SetBlend(REAL *blendFactors, REAL *blendPositions, INT count);
    Первый параметр, blendFactors, указывает на массив значений типа float, которые задают факторы наложения. Значение каждого элемента в этом массиве определяет процент от конечного цвета линейного градиента и должно задаваться в пределах от 0 до 1.0.
    Второй параметр, blendPositions, указывает на массив значений типа float, которые задают положение фактора наложения в градиенте. Значение каждого элемента этого массива должно находиться в диапазоне от 0 до 1.0, где 0 указывает начало градиента, а 1.0 – окончание градиента.
    Третий параметр, count, задает количество элементов в массиве blendFactors. При этом количество элементов в массиве blendFactors должно быть таким же, как и в массиве blendPositions.
    Пример демонстрирует создание кисти линейного градиента, изображенного на рисунке б.
    Создание градиентной кисти с неоднородным изменением цвета
    Код (C):
    1.  // создаем кисть линейного градиента
    2.  LinearGradientBrush linGrBrush( Point(0, 0), Point(0, 200),
    3.  Color::Red, // красный цвет
    4.  Color::Blue); // синий цвет
    5.  // изменяем параметры кисти линейного градиента...
    6.  float factors[4] = {
    7.  0.0f, // 0% синего цвета, соответственно 100% красного
    8.  0.4f, // 40% синего цвета, соответственно 60% красного
    9.  0.6f, // 60% синего цвета, соответственно 40% красного
    10.  1.0f}; // 100% синего цвета, соответственно 0% красного
    11.  float pos[4] = {
    12.  0.0f, // начало градиента
    13.  0.2f, // 20% от начала градиента до его конца
    14.  0.8f, // 80% от начала градиента до его конца
    15.  1.0f}; // конец градиента
    16.  linGrBrush.SetBlend(factors, pos, 4);
    01.png 02.png
    Цветовые градиенты с однородным (а) и неоднородным (б)
    изменением цвета
    Определить количество установленных факторов наложения в линейном градиенте можно с помощью метода GetBlendCount, а получить значения этих факторов и их позиции в градиенте можно с помощью метода GetBlend. Прототипы этих методов имеют следующий вид:
    INT GetBlendCount()
    GetBlend(REAL *blendFactors, REAL *blendPositions, INT count)
    Первый параметр, blendFactors, указывает на массив типа float, в который будут сохранены значения факторов наложения в линейном градиенте.
    Второй параметр, blendPositions, указывает на массив значений типа float, в который будут сохранены позиции факторов наложения в градиенте.
    Третий параметр, count, задает количество элементов в массиве blendFactors. При этом количество элементов в массиве blendFactors должно быть таким же, как в массиве blendPositions.
    Чтобы интенсивность цветов в линейном градиенте была распределена более равномерно, можно включить гамма-коррекцию. Для этого в классе LinearGradientBrush определен метод SetGammaCorrection:
    SetGammaCorrection(BOOL useGammaCorrection);
    Параметр useGammaCorrection определяет, будет ли включена гамма-коррекция или нет. Если значение этого параметра равно TRUE, гамма-коррекция будет включена. По умолчанию гамма-коррекция отключена.
    На рисунке два линейных градиента: в одном гамма-коррекция отключена (а), в другом – включена (б).
    00.png 01.png
    Линейный градиент: а – без гамма-коррекции; б – с гамма-коррекцией
    Определить включена или нет гамма-коррекция можно с помощью метода GetGammaCorrection() Если гамма-коррекция включена, метод возвращает значение TRUE, в противном случае – FALSE .
    Класс LinearGradientBrush (подобно классу TextureBrush) позволяет определить режим заполнения, когда размер линейного градиента меньше заполняемой области. Для этого у него есть два метода – GetWrapMode и SetWrapMode, которые, соответственно, возвращает и задает режим заполнения. Методы имеют следующие прототипы:
    GetWrapMode()
    SetWrapMode(WrapMode wrapMode);
    На рисунке а показан пример мозаичного заполнения прямоугольника линейным градиентом, представленным на рисунке б.
    00.png 01.png
    Мозаичное заполнение прямоугольника (а)
    линейным градиентом (б)
    Также класс LinearGradientBrush позволяет определить границы линейного градиента с помощью метода GetRectangle:
    GetRectangle(Rect *rect);
    GetRectangle(RectF *rect);
    Параметр rect указывает на объект класса Rect (или RectF), в который будет сохранен прямоугольник, определяющий границы линейного градиента.
    Кисти градиента контура
    Кисть градиента контура (класс PathGradientBrush) используется для заполнения замкнутой фигуры цветовым градиентом, в котором цвет меняется от центральной точки наружу до границы, определяемой замкнутым контуром.
    Класс PathGradientBrush определен в заголовочном файле gdipluspath.h и имеет следующие конструкторы:
    PathGradientBrush(GraphicsPath *path);
    PathGradientBrush(Point *points, INT count, WrapMode wrapMode = WrapModeClamp);
    PathGradientBrush(Point *points, INT count, WrapMode wrapMode = WrapModeClamp);
    Первый конструктор создает объект класса PathGradientBrush на основе объекта класса GraphicsPath, который в GDI+ используется для работы с контурами. Второй и третий конструкторы создают объект класса PathGradientBrush на основе массива точек, на который указывает параметр points, а параметр count задает количество элементов в этом массиве. Параметр wrapMode задает режим заполнения мозаичного заполнения. По умолчанию заполнение не производится.
    В следующем примере продемонстрировано создание кисти градиента контура на основе контура треугольной формы.
    Пример создания кисти градиента контура
    Код (C):
    1.  // вершины треугольника
    2.  Point points[3] = { Point(100, 0), Point(200, 200), Point(0, 200)};
    3.  // создаем кисть градиента контура
    4.  PathGradientBrush pthGrBrush(points, 3);
    Рассмотрим на основе этого примера некоторые методы класса PathGradientBrush, которые могут пригодиться при работе кистями градиента контура. Полный перечень и подробное описание методов класса PathGradientBrush в документации Platform SDK.
    Класс PathGradientBrush позволяет определять отдельные цвета для центра, границы и даже для каждой точки на границе контура. Для работы с цветом центра контура в классе PathGradientBrush определены два метода – GetCenterColor и SetCenterColor:
    GetCenterColor(Color *color);
    SetCenterColor(Color &color);
    Метод GetCenterColor сохраняет текущее значение цвета центра контура в объект класса Color, на который указывает параметр color, а метод SetCenterColor задает новое значение цвета для центра контура.
    Для задания цвета границы контура в классе PathGradientBrush определен метод SetSurroundColors:
    SetSurroundColors(Color *colors, INT *count);
    Первый параметр, colors, указывает на массив объектов класса Color, каждый из которых хранит значение цветов.
    Второй параметр, count, указывает на переменную типа int, которая должна содержать количество задаваемых цветов. Если метод SetSurroundColors будет выполнен успешно, в переменную, на которую указывает этот параметр, будет сохранено количество заданных цветов.
    В листинге продемонстрирован пример задания отдельных цветов для центра и точек на границе контура для кисти, созданной в предыдущем примере. Полученный результат показан на рисунке а.
    Пример задания цветов для кисти градиента контура
    Код (C):
    1.  // задаем цвет центра контура
    2.  pthGrBrush.SetCenterColor(Color::Red);
    3.  // задаем цвета для каждой точки на границе контура...
    4.  Color colors[3] = { Color::DarkGreen, Color::Aqua, Color::Blue};
    5.  int n = 3;
    6.  pthGrBrush.SetSurroundColors(colors, &n);
    Следующий пример демонстрирует задание цветов для центра и для всей границы контура для кисти из примера в листинге. Результат представлен на рисунке б.
    Еще один пример задания цветов для кисти градиента контура
    Код (C):
    1.  // задаем цвет центра контура
    2.  pthGrBrush.SetCenterColor(Color::Aqua);
    3.  // задаем цвет границы контура...
    4.  Color color = Color::Blue;
    5.  int n = 1;
    6.  pthGrBrush.SetSurroundColors(&color, &n);
    Различные варианты градиента контура: а – каждая точка на границе имеет свой цвет; б – общий цвет для всей границы
    Еще один пример задания цветов для кисти градиента контура
    Код (C):
    1. // задаем цвет центра контура
    2.  pthGrBrush.SetCenterColor(Color::Aqua);
    3.  // задаем цвет границы контура...
    4.  Color color = Color::Blue;
    5.  int n = 1;
    6.  pthGrBrush.SetSurroundColors(&color, &n);
    01.png 02.png
    Различные варианты градиента контура:
    а – каждая точка на границе имеет свой цвет;
    б – общий цвет для всей границы
    Определить количество установленных цветов в градиенте контура можно с помощью метода GetSurroundColorCount, а получить значения этих цветов можно с помощью метода GetSurroundColors. Прототипы этих методов записываются следующим образом:
    INT GetSurroundColorCount();
    GetSurroundColors(Color *colors, INT *count);
    Первый параметр, colors, указывает на массив объектов класса Color, в который будут сохранены значения цветов.
    Второй параметр, count, указывает на переменную типа int, которая должна содержать количество запрашиваемых цветов. Если метод GetSurroundColors будет выполнен успешно, в переменную, на которую указывает этот параметр, будет сохранено количество полученных цветов.
    Цвет центра используется не только в центральной точке, но и везде в пределах внутреннего контура. Класс PathGradientBrush позволяет настраивать внутренний контур, увеличивая размер фокуса с помощью метода SetFocusScales:
    SetFocusScales(REAL xScale, REAL yScale);
    Параметры xScale и yScale задают коэффициенты масштабирования, соответственно по шкале x и y.
    На рисунке показан эффект применения коэффициентов масштабирования к фокусу кисти градиента контура, который можно получить, если добавить в предыдущий пример следующий программный код:
    Код (C):
    1. // применим коэффициенты масштабирования
    2.  pthGrBrush.SetFocusScales(0.3f, 0.7f);
    00.png
    Масштабирование фокуса кисти градиента контура​
    Чтобы получить установленные коэффициенты масштабирования фокуса нужно использовать метод GetFocusScales:
    GetFocusScales(REAL *xScale, REAL *yScale);
    Параметры xScale и yScale указывают на переменные типа float, в которые будут записаны коэффициенты масштабирования, соответственно по шкале x и y.
    По умолчанию центральной точкой кисти градиента контура является центр контура, используемого при создании этой кисти. Положение центральной точки можно изменить с помощью метода SetCenter.Point класса PathGradientBrush:
    SetCenterPoint(Point &point);
    SetCenterPoint(PointF &point);
    Параметр point ссылается на объект класса Point (или PointF), в котором представлены координаты новой центральной точки.
    На рисунке а показан результат изменения положения центральной точки, который можно получить, если добавить в пример из листинга следующий программный код:
    Код (C):
    1.  // изменяем положение центральной точки
    2.  pthGrBrush.SetCenterPoint( Point(80,120) );
    В качестве центральной точки кисти градиента контура можно установить точку, которая лежит вне контура. На рисунке б показан результат задания центральной точки вне контура, представленного в следующем фрагменте программного кода:
    Код (C):
    1.  // изменяем положение центральной точки
    2.  pthGrBrush.SetCenterPoint( Point(-10,210) );
    00.png 01.png
    Изменение положения центральной точки кисти
    градиента контура: а – точка внутри контура;
    б – точка вне контура
    Текущее положение центральной точки определяют с помощью метода GetCenterPoint:
    GetCenterPoint(Point *point);
    GetCenterPoint(PointF *point);
    Параметр point указывает на объект класса Point (или PointF), в который будут сохранены координаты центральной точки.
    Нужно отметить, что в классе PathGradientBrush также имеются методы аналогичные тем, что были рассмотрены в классе LinearGradientBrush. Вот эти методы:
    • GetBlend;
    • GetBlendCount;
    • GetGammaCorrection;
    • GetInterpolationColorCount;
    • GetInterpolationColors;
    • GetRectangle;
    • GetWrapMode;
    • SetBlend;
    • SetGammaCorrection;
    • SetInterpolationColors;
    • SetWrapMode.
    Перечисленные методы класса PathGradientBrush дают несколько другой эффект чем аналогичные методы класса LinearGradientBrush. В листинге показан пример использования метода SetInterpolationColors для того, чтобы изменить созданную кисть градиента контура, как показано на рисунке.
    00.png
    Градиент контура, определяемый тремя цветами​
    Создание кисти с неоднородным изменением цвета
    Код (C):
    1. // изменяем параметры кисти градиента контура...
    2.  Color colors[3] = { Color::DarkGreen, Color::Aqua, Color::Blue};
    3.  float pos[3] = { 0.0f, // начало градиента
    4.  0.4f, // 40% от начала градиента до его конца
    5.  1.0f}; // конец градиента
    6.  pthGrBrush.SetInterpolationColors(colors, pos, 3);
    Класс Brush
    Класс Brush является родительским для классов SolidBrush, HatchBrush, TextureBrush, LinearGradientBrush и PathGradientBrush. Однако в отличие от своих потомков сам по себе класс Brush практически бесполезен, так как его нельзя использовать непосредственно.
    Различные классы GDI+ в своих методах, выполняющих заполнение замкнутой фигуры, требуют указывать в качестве аргумента именно объект класса Brush. Это сделано только для того, чтобы такие методы могли работать идентично вне зависимости от кисти, используемой для заполнения. Дело в том, что все классы для работы кистями, являясь производными от класса Brush, могут использоваться в качестве аргумента в методах, которые требуют объект класса Brush.
    Следует также отметить, что класс Brush имеет несколько методов, которые наследуют все потомки этого класса. Среди этих методов есть уже рассмотренный ранее метод GetLastStatus.
    В классе также есть метод Clone, который клонирует текущий объект класса производного от класса Brush. Метод Clone имеет следующий прототип:
    Brush* Clone() ;
    В случае успеха метод возвращает указатель на объект класса Brush, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    В листинге пример использования метода Clone для клонирования объекта класса SolidBrush. При этом если аргумент brush указывает не на объект класса SolidBrush, клонирование не выполняется.
     
    Последнее редактирование: 6 янв 2025
    Thetrik, MaKsIm и Marylin нравится это.
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896
    Создание кисти с неоднородным изменением цвета
    Код (C):
    1.  // изменяем параметры кисти градиента контура...
    2.  Color colors[3] = { Color::DarkGreen, Color::Aqua, Color::Blue};
    3.  float pos[3] = { 0.0f, // начало градиента
    4.  0.4f, // 40% от начала градиента до его конца
    5.  1.0f}; // конец градиента
    6.  pthGrBrush.SetInterpolationColors(colors, pos, 3);
    Класс Brush
    Класс Brush является родительским для классов SolidBrush, HatchBrush, TextureBrush, LinearGradientBrush и PathGradientBrush. В отличие от своих потомков сам по себе класс Brush практически бесполезен, так как его нельзя использовать непосредственно.
    Различные классы GDI+ в своих методах, выполняющих заполнение замкнутой фигуры, требуют указывать в качестве аргумента объект класса Brush. Это сделано только для того, чтобы такие методы могли работать идентично вне зависимости от кисти, используемой для заполнения. Все классы для работы кистями, являясь производными от класса Brush, могут использоваться в качестве аргумента в методах, которые требуют объект класса Brush.
    Класс Brush имеет несколько методов, которые наследуют все потомки этого класса. Среди этих методов GetLastStatus.
    В классе есть метод Clone, который клонирует текущий объект класса производного от класса Brush. Метод Clone имеет следующий прототип:
    Brush* Clone();
    В случае успеха метод возвращает указатель на объект класса Brush, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    В листинге продемонстрирован пример использования метода Clone для клонирования объекта класса SolidBrush. Если аргумент brush указывает не на объект класса SolidBrush, клонирование не выполняется.
    Функция клонирования объекта класса SolidBrush
    Код (C):
    1.  SolidBrush* CloneSolidBrush(Brush *brush)
    2.  {  SolidBrush *result = dynamic_cast<SolidBrush *>(brush);
    3.  if (NULL != result)
    4.  result = (SolidBrush *)result->Clone();
    5.  return result;
    6.  } // CloneSolidBrush
    Функцию из предыдущего примера можно использовать следующим образом:
    Код (C):
    1.  SolidBrush *cloneBrush = NULL;
    2.  // создаем сплошную кисть
    3.  SolidBrush solidBrush(Color::Red);
    4.  // создаем штриховую кисть
    5.  HatchBrush hatchBrush(HatchStyleCross, Color::Blue);
    6.  // клонируем объект solidBrush
    7.  // результат - указатель новый экземпляр класса SolidBrush
    8.  cloneBrush = CloneSolidBrush(&solidBrush);
    9.  // удаляем клон
    10.  delete cloneBrush, cloneBrush = NULL;
    11.  // клонируем объект hatchBrush
    12.  // результат - NULL
    13.  cloneBrush = CloneSolidBrush(&hatchBrush);
    Определить тип кисти можно и без использования оператора dynamic_cast. В классе Brush есть метод GetType, который возвращает тип кисти. Прототип метода GetType имеет следующий вид:
    BrushType GetType();
    Метод возвращает одно из следующих значений перечисляемого типа BrushType:
    • BrushTypeSolidColor – сплошная кисть;
    • BrushTypeHatchFill – штриховая кисть;
    • BrushTypeTextureFill – текстурная кисть;
    • BrushTypePathGradient – кисть градиента контура;
    • BrushTypeLinearGradient – кисть линейного градиента.
    В следующем примере продемонстрирована видоизмененная функция, которая клонирует объект класса SolidBrush:
    Функция клонирования объекта класса SolidBrush
    Код (C):
    1.  SolidBrush* CloneSolidBrush(Brush *brush)
    2.  { BrushType type = brush->GetType();
    3.  if (type == BrushTypeSolidColor)
    4.  return (SolidBrush *)brush->Clone();
    5.  return NULL; } // CloneSolidBrush

    Перья

    Для рисования линий, кривых и границ (контуров) различных фигур используется перо (pen), которое определяет графические атрибуты такие, как цвет, толщина, стиль штриха и т.п. Работа с перьями в GDI+ осуществляется с помощью класса Pen, который определен в заголовочном файле gdipluspen.h.
    Класс Pen имеет следующие конструкторы:
    Pen(Color &color, REAL width = 1.0f);
    Pen(Brush *brush, REAL width = 1.0f);
    Первый конструктор создает объект класса Pen на основе объекта класса Color. Второй конструктор создает объект класса Pen на основе объекта класса Brush. Параметр width задает толщину пера в логических единицах.
    В следующем примере показаны два способа создания пера красного цвета и толщиной 4.
    Код (C):
    1.  // способ первый:
    2.  // просто создаем объект класса Pen
    3.  Pen pen1(Color(255, 0, 0), 4.f);
    4.  // способ второй:
    5.  // сперва создаем сплошную кисть
    6.  SolidBrush sBrush(Color::Red); // красный цвет
    7.  // а затем создаем объект класса Pen на основе объекта sBrush
    8.  Pen pen2(&sBrush, 4.f);
    Прежде чем перейти к изучению основных методов класса Pen, следует отметить, что в этом классе (как и в классе Brush) есть методы GetLastStatus и Clone. Метод Clone имеет следующий прототип:
    Pen* Clone();
    В случае успеха метод Clone возвращает указатель на объект класса Pen, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.

    Цвет пера

    Цвет пера определяет цвет рисуемых линий. В классе Pen определены два метода – GetColor и SetColor, которые работают с цветом пера. Эти методы имеют следующие прототипы:
    GetColor(Color *color);
    SetColor(Color &color);
    Метод GetColor сохраняет текущее значение цвета пера в объект класса Color, на который указывает параметр color, а метод SetColor задает новое значение цвета пера.

    Толщина и выравнивание пера

    Толщину пера можно указать в качестве одного из параметров конструктора класса Pen при создании объекта это класса. Можно также изменять толщину пера с помощью метода SetWidth:
    SetWidth(REAL width);
    Параметр width задает новую толщину пера. Определить текущую толщину пера можно с помощью метода GetWidth класса Pen:
    REAL GetWidth();
    Если толщина пера больше 1.0, при рисовании замкнутого контура можно указать положение такого пера относительно рисуемого контура. Для этого используется метод SetAlignment класса Pen:
    SetAlignment(PenAlignment penAlignment);
    Параметр penAlignment задает положение пера. Этот параметр может принимать одно из значений перечисляемого типа PenAlignment:
    PenAlignmenthex
    PenAlignmentCenter0перо располагается по центру контура рисуемой фигуры 00.png
    PenAlignmentInset1перо располагается с внутренней стороны контура рисуемой фигуры 01.png
    На рисунке показаны различные варианты положения пера при рисовании окружности.
    Создание кисти с неоднородным изменением цвета
    Код (C):
    1.  // изменяем параметры кисти градиента контура...
    2.  Color colors[3] = { Color::DarkGreen, Color::Aqua, Color::Blue};
    3.  float pos[3] = { 0, // начало градиента
    4.  0.4, // 40% от начала градиента до его конца
    5.  1.0}; // конец градиента
    6.  pthGrBrush.SetInterpolationColors(colors, pos, 3);
    Класс Brush
    Как уже было сказано ранее класс Brush является родительским для классов SolidBrush, HatchBrush, TextureBrush, LinearGradientBrush и PathGradientBrush. Однако в отличие от своих потомков сам по себе класс Brush практически бесполезен, так как его нельзя использовать непосредственно.
    Несмотря на это, различные классы GDI+ в своих методах, выполняющих заполнение замкнутой фигуры, требуют указывать в качестве аргумента именно объект класса Brush. Это сделано только для того, чтобы такие методы могли работать идентично вне зависимости от кисти, используемой для заполнения. Дело в том, что все классы для работы кистями, являясь производными от класса Brush, могут использоваться в качестве аргумента в методах, которые требуют объект класса Brush.
    Следует также отметить, что класс Brush имеет несколько методов, которые наследуют все потомки этого класса. Среди этих методов есть уже рассмотренный ранее метод GetLastStatus.
    В классе есть метод Clone, который клонирует текущий объект класса производного от класса Brush. Метод Clone имеет следующий прототип:
    Brush* Clone();
    В случае успеха этот метод возвращает указатель на объект класса Brush, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    В листинге продемонстрирован пример использования метода Clone для клонирования объекта класса SolidBrush. При этом если аргумент brush указывает не на объект класса SolidBrush, клонирование не выполняется.
    Функция клонирования объекта класса SolidBrush
    Код (C):
    1.  SolidBrush* CloneSolidBrush(Brush *brush)
    2.  {  SolidBrush *result = dynamic_cast<SolidBrush *>(brush);
    3.  if (NULL != result)
    4.  result = (SolidBrush *)result->Clone();
    5.  return result;
    6.  } // CloneSolidBrush
    Функцию из предыдущего примера можно использовать следующим образом:
    Код (C):
    1.  SolidBrush *cloneBrush = NULL;
    2.  // создаем сплошную кисть
    3.  SolidBrush solidBrush(Color::Red);
    4.  // создаем штриховую кисть
    5.  HatchBrush hatchBrush(HatchStyleCross, Color::Blue);
    6.  // клонируем объект solidBrush
    7.  // результат - указатель новый экземпляр класса SolidBrush
    8.  cloneBrush = CloneSolidBrush(&solidBrush);
    9.  // удаляем клон
    10.  delete cloneBrush, cloneBrush = NULL;
    11.  // клонируем объект hatchBrush
    12.  // результат - NULL
    13.  cloneBrush = CloneSolidBrush(&hatchBrush);
    Определить тип кисти можно и без использования оператора dynamic_cast. В классе Brush есть метод GetType, который возвращает тип кисти. Прототип метода GetType имеет следующий вид:
    BrushType GetType();
    Этот метод возвращает одно из следующих значений перечисляемого типа BrushType:
    • BrushTypeSolidColor – сплошная кисть;
    • BrushTypeHatchFill – штриховая кисть;
    • BrushTypeTextureFill – текстурная кисть;
    • BrushTypePathGradient – кисть градиента контура;
    • BrushTypeLinearGradient – кисть линейного градиента.
    В следующем примере продемонстрирована видоизмененная функция, которая клонирует объект класса SolidBrush:
    Функция клонирования объекта класса SolidBrush
    Код (C):
    1.  SolidBrush* CloneSolidBrush(Brush *brush)
    2.  {   BrushType type = brush->GetType();
    3.  if (type == BrushTypeSolidColor)
    4.  return (SolidBrush *)brush->Clone();
    5.  return NULL;
    6.  } // CloneSolidBrush

    Перья

    Для рисования линий, кривых и границ (контуров) различных фигур используется перо (pen), которое определяет графические атрибуты такие, как цвет, толщина, стиль штриха и т.п. Работа с перьями в GDI+ осуществляется с помощью класса Pen, который определен в заголовочном файле gdipluspen.h.
    Класс Pen имеет следующие конструкторы:
    Pen(Color &color, REAL width = 1.0);
    Pen(Brush *brush, REAL width = 1.0);
    Первый конструктор создает объект класса Pen на основе объекта класса Color. Второй конструктор создает объект класса Pen на основе объекта класса Brush. Параметр width задает толщину пера в логических единицах.
    В следующем примере показаны два способа создания пера красного цвета и толщиной 4.
    Код (C):
    1.  // способ первый: просто создаем объект класса Pen
    2.  Pen pen1(Color(255, 0, 0), 4.0);
    3.  // способ второй:  сперва создаем сплошную кисть
    4.  SolidBrush sBrush(Color::Red); // красный цвет
    5.  // а затем создаем объект класса Pen на основе объекта sBrush
    6.  Pen pen2(&sBrush, 4.0);
    Прежде чем перейти к изучению основных методов класса Pen, следует отметить, что в этом классе (как и в классе Brush) есть методы GetLastStatus и Clone. Метод Clone имеет следующий прототип:
    Pen* Clone();
    В случае успеха метод Clone возвращает указатель на объект класса Pen, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.

    Цвет пера

    Цвет пера определяет цвет рисуемых линий. В классе Pen определены два метода – GetColor и SetColor, которые работают с цветом пера. Эти методы имеют следующие прототипы:
    GetColor(Color *color);
    SetColor(Color &color);
    Метод GetColor сохраняет текущее значение цвета пера в объект класса Color, на который указывает параметр color, а метод SetColor задает новое значение цвета пера.

    Толщина и выравнивание пера

    Толщину пера можно указать в качестве одного из параметров конструктора класса Pen при создании объекта это класса. Можно также изменять толщину пера с помощью метода SetWidth:
    SetWidth(REAL width);
    Параметр width задает новую толщину пера. Определить текущую толщину пера можно с помощью метода GetWidth класса Pen:
    REAL GetWidth();
    Если толщина пера больше 1.0, при рисовании замкнутого контура можно указать положение такого пера относительно рисуемого контура. Для этого используется метод SetAlignment класса Pen:
    SetAlignment(PenAlignment penAlignment);
    Параметр penAlignment задает положение пера. Этот параметр может принимать одно из значений перечисляемого типа PenAlignment:
    • PenAlignmentCenter – перо располагается по центру контура рисуемой фигуры;
    • PenAlignmentInset – перо располагается с внутренней стороны контура рисуемой фигуры.
    По умолчанию перо имеет положение по центру контура. Определить текущее положение пера относительно контура можно с помощью метода GetAlignment класса Pen:
    PenAlignment GetAlignment();

    Стиль штриха

    Стиль штриха определяет, каким образом будут рисоваться различные линии и контуры. Например, они могут рисоваться непрерывно или пунктиром, или еще как-нибудь. В классе Pen есть метод SetDashStyle, который задает стиль штриха. Этот метод имеет следующий прототип:
    SetDashStyle(DashStyle dashStyle);
    Параметр dashStyle определяет новый стиль штриха. Этот параметр должен принимать одно из значений перечисляемого типа DashStyle:
    • DashStyleSolid – сплошная линия;
    • DashStyleDash – обычный штрих;
    • DashStyleDot – точки;
    • DashStyleDashDot – штрих-пунктир;
    • DashStyleDashDotDot – штрих-две точки.
    На рисунке представлены варианты линий, нарисованных с различными стилями штриха.

    Положение пера при рисовании окружности

    По умолчанию перо имеет положение по центру контура. Определить текущее положение пера относительно контура можно с помощью метода GetAlignment класса Pen:
    PenAlignment GetAlignment();

    Стиль штриха

    Стиль штриха определяет, каким образом будут рисоваться различные линии и контуры. Например, они могут рисоваться непрерывно или пунктиром, или еще как-нибудь. В классе Pen есть метод SetDashStyle, который задает стиль штриха. Этот метод имеет следующий прототип:
    SetDashStyle(DashStyle dashStyle);
    Параметр dashStyle определяет новый стиль штриха. Этот параметр должен принимать одно из значений перечисляемого типа DashStyle:
    DashStylehex
    DashStyleSolid0сплошная линия 00.png
    DashStyleDash1обычный штрих 01.png
    DashStyleDot2точки 02.png
    DashStyleDashDot3штрих-пунктир 03.png
    DashStyleDashDotDot4штрих-две точки 00.png
    По умолчанию перо рисует сплошную линию. Определить текущий стиль штриха можно с помощью метода GetDashStyle класса Pen:
    DashStyle GetDashStyle();
    Если стандартные стили штрихов не подходят, можно использовать собственный шаблон штриха. В классе Pen есть метод SetDashPattern, который задает шаблон штриха. Этот метод имеет следующий прототип:
    SetDashPattern(REAL *dashArray, INT count);
    1. dashArray, указывает на массив значений типа float, каждое из которых определяет длину штрихов и пробелов между ними. Все значения в этом массиве должны быть больше нуля.
    2. count, определяет количество элементов в массиве, на который указывает параметр dashArray.
    В следующем примере показано, как можно задавать шаблон штриха с помощью метода SetDashPattern класса Pen.
    Пример задания шаблона штриха
    Код (C):
    1.  // массив штрихов и пробелов
    2.  float dash[8] = { 6.0, // штрих длиной 6
    3.  3.0, // пробел длиной 3
    4.  1.0, // штрих длиной 1
    5.  2.0, // пробел длиной 2
    6.  1.0, // штрих длиной 1
    7.  2.0, // пробел длиной 2
    8.  1.0, // штрих длиной 1
    9.  3.0}; // пробел длиной 3
    10.  // создаем перо черного цвета и толщиной 2
    11.  Pen pen(Color::Black, 2.0);
    12.  // задаем шаблон штриха
    13.  pen.SetDashPattern(dash, 8);
    В приведенном примере шаблон штриха создается на основе массива {6, 3, 1, 2, 1, 2, 1, 3}. Умножив элементы этого массива на толщину пера, равную 2, получим массив {12, 6, 2, 4, 2, 4, 2, 6}. Получившиеся штрихи будут иметь длину 12 и 2, а длина промежутков между ними будет равна 6 или 4. Нарисованная с помощью такого пера линия показана на рисунке.
    02.png
    Пример штриховой линии​
    Если для пера установлен шаблон штриха, определить количество элементов в массиве, задающем длину штрихов и пробелов, можно с помощью метода GetDashPatternCount класса Pen, получить значения этого массива с помощью метода GetDashPattern.
    INT GetDashPatternCount();
    GetDashPattern(REAL *dashArray, INT count);
    1. dashArray, указывает на массив типа float, в который будут сохранены длины штрихов и пробелов в установленном шаблоне штриха.
    2. count, задает количество элементов в массиве, на который указывает параметр dashArray.
    Стиль штриха определяет не только длину штрихов, но и форму их концов. В классе Pen есть метод SetDashCap, который указывает форму обоих концов каждого штриха. Метод SetDashCap имеет следующий прототип:
    SetDashCap(DashCap dashCap);
    Параметр dashCap задает форму концов штриха. Этот параметр должен принимать одно из значений перечисляемого типа DashCap:
    На рисунке представлены линии, нарисованные с различными концами штриха.
    DashCaphex
    DashCapFlat0прямоугольная форма 00.png
    DashCapRound2круглая форма 01.png
    DashCapTriangle3треугольная форма 02.png
    Штрихованные линии с различными формами концов штриха
    По умолчанию перо использует прямоугольную форму для обоих концов штриха. Определить текущую форму конца штриха можно с помощью метода GetDashCap класса Pen: GetDashCap();
    При рисовании линий также можно указать расстояние от начала линии до начала штриха. На рисунке, показана линия, для которой расстояние от начала линии до начала штриха равно 0, а на рисунке б – линия, для которой такое расстояние равно 3. При этом в обоих случаях используется шаблон штриха из примера в листинге.
    00.png 01.png
    а​
    б​
    Пример штриховой линии, в которой штрих начинается:
    а – с начала; б – с небольшим смещением
    В классе Pen есть два метода – GetDashOffset и SetDashOffset. Метод GetDashOffset возвращает текущее расстояние от начала линии до начала штриха, а метод SetDashOffset изменяет это расстояние.
    REAL GetDashOffset();
    SetDashOffset(REAL dashOffset);

    Соединение и концы линий

    Соединение линий – это область, образуемая двумя линиями с соприкасающимися концами. Стиль соединения линий является атрибутом. После задания стиля соединения линий для объекта класса Pen этот стиль будет применяться ко всем соединенным линиям, для рисования которых используется данный объект.
    Для задания стиля соединения линий в классе Pen служит метод SetLineJoin:
    SetLineJoin(LineJoin lineJoin);
    Параметр lineJoin задает новый стиль соединения линий. Этот параметр должен принимать одно из значений перечисляемого типа LineJoin:
    LineJoinhex
    LineJoinMiter0угловое соединение со скосом в 45°. Получается острый (рис. а) или обрезанный угол (рис. б) в зависимости от того, превышает ли длина среза ограничение по срезу
    LineJoinBevel1скошенное соединение. Получается угол при диагонали
    LineJoinRound2круговое соединение. Получается ровная круговая дуга между двумя линиями
    LineJoinMiterClipped3угловое соединение со скосом в 45°. Получается острый (рис. а) или срезанный угол (рис. б) в зависимости от того, превышает ли длина среза ограничение по срезу
    01.png 00.png
    а​
    б​
    Угловое соединение, в котором длина среза:
    а – не превышает ограничение;
    б – превышает ограничение
    По умолчанию перо использует угловое соединение. Определить текущий стиль соединения линий можно с помощью метода GetLineJoin класса Pen: GetLineJoin();
    Для того чтобы установить ограничение по срезу следует использовать метод SetMiterLimit класса Pen: SetMiterLimit(REAL miterLimit);
    Параметр miterLimit задает новое ограничение по срезу. Если значение параметра miterLimit меньше 1, оно будет заменено на 1.
    По умолчанию ограничение по срезу имеет значение 10. Определить текущее значение ограничения по срезу можно с помощью метода GetMiterLimit класса Pen:
    REAL GetMiterLimit();
    Еще одним атрибутом является форма концов линии. Для указания формы концов линий в классе Pen есть два метода – SetStartCap и SetEndCap. Метод SetStartCap задает форму начала линии, а метод SetEndCap – форму окончания линии. Прототипы этих методов имеют следующий вид:
    SetStartCap(LineCap startCap);
    SetEndCap(LineCap endCap);
    Параметр startCap (endCap) определяет форму начала (окончания) линии. Этот параметр должен принимать одно из значений перечисляемого типа LineCap:
    ▪ LineCapFlat – прямоугольная форма;
    ▪ LineCapSquare – квадратная форма;
    ▪ LineCapRound – круглая форма;
    ▪ LineCapTriangle – треугольная форма;
    ▪ LineCapNoAnchor – без маркера;
    ▪ LineCapSquareAnchor – квадратный маркер;
    ▪ LineCapRoundAnchor – круглый маркер;
    ▪ LineCapDiamondAnchor – маркер в форме ромба;
    ▪ LineCapArrowAnchor – маркер в форме стрелки.
    По умолчанию на обоих концах перо использует плоское завершение. Определить текущую форму можно с помощью двух методов класса Pen – GetStartCap и GetEndCap. Метод GetStartCap определяет форму начала линии, а метод GetEndCap – форму окончания линии.
    GetStartCap();
    GetEndCap();
    На рисунке показаны различные стили соединений в сочетании с разными формами начала и окончания ломаной линии.
    LineJoinMiterLineJoinBevelLineJoinRound
    LineCapFlat 00.png
    LineCapSquare 01.png
    LineCapRound 02.png
    LineCapTriangle 03.png
    Ломаные линии с различными стилями соединений в сочетании с разными формами начала и окончания
    Обратите внимание на рисунок, на котором представлены варианты линий, на обоих концах которых нарисованы специальные фигуры, называемые маркерами.
    hex
    LineCapSquareAnchor11 00.png
    LineCapRoundAnchor12 01.png
    LineCapDiamondAnchor13 02.png
    LineCapArrowAnchor14 03.png
    Линии с различными типами маркеров
    Нужно отметить, что в классе Pen имеется метод SetLineCap, который позволяет сразу задать форму для обоих концов линии и форму для концов штриха. Метод имеет SetLineCap следующий прототип:
    SetLineCap(LineCap startCap, LineCap endCap, DashCap dashCap);
    Параметры startCap и endCap определяют форму, соответственно, начала и окончания линии. Эти параметры должны принимать одно из значений перечисляемого типа LineCap.
    Последний параметр, dashCap, определяет форму обоих концов каждого штриха. Этот параметр должен принимать одно из значений перечисляемого типа DashCap.
     
    Последнее редактирование: 8 янв 2025
    MaKsIm и Thetrik нравится это.
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Составные перья

    Составное перо рисует составную (сложную) линию, состоящую из параллельных линий и разделяющих их промежутков.
    Класс Pen позволяет делать из обычного пера составное перо. Для этого в классе Pen есть метод SetCompoundArray:
    SetCompoundArray(REAL *compoundArray, INT count);
    1. compoundArray, указывает на массив значений типа float, определяющих составное перо. Значения в массиве должны быть в порядке возрастания и находиться в диапазоне от 0 до 1.0.
    2. count, определяет количество элементов в массиве, на который указывает параметр compoundArray.
    В листинге приведен пример создания составного пера, которым нарисованы контуры для фигур, изображенных на рисунке.
    Пример создания составного пера
    Код (C):
    1.  // создаем перо черного цвета и толщиной 10
    2.  Gdiplus::Pen pen(Color::Black, 10.f);
    3.  // массив, определяющий составное перо
    4.  float comp[6] = { 0.0f, 0.2f, // 1-я линия: от 0% до 20% от толщины пера
    5.  0.3f, 0.7f, // 2-я линия: от 30% до 70% от толщины пера
    6.  0.8f, 1.0f}; // 3-я линия: от 80% до 100% от толщины пера
    7.  pen.SetCompoundArray(comp, 6); // делаем из пера составное перо
    00.png
    Рисование контуров составным пером​
    Если перо является составным, определить количество элементов в массиве, определяющем это составное перо, можно с помощью метода GetCompoundArrayCount класса Pen, получить значения этого массива с помощью метода GetCompoundArray.
    INT GetCompoundArrayCount();
    GetCompoundArray(REAL *compoundArray, INT count);
    1. compoundArray, указывает на массив типа float, в который будут сохранены значения массив, определяющего это составного перо.
    2. count, задает количество элементов в массиве, на который указывает параметр compoundArray.

    Перья с текстурным заполнением

    Вместо рисования линий сплошным цветом можно нарисовать их с текстурной заливкой, например, как на рисунке. Для рисования линий с текстурной заливкой необходимо создать объект класса TextureBrush, определяющего текстурную кисть, и передать этот объект конструктору класса Pen при создании пера.
    00.png
    Рисование пером с текстурным наполнением​

    Шрифты

    Для отображения текста используется шрифт (font), который определяет форму букв отображаемого текста. Работа с шрифтами в GDI+ осуществляется с помощью класса Font, который определен в заголовочном файле gdiplusheaders.h.
    Класс Font имеет следующие конструкторы:
    Font(HDC hdc);
    Font(HDC hdc, LOGFONTA *logfont);
    Font(HDC hdc, LOGFONTW *logfont);
    Font(HDC hdc, HFONT hfont);
    Font(FontFamily *family, REAL emSize, INT style = FontStyleRegular, Unit unit = UnitPoint);
    Font(WCHAR *familyName, REAL emSize, INT style = FontStyleRegular, Unit unit = UnitPoint, FontCollection *fontCollection = NULL);
    Первый конструктор создает объект класса Font на основе дескриптора контекста устройства, на который указывает параметр hdc.
    Второй и третий конструкторы создают объект класса Font на основе дескриптора контекста устройства и структуры LOGFONT, на которую указывает параметр logfont. Структура LOGFONT используется в библиотеке GDI для создания шрифтов.
    Четвертый конструктор создает объект класса Font на основе дескриптора контекста устройства и дескриптора шрифта, на который указывает параметр hfont. Дескриптор шрифта возвращают функции библиотеки GDI, которые создают шрифт, – CreateFont и CreateFontIndirect.
    Пятый и шестой конструкторы создают объект класса Font на основе имени гарнитуры шрифта, одними из известных гарнитур являются Arial, Times New Roman и Courier New. В пятом конструкторе имя гарнитуры определяется объектом класса FontFamily, на который указывает параметр family, а в шестом – строкой в формате Unicode, на которую указывает familyName.
    Параметр emSize задает размер шрифта в единицах измерения, задаваемых параметром unit. Параметр unit должен принимать одно из значений перечисляемого типа Unit.
    Параметр style задет стиль шрифта. Этот параметр должен принимать одно (или комбинацию) из значений перечисляемого типа FontStyle:
    FontStylehex
    FontStyleRegular0обычный текст
    FontStyleBold1полужирный текст
    FontStyleItalic2курсивный текст
    FontStyleBoldItalic3полужирный и курсивный текст
    FontStyleUnderline4подчеркнутый текст
    FontStyleStrikeout8перечеркнутый текст
    Параметр fontCollection указывает на объект класса FontCollection. Класс FontCollection используется в GDI+ для представления набора шрифтов, из которого будет выбираться шрифт, подходящий под задаваемые параметры, при создании объекта класса Font. Если этот параметр установлен в NULL, шрифт будет выбираться из набора шрифтов, установленных в операционной системе.
    В следующем примере показаны два способа создания шрифта Times New Roman размером 14 пт., который соответствует курсивному и перечеркнутому тексту.
    Пример создания шрифта
    Код (C):
    1.  // способ первый: просто создаем объект класса Font
    2.  Font font1(L"Times New Roman", 14.0,
    3.  FontStyleItalic|FontStyleUnderline);
    4.  // способ второй: сперва объект класса FontFamily,
    5.  FontFamily family(L"Times New Roman");
    6.  // а затем объект класса Font
    7.  Font font2(&family, 14.0, FontStyleItalic|FontStyleUnderline);
    На рисунке показаны различные варианты гарнитур Arial, Times New Roman и Courier New в сочетании с различными стилями.
    FontStyleUnderlineFontStyleUnderlineFontStyleStrikeout
    FontStyleRegular 00.png
    FontStyleBold 01.png
    FontStyleItalic 02.png
    FontStyleBoldItalich 03.png
    Варианты шрифтов с различными стилями
    В классе Font определено несколько методов, которые могут быть полезны при работе с объектами этого класса. Основные методы этого класса перечислены в таблице. Подробное описание методов класса Font можно найти в документации Platform SDK.
    Методы класса Font
    МетодОписание
    Font* Clone()Клонирует текущий объект класса Font.
    Возвращает указатель на созданный объект класса Font, который должен быть удален вызовом оператора delete после того как станет не нужен
    GetFamily(FontFamily *family)Возвращает имя гарнитуры шрифта. Результат сохраняется в объекте класса FontFamily, на который указывает параметр family
    REAL GetHeight(REAL dpi);
    REAL GetHeight(Graphics *graphics);
    Возвращает значение междустрочного интервала шрифта
    GetLastStatus()Возвращает значение, указывающее на причину возникновения ошибки (или ее отсутствие) в последнем вызове одного из методов класса Font
    GetLogFontA(Graphics *g, LOGFONTA *logfontA);
    GetLogFontW(Graphics *g, LOGFONTW *logfontW)
    Возвращает информацию о шрифте.
    Результат сохраняется в структуру LOGFONTA (LOGFONTW), на которую указывает параметр logfontA (logfontW)
    REAL GetSize()Возвращает размер шрифта
    INT GetStyle()Возвращает стиль шрифта
    Unit GetUnit()Возвращает единицы изменения, в которых задается размер шрифта
    BOOL IsAvailable()Возвращает TRUE, если объект класса Font успешно создан, в противном случае – FALSE

    Изображения

    Для работы с изображениями в GDI+ имеется класс Image и два его потомка Metafile и Bitmap. Все эти классы определены в заголовочном файле gdiplusheaders.h.

    Векторные изображения

    Для работы с векторным изображением в GDI+ используется класс Metafile, который является потомком класса Image.
    Конструктор класса Metafile: Metafile(WCHAR *filename);
    Конструктор создает объект класса Metafile на основе метафайла (metafile). Параметр filename указывает на Unicode-строку, содержащую имя метафайла.
    В примере показано, как создать объект класса Metafile из метафайла Sample.emf.
    Код (C):
    1.  // загрузка из файла Sample.emf
    2.  Metafile mf(L"Sample.emf");
    Кроме загрузки векторных изображений из файла, объект класса Metafile можно создавать с помощью других конструкторов:
    Metafile(HMETAFILE hWmf, WmfPlaceableFileHeader *wmfPlaceableFileHeader, BOOL deleteWmf = FALSE);
    Metafile(HENHMETAFILE hEmf, BOOL deleteEmf = FALSE);
    Metafile(WCHAR *filename, WmfPlaceableFileHeader *wmfPlaceableFileHeader);
    Metafile(IStream *stream);
    Metafile(HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(HDC referenceHdc, RectF &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(HDC referenceHdc, Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(WCHAR *fileName, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(WCHAR *fileName, HDC referenceHdc, RectF &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi,
    EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(WCHAR *fileName, HDC referenceHdc, Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(IStream *stream, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(IStream *stream, HDC referenceHdc, RectF &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Metafile(IStream *stream, HDC referenceHdc, Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, WCHAR *description = NULL);
    Подробное описание этих конструкторов, а также всех методов класса Metafile можно найти в документации Platform SDK.
     
    Последнее редактирование: 8 янв 2025
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Растровые изображения

    Для работы с растровым изображением в GDI+ используется класс Bitmap, который является потомком класса Image.
    Класс Bitmap имеет следующие конструкторы:
    Bitmap( WCHAR *filename, BOOL useIcm = FALSE);
    Bitmap(INT width, INT height, PixelFormat format = PixelFormat32bppARGB);
    Первый конструктор создает объект класса Bitmap на основе растрового файла. Параметр filename указывает на Unicode-строку, содержащую имя файла, а параметр useIcm указывает, применяется ли цветокоррекция согласно информации об управлении цветом в файле с изображением. Если параметр useIcm имеет значение FALSE, цветокоррекция не применяется.
    Второй конструктор создает объект класса Bitmap на основе параметров width и height, которые определяют, соответственно ширину и высоту растрового изображений. Параметр format задает формат кодирования цвета в новом растровом изображении. Этот параметр должен принимать одно следующих значений:
    • PixelFormat1bppIndexed – индексированные цвета, которые кодируются 1 битом (палитра содержит 21=2 цвета);
    • PixelFormat4bppIndexed – индексированные цвета, которые кодируются 4 битами (палитра содержит 24=16 цветов);
    • PixelFormat8bppIndexed – индексированные цвета, которые кодируются 8 битами (палитра содержит 28=256 цветов);
    • PixelFormat16bppGrayScale – оттенки серого, которые кодируются 16 битами (216=65536 оттенков серого);
    • PixelFormat16bppRGB555 – цвет кодируется 5+5+5+1=16 битами: по 5 бит на красный, зеленый и синий компоненты модели RGB. Оставшийся бит не используется;
    • PixelFormat16bppRGB565 – цвет кодируется 5+5+6=16 битами: по 5 бит на красный и синий, и по 6 бит на зеленый компоненты модели RGB;
    • PixelFormat16bppARGB1555 – цвет кодируется 1+5+5+5=16 битами: по 5 бит на красный, зеленый и синий компоненты модели RGB. Оставшийся бит используется на альфа-фактор;
    • PixelFormat24bppRGB – цвет кодируется 8+8+8=24 битами: по 8 бит на красный, зеленый и синий компоненты модели RGB;
    • PixelFormat32bppARGB – цвет кодируется 8+8+8+8=32 битами: по 8 бит на красный, зеленый и синий компоненты модели RGB. Оставшиеся биты используются на альфа-фактор;
    • PixelFormat32bppRGB – цвет кодируется 8+8+8+8=32 битами: по 8 бит на красный, зеленый и синий компоненты модели RGB. Оставшиеся биты не используются;
    • PixelFormat48bppRGB – цвет кодируется 16+16+16+16=64 битами: по 16 бит на красный, зеленый и синий компоненты модели RGB. Оставшиеся биты не используются;
    • PixelFormat64bppARGB – цвет кодируется 16+16+16+16=64 битами: по 16 бит на красный, зеленый и синий компоненты модели RGB. Оставшиеся биты используются на альфа-фактор.
    В следующем примере показано, как можно создать объект класса Bitmap из файла Sample.png.
    Код (C):
    1.  // загрузка из файла Sample.png
    2.  Bitmap bmp(L"Sample.png");
    Кроме уже рассмотренных конструкторов класс Bitmap имеет еще и следующие конструкторы:
    Bitmap(IStream *stream, BOOL useEmbeddedColorManagement = FALSE);
    Bitmap(INT width, INT height, INT stride, PixelFormat format, BYTE *scan0);
    Bitmap(INT width, INT height, Graphics *target);
    Bitmap(IDirectDrawSurface7 *surface);
    Bitmap(BITMAPINFO *gdiBitmapInfo, VOID *gdiBitmapData);
    Bitmap(HBITMAP hbm, HPALETTE hpal);
    Bitmap(HICON hicon);
    Bitmap(HINSTANCE hInstance, WCHAR *bitmapName);
    Для получения и установки цвета определенного пиксела в растровом изображении класс предоставляет методы GetPixel и SetPixel:
    GetPixel(INT x, INT y, Color *color);
    SetPixel(INT x, INT y, Color &color);
    Метод GetPixel сохраняет текущее значение цвета пикселя в объект класса Color, на который указывает параметр color, а метод SetPixel задает новое значение цвета пикселя. Параметры x и y задают координаты указанного пикселя.

    Класс Image

    Класс Image позволяет работать, как с векторным изображением, так и растровым.
    Класс Image имеет следующие конструкторы:
    Image(WCHAR *filename, BOOL useEmbeddedColorManagement = FALSE);
    Image(IStream *stream, BOOL useEmbeddedColorManagement = FALSE);
    Первый конструктор создает объект класса Image на основе файла (векторного или растрового). Параметр filename указывает на Unicode-строку, содержащую имя файла. Второй конструктор создает объект класса Image на основе интерфейса IStream COM-объекта, на который указывает параметр stream. Параметр useEmbeddedColorManagement указывает, применяется ли цветокоррекция согласно информации об управлении цветом в файле с изображением. Если параметр useEmbeddedColorManagement имеет значение FALSE, цветокоррекция не применяется.
    Рассмотрим некоторые методы класса Image, которые наследуют все потомки этого класса.
    Среди методов класса Image есть методы GetLastStatus и Clone. Метод Clone имеет следующий прототип:
    Image* Clone();
    В случае успеха метод Clone возвращает указатель на объект класса Image, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    Определить тип изображения можно с помощью метода GetType класса Image. Этот метод имеет следующий прототип:
    ImageType GetType();
    Метод возвращает одно из следующих значений перечисляемого типа ImageType:
    ImageTypehex
    ImageTypeUnknown0неизвестный тип изображения
    ImageTypeBitmap1растровое изображение
    ImageTypeMetafile2векторное изображение
    Для определения формата кодирования цвета в изображении в классе Image есть метод GetPixelFormat(); Метод возвращает одно из значений перечисляемого типа PixelFormat.
    Ширину и высоту изображения можно определить, соответственно, с помощью методов GetWidth и GetHeight класса Image:
    UINT GetWidth();
    UINT GetHeight();
    В классе Image есть два статических метода FromFile и FromStream, которые создают объект класса Image аналогично его конструкторам:
    static Image* FromFile(WCHAR *filename, BOOL useEmbeddedColorManagement = FALSE);
    static Image* FromStream(IStream *stream, BOOL useEmbeddedColorManagement = FALSE);
    В случае успеха методы FromFile и FromStream возвращают указатель на объект класса Image, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    Следующий небольшой пример демонстрирует загрузку растрового изображения из файла с помощью метода FromFile класса Image:
    Код (C):
    1. // загрузка из файла Sample.png
    2.  Image *image = Image::FromFile(L"Sample.png");
    3.  if (NULL != image)
    4.  { /* файл успешно загружен */
    5. } // if
    Метод FromStream класса Image можно, например, использовать для загрузки изображений из ресурсов приложения Windows, как показано в примере из листинга.
    Функция загрузки изображения из ресурсов приложения
    Код (C):
    1.  Image* ImageFromResource(HINSTANCE hInstance, LPCTSTR szResName, LPCTSTR szResType)
    2.  { // поиск ресурса указанного типа
    3.  HRSRC hRsrc = FindResource(hInstance, szResName, szResType);
    4.  if (NULL == hRsrc) return NULL;
    5.  // загрузка ресурса
    6.  HGLOBAL hResource = LoadResource(hInstance, hRsrc);
    7.  if (NULL == hResource) return NULL;
    8. // определяем размера ресурса
    9. DWORD cbImage = SizeofResource(hInstance, hRsrc);
    10.  // выделение памяти для буфера
    11.  HGLOBAL hData = GlobalAlloc(GMEM_FIXED, cbImage);
    12.  if (NULL != hData)
    13.  { // копируем изображение в буфер
    14.  CopyMemory(GlobalLock(hData), LockResource(hResource), cbImage);
    15.  GlobalUnlock(hData);
    16.  UnlockResource(hResource);
    17.  } // if
    18.  FreeResource(hResource); // освобождение ресурса
    19.  //////////////////
    20.  if (NULL != hData)
    21.  { IStream *pStream = NULL;
    22.  // создание COM-объекта
    23.  HRESULT hr = CreateStreamOnHGlobal(hData, TRUE, &pStream);
    24.  if (SUCCEEDED(hr) && NULL != pStream)
    25.  { Image *image = Image::FromStream(pStream); // загрузка изображения
    26.  pStream->Release();
    27.  return image;
    28.  } // if
    29.  GlobalFree(hData); // освобождение памяти
    30.  } // if
    31.  return NULL;
    32.  } // ImageFromResource
    Класс Image предоставляет очень удобный механизм создания эскизов изображений, которые содержат уменьшенную копию изображения. Поскольку эскизы имеют очень малые размеры, они очень быстро отображаются. Для создания эскизов в классе Image определен метод GetThumbnailImage:
    Image* GetThumbnailImage(UINT thumbWidth, UINT thumbHeight, GetThumbnailImageAbort callback = NULL, VOID *callbackData = NULL);
    Первые два параметра, thumbWidth и thumbHeight, указывают требуемые размеры эскиза: соответственно, ширину и высоту. Параметры callback и callbackData могут использоваться, если нужна возможность прерывания процесса создания эскиза. Эти параметры могут быть установлены в NULL.
    В случае успеха метод GetThumbnailImage возвращает указатель на объект класса Image, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.
    Следующий пример демонстрирует создание эскиза размером 320×240 из файла растрового изображения:
    Код (C):
    1.  // загрузка изображения 320x240 из файла Sample.png
    2.  Image *image = Image(L"Sample.png").GetThumbnailImage(320, 240);
    3.  if (NULL != image)
    4.  { /* Изображение успешно загружено */
    5.  } // if
     
    Последнее редактирование: 9 янв 2025
  7. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Вывод графики с помощью GDI+

    Все операции графического вывода в GDI+ выполняются с помощью методов класса Graphics, который определен в заголовочном файле gdiplusgraphics.h.
    Класс Graphics имеет следующие конструкторы:
    Graphics(HDC hdc);
    Graphics(HDC hdc, HANDLE hdevice);
    Graphics(HWND hwnd, BOOL icm = FALSE);
    Graphics(Image *image);
    Первый и второй конструкторы создают объект класса Graphics на основе дескриптора контекста устройства, на который указывает параметр hdc. Второй конструктор для создания объекта класса Graphics также использует дескриптор устройства отображения (параметр hdevice). Третий конструктор создает объект класса Graphics на основе дескриптора окна hwnd. Параметр icm определяет, будет ли применяться настройка цвета. Если параметр icm имеет значение FALSE, настройка цвета не применяется. Четвертый конструктор создает объект класса Graphics на основе объекта класса Image, на который указывает параметр image.
    В приведенном далее примере показана функция отображения, в которой на основе контекста устройства отображения создается объект класса Graphics.
    Пример функции отображения
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  } // Display

    Очистка

    Рисование на экране компьютера отличается от рисования на бумаге, так как бумага изначально является белой и все, что нужно сделать – это нарисовать на ней изображение. Однако при рисовании на экране компьютера прежде необходимо удалить старое уже нарисованное изображение, хранящееся в памяти компьютера.
    В классе Graphics есть метод Clear, который очищает область отображения некоторым цветом фона. Метод Clear имеет следующий прототип:
    Clear(Color &color);
    Параметр color – объект класса Color, в котором представлен цвет фона, используемый для очистки области отображения.

    Рисование фигур и линий

    В классе Graphics все методы рисования имеют две версии: методы с префиксом Draw для рисования линий, контуров и т.п. и c префиксом Fill для заливки замкнутых фигур. Методам с префиксом Draw в качестве параметра требуется указатель на объект класса Pen, методам с префиксом Fill передается указатель на объект класса, порожденного от класса Brush.

    Рисование линий

    Для рисования различных линий используется метод DrawLine класса Graphics. Метод имеет следующие прототипы:
    DrawLine(Pen *pen, INT x1, INT y1, INT x2, INT y2);
    DrawLine(Pen *pen, REAL x1, REAL y1, REAL x2, REAL y2);
    DrawLine(Pen *pen, Point &pt1, Point &pt2);
    DrawLine(Pen *pen, PointF &pt1, PointF &pt2);
    Параметр pt1 (pt2), а также параметры x1 (x2) и y1 (y2) определяют координаты первой (второй) точки рисуемой линии.
    В листинге представлен пример, в котором демонстрируется рисование двух линий пером черного цвета.
    Пример рисования линий
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  // рисуем линию с координатами (100,100) и (200,80)
    9.  g.DrawLine(&blackPen, 100, 100, 200, 80);
    10.  Point pt1(120, 20); // точка (120,20)
    11.  Point pt2(40, 60); // точка (40,60)
    12.  // рисуем линию с координатами (120,20) и (40,60)
    13.  g.DrawLine(&blackPen, pt1, pt2);
    14.  } // Display
    Для рисования ломаных линий используется метод DrawLines класса Graphics. Этот метод имеет следующие прототипы:
    DrawLines(Pen *pen, Point *points, INT count);
    DrawLines(Pen *pen, PointF *points, INT count);
    Параметр points указывает на массив объектов класса Point (PointF), которые содержат координаты вершин рисуемой ломаной линии, параметр count задает количество элементов в массиве, на который указывает параметр points.
    В следующем примере демонстрируется рисование ломаной линии из четырех точек с помощью пера черного цвета.
    Пример рисования ломаной линии
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4. // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  Point points[4] = {
    9.  Point(100, 100), // точка (100,100)
    10.  Point(200, 80), // точка (200,80)
    11.  Point(120, 20), // точка (120,20)
    12.  Point(40, 60) // точка (40,60)
    13.  };
    14.  // рисуем ломаную линию
    15.  g.DrawLines(&blackPen, points, 4);
    16.  } // Display

    Рисование прямоугольников

    Для рисования прямоугольников используется метод DrawRectangle класса Graphics, а для закрашивания прямоугольников используется метод FillRectangle этого класса. Методы DrawRectangle и FillRectangle имеет следующие прототипы:
    DrawRectangle(Pen *pen, INT x, INT y, INT width, INT height);
    DrawRectangle(Pen *pen, REAL x, REAL y, REAL width, REAL height);
    DrawRectangle(Pen *pen, Rect &rect);
    DrawRectangle(Pen *pen, RectF &rect);
    FillRectangle(Brush *brush, INT x, INT y, INT width, INT height);
    FillRectangle(Brush *brush, REAL x, REAL y, REAL width, REAL height);
    FillRectangle(Brush *brush, Rect &rect);
    FillRectangle(Brush *brush, RectF &rect);
    Параметр rect, а также параметры x, y, width и height, определяют расположение и размер прямоугольника.
    Как уже было сказано ранее, в классе Graphics методы закрашивания замкнутых фигур отделены от методов рисования контуров таких фигур. Поэтому если необходимо нарисовать закрашенный прямоугольник с контуром, то первым делом необходимо нарисовать закрашенный прямоугольник с помощью метода FillRectangle, а затем контур этого прямоугольника с помощью метода DrawRectangle.
    В листинге представлен пример демонстрирующий рисование двух прямоугольников, изображенных на рисунке.
    Пример рисования прямоугольников
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо зеленого цвета
    7.  Pen pen(Color(0, 128, 0));
    8.  // создаем сплошную кисть
    9.  SolidBrush solidBrush(Color::Yellow); // желтый цвет
    10.  // рисуем закрашенный прямоугольник
    11.  g.FillRectangle(&solidBrush, 100, 70, 120, 50);
    12.  // рисуем контур прямоугольника
    13.  g.DrawRectangle(&pen, 100, 70, 120, 50);
    14.  Rect rect(10, 10, 100, 50);
    15. // рисуем закрашенный прямоугольник
    16.  g.FillRectangle(&solidBrush, rect);
    17.  // рисуем контур прямоугольника
    18.  g.DrawRectangle(&pen, rect);
    19.  } // Display
    00.png
    Пример нарисованных прямоугольников​
    Для рисования и закрашивания сразу нескольких прямоугольников используются, соответственно, методы DrawRectangles и FillRectangles класса Graphics. Эти методы имеет следующие прототипы:
    DrawRectangles(Pen *pen, Rect *rects, INT count);
    DrawRectangles( Pen *pen, RectF *rects, INT count);
    FillRectangles(Brush *brush, Rect *rects, INT count);
    FillRectangles(Brush *brush, RectF *rects, INT count);
    Параметр rects указывает на массив объектов класса Rect (RectF), которые определяют расположение и размеры прямоугольников, а параметр count задает количество элементов в массиве, на который указывает параметр rects.
    В листинге представлен немного видоизменный пример. В этом примере для рисования сразу двух прямоугольников используются методы FillRectangles и DrawRectangles.
    Пример рисования сразу нескольких прямоугольников
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо зеленого цвета
    7.  Pen pen(Color(0, 128, 0));
    8.  // создаем сплошную кисть
    9.  SolidBrush solidBrush(Color::Yellow); // желтый цвет
    10.  // массив прямоугольников
    11.  Rect rects[2] = { Rect(100, 70, 120, 50), Rect(10, 10, 100, 50) };
    12.  // рисуем закрашенные прямоугольники
    13.  g.FillRectangles(&solidBrush, rects, 2);
    14.  // рисуем контуры прямоугольников
    15.  g.DrawRectangles(&pen, rects, 2);
    16.  } // Display
    Рисование многоугольников
    Для рисования и закрашивания полигонов (многоугольников) используются, соответственно, методы DrawPolygon и FillPolygon класса Graphics. Эти методы имеют следующие прототипы:
    DrawPolygon(Pen *pen, Point *points, INT count);
    DrawPolygon(Pen *pen, PointF *points, INT count);
    FillPolygon(Brush *brush, Point *points, INT count);
    FillPolygon(Brush *brush, PointF *points, INT count);
    FillPolygon(Brush *brush, Point *points, INT count, FillMode fillMode);
    FillPolygon(Brush *brush, PointF *points, INT count, FillMode fillMode);
    Параметр points указывает на массив объектов класса Point (PointF), которые содержат координаты вершин рисуемого полигона, а параметр count задает количество элементов в массиве, на который указывает параметр points. Параметр fillMode определяет, как будет производиться заполнение для внутренней части полигона. Этот параметр должен принимать одно из значений FillMode.
    При заполнении полигонов необходимо определить область, которая должна быть заполнена. По умолчанию используется режим заполнения с чередованием. Для того чтобы определить область заполнения в режиме заполнения с чередованием, строится луч из произвольной точки внутри полигона к некоторой точке, которая явно расположена вне полигона. Если луч пересекает нечетное число ребер полигона, выбранная точка расположена в заполняемой области. Четное число пересечений означает, что точка не находится в области заполнения.
    В режиме заполнения с поворотом, так же строится луч, а затем находятся пересечения этого луча с ребрами полигона. Каждому такому пересечению присваивается +1 или –1, в зависимости от того, как ребро пересекает луч – по часовой (слева направо) или против часовой стрелки (справа налево). Если сумма этих значений будет отлична от нуля, точка считается расположенной внутри области заполнения. Если же сумма равна нулю, точка находится вне области заполнения.
    На рисунке показана пятиконечная звезда, нарисованная с различными режимами заполнения.
    Примеры заполнения полигонов (с указанием вершин)
    FillModehex
    FillModeAlternate0режим заполнения с чередованием 01.png
    FillModeWinding1режим заполнения с поворотом 02.png
    В следующем примере демонстрируется рисование закрашенного треугольника с контуром черного цвета.
    Пример рисования треугольника
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  // создаем штриховую кисть
    9.  HatchBrush hatchBrush(
    10.  HatchStyleDiagonalBrick, Color::Black, Color::LightGray);
    11.  // вершины треугольника
    12.  Point points[3] = { Point(100, 100), // точка (100,100)
    13.  Point(200, 130), // точка (200,130)
    14.  Point(110, 200) // точка (110,200)
    15.  };
    16.  // рисуем закрашенный треугольник
    17.  g.FillPolygon(&hatchBrush, points, 3);
    18.  // рисуем контур треугольника
    19.  g.DrawPolygon(&blackPen, points, 3);
    20.  } // Display

    Рисование эллипсов, окружностей, дуг и секторов

    Для рисования и закрашивания эллипсов используются, соответственно, методы DrawEllipse и FillEllipse класса Graphics. Эти методы имеют следующие прототипы:
    DrawEllipse(Pen *pen, INT x, INT y, INT width, INT height);
    DrawEllipse(Pen *pen, REAL x, REAL y, REAL width, REAL height);
    DrawEllipse(Pen *pen, Rect &rect);
    DrawEllipse(Pen *pen, RectF &rect);
    FillEllipse(Brush *brush, INT x, INT y, INT width, INT height);
    FillEllipse(Brush *brush, REAL x, REAL y, REAL width, REAL height);
    FillEllipse(Brush *brush, Rect &rect);
    FillEllipse(Brush *brush, RectF &rect);
    Параметр rect, а также параметры x, y, width и height, определяют расположение и размер эллипса, как показано на рисунке.
    03.png
    Расположение и размер эллипса​
    Следующий пример демонстрирует рисование закрашенного эллипса, круга и окружности, изображенных на рисунке.
    Пример рисования эллипса, круга и окружности
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  // создаем две сплошные кисти
    9.  SolidBrush solidBrush1(Color::Yellow);
    10.  SolidBrush solidBrush2(Color::Aqua);
    11.  // рисуем закрашенный эллипс
    12.  g.FillEllipse(&solidBrush1, 10, 10, 160, 80);
    13.  // рисуем контур эллипса
    14.  g.DrawEllipse(&blackPen, 10, 10, 160, 80);
    15.  Rect rect(180, 50, 70, 70);
    16.  // рисуем круг
    17.  g.FillEllipse(&solidBrush2, rect);
    18.  // рисуем окружность
    19.  g.DrawEllipse(&blackPen, rect);
    20.  } // Display
    Как видно из приведенного примера, перечисленные методы класса Graphics для рисования и закрашивания эллипсов также можно использовать, соответственно, для рисования окружности и круга.
    00.png
    Пример эллипса, круга и окружности​
    Рисование дуги похоже на рисование эллипса. Для рисования дуг использует метод DrawArc класса Graphics. Этот метод имеет следующие прототипы:
    DrawArc(Pen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);
    DrawArc(Pen *pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);
    DrawArc(Pen *pen, Rect &rect, REAL startAngle, REAL sweepAngle);
    DrawArc(Pen *pen, RectF &rect, REAL startAngle, REAL sweepAngle);
    Параметр rect, а также параметры x, y, width и height, определяют расположение и размер прямоугольника, в который вписывается рисуемая дуга. Параметр startAngle задает угол (в градусах) между осью х и начальной точкой дуги. Параметр sweepAngle задает угол (в градусах) между начальной и конечной точкой дуги.
    На рисунке показано, как рисуется дуга по заданным параметрам.
    01.png
    Рисование дуги​
    В листинге представлен пример демонстрирующий рисование двух дуг пером красного цвета и толщиной 2.
    Пример рисования дуг
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6. (x,y)heightwidthx
    7.  // создаем перо красного цвета и толщиной 2
    8.  Pen redPen(Color::Red, 2.f);
    9.  // рисуем дугу от -10 градусов до 130 градусов
    10.  g.DrawArc(&redPen, 100, 70, 120, 50, -10.f, 140.f);
    11.  Rect rect(10, 10, 100, 100);
    12.  // рисуем дугу от 90 градусов до 300 градусов
    13.  g.DrawArc(&redPen, rect, 90.f, 210.f);
    14.  } // Display
    Для того чтобы нарисовать фигуру «сектор» в классе Graphics есть метод DrawPie и есть метод FillPie, который закрашивает эту фигуру.
    02.png
    Пример рисования секторов​
    Методы DrawPie и FillPie класса Graphics имеют следующие прототипы:
    DrawPie(Pen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);
    DrawPie(Pen *pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);
    DrawPie(Pen *pen, Rect &rect, REAL startAngle, REAL sweepAngle);
    DrawPie(Pen *pen, RectF &rect, REAL startAngle, REAL sweepAngle);
    FillPie(Brush *brush, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);
    FillPie(Brush *brush, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);
    FillPie(Brush *brush, Rect &rect, REAL startAngle, REAL sweepAngle);
    FillPie(Brush *brush, RectF &rect, REAL startAngle, REAL sweepAngle);
    Параметр rect, а также параметры x, y, width и height, определяют расположение и размер прямоугольника, в который вписывается сектор. Параметр startAngle задает угол (в градусах) между осью х и начальной точкой сектора. Параметр sweepAngle задает угол (в градусах) между начальной и конечной точкой сектора.
    В следующем примере продемонстрировано рисование диаграммы, состоящей из четырех секторов.
    Пример рисования секторной диаграммы
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  // создаем сплошную кисть
    9.  SolidBrush solidBrush(Color::Red); // красный цвет
    10.  // рисуем первый сектор
    11.  g.FillPie(&solidBrush, -5, 30, 300, 300, 110.f, 30.f);
    12.  // рисуем контур первого сектора
    13.  g.DrawPie(&blackPen, -5, 30, 300, 300, 110.f, 30.f);
    14.  // рисуем еще три сектора...
    15.  Color colors[3] = { Color(255, 192, 0), Color(192, 0, 0), Color(0, 176, 80)};
    16.  float sweepAngle[3] = { 100.f, 115.f, 115.f};
    17.  float angle = 140.f; // начальный угол
    18.  Rect rect(10, 10, 300, 300);
    19.  for (int i = 0; i < 3; ++i) {
    20.  solidBrush.SetColor(colors[I])[/I]; // изменяем цвет кисти
    21.  // рисуем сектор
    22.  g.FillPie(&solidBrush, rect, angle, sweepAngle);
    23.  // рисуем контур сектора
    24.  g.DrawPie(&blackPen, rect, angle, sweepAngle);
    25.  angle += sweepAngle; // увеличиваем угол
    26.  } // for
    27.  } // Display
     
    Последнее редактирование: 9 янв 2025
  8. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Рисование сплайнов

    В дополнение к рисованию линий и дуг GDI+ поддерживает рисование сплайнов (splines), которые являются очень удобным инструментом для рисования кривых в компьютерной графике.
    В классе Graphics есть несколько методов, которые позволяют рисовать кубические сплайны (cubic splines) и сплайны Безье (splines Bezier). Для рисования кубических сплайнов необходимо использовать методы DrawCurve и DrawClosedCurve. Метод DrawCurve рисует обычный кубический сплайн, а метод DrawClosedCurve – замкнутый кубический сплайн. Эти методы имеют следующие прототипы:
    DrawCurve(Pen *pen, Point *points, INT count);
    DrawCurve(Pen *pen, PointF *points, INT count);
    DrawCurve(Pen *pen, Point *points, INT count, REAL tension);
    DrawCurve(Pen *pen, PointF *points, INT count, REAL tension);
    DrawCurve(Pen *pen, Point *points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);
    DrawCurve(Pen *pen, PointF *points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);
    DrawClosedCurve(Pen *pen, Point *points, INT count);
    DrawClosedCurve(Pen *pen, PointF *points, INT count);
    DrawClosedCurve(Pen *pen, Point *points, INT count, REAL tension);
    DrawClosedCurve(Pen *pen, PointF *points, INT count, REAL tension);
    Параметр points указывает на массив объектов класса Point (PointF), определяющий набор точек, через которые проходит сплайн, а параметр count задает количество элементов в массиве, на который указывает параметр points.
    Параметр tension задает напряжение сплайна. По умолчанию напряжение сплайна равно 0.5.
    Параметр offset указывает индекс (начиная с 0) точки в массиве, с которой начинается рисование сплайна, а параметр numberOfSegments указывает их количество. Важно отметить, что все «невидимые» точки из массива, на который указывает параметр points, все равно будут использованы для расчетов.
    00.png
    Кубический сплайн, заданный четырьмя точками​
    В классе Graphics есть метод FillClosedCurve для закрашивания замкнутых кубических сплайнов.
    FillClosedCurve(Brush *brush, Point *points, INT count);
    FillClosedCurve(Brush *brush, PointF *points, INT count);
    FillClosedCurve(Brush *brush, Point *points, INT count, FillMode fillMode, REAL tension = 0.5f);
    FillClosedCurve(Brush *brush, PointF *points, INT count, FillMode fillMode, REAL tension = 0.5f);
    Параметры points, count и tension аналогичны одноименным параметрам метода DrawClosedCurve. Параметр fillMode определяет, как будет производиться заполнение области, образуемой замкнутым сплайном. Этот параметр должен принимать одно из значений перечисляемого типа FillMode.
    В листинге показан пример рисования замкнутого кубического сплайна, проходящего через семь точек.
    Пример рисования замкнутого кубического сплайна
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо зеленого цвета
    7.  Pen pen(Color::Green);
    8.  // создаем сплошную кисть
    9.  SolidBrush solidBrush(Color::Yellow); // желтый цвет
    10.  // массив точек, через кот. Проходит сплайн
    11.  Point points[7] = { Point(50, 50), // точка (50,50)
    12.  Point(100, 25), // точка (100,25)
    13.  Point(200, 5), // точка (200,5)
    14.  Point(250, 50), // точка (250,50)
    15.  Point(300, 100), // точка (300,100)
    16.  Point(350, 200), // точка (350,200)
    17.  Point(250, 250) // точка (250,250)
    18.  };
    19.  // закрашиваем замкнутый сплайн
    20.  g.FillClosedCurve(&solidBrush, points, 7);
    21.  // рисуем замкнутый сплайн
    22.  g.DrawClosedCurve(&pen, points, 7);
    23.  } // Display
    Если нужно нарисовать сплайн Безье следует использовать метод DrawBezier или DrawBeziers. Метод DrawBezier рисует обычный сплайн
    Безье, а метод DrawBeziers – последовательность соединенных сплайнов Безье.
    Метод DrawBezier имеет следующие прототипы:
    DrawBezier(Pen *pen, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);
    DrawBezier(Pen *pen, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4);
    DrawBezier(Pen *pen, Point &pt1, Point &pt2, Point &pt3, Point &pt4);
    DrawBezier(Pen *pen, PointF &pt1, PointF &pt2, PointF &pt3, PointF &pt4);
    Параметры pt1, pt2, pt3 и pt4, а также параметры x1, y1, x2, y2, x3, y3, x4 и y4 задают координаты точек, определяющих положение и кривизну сплайна Безье.
    В следующем примере демонстрируется рисование двух различных сплайнов Безье с помощью метода DrawBezier класса Graphics.
    Пример рисования сплайнов Безье
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем два пера
    7.  Pen pen1(Color::Green); // зеленый цвет
    8.  Pen pen2(Color::Red); // красный цвет
    9.  // рисуем сплайн Безье с начальной точкой (100,100)
    10.  // и конечной точкой (500,100)
    11.  g.DrawBezier(&pen1, 100, 100, 200, 10, 350, 50, 500, 100);
    12.  Point pt1(100, 200); // точка (100,200)
    13.  Point pt2(200, 150); // точка (200,150)
    14.  Point pt3(400, 110); // точка (400,110)
    15.  Point pt4(500, 200); // точка (500,200)
    16.  // рисуем сплайн Безье с начальной точкой (100,200) и конечной точкой (500,200)
    17.  g.DrawBezier(&pen2, pt1, pt2, pt3, pt4);
    18.  } // Display
    Метод DrawBeziers имеет следующие прототипы:
    DrawBeziers(Pen *pen, Point *points, INT count);
    DrawBeziers(Pen *pen, PointF *points, INT count);
    Параметр points указывает на массив объектов класса Point (PointF), определяющий набор контрольных точек сплайнов Безье, а параметр count задает количество элементов в массиве, на который указывает параметр points. При этом точки в массиве должны располагаться так, чтобы последняя точка одного сплайна Безье, являлась начальной точкой следующего сплайна Безье.
    Следующий пример демонстрирует рисование кривой, состоящей сразу из двух сплайнов Безье.
    Пример рисования кривой, состоящей из сплайнов Безье
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо синего цвета
    7.  Pen pen(Color::Blue);
    8.  Point points[7] = { Point(100, 100), // начальная точка 1-го сплайна
    9.  Point(200, 50), Point(400, 10), Point(500, 100), // конечная точка 1-го сплайна
    10.  Point(600, 200), Point(500, 400), Point(800, 350)}; // конечная точка 2-го сплайна
    11.  // рисуем кривую из сплайнов Безье
    12.  g.DrawBeziers(&pen, points, 7);
    13.  } // Display
     
    Последнее редактирование: 6 янв 2025
  9. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Отображение текста

    Для отображения текста в классе Graphics определен метод DrawString, который имеет следующие прототипы:
    DrawString(WCHAR *string, INT length, Font *font, PointF &origin, Brush *brush);
    DrawString( WCHAR *string, INT length, Font *font, PointF &origin, StringFormat *stringFormat, Brush *brush);
    DrawString(WCHAR *string, INT length, Font *font, RectF &layoutRect, StringFormat *stringFormat, Brush *brush);
    Первый параметр, string, указывает на Unicode-строку, содержащую отображаемый текст, а второй параметр, length, задает длину этой строки. Параметр length может принимать значение -1, если строка завершается нуль-символом.
    Третий параметр, font, указывает на объект класса Font, который представляет шрифт для отображения текста.
    Параметр origin – объект класса PointF, который содержит координаты точки расположения текста, а параметр layoutRect определяет прямоугольник, в котором будет отображаться текст.
    Параметр stringFormat указывает на объект класса StringFormat, который управляет форматированием текста.
    Последний параметр, brush, указывает на объект класса Brush, который представляет кисть для отображения текста.
    В следующем примере показано, как с помощью метода DrawString класса Graphics вывести текст «Привет мир!» в виде одной горизонтальной строки.
    Пример простого вывода текста
    Код (C):
    1. void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем шрифт Times New Roman
    7.  Font font(L"Times New Roman", 20.f, FontStyleBold);
    8.  // создаем сплошную кисть
    9.  SolidBrush blackBrush(Color::Black); // черный цвет
    10.  // выводим текст, который начинается в точке (10,10)
    11.  g.DrawString(L"Привет мир!", -1, &font, PointF(10.f, 10.f), &blackBrush);
    12.  } // Display
    При необходимости форматированного вывода текста необходимо использовать объект класса StringFormat, который определен в заголовочном файле gdiplusstringformat.h.
    Класс StringFormat имеет следующие конструкторы:
    StringFormat(INT formatFlags = 0, LANGID language = LANG_NEUTRAL);
    StringFormat(StringFormat *format);
    Первый конструктор создает объект класса StringFormat на основе флагов форматирования, которые задает параметр formatFlags, и идентификатора язык, который задается параметром language.
    Параметр formatFlags может принимать одно (или комбинацию) из перечисляемого типа StringFormatFlags, а значение параметра language можно задавать с помощью макроса MAKELANGID, следующим образом:
    Код (C):
    1.  LANGID language = MAKELANGID(LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA);
    Второй конструктор класса StringFormat создает копию объекта этого же класса, на который указывает параметр format.
    В листинге представлен пример форматированного вывода текста, результат которого показан на рисунке.
    Пример форматированного вывода текста
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем шрифт Times New Roman
    7.  Font font(L"Times New Roman", 20.f, FontStyleBold);
    8.  // создаем сплошную кисть
    9.  SolidBrush blackBrush(Color::Black); // черный цвет
    10.  // создаем перо красного цвета
    11.  Pen pen(Color::Red);
    12.  // создаем объект класса StringFormat для форматированного вывода текста
    13.  StringFormat sf;
    14.  // ограничивающий прямоугольник
    15.  RectF rect(10.f, 10.f, 300.f, 80.f);
    16.  // выводим текст
    17.  g.DrawString(L"Съешь ещё этих мягких французских булок, да выпей чаю.", -1, &font, rect, &sf, &blackBrush);
    18.  // рисуем прямоугольник (только для наглядности)
    19.  g.DrawRectangle(&pen, rect);
    20.  } // Display
    00.png
    Форматированный вывод текста​
    Прежде чем перейти к изучению методов класса StringFormat, следует отметить, что в этом классе (как и во многих других классах GDI+) есть методы GetLastStatus и Clone. Метод Clone имеет следующий прототип:
    StringFormat* Clone();
    В случае успеха метод Clone возвращает указатель на объект класса StringFormat, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.

    Флаги форматирования

    Флаги форматирования можно задавать в качестве одного из параметров конструктора класса StringFormat при создании объекта это класса. Можно также задать флаги форматирования с помощью метода SetFormatFlags:
    SetFormatFlags(INT flags);
    Параметр flags может принимать одно (или комбинацию) из следующих значений перечисляемого типа StringFormatFlags:
    ▪ StringFormatFlagsDirectionRightToLeft – текст будет отображаться справа на лево;
    ▪ StringFormatFlagsDirectionVertical – текст будет отображаться вертикально;
    ▪ StringFormatFlagsNoFitBlackBox – текст будет отображаться без дополнительного пустого пространства между внутренним контуром прямоугольной зоны форматирования и прямоугольником, ограничивающего отображаемый текст;
    ▪ StringFormatFlagsDisplayFormatControl – разрешает отображение управляющих символов, например, таких как метка слева направо (LefttoRight Embedding, LRE);
    ▪ StringFormatFlagsNoFontFallback – запрещается обращение к альтернативным шрифтам при отображении символов, не поддерживаемых в указанном шрифте. Такие символы, как правило, будут отображаться с помощью пустого квадрата;
    ▪ StringFormatFlagsMeasureTrailingSpaces – запрещается исключать пробелы в конце каждой строки при определении размеров ограничивающего прямоугольника;
    ▪ StringFormatFlagsNoWrap – запрещается автоматический перенос текста на новую строку при форматировании в прямоугольнике;
    ▪ StringFormatFlagsLineLimit – при форматировании в прямоугольнике будут отображаться только целые строки;
    ▪ StringFormatFlagsNoClip – разрешается отображать текст, выходящий за пределы прямоугольной зоны форматирования.
    Определить установленные флаги форматирования можно с помощью метода GetFormatFlags класса StringFormat:
    INT GetFormatFlags();
    На рисунке показаны результаты использования некоторых флагов форматирования текста.

    Выравнивание текста

    При отображении текста может потребоваться выровнять этот текст. Чтобы выровнять текст необходимо в метод DrawString класса Graphics передать объект класса StringFormat, в котором задать параметры выравнивания текста с помощью методов SetAlignment и SetLineAlignment. Метод SetAlignment задает выравнивание текста по горизонтали, а метод SetLineAlignment – по вертикали. Эти методы имеют следующие прототипы:
    Status SetAlignment(StringAlignment align);
    Status SetLineAlignment(StringAlignment align);

    Применение флагов форматирования текста


    hex
    00.pngStringFormatFlagsNoFitBlackBox4
    01.pngStringFormatFlagsNoWrap1000
    02.pngStringFormatFlagsLineLimit2000
    03.pngStringFormatFlagsNoClip4000
    Параметр align задает выравнивание текста относительно точки расположения текста или относительно границ прямоугольника, в котором будет отображаться текст. Этот параметр должен принимать одно из следующих значений перечисляемого типа StringAlignment:
    ▪ StringAlignmentNear – выравнивание по ближнему краю;
    ▪ StringAlignmentCenter – выравнивание по центру;
    ▪ StringAlignmentFar – выравнивание по дальнему краю.
    На рисунках показаны различные варианты выравнивания текста относительно точки и границ прямоугольника.
    Варианты выравнивания текста относительно точки
    StringAlignmentNearStringAlignmentCenterStringAlignmentFar
    StringAlignmentNear 00.png
    StringAlignmentCenter 01.png
    StringAlignmentFar 02.png
    Варианты выравнивания текста относительно границ прямоугольника
    StringAlignmentNearStringAlignmentCenterStringAlignmentFar
    StringAlignmentNear 00.png
    StringAlignmentCenter 01.png
    StringAlignmentFar 02.png
    Для горизонтального выравнивания ближним краем будет левый, а дальним краем – правый. Однако, при отображений текста справа на лево ближним краем будет правый, а дальним краем – левый. Для вертикального выравнивания ближним краем будет верхний, а дальним краем – нижний.
    Определить текущее горизонтальное и вертикальное выравнивание можно, соответственно, с помощью методов GetAlignment и GetLineAlignment класса StringFormat. Эти методы имеют следующие прототипы:
    StringAlignment GetAlignment();
    StringAlignment GetLineAlignment();

    Вывод текста с табуляцией

    Для отображаемого текста можно устанавливать позиции табуляции. Для этого в классе StringFormat есть метод SetTabStops. Этот метод имеет следующий прототип:
    SetTabStops(REAL firstTabOffset, INT count, REAL *tabStops);
    Первый параметр, firstTabOffset, задает первое смещение позиции табуляции. Второй параметр, count, определяет количество элементов в массиве табуляции, на который указывает третий параметр – tabStops. Параметр tabStops указывает на массив значений типа float, которые задают смешение позиции табуляции.
    Каждое смещение позиции табуляции, кроме первого, выполняется относительно предыдущей позиции. Первое смещение позиции табуляции выполняется относительно первоначальной позиции смещения. Например, если начальная позиция смещения равна 5 и первое смещение позиции табуляции равно 40, первое смещение позиции табуляции расположено в позиции 45. Если начальная позиция смещения равна нулю, первое смещение позиции табуляции определяется относительно позиции 0, начала строки.
    Следующий пример демонстрирует форматированный вывода текста с табуляцией. Результат показан на рисунке.
    Пример задания позиций табуляции для выводимого текста
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем шрифт Arial
    7.  Font font(L"Arial", 11.f, FontStyleRegular);
    8.  // создаем сплошную кисть
    9.  SolidBrush blackBrush(Color::Black); // черный цвет
    10.  // создаем перо серого цвета
    11.  Pen pen(Color::Gray);
    12.  // создаем объект класса StringFormat для форматированного вывода текста
    13.  StringFormat sf;
    14.  // задаем выравнивание по левому краю
    15.  sf.SetAlignment(StringAlignmentNear);
    16.  // задаем выравнивание по верхнему краю
    17.  sf.SetLineAlignment(StringAlignmentNear);
    18.  float tabs[4] = {50.f, 100.f, 100.f, 100.f};
    19.  // устанавливаем позиции табуляции
    20.  sf.SetTabStops(0.0, 4, tabs);
    21.  // ограничивающий прямоугольник
    22.  RectF rect(10.0, 10.0, 350.0, 90.0);
    23.  wchar_t text[] = L"№\tФамилия\tИмя\tОтчество\n\
    24. 1.\tАндреев\tАлександр\tДмитриевич\n\
    25. 2.\tВасильев\tЮрий\tГеннадиевич\n\
    26. 3.\tГромова\tИнна\tВикторовна\n\
    27. 4.\tМартынов\tПавел\tБорисович";
    28.  // выводим текст
    29.  g.DrawString(text, -1, &font, rect, &sf, &blackBrush);
    30.  // рисуем прямоугольник
    31.  g.DrawRectangle(&pen, rect);
    32.  } // Display
    00.png
    Форматированный вывод текста с табуляцией​
    Определить количество установленных позиций табуляции можно с помощью метода GetTabStopCount, а получить значения этих позиций можно с помощью метода GetTabStops. Прототипы этих методов записываются следующим образом:
    INT GetTabStopCount();
    GetTabStops(INT count, REAL *firstTabOffset, REAL *tabStops);
    Первый параметр, count, указывает количество элементов в массиве, на который указывает параметр tabStops.
    Второй параметр, firstTabOffset, указывает на переменную типа float, в которую будет записано значение первого смещения позиции табуляции.
    Третий параметр, tabStops, указывает на массив типа float, в который будут сохранены значения установленных позиций табуляции.

    Вывод «горячих» клавиш

    Символ «&» (амперсанд) имеет специальное назначение в тексте, используемом в меню, кнопках и других элементах управления – он означает, что следующий за ним знак должен быть подчеркнут и будет использоваться для быстрого доступа к элементу управления. В классе StringFormat есть метод SetHotkeyPrefix, который определяет, как при отображении интерпретируются амперсанды.
    Метод SetHotkeyPrefix имеет следующий прототип:
    SetHotkeyPrefix(HotkeyPrefix hotkeyPrefix);
    Параметр hotkeyPrefix определяет, как будут интерпретироваться амперсанды. Этот параметр должен принимать одно из следующих значений перечисляемого типа HotkeyPrefix:
    HotkeyPrefixhex
    HotkeyPrefixNone0префикс «горячих» клавиш отсутствует 00.png
    HotkeyPrefixShow1отображать префикс «горячих» клавиш 01.png
    HotkeyPrefixHide2не отображать префикс «горячих» клавиш 02.png
    По умолчанию префикс «горячих» клавиш отсутствует. Определить, как интерпретируются амперсанды можно с помощью метода GetHotkeyPrefix класса StringFormat. Этот метод имеет следующий прототип:
    HotkeyPrefix GetHotkeyPrefix();
    В таблице показаны варианты отображения текста «&Файл» с различными режимами интерпретации амперсанда.

    Обрезание текста

    В классе StringFormat есть метод SetTrimming, который определяет, как должны отображаться символы, если текст не полностью помещается в ограничивающий прямоугольник. Метод SetTrimming имеет следующий прототип:
    SetTrimming(StringTrimming trimming);
    Параметр trimming определяет формат обрезания текста. Этот параметр должен принимать одно из следующих значений перечисляемого типа StringTrimming:
    StringTrimminghex
    StringTrimmingNone0текст не обрезается 00.png
    StringTrimmingCharacter1текст обрезается
    по ближайшему символу
    01.png
    StringTrimmingWord2текст обрезается
    по ближайшему слову
    02.png
    StringTrimmingEllipsisCharacter3текст обрезается по
    ближайшему символу и в
    конце обрезанной строки
    вставляется троеточие
    00.png
    StringTrimmingEllipsisWord4текст обрезается по
    ближайшему слову и в
    конце обрезанной строки
    вставляется троеточие
    01.png
    StringTrimmingEllipsisPath5если текст не помещается
    в ограничивающий
    прямоугольник из него
    удаляется центральная
    часть и заменяется
    троеточием
    02.png
    По умолчанию текст обрезается по ближайшему символу. Определить текущий формат обрезания текста можно с помощью метода GetTrimming класса StringFormat. Этот метод имеет следующий формат:
    StringTrimming GetTrimming();
    На рисунке показаны различные варианты обрезания символов, если текст не помещается в ограничивающий прямоугольник.
    Определить ограничивающий прямоугольник для отображения текста с заданным шрифтом можно с помощью метода MeasureString класса Graphics. Этот метод имеет следующие прототипы:
    MeasureString(WCHAR *string, INT length, Font *font, PointF &origin, RectF *boundingBox);
    MeasureString(WCHAR *string, INT length, Font *font, RectF &layoutRect, RectF *boundingBox);
    MeasureString(WCHAR *string, INT length, Font *font, PointF &origin, StringFormat *stringFormat, RectF *boundingBox);
    MeasureString(WCHAR *string, INT length, Font *font, RectF &layoutRect, StringFormat *stringFormat, RectF *boundingBox, INT *codepointsFitted = 0, INT *linesFilled = 0);
    MeasureString(WCHAR *string, INT length, Font *font, RectF &layoutRect, StringFormat *stringFormat, SizeF *size, INT *codepointsFitted = 0, INT *linesFilled = 0);
    Параметры string, length, font, origin, layoutRect и stringFormat аналогичны одноименным параметрам метода DrawString класса Graphics.
    Параметр boundingBox указывает на объект класса RectF, в который будут сохранены расположение и размер ограничивающего прямоугольника.
    Параметр size указывает на объект класса SizeF, в который будет сохранен размер ограничивающего прямоугольника.
    Параметр codepointsFitted указывает на переменную типа INT, в которую записывается количество символов в тексте, размещенном в ограничивающем прямоугольнике.
    Параметр linesFilled указывает на переменную типа INT, в которую записывается количество строк в тексте, размещенном в ограничивающем прямоугольнике.
    Предопределенные форматы
    В классе StringFormat есть два статических метода GenericDefault и GenericTypographic, которые возвращают указатель на предопределенный объект класса StringFormat:
    StringFormat* GenericDefault();
    StringFormat* GenericTypographic();
    Метод GenericDefault возвращает указатель на объект класса StringFormat, который представляет следующими параметрами форматирования:
    ▪ флагов форматирования нет;
    ▪ горизонтальное выравнивание по ближнему краю;
    ▪ вертикальное выравнивание по ближнему краю;
    ▪ позиции табуляции не установлены;
    ▪ префикс «горячих» клавиш отсутствует;
    ▪ текст обрезается по ближайшему символу.
    Метод GenericTypographic возвращает указатель на объект класса StringFormat, который обладает следующими параметрами форматирования:
    ▪ заданы флаги форматирования StringFormatFlagsLineLimit, StringFormatFlagsNoClip и StringFormatFlagsNoFitBlackBox;
    ▪ горизонтальное выравнивание по ближнему краю;
    ▪ вертикальное выравнивание по ближнему краю;
    ▪ позиции табуляции не установлены;
    ▪ префикс «горячих» клавиш отсутствует;
    ▪ текст не обрезается.
    Важно отметить, что не нужно удалять объект, указатель на который возвращают методы метода GenericDefault и GenericTypographic, после того, как необходимость в нем отпадет.
    В следующем примере демонстрируется использование предопределенных объектов класса StringFormat для вывода текста.
    Пример форматированного вывода текста
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем шрифт Arial
    7.  Font font(L"Arial", 14.f, FontStyleRegular);
    8.  // создаем сплошную кисть
    9.  SolidBrush blackBrush(Color::Black); // черный цвет
    10.  // выводим текст, который начинается в точке (10,50)
    11.  g.DrawString(L"Привет мир!", -1, &font, PointF(10.f, 50.f), StringFormat::GenericDefault(), &blackBrush);
    12.  // создаем объект класса StringFormat на основе предопределенного объекта
    13.  StringFormat sf(StringFormat::GenericTypographic());
    14.  // выводим текст, который начинается в точке (10,10)
    15.  g.DrawString(L"Привет мир!", -1, &font, PointF(10.f, 10.f), &sf, &blackBrush);
    16.  } // Display
     
  10. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Вывод графических изображений

    Для отображения содержимого растрового или векторного изображения в классе Graphics есть метод DrawImage, который имеет огромное количество перегруженных вариантов. Наиболее употребительные варианты имеют следующие прототипы:
    DrawImage(Image *image, INT x, INT y);
    DrawImage(Image *image, REAL x, REAL y);
    DrawImage(Image *image, INT x, INT y, INT width, INT height);
    DrawImage(Image *image, REAL x, REAL y, REAL width, REAL height);
    DrawImage(Image *image, Point &point);
    DrawImage(Image *image, PointF &point);
    DrawImage(Image *image, Rect &rect);
    DrawImage(Image *image, RectF &rect);
    Первый параметр, image, указывает на объект класса Image или класса, производного от класса Image. Этот объект представляет изображение, содержимое которого необходимо отобразить.
    Параметр point, а также параметры x и y, определяют расположение выводимого изображения.
    Параметр rect, а также параметры x, y, width и height, определяют расположение и размер выводимого изображения.
    В следующем примере демонстрируется использование метода DrawImage класса Graphics для вывода изображения.
    Пример вывода изображения
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // загружаем изображение Sample.png
    7.  Image image(L"Sample.png");
    8.  // вывод загруженного изображения
    9.  g.DrawImage(&image, 10, 10);
    10.  } // Display
    Важно отметить, что чтение изображения из файла может происходить достаточно медленно. Поэтому разумнее всего было бы вынести загрузку выводимых изображений из функции отображения, а не так как это сделано в приведенном примере.

    Пропорциональное масштабирование изображения

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

    Искажение изображения

    00.png
    Форматное соотношение – это отношение ширины и высоты, которое находится по следующей формуле:
    [math]ratio=\frac{\displaystyle width}{\displaystyle height}[/math](1.2)​
    где [math]ratio[/math] – форматное соотношение, а [math]width[/math] и [math]height[/math] – ширина и высота.
    Для того чтобы при масштабировании изображения не происходило его искажения необходимо найти для него такие ширину и высоту, для которых бы сохранялось их изначальное отношение и которые бы полностью влезали бы в заданный прямоугольник.
    Рассмотрим случай, когда форматное соотношение изображения больше чем форматное соотношение заданного прямоугольника. В этом случае ширина и высота изображения находятся по формуле:
    [math]Image.width=Rectangle.width[/math],
    [math]Image.height=\frac{\displaystyle 1}{\displaystyle ratio}\cdot Rectangle.width[/math] (1.3)​
    где [math]Image.width[/math] и [math]Image.height[/math] – новые ширина и высота изображения; [math]Rectangle.width[/math] – ширина прямоугольника; [math]ratio[/math] – форматное соотношение изображения.
    В другом случае, когда изображение имеет меньшее форматное соотношение, чем у заданного прямоугольника, новые ширина и высота изображения находятся по другой формуле:
    [math]Image.width=ratio\cdot Rectangle.heigth[/math],
    [math]Image.heigth=Rectangle.heigth[/math] (1.4)​
    где [math]Image.width[/math] и [math]Image.heigth[/math] – новые ширина и высота изображения; [math]Rectangle.heigth[/math] – высота прямоугольника; [math]ratio[/math] – форматное соотношение изображения.
    В листинге представлена функция, определяющей ширину и высоту изображения, для которых сохраняется их изначальное отношение, и которые будут полностью влезать в прямоугольник.
    Функция определяющая положение и размер изображения
    Код (C):
    1.  MeasureImage(Image *image, RectF &layout, StringAlignment align, RectF *result)
    2.  {
    3.  if (NULL == image || layout.IsEmptyArea() || NULL == result)
    4.  {
    5.  return InvalidParameter;
    6.  } // if
    7.  RectF rect;
    8.  // форматное соотношение изображения
    9.  float fRatio = (float)image->GetWidth() / (float)image->GetHeight();
    10.  if (fRatio > (layout.Width / layout.Height))
    11.  {
    12.  rect.Width = layout.Width;
    13.  rect.Height = layout.Width / fRatio;
    14.  rect.X = layout.GetLeft();
    15.  // выравнивание по вертикали
    16.     switch (align)   {
    17.  case StringAlignmentNear: // по ближнему краю
    18.  rect.Y = layout.GetTop();
    19.  break;
    20.  case StringAlignmentCenter: // по центру
    21.  rect.Y = layout.Y + (layout.Heightrect.Height)/2.f;
    22.  break;
    23.  case StringAlignmentFar: // по дальнему краю
    24.  rect.Y = layout.GetBottom() - rect.Height;
    25.  break;  } // switch
    26.  } // if
    27.  else
    28.  { rect.Width = fRatio * layout.Height;
    29.  rect.Height = layout.Height;
    30.  rect.Y = layout.GetTop();
    31.  // выравнивание по горизонтали
    32.  switch (align) {
    33.  case StringAlignmentNear: // по ближнему краю
    34.  rect.X = layout.GetLeft();
    35.  break;
    36.  case StringAlignmentCenter: // по центру
    37.          rect.X = layout.X + (layout.Width-rect.Width)/2.f;
    38.          break;
    39.  case StringAlignmentFar: // по дальнему краю
    40.        rect.X = layout.GetRight() - rect.Width;
    41.        break; } // switch
    42.        } // else
    43.  rect.GetBounds(result); // возвращаем результат
    44.  return Ok;
    45.  } // MeasureImage
    Функция, приведенная в этом примере, определяет также положение изображения в задаваемом прямоугольнике в зависимости от параметров выравнивания, т.к. в результате пропорционального масштабирования может оставаться неиспользованное пространство.
    На рисунке представлены различные варианты выравнивания изображения для двух рассмотренных случаев соотношения изображения и прямоугольника.

    Контуры

    Контур (path) представляет собой последовательность графических примитивов (линий, прямоугольников, кривых, текста и т. п.), которые обрабатываются и отображаются как один объект. Контур можно разделить на отдельные фигуры, которые являются либо незамкнутыми, либо замкнутыми.
    В GDI+ создание контуров выполняется с помощью методов класса GraphicsPath, определенного в заголовочном файле gdipluspath.h.
    hex
    StringAlignmentNear 01.png
    StringAlignmentCenter 02.png
    StringAlignmentFar 03.png
    Варианты выравнивания изображения относительно границ прямоугольника
    Класс GraphicsPath имеет следующие конструкторы:
    GraphicsPath(FillMode fillMode = FillModeAlternate);
    GraphicsPath(Point *points, BYTE *types, INT count, FillMode fillMode = FillModeAlternate);
    GraphicsPath(PointF *points, BYTE *types, INT count, FillMode fillMode = FillModeAlternate);
    Первый конструктор создает объект класса GraphicsPath на основе режима заполнения, который задает параметр fillMode.
    Второй и третий конструкторы создают объект класса Graphics-Path на основе массива точек, на который указывает параметр points, а параметр count задает количество элементов в этом массиве. Пара-метр types указывает на массив типа INT, элементы которого определяют тип точек, указанных в массиве. Параметр fillMode задает режим заполнения.
    Тип точек определяется одним (или комбинацией) из значений перечисляемого типа PathPointType.
    Для построения контура в классе GraphicsPath есть множество методов схожих по названию с методами класса Graphics, предназначенных для рисования таких же фигур. В таблице перечислены схожие методы класса GraphicsPath и класса Graphics.
    Таблица Сопоставление методов классов Graphics и GraphicsPath
    Метод класса GraphicsPathАналог в классе GraphicsОписание
    AddArcDrawArcДобавляет в контур дугу
    AddBezierDrawBezierДобавляет в контур сплайн Безье
    AddBeziersDrawBeziersДобавляет в контур кривую, состоящую из сплайнов Безье
    AddClosedCurveDrawClosedCurveДобавляет в контур замкнутый кубический сплайн
    AddCurveDrawCurveДобавляет в контур кубический сплайн
    AddEllipseDrawEllipseДобавляет в контур эллипс
    AddLineDrawLineДобавляет в контур линию
    AddLinesDrawLinesДобавляет в контур ломаную линию
    AddPathDrawPathДобавляет в контур другой контур
    AddPieDrawPieДобавляет в контур сектор
    AddPolygonDrawPolygonДобавляет в контур полигон
    AddRectangleDrawRectangleДобавляет в контур прямоугольник
    AddRectanglesDrawRectanglesДобавляет в контур несколько прямоугольников
    AddStringDrawStringДобавляет в контур строку
    Каждый метод класса GraphicsPath, имеет несколько прототипов схожих с аналогичными методами класса Graphics (подробнее см. в документации Platform SDK).
    Следует отметить, что в классе GraphicsPath, как и в других классах GDI+, есть методы GetLastStatus и Clone. Метод Clone имеет следующий прототип:
    GraphicsPath* Clone();
    В случае успеха метод Clone возвращает указатель на объект класса GraphicsPath, который должен быть удален вызовом оператора delete после того как станет не нужен. В случае ошибки – NULL.

    Рисование контуров

    Для рисования контуров используется метод DrawPath класса Graphics, а для закрашивания контуров используется метод FillPath этого класса. Эти методы имеют следующие прототипы:
    DrawPath(Pen *pen, GraphicsPath *path);
    FillPath(Brush *brush, GraphicsPath *path);
    Параметр path указывает на объект класса GraphicsPath, который представляет отображаемый контур.
    В листинге представлен пример демонстрирующий рисование контура, изображенного на рисунке.
    Пример рисования контура
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  // выполняем очистку перед рисованием
    5.  g.Clear(Color::White); // белый цвет фона
    6.  // создаем перо черного цвета
    7.  Pen blackPen(Color::Black);
    8.  // создаем сплошную кисть
    9.  SolidBrush solidBrush(Color::Yellow); // желтый цвет
    10.  Rect rect(70, 70, 100, 100);
    11.  // создаем объект класса GraphicsPath для построения контура
    12.  GraphicsPath path;
    13.  // добавляем в контур прямоугольник
    14.  path.AddRectangle(rect);
    15.  rect.Inflate(50, 50);
    16.  // добавляем в контур круг
    17.  path.AddEllipse(rect);
    18.  // рисуем закрашенный контур
    19.  g.FillPath(&solidBrush, &path);
    20.  // рисуем контур
    21.  g.DrawPath(&blackPen, &path);
    22.  } // Display
    00.png
    Пример контура​
     
    Последнее редактирование: 9 янв 2025
  11. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Замкнутые контуры

    Для создания замкнутого контура в классе GraphicsPath есть методы StartFigure, CloseFigure и CloseAllFigures.
    Методы StartFigure, CloseFigure и CloseAllFigures имеют следующие прототипы:
    StartFigure();
    CloseFigure();
    CloseAllFigures();
    Метод StartFigure открывает новую фигуру в контуре, не замыкая при этом текущую фигуру. Все последующие примитивы, добавляемые к контуру, добавляются к этой новой фигуре.
    Метод CloseFigure замыкает текущую фигуру и открывает новую фигуру. Если текущая фигура содержит последовательность соединенных линий, метод CloseFigure замыкает ее путем соединения начальной и конечной точек этих линий.
    Метод CloseAllFigures замыкает все незамкнутые фигуры в контуре и открывает новую фигуру.
    В листинге приведен пример создания замкнутого контура прямоугольника с закругленными углами.
    01.png
    Прямоугольник с закругленными краями​
    Функция, создающая замкнутый контур
    Код (C):
    1.  GraphicsPath* CreateRoundRectangle(Rect &rect, int Radius)
    2.  { // создаем объект класса GraphicsPath для построения контура
    3.  GraphicsPath path;
    4.  // добавляем в контур линию
    5.  path.AddLine(rect.GetLeft()+Radius, rect.GetTop(), rect.GetRight()-Radius, rect.GetTop());
    6.  // добавляем в контур дугу
    7.  path.AddArc(rect.GetRight()-Radius, rect.GetTop(), Radius, Radius, 270.f, 90.f);
    8.  // добавляем в контур линию
    9.  path.AddLine(rect.GetRight(), rect.GetTop()+Radius, rect.GetRight(), rect.GetBottom()-Radius);
    10.  // добавляем в контур дугу
    11.  path.AddArc(rect.GetRight()-Radius, rect.GetBottom()-Radius, Radius, Radius, 0.f, 90.f);
    12.  // добавляем в контур линию
    13.  path.AddLine(rect.GetRight()-Radius, rect.GetBottom(), rect.GetLeft()+Radius, rect.GetBottom());
    14.  // добавляем в контур дугу
    15.  path.AddArc(rect.GetLeft(), rect.GetBottom() - Radius, Radius, Radius, 90.f, 90.f);
    16.  // добавляем в контур линию
    17.  path.AddLine(rect.GetLeft(), rect.GetBottom()-Radius, rect.GetLeft(), rect.GetTop()+Radius);
    18.  // добавляем в контур дугу
    19.  path.AddArc(rect.GetLeft(), rect.GetTop(), Radius, Radius, 180.f, 90.f);
    20.  // добавляем закрываем фигуру в контуре
    21.  path.CloseFigure();
    22.  return path.Clone(); // клонируем объект класса GraphicsPath
    23.  } // CreateRoundRectangle
    Функцию из приведенного примера можно использовать следующим образом:
    Код (C):
    1.  Rect rect(30, 30, 200, 100);
    2.  // создаем контур
    3.  GraphicsPath *path = CreateRoundRectangle(rect, 20);
    4.  if (NULL != path)
    5.  { /* контур успешно создан */
    6.  } // if
    Когда объект класса GraphicsPath, на который указывает переменная path из приведенного примера, более станет не нужен, он должен быть удален с помощью оператора delete.
     
    Последнее редактирование: 9 янв 2025
  12. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Поддержка полупрозрачности

    В GDI+ можно создавать, как непрозрачные перья и кисти, так и полупрозрачные перья и кисти. При рисовании полупрозрачным пером или кистью выполняется альфа-смешивание, которое представляет собой смешение фонового цвета и цвета пера или кисти. Каждый из трех компонентов (красный, зеленый, синий) фонового цвета смешивается с соответствующим компонентом цвета пера или кисти, согласно следующей формуле:
    [math]Color=SrcColor\cdot\frac{\displaystyle alpha}{\displaystyle 255}+BlndColor\cdot\frac{\displaystyle 255−alpha}{\displaystyle 255}[/math] (1.5)​
    где [math]Color[/math]– отображаем цвет; [math]BlndColor[/math] – фоновый цвет; [math]SrcColor[/math] – цвет пера или кисти, а [math]alpha[/math] – альфа-фактор цвета пера или кисти.
    Для создания непрозрачного пера или кисти следует установить для цвета альфа-фактор равным 255. Чтобы создать полупрозрачное перо или кисть, нужно задать альфа-фактору любое значение из диапазона от 1 до 254.
    В листинге приведен пример альфа-смешивания при рисовании изображения, показанного на рисунке.
    02.png
    Пример альфа-смешивания​
    Пример рисования полупрозрачными графическими объектами
    Код (C):
    1.  void Display(HDC hdc)
    2.  { // создаем объект класса Graphics для рисования
    3.  Graphics g(hdc);
    4.  g.SetSmoothingMode(SmoothingModeHighQuality);
    5.  // выполняем очистку перед рисованием
    6.  g.Clear(Color::White); // белый цвет фона
    7.  Rect rect(10, 20, 200, 100);
    8.  // создаем эллиптический контур
    9.  GraphicsPath path;
    10.  path.AddEllipse(rect);
    11.  // создаем полупрозрачное перо
    12.  Pen pen1(Color(128, 0, 128, 0), 20.f);
    13.  // создаем непрозрачное перо
    14.  Pen pen2(Color(255, 0, 128, 0), 20.f);
    15.  // создаем штриховую кисть с полупрозрачным фоном
    16.  HatchBrush hatchBrush(HatchStyleCross, Color::Red, Color(100, 255, 0, 0));
    17.  // создаем непрозрачную кисть градиента контура
    18.  PathGradientBrush pthGrBrush(&path);
    19.  // задаем цвет центра контура
    20.  pthGrBrush.SetCenterColor(Color::Aqua);
    21.  // задаем цвет границы контура...
    22.  Color color = Color::Blue;
    23.  int n = 1;
    24.  pthGrBrush.SetSurroundColors(&color, &n);
    25.  // рисуем непрозрачный контур
    26.  g.FillPath(&pthGrBrush, &path);
    27.  // рисуем полупрозрачный прямоугольник
    28.  g.FillRectangle(&hatchBrush, 30, 10, 50, 120);
    29.  // рисуем полупрозрачную линию
    30.  g.DrawLine(&pen1, 150, 10, 150, 130);
    31.  // рисуем непрозрачную линию
    32.  g.DrawLine(&pen2, 180, 10, 180, 130);
    33.  } // Display

    Настройка графического вывода

    Класс Graphics содержит также методы, которые способны влиять на качество отображаемых объектов.

    Сглаживание линий и текста

    При отображении различных линий, кривых и текста могут появляться контурные неровности. Для устранения контурных неровностей применяется сглаживание (smoothing). Обычно отображение более качественных сглаженных линии, кривых и текста требует больших затрат вычислительных ресурсов, чем менее качественных.
    В классе Graphics есть метод SetSmoothingMode, который задает режим сглаживания линий. Этот метод имеет следующий прототип:
    SetSmoothingMode(SmoothingMode smoothingMode);
    Параметр smoothingMode задает режим сглаживания линий. Этот параметр может принимать одно из следующих значений перечисляемого типа SmoothingMode:
    SmoothingModehex
    SmoothingModeDefaultотображение без сглаживания линий
    SmoothingModeHighSpeedотображение без сглаживания линий
    SmoothingModeHighQualityотображение со сглаживанием линий
    SmoothingModeNoneотображение без сглаживания линий 00.png
    SmoothingModeAntiAliasотображение со сглаживанием линий 01.png
    На рисунке изображен сплайн в двух вариантах без применения и с применением сглаживания линий.
    По умолчанию сглаживание линий не применяется. Определить текущий режим сглаживания линий можно с помощью метода GetSmoothingMode класса Graphics:
    SmoothingMode GetSmoothingMode();
    Режим сглаживания линий никак не влияет на качество отображения текста. Чтобы задать режим сглаживания текста, используется метод SetTextRenderingHint класса Graphics. Этот метод имеет следующий прототип:
    SetTextRenderingHint(TextRenderingHint newMode);
    Параметр newMode задает режим сглаживания текста. Этот параметр может принимать одно из следующих значений перечисляемого типа TextRenderingHint:
    TextRenderingHinthex
    TextRenderingHintSystemDefault0отображение текста с параметрами
    сглаживания, указанными для
    операционной системы
    00.png
    TextRenderingHintSingleBitPerPixelGridFit1отображение текста без сглаживания
    и с хинтованием
    01.png
    TextRenderingHintSingleBitPerPixel2отображение текста без сглаживания
    и без хинтования
    02.png
    TextRenderingHintAntiAliasGridFit3отображение текста со сглаживанием
    и хинтованием
    00.png
    TextRenderingHintAntiAlias4отображение текста со сглаживанием
    и без хинтования
    01.png
    TextRenderingHintClearTypeGridFit5отображение текста со сглаживанием
    текста по технологии ClearType,
    применяемой для ЖК-мониторов
    02.png
    В таблице приведены различные варианты сглаживания текста.
    Определить текущий режим сглаживания текста можно с помощью метода GetTextRenderingHint класса Graphics. Прототип метода: TextRenderingHint GetTextRenderingHint();
     
    Последнее редактирование: 8 янв 2025
  13. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Качество растровых изображений

    При масштабировании растрового изображения происходит потеря качества этого изображения. В GDI+ реализованы различные алгоритмы интерполяции, позволяющие добиться улучшения качества масштабируемого изображения.
    В классе Graphics определен метод SetInterpolationMode, который позволяет указать, какой алгоритм интерполяции будет использоваться при выводе растровых изображений с изменением его размеров.
    Метод SetInterpolationMode имеет следующий прототип:
    SetInterpolationMode( InterpolationMode interpolationMode);
    Параметр interpolationMode задает режим интерполяции изображения. Этот параметр должен принимать одно из следующих значений перечисляемого типа InterpolationMode:
    00.png
    Изображение для масштабирования​
    На рисунке представлены различные варианты интерполяции увеличенного в три раза изображения, показанного на рисунке.
    InterpolationModehex
    InterpolationModeDefault0интерполяция по умолчанию
    InterpolationModeLowQuality1низкокачественная интерполяция 00.png
    InterpolationModeHighQuality2высококачественная интерполяция 01.png
    InterpolationModeBilinear3билинейная интерполяция
    (не используется для сжатия
    изображения до размера менее
    50% от его исходного размера)
    02.png
    InterpolationModeBicubic4бикубическая интерполяция
    (не используется для сжатия
    изображения до размера менее
    25% от его исходного размера)
    00.png
    InterpolationModeNearestNeighbor5интерполяция по ближайшим
    соседним значениям
    InterpolationModeHighQualityBilinear6высококачественная
    билинейная интерполяция
    03.png
    InterpolationModeHighQualityBicubic7высококачественная
    бикубическая интерполяция
    01.png
    Определить текущий режим интерполяции изображения можно с помощью метода GetInterpolationMode класса Graphics. Этот метод имеет следующий формат:
    InterpolationMode GetInterpolationMode()

    Логические единицы

    Класс Graphics позволяет абстрагироваться от физических характеристик устройства, позволяя указать, в какой логической системе координат будет происходить графический вывод.
    Для установки логической системы координат в классе Graphics имеется метод SetPageUnit. Этот метод имеет следующий прототип:
    SetPageUnit(Unit unit);
    Параметр unit указывает логические единицы устройства отображения. Этот параметр должен принимать одно из следующих перечисляемого типа Unit:
    Unithex
    UnitWorld0мировые (не физические) единицы
    UnitDisplay1дисплейные единицы (пиксели)
    UnitPixel2пиксели
    UnitPoint31 единица равна 1/72 дюйма
    UnitInch4дюймы
    UnitDocument51 единица равна 1/300 дюйма
    UnitMillimeter6миллиметры
    Определить, какие используются логические единицы можно с помощью метода GetPageUnit класса Graphics:
    Unit GetPageUnit();
    Кроме того, можно задать коэффициент масштабирования логических единиц. Для этого в классе Graphics существует метод SetPageScale. Этот метод имеет следующий прототип:
    SetPageScale(REAL scale);
    Параметр scale определяет коэффициент масштабирования.
    В следующем небольшом примере продемонстрированно, как задать в качестве логической единицы 1 см.
    Код (C):
    1.  Graphics g(hdc);
    2.  // выбираем миллиметры в качестве логических единиц
    3.  g.SetPageUnit(UnitMillimeter);
    4.  // устанавливаем масштабирование логических единиц
    5.  g.SetPageScale(10.f);
    Определить текущий коэффициент масштабирования логических единиц можно с помощью метода GetPageScale класса Graphics:
    REAL GetPageScale();
     
    Последнее редактирование: 9 янв 2025
  14. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Использование GDI+ в приложениях Win64

    Библиотека GDI+ полностью реализована в DLL-библиотеке GdiPlus.dll, для получения доступа к которой следует подключить к программе библиотеку импорта GdiPlus.lib и заголовочный файл gdiplus.h.
    Библиотека GDI+ прибывает в собственном пространстве имен Gdiplus. Чтобы открыть прямой доступ к функциям и классам, определенным внутри GDI+, необходимо использовать директиву:
    using namespace Gdiplus;

    Инициализация и завершение работы GDI+

    Перед использованием классов и функций GDI+ эту библиотеку инициализируют с помощью функции GdiplusStartup, которая должна быть первой из функций GDI+, вызываемых в программе. Функция GdiplusStartup имеет прототип:
    GdiplusStartup(ULONG_PTR *token, GdiplusStartupInput *input, GdiplusStartupOutput *output);
    Первый параметр, token, указывает на переменную типа ULONG_PTR, в которую сохраняется маркер, необходимый для завершения работы с GDI+.
    Второй параметр, input, указывает на структуру GdiplusStartupInput, поля которой управляют различными аспектами использования библиотеки GDI+.
    Третий параметр, output, указывает на структуру GdiplusStartupOutput. Это поле может быть установлено в NULL.
    После выполнения функция GdiplusStartup возвращает одно из значений перечисляемого типа Status, определенного в заголовочном файле GdiPlusTypes.h. В случае успешного выполнения эта функция возвращается значение Ok.
    Описание структуры GdiplusStartupInput:
    Код (C):
    1. struct GdiplusStartupInput
    2. {  UINT32 GdiplusVersion; // версия
    3.     DebugEventProc DebugEventCallback; // функция отладки
    4.     BOOL SuppressBackgroundThread; // флаг, разрешающий // отложенную инициализацию
    5.     BOOL SuppressExternalCodecs; // флаг, разрешающий // использование внешних // кодеков изображений
    6. };
    Первое поле, GdiplusVersion, задает версию GDI+. Это поле принимает значение 1, которое соответствует версии 1.0.
    Второе поле, DebugEventCallback, указывает на функцию, которая будет вызываться при возникновении ошибки в различных функциях GDI+. Поле может быть установлено в NULL.
    Третье поле, SuppressBackgroundThread, определяет, необходимо ли создавать фоновый поток (например, когда начинаются манипуляции с изображениями) для окончательной инициализации GDI+. При этом инициализируется только часть библиотеки GDI+ (такой механизм отложенной инициализации довольно распространен в библиотеках Microsoft). Если поле SuppressBackgroundThread принимает значение TRUE, то функция GdiplusStartup возвращает (в параметре output) указатель на специальные функции, которые должны быть вызваны в том же потоке, что и функция GdiplusStartup.
    Четвертое поле, SuppressExternalCodecs, определяет, необходимо ли использовать внешние кодеки изображений. Так как GDI+ версии 1.0 не поддерживает внешние кодеки изображений, поэтому значения этого поля игнорируются.
    Конструктор структуры GdiplusStartupInput по умолчанию выполняет инициализацию ее полей, достаточную для большинства программ. По умолчанию поле GdiplusVersion равно 1, поле DebugEventCallback = NULL, поля SuppressBackgroundThread и SuppressExternalCodecs равны FALSE.
    Функция, на которую указывает поле DebugEventCallback, может называться как угодно, но должна имеет следующую сигнатуру:
    Код (C):
    1. void WINAPI DebugEventProc(DebugEventLevel level, CHAR *message);
    Первый параметр, level, определяет уровень сообщения отладки и может принимать одно из следующих значений:
    ▪ DebugEventLevelFatal – критическая ошибка;
    ▪ DebugEventLevelWarning – предупреждение.
    Второй параметр, message, указывает на строку, в которой содержится текст сообщения отладки.
    Структура GdiplusStartupOutput имеет следующее описание:
    Код (C):
    1. struct GdiplusStartupOutput
    2. { NotificationHookProc NotificationHook;
    3.    NotificationUnhookProc NotificationUnhook;
    4. };
    Поля этой структуры, NotificationHook и NotificationUnhook, указывают на функции, которые нужно вызвать, соответственно, до и после цикла обработки оконных сообщений в приложении Win64.
    Функция, на которую указывает поле NotificationHook, имеет следующую сигнатуру:
    WINAPI NotificationHookProc(ULONG_PTR *token);
    Параметр token указывает на переменную типа ULONG_PTR, в которую будет сохранен маркер, необходимый для вызова функции, на которую указывает поле NotificationUnhook.
    Функция, на которую указывает поле NotificationUnhook, имеет следующую сигнатуру:
    void WINAPI NotificationUnhookProc(ULONG_PTR token);
    Когда больше нет необходимости в использовании функций и классов GDI+, следует вызвать функцию GdiplusShutdown:
    void GdiplusShutdown(ULONG_PTR token);
    В качестве параметра необходимо передать маркер, который вернула функция GdiplusStartup через параметр token.
    Следующий пример демонстрирует фрагмент программного кода инициализации и завершения работы с GDI+.
    Пример инициализации и завершения работы с GDI+
    Код (C):
    1.  ULONG_PTR gdiplusToken;
    2.  GdiplusStartupInput gdiplusStartupInput;
    3.  GdiplusStartupOutput gdiplusStartupOutput;
    4.  // указываем функцию отладки
    5.  gdiplusStartupInput.DebugEventCallback = GdiplusDebugProc;
    6.  // разрешаем отложенную инициализацию
    7.  gdiplusStartupInput.SuppressBackgroundThread = TRUE;
    8.  // инициализация GDI+
    9.  Status stRet = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, &gdiplusStartupOutput);
    10.  if (Ok == stRet) {
    11.  ULONG_PTR token;
    12.  gdiplusStartupOutput.NotificationHook(&token);
    13.  /* цикл обработки оконных сообщений */
    14.  gdiplusStartupOutput.NotificationUnhook(token);
    15.  GdiplusShutdown(gdiplusToken); // завершение работы GDI+
    16.  } // if
    В примере используется отложенная инициализация GDI+ при дальнейшей отладке программы используется функция обратного вызова GdiplusDebugProc, которая может быть такой:
    Код (C):
    1.  void WINAPI GdiplusDebugProc(DebugEventLevel level, CHAR *message)
    2.  {
    3.  switch (level)
    4.  {
    5.  case DebugEventLevelFatal:
    6.  MessageBoxA(NULL, message, "Критическая ошибка", MB_OK | MB_ICONERROR | MB_TASKMODAL);
    7.  break;
    8.  case DebugEventLevelWarning:
    9.  MessageBoxA(NULL, message, "Предупреждение", MB_OK | MB_ICONWARNING | MB_TASKMODAL);
    10.  break;
    11.  } // switch
    12.  } // GdiplusDebugProc
    В большинстве программ инициализация GDI+ выполняется проще. Следующий пример демонстрирует фрагмент программного кода более простой инициализации и завершения работы GDI+:
    Пример простой инициализации и завершения работы с GDI+
    Код (C):
    1.  ULONG_PTR gdiplusToken;
    2.  GdiplusStartupInput gdiplusStartupInput;
    3.  // инициализация GDI+
    4.  Status stRet = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    5.  if (Ok == stRet)
    6.  { /* цикл обработки оконных сообщений */
    7.  GdiplusShutdown(gdiplusToken); // завершение работы GDI+
    8.  } // if
     
    Последнее редактирование: 7 янв 2025
  15. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.896

    Вместо эпилога

    Статья "Введение в GDI+" написана вчерне. Впереди перевод на masm64, добавление иллюстраций, удаление ошибок
     
    Последнее редактирование: 8 янв 2025
    alex_dz, E.D. и Research нравится это.