28. OpenCV шаг за шагом. Преобразование Хафа
На прошлом шаге мы узнали о функции, реализующей детектор границ Кенни. Если вы немного поэкспериментировали с представленным примером, то обратили внимание, что cvCanny() помогает замечательно выделять границы предметов и окружающей обстановки. В нашем рукотворном мире городов и квартир преобладают прямые линии и другие простые геометрические формы (квадрат, прямоугольник, треугольник, круг).
Поэтому, одной из задач зрения робота может быть детектирование этих линий (для поиска каких-либо геометрических форм, например, дверного проёма, круглой розетки и т.п.)
Эта задача весьма неплохо решается с помощью т.н. преобразования Хафа.
Преобразование Хафа (Hough Transform) — это метод для поиска линий, кругов и других простых форм на изображении.
метод Хафа был впервые применен для анализа изображений пузырьковой камеры
Преобразование Хафа предназначено для поиска объектов, принадлежащих определённому классу фигур с использованием процедуры голосования. Процедура голосования применяется к пространству параметров, из которого и получаются объекты определённого класса фигур по локальному максимуму в, так называемом, накопительном пространстве (accumulator space) которое строится при вычислении трансформации Хафа.
Преобразование Хафа основывается на представлении искомого объекта в виде параметрического уравнения. Параметры этого уравнения представляют фазовое пространство (т.н. аккумуляторный массив/пространство, пространство Хафа).
Затем, берётся двоичное изображение (например, результат работы детектора границ Кенни). Перебираются все точки границ и делается предположение, что точка принадлежит линии искомого объекта — т.о. для каждой точки изображения рассчитывается нужное уравнение и получаются необходимые параметры, которые сохраняются в пространстве Хафа.
Финальным шагом является обход пространства Хафа и выбор максимальных значений, за которые «проголосовало» больше всего пикселей картинки, что и даёт нам параметры для уравнений искомого объекта.
Запутано? Попробуем разобраться на примерах
Самым распространённым и простым случаем преобразования Хафа является поиск линий
Преобразовании Хафа для поиска линий (Hough Line Transform)
В основе теории преобразования Хафа лежит утверждение, что любая точка двоичного изображения может быть частью некоторого набора возможных линий.
y = a*x+b // в декартовых координатак p = x*cos(f)+y*sin(f) // в полярных координатах
Прямую на плоскости можно представить:
x*cos(f) + y*sin(f) = R
, где
R – длина перпендикуляра опущенного на прямую из начала координат,
f — угол между перпендикуляром к прямой и осью OX.
f находится в пределах от 0 до 2*PI,
R ограничено размерами входного изображения.
Через каждую точку (x, y) изображения можно провести несколько прямых с разными R и f, то есть каждой точке (x, y) изображения соответствует набор точек в фазовом пространстве (R, f), образующий синусоиду.
Так же каждой точке (R0, f0) пространства (R, f) можно поставить в соответствие счетчик, соответствующий количеству точек (x, y), лежащих на прямой
x*cos(f0) + y sin(f0) = R0
Теперь непрерывное фазовое пространство нужно перевести в дискретное, введя сетку на пространстве (R, f), одной ячейке которой соответствует набор прямых с близкими значениями R и f.
Можно попробовать реализовать преобразование Хафа самостоятельно, например что-то вроде этого:
// // Hough transform - преобразование Хафа // - нахождение линий // // долгий и нудный перебор, поэтому лучше тестировать // на маленьких картинках :) // // https://robocraft.ru // #include #include #include #include #include // // преобразование Хафа для нахождения линий // // код на Паскале: http://forum.graphicon.ru/viewtopic.php?p=20222#p20222 // void houghLine(IplImage* original, float accuracy=0.1) < assert(original!=0); IplImage *src=0, *rgb=0; IplImage *bin=0; IplImage *phase=0; src=cvCloneImage(original); // заведём цветную картинку rgb = cvCreateImage(cvGetSize(src), 8, 3); cvConvertImage(src, rgb, CV_GRAY2BGR); // бинарная картинка - для контуров bin = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1); cvCanny(src, bin, 50, 200); cvNamedWindow( "bin", 1 ); cvShowImage( "bin", bin ); // максимальное расстояние от начала координат - это длина диагонали int RMax = cvRound( sqrt( (double)(src->width*src->width + src->height*src->height) ) ); // картинка для хранения фазового пространства Хафа (r, f) // 0 < r < RMax // 0 < f < 2*PI phase = cvCreateImage(cvSize(RMax, 180), IPL_DEPTH_16U, 1); cvZero(phase); int x=0, y=0, r=0, f=0; float theta=0; // пробегаемся по пикселям изображения контуров for(y=0; yheight; y++)< uchar* ptr = (uchar*) (bin->imageData + y * bin->widthStep); for(x=0; xwidth; x++)< if(ptr[x]>0)< // это пиксель контура? // рассмотрим все возможные прямые, которые могут // проходить через эту точку for(f=0; fimageData + f * phase->widthStep); for(r=0; r > > > > > cvNamedWindow( "phase", 1 ); cvShowImage( "phase", phase ); // увеличим фазовую картинку IplImage* phaseImage = cvCreateImage( cvSize(phase->width*3, phase->height*3), IPL_DEPTH_16U, 1); cvResize(phase, phaseImage); cvNamedWindow( "phaseImage", 1 ); cvShowImage( "phaseImage", phaseImage); // Выбираем точку фазового пространства которая набрала наибольшее число попаданий unsigned int MaxPhaseValue = 0; float Theta=0; int R=0; for(f=0; fimageData + f * phase->widthStep); for(r=0; rMaxPhaseValue) < MaxPhaseValue = ptrP[r]; Theta = f; R = r; >> > #if 1 printf("[M] %d\n", MaxPhaseValue); // нормировка float scaler = 0xFFFFFFFF/(float)MaxPhaseValue; for(y=0; yheight; y++)< short* ptr = (short*) (phaseImage->imageData + y * phaseImage->widthStep); for(x=0; xwidth; x++) < ptr[x]*=scaler; >> cvNamedWindow( "phaseImage2", 1 ); cvShowImage( "phaseImage2", phaseImage); #endif // Рисуем линию по точкам для R, Teta которые получили в результате преобразования Theta=Theta*CV_PI/180.0; for(y=0; yheight; y++)< uchar* ptr = (uchar*) (rgb->imageData + y * rgb->widthStep); for(x=0; xwidth; x++) < if ( cvRound(((y) * sin(Theta) + (x) * cos(Theta))) == R)< ptr[3*x]=0; ptr[3*x+1]=0; ptr[3*x+2]=255; >> > cvNamedWindow( "line", 1 ); cvShowImage( "line", rgb ); // освобождаем ресурсы cvReleaseImage(&src); cvReleaseImage(&rgb); cvReleaseImage(&bin); cvReleaseImage(&phase); cvReleaseImage(&phaseImage); > int main(int argc, char* argv[]) < IplImage *original=0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку original = cvLoadImage(filename, 0); printf("[i] image: %s\n", filename); assert( original != 0 ); // покажем изображения cvNamedWindow( "original", 1 ); cvShowImage( "original", original ); houghLine(original); cvWaitKey(0); cvReleaseImage(&original); // удаляем окна cvDestroyAllWindows(); return 0; >

скачать иcходник (28-houghLine.cpp)
— получается оооочень долго
Но, в OpenCV уже есть функция, реализующая преобразование Хафа для поиска линий
CVAPI(CvSeq*) cvHoughLines2( CvArr* image, void* line_storage, int method, double rho, double theta, int threshold, double param1 CV_DEFAULT(0), double param2 CV_DEFAULT(0));
— нахождение линий на двоичном изображении, используя преобразование Хафа
image — 8-битное двоичное изображение (в случае вероятностного метода изображение будет модифицироваться)
line_storage — хранилище памяти для сохранения найденных линий (можно использовать матрицу 1xЧисло_линий CvMat)
method — метод:
#define CV_HOUGH_STANDARD 0 #define CV_HOUGH_PROBABILISTIC 1 #define CV_HOUGH_MULTI_SCALE 2
CV_HOUGH_STANDARD — классический вариант трансформации Хафа. Каждая линия представляется двумя числами типа float (rho, theta), где rho — дистанция между точкой (0,0) и линией, а theta — угол между осью x и нормалью к линии (т.е. матрица должна иметь тип of CV_32FC2)
CV_HOUGH_PROBABILISTIC — вероятностный метод трансформации Хафа (более эффективен с случае изображений с несколькими длинными линейными сегментами). Возвращает сегменты линии, которые представляются точками начала и конца (т.е. матрица должна иметь тип of CV_32SC4)
CV_HOUGH_MULTI_SCALE — масштабный вариант классической трансформации Хафа. Линии представлены так же, как и в CV_HOUGH_STANDARD
Вероятностное преобразование Хафа (Probabilistic Hough Transform)
заключается в том, что для нахождения объекта достаточно провести преобразование Хафа только для части (a) точек исходного изображения, 0%
rho — разрешение по дистанции
theta — разрешение по углу (в радианах)
threshold — пороговый параметр. Линия возвращается, если аккумулирующий параметр больше порогового значения.
param1 — первый параметр (в зависимости от метода трансфрмации:
CV_HOUGH_STANDARD — 0 — не используется
CV_HOUGH_PROBABILISTIC — минимальная длина линии
CV_HOUGH_MULTI_SCALE — делитель разрешения по дистанции (rho/param1))
param2 — второй параметр (в зависимости от метода трансфрмации:
CV_HOUGH_STANDARD — 0 — не используется
CV_HOUGH_PROBABILISTIC — максимальный промежуток между сегментами линии, лежащими на одной линии, чтобы считать их одним сегментом (объединить их вместе)
CV_HOUGH_MULTI_SCALE — делитель разрешения по углу (theta/param1))
если line_storage — указатель на хранилище памяти, то функция вернёт указатель на первый элемент последовательности, содержащей найденные линии.
В составе OpenCV уже идёт пример, демонстрирующий работу cvHoughLines2():
\OpenCV\samples\c\houghlines.c
// // нахождение линий на изображении, // с использованием преобразования Хафа cvHoughLines2() // // модифицированный пример samples\c\houghlines.c // // https://robocraft.ru // #include #include #include int main(int argc, char* argv[]) < IplImage* src = 0; IplImage* dst=0; IplImage* color_dst=0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку (в градациях серого) src = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); if( !src ) < printf("[!] Error: cant load image: %s \n", filename); return -1; >printf("[i] image: %s\n", filename); // хранилище памяти для хранения найденных линий CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* lines = 0; int i = 0; dst = cvCreateImage( cvGetSize(src), 8, 1 ); color_dst = cvCreateImage( cvGetSize(src), 8, 3 ); // детектирование границ cvCanny( src, dst, 50, 200, 3 ); // конвертируем в цветное изображение cvCvtColor( dst, color_dst, CV_GRAY2BGR ); // нахождение линий lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 50, 50, 10 ); // нарисуем найденные линии for( i = 0; i < lines->total; i++ ) < CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i); cvLine( color_dst, line[0], line[1], CV_RGB(255,0,0), 3, CV_AA, 0 ); >// показываем cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvNamedWindow( "Hough", 1 ); cvShowImage( "Hough", color_dst ); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMemStorage(&storage); cvReleaseImage(&src); cvReleaseImage(&dst); cvReleaseImage(&color_dst); cvDestroyAllWindows(); return 0; >

скачать иcходник (28-cvHoughLines2.cpp)
Преобразовании Хафа для нахождения окружностей (Hough Circle Transform)
точки окружности можно представить формулой:
(x - a)^2 + (y - b)^2 = R2,
, где (a, b) – координаты центра окружности, а R – ее радиус.
т.е. формула, задающая семейство окружностей, имеет вид:
F (a, b, R, x, y) = (x - a)^2 + (y - b)^2 - R2
Как видим, для нахождения окружностей нужно задавать уже 3 пераметра — координаты центра окружности и её радиус. Это приводит к увеличению пространства Хафа на целое измерение, что в итоге сказывается на скорости работы. Поэтому для поиска окружностей применяется т.н. градиентный метод Хафа (Hough gradient method).
эффективность использования преобразования Хафа резко падает при увеличении размерности фазового пространства, поэтому перед его применением желательно минимизировать каким-либо образом количество параметров кривой.
Можно существенно снизить количество кривых, потенциально проходящих через данную точку изображения, если рассматривать только кривые, касательная которой перпендикулярна градиенту яркости изображения в рассматриваемой точке. Таким образом, можно, например, свести задачу выделения окружностей с неизвестным радиусом к двумерному фазовому пространству.
Нахождение кругов
1. используется детектор границ Кенни для нахождения границ на изображении
2. для ненулевых точек высчитывается градиент (через вычисление 1-й производной по X и Y через cvSobel())
3. определяются центры кругов
4. относительно центра определяются ненулевые точки, лежащие на одном расстоянии
в OpenCV, преобразовании Хафа для нахождения окружностей реализуется функцией cvHoughCircles():
CVAPI(CvSeq*) cvHoughCircles( CvArr* image, void* circle_storage, int method, double dp, double min_dist, double param1 CV_DEFAULT(100), double param2 CV_DEFAULT(100), int min_radius CV_DEFAULT(0), int max_radius CV_DEFAULT(0));
— нахождение кругов на изображении
image — исходное изображение (8-битное, одноканальное, градации серого)
line_storage — хранилище памяти для сохранения найденных кругов (можно использовать матрицу типа CV_32FC3, 1xЧисло_кругов CvMat). Круг хранится в виде трёх чисел типа float: координаты центра (x,y) и радиус.
method — метод, на настоящее время реализован только:
#define CV_HOUGH_GRADIENT 3
dp — разрешение сумматора, используемое для детектирования центров кругов (1 — одинаково с исходным изображением, 2 — половина высоты/ширины и т.д.)
min_dist — минимальная дистанция между центрами детектируемых кругов
param1 — первый параметр (в зависимости от метода трансфрмации:
CV_HOUGH_GRADIENT — верхнее пороговое значение, передаваемое детектору границ Кенни (нижнее пороговое значение будет в 2 раза меньше)
param2 — второй параметр (в зависимости от метода трансфрмации:
CV_HOUGH_GRADIENT — суммирующее пороговое значение детектированя центров
min_radius — минимальный радиус круга
max_radius — максимальный радиус круга
// // Несколько модифицированный пример example 6-1 Hough circles // нахождение кругов на изображении, // с использованием трансформации Хафа cvHoughCircles() // // из книги: // Learning OpenCV: Computer Vision with the OpenCV Library // by Gary Bradski and Adrian Kaehler // Published by O'Reilly Media, October 3, 2008 // // // https://robocraft.ru // #include #include #include int main(int argc, char* argv[]) < IplImage* image = 0; // имя картинки задаётся первым параметром char* filename = argc >= 2 ? argv[1] : "Image0.jpg"; // получаем картинку (в градациях серого) image = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); printf("[i] image: %s\n", filename); assert( image != 0 ); // загрузим оригинальное изображении IplImage* src = cvLoadImage(filename ); // хранилище памяти для кругов CvMemStorage* storage = cvCreateMemStorage(0); // сглаживаем изображение cvSmooth(image, image, CV_GAUSSIAN, 5, 5 ); // поиск кругов CvSeq* results = cvHoughCircles( image, storage, CV_HOUGH_GRADIENT, 10, image->width/5 ); // пробегаемся по кругам и рисуем их на оригинальном изображении for( int i = 0; i < results->total; i++ ) < float* p = (float*) cvGetSeqElem( results, i ); CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) ); cvCircle( src, pt, cvRound( p[2] ), CV_RGB(0xff,0,0) ); >// показываем cvNamedWindow( "cvHoughCircles", 1 ); cvShowImage( "cvHoughCircles", src); // ждём нажатия клавиши cvWaitKey(0); // освобождаем ресурсы cvReleaseMemStorage(&storage); cvReleaseImage(& image); cvReleaseImage(&src); cvDestroyAllWindows(); return 0; >

скачать иcходник (28-cvHoughCircles.cpp)
результат cvHoughCircles() очень сильно зависит от параметров,
например,
CvSeq* results = cvHoughCircles( image, storage, CV_HOUGH_GRADIENT, 2, image->width/5 );

уже даёт результат:
Существует и так называемое Обобщённое преобразование Хафа, с помощью которого можно искать фигуры произвольной формы.
( хм… об Обобщённом преобразовании Хафа даже нету странички в русской википедии — сейчас исправим :))
Линейный градиент SkiaSharp
Класс SKPaint определяет Color свойство, которое используется для обводки линий или заливки областей сплошным цветом. Кроме того, можно обводить линии или заполнить области градиентами, которые представляют собой постепенное сочетание цветов:

Самый базовый тип градиента — линейный . Сочетание цветов происходит на линии (называемой линией градиента) от одной точки к другой. Линии, перпендикулярные линии градиента, имеют одинаковый цвет. Линейный градиент создается с помощью одного из двух статических SKShader.CreateLinearGradient методов. Разница между двумя перегрузками заключается в том, что одна из них включает преобразование матрицы, а другая — нет.
Эти методы возвращают объект типа SKShader , которому присваивается Shader свойство SKPaint . Shader Если свойство не равно NULL, оно переопределяет Color свойство . Любая обводка линии или любая область, заполненная с помощью этого SKPaint объекта, основана на градиенте, а не на сплошном цвете.
Свойство Shader игнорируется при включении SKPaint объекта в DrawBitmap вызов. Вы можете использовать Color свойство , чтобы задать уровень прозрачности для отображения растрового изображения (как описано в статье Отображение растровых рисунков SkiaSharp), но нельзя использовать Shader свойство для отображения растрового изображения с градиентной прозрачностью SKPaint . Доступны и другие методы отображения растровых изображений с градиентными прозрачностями. Они описаны в статьях Циклические градиенты SkiaSharp и Режимы создания и наложения SkiaSharp.
Градиенты между углами
Часто линейный градиент распространяется от одного угла прямоугольника к другому. Если начальная точка является левым верхним углом прямоугольника, градиент может расширяться:
- по вертикали в левый нижний угол
- горизонтально в правый верхний угол
- по диагонали в правый нижний угол
Диагональный линейный градиент показан на первой странице в разделе Шейдеры SkiaSharp и другие эффекты примера SkiaSharpFormsDemos . Страница «Градиент из угла в угол » создает в конструкторе SKCanvasView . Обработчик PaintSurface создает SKPaint объект в операторе using , а затем определяет прямоугольник площадью 300 пикселей по центру на холсте:
public class CornerToCornerGradientPage : ContentPage < ··· public CornerToCornerGradientPage () < Title = "Corner-to-Corner Gradient"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; ··· >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < // Create 300-pixel square centered rectangle float x = (info.Width - 300) / 2; float y = (info.Height - 300) / 2; SKRect rect = new SKRect(x, y, x + 300, y + 300); // Create linear gradient from upper-left to lower-right paint.Shader = SKShader.CreateLinearGradient( new SKPoint(rect.Left, rect.Top), new SKPoint(rect.Right, rect.Bottom), new SKColor[] < SKColors.Red, SKColors.Blue >, new float[] < 0, 1 >, SKShaderTileMode.Repeat); // Draw the gradient on the rectangle canvas.DrawRect(rect, paint); ··· > > >
Свойству Shader SKPaint присваивается возвращаемое SKShader значение из статического SKShader.CreateLinearGradient метода. Ниже приведены пять аргументов.
- Начальная точка градиента, установленная здесь в верхнем левом углу прямоугольника.
- Конечная точка градиента, установленная здесь в правом нижнем углу прямоугольника.
- Массив из двух или более цветов, которые влияют на градиент
- Массив значений float , указывающий относительное положение цветов в линии градиента.
- Элемент перечисления , указывающий SKShaderTileMode , как ведет себя градиент за пределами линии градиента.
После создания объекта градиента метод рисует прямоугольник площадью DrawRect 300 пикселей с помощью SKPaint объекта, включающего шейдер. Здесь он выполняется в iOS, Android и универсальная платформа Windows (UWP):
Линия градиента определяется двумя точками, указанными в качестве первых двух аргументов. Обратите внимание, что эти точки относятся к холсту , а не к графическому объекту, отображаемого с градиентом. Вдоль линии градиента цвет постепенно переходит от красного в верхнем левом углу к синему в правом нижнем углу. Любая линия, перпендикулярная линии градиента, имеет постоянный цвет.
Массив значений, указанных float в качестве четвертого аргумента, имеет один-к-одному соответствие массиву цветов. Значения указывают относительное положение вдоль линии градиента, в которой встречаются эти цвета. Здесь значение 0 означает, что Red происходит в начале линии градиента, а 1 — в Blue конце строки. Числа должны быть возрастающими и находиться в диапазоне от 0 до 1. Если они не в этом диапазоне, они будут скорректированы так, чтобы они были в этом диапазоне.
Для двух значений в массиве можно задать значение, отличное от 0 и 1. Попробуйте выполните следующее.
new float[]
Теперь весь первый квартал градиентной линии чисто красный, а последний квартал чисто синий. Сочетание красного и синего ограничивается центральной половиной линии градиента.
Как правило, эти значения позиций нужно расположить в диапазоне от 0 до 1. В этом случае можно просто указать null в качестве четвертого аргумента в CreateLinearGradient .
Хотя этот градиент определен между двумя углами прямоугольника площадью 300 пикселей, он не ограничивается заполнением этого прямоугольника. Страница «Градиент от угла к углу » содержит дополнительный код, который реагирует на касания или щелчки мышью на странице. Поле drawBackground переключается между true и false при каждом касании. Если значение равно true , обработчик PaintSurface использует тот же SKPaint объект для заполнения всего холста, а затем рисует черный прямоугольник, указывающий на меньший прямоугольник:
public class CornerToCornerGradientPage : ContentPage < bool drawBackground; public CornerToCornerGradientPage () < ··· TapGestureRecognizer tap = new TapGestureRecognizer(); tap.Tapped += (sender, args) =>< drawBackground ^= true; canvasView.InvalidateSurface(); >; canvasView.GestureRecognizers.Add(tap); > void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < ··· using (SKPaint paint = new SKPaint()) < ··· if (drawBackground) < // Draw the gradient on the whole canvas canvas.DrawRect(info.Rect, paint); // Outline the smaller rectangle paint.Shader = null; paint.Style = SKPaintStyle.Stroke; paint.Color = SKColors.Black; canvas.DrawRect(rect, paint); >> > >
Вот что вы увидите после касания экрана:
Обратите внимание, что градиент повторяется в том же шаблоне за пределами точек, определяющих линию градиента. Это повторение происходит из-за того, что последним аргументом для CreateLinearGradient является SKShaderTileMode.Repeat . (Вскоре вы увидите другие варианты.)
Также обратите внимание, что точки, используемые для указания линии градиента, не являются уникальными. Линии, перпендикулярные линии градиента, имеют одинаковый цвет, поэтому для одного и того же эффекта можно указать бесконечное количество линий градиента. Например, при заполнении прямоугольника горизонтальным градиентом можно указать верхний левый и верхний правый углы, нижний левый и нижний правый углы, а также любые две точки, которые находятся даже с и параллельными этими линиями.
Интерактивный эксперимент
Вы можете интерактивно экспериментировать с линейными градиентами на странице Интерактивный линейный градиент . На этой странице используется InteractivePage класс , представленный в статье Три способа рисования дуги. InteractivePage Обрабатывает TouchEffect события для поддержания TouchPoint коллекции объектов, которые можно перемещать пальцами или мышью.
XAML-файл прикрепляет TouchEffect к родительскому элементу SKCanvasView , а также содержит Picker объект , который позволяет выбрать один из трех элементов перечисления SKShaderTileMode :
Конструктор в файле кода программной части создает два TouchPoint объекта для начальной и конечной точек линейного градиента. Обработчик PaintSurface определяет массив из трех цветов (для градиента от красного к зеленому к синему) и получает текущий SKShaderTileMode из Picker :
public partial class InteractiveLinearGradientPage : InteractivePage < public InteractiveLinearGradientPage () < InitializeComponent (); touchPoints = new TouchPoint[2]; for (int i = 0; i < 2; i++) < touchPoints[i] = new TouchPoint < Center = new SKPoint(100 + i * 200, 100 + i * 200) >; > InitializeComponent(); baseCanvasView = canvasView; > void OnPickerSelectedIndexChanged(object sender, EventArgs args) < canvasView.InvalidateSurface(); >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); SKColor[] colors = < SKColors.Red, SKColors.Green, SKColors.Blue >; SKShaderTileMode tileMode = (SKShaderTileMode)(tileModePicker.SelectedIndex == -1 ? 0 : tileModePicker.SelectedItem); using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateLinearGradient(touchPoints[0].Center, touchPoints[1].Center, colors, null, tileMode); canvas.DrawRect(info.Rect, paint); >··· > >
Обработчик PaintSurface создает объект на SKShader основе всех сведений и использует его для раскраски всего холста. Массив значений float имеет значение null . В противном случае для равномерного размещения трех цветов необходимо задать для этого параметра массив со значениями 0, 0,5 и 1.
Основная часть обработчика PaintSurface предназначена для отображения нескольких объектов: точек касания в виде контурных кругов, линии градиента и линий, перпендикулярных линиям градиента в точках касания:
public partial class InteractiveLinearGradientPage : InteractivePage < ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < ··· // Display the touch points here rather than by TouchPoint using (SKPaint paint = new SKPaint()) < paint.Style = SKPaintStyle.Stroke; paint.Color = SKColors.Black; paint.StrokeWidth = 3; foreach (TouchPoint touchPoint in touchPoints) < canvas.DrawCircle(touchPoint.Center, touchPoint.Radius, paint); >// Draw gradient line connecting touchpoints canvas.DrawLine(touchPoints[0].Center, touchPoints[1].Center, paint); // Draw lines perpendicular to the gradient line SKPoint vector = touchPoints[1].Center - touchPoints[0].Center; float length = (float)Math.Sqrt(Math.Pow(vector.X, 2) + Math.Pow(vector.Y, 2)); vector.X /= length; vector.Y /= length; SKPoint rotate90 = new SKPoint(-vector.Y, vector.X); rotate90.X *= 200; rotate90.Y *= 200; canvas.DrawLine(touchPoints[0].Center, touchPoints[0].Center + rotate90, paint); canvas.DrawLine(touchPoints[0].Center, touchPoints[0].Center - rotate90, paint); canvas.DrawLine(touchPoints[1].Center, touchPoints[1].Center + rotate90, paint); canvas.DrawLine(touchPoints[1].Center, touchPoints[1].Center - rotate90, paint); > > >
Градиентную линию, соединяющую две точки касания, легко нарисовать, но перпендикулярные линии требуют дополнительной работы. Градиентная линия преобразуется в вектор, нормализована, чтобы иметь длину в одну единицу, а затем поворачивается на 90 градусов. Затем этот вектор получает длину 200 пикселей. Он используется для рисования четырех линий, которые простираются от точек касания до перпендикулярной линии градиента.
Перпендикулярные линии совпадают с началом и концом градиента. Что происходит за этими строками, зависит от настройки перечисления SKShaderTileMode :

На трех снимках экрана показаны результаты трех различных значений . SKShaderTileMode На снимках экрана в iOS показан SKShaderTileMode.Clamp элемент , который просто расширяет цвета на границе градиента. Параметр SKShaderTileMode.Repeat на снимке экрана Android показывает, как повторяется шаблон градиента. Параметр SKShaderTileMode.Mirror на снимке экрана UWP также повторяет шаблон, но он каждый раз изменяется обратно, что не приводит к разрыву цвета.
Градиенты на градиентах
Класс SKShader не определяет никаких открытых свойств или методов, Dispose кроме . Таким SKShader образом, объекты, созданные статическими методами, являются неизменяемыми. Даже если вы используете один и тот же градиент для двух разных объектов, скорее всего, вам потребуется немного изменить градиент. Для этого необходимо создать новый SKShader объект .
На странице Текст градиента отображается текст и фигурные скобки, которые окрашены похожими градиентами:

Единственными различиями в градиентах являются начальная и конечная точки. Градиент, используемый для отображения текста, основан на двух точках на углах ограничивающего прямоугольника для текста. Для фона эти две точки основаны на всем холсте. Вот этот код:
public class GradientTextPage : ContentPage < const string TEXT = "GRADIENT"; public GradientTextPage () < Title = "Gradient Text"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < // Create gradient for background paint.Shader = SKShader.CreateLinearGradient( new SKPoint(0, 0), new SKPoint(info.Width, info.Height), new SKColor[] < new SKColor(0x40, 0x40, 0x40), new SKColor(0xC0, 0xC0, 0xC0) >, null, SKShaderTileMode.Clamp); // Draw background canvas.DrawRect(info.Rect, paint); // Set TextSize to fill 90% of width paint.TextSize = 100; float width = paint.MeasureText(TEXT); float scale = 0.9f * info.Width / width; paint.TextSize *= scale; // Get text bounds SKRect textBounds = new SKRect(); paint.MeasureText(TEXT, ref textBounds); // Calculate offsets to center the text on the screen float xText = info.Width / 2 - textBounds.MidX; float yText = info.Height / 2 - textBounds.MidY; // Shift textBounds by that amount textBounds.Offset(xText, yText); // Create gradient for text paint.Shader = SKShader.CreateLinearGradient( new SKPoint(textBounds.Left, textBounds.Top), new SKPoint(textBounds.Right, textBounds.Bottom), new SKColor[] < new SKColor(0x40, 0x40, 0x40), new SKColor(0xC0, 0xC0, 0xC0) >, null, SKShaderTileMode.Clamp); // Draw text canvas.DrawText(TEXT, xText, yText, paint); > > >
Сначала Shader SKPaint свойство объекта задается для отображения градиента для покрытия фона. Точки градиента задаются в левом верхнем и нижнем правом углах холста.
Код задает TextSize свойство SKPaint объекта таким образом, чтобы текст отображался на 90 % ширины холста. Текстовые границы используются для вычисления xText и yText значений, которые передаются методу DrawText для центрирования текста.
Однако точки градиента для второго CreateLinearGradient вызова должны ссылаться на верхний левый и правый нижний угол текста относительно холста при его отображении. Это достигается путем сдвига textBounds прямоугольника на те же xText значения и yText :
textBounds.Offset(xText, yText);
Теперь верхний левый и правый нижний углы прямоугольника можно использовать для задания начальной и конечной точек градиента.
Анимация градиента
Существует несколько способов анимации градиента. Один из подходов заключается в анимации начальной и конечной точек. На странице Анимация градиента две точки перемещаются по окружности по центру холста. Радиус этого круга составляет половину ширины или высоты холста, в зависимости от того, что меньше. Начальная и конечная точки находятся напротив друг друга в этом круге, а градиент переходит от белого к черному в режиме Mirror плитки:

Конструктор создает SKCanvasView объект . Методы OnAppearing и OnDisappearing обрабатывают логику анимации:
public class GradientAnimationPage : ContentPage < SKCanvasView canvasView; bool isAnimating; double angle; Stopwatch stopwatch = new Stopwatch(); public GradientAnimationPage() < Title = "Gradient Animation"; canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >protected override void OnAppearing() < base.OnAppearing(); isAnimating = true; stopwatch.Start(); Device.StartTimer(TimeSpan.FromMilliseconds(16), OnTimerTick); >protected override void OnDisappearing() < base.OnDisappearing(); stopwatch.Stop(); isAnimating = false; >bool OnTimerTick() < const int duration = 3000; angle = 2 * Math.PI * (stopwatch.ElapsedMilliseconds % duration) / duration; canvasView.InvalidateSurface(); return isAnimating; >··· >
Метод OnTimerTick вычисляет angle значение, которое анимируется от 0 до 2π каждые 3 секунды.
Вот один из способов вычисления двух точек градиента. Значение SKPoint с именем vector вычисляется для расширения от центра холста до точки на радиусе окружности. Направление этого вектора основано на значениях синуса и косисинуса угла. Затем вычисляются две противоположные точки градиента: одна точка вычисляется путем вычитания этого вектора из центральной точки, а другая точка вычисляется путем добавления вектора в центральную точку:
public class GradientAnimationPage : ContentPage < ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < SKPoint center = new SKPoint(info.Rect.MidX, info.Rect.MidY); int radius = Math.Min(info.Width, info.Height) / 2; SKPoint vector = new SKPoint((float)(radius * Math.Cos(angle)), (float)(radius * Math.Sin(angle))); paint.Shader = SKShader.CreateLinearGradient( center - vector, center + vector, new SKColor[] < SKColors.White, SKColors.Black >, null, SKShaderTileMode.Mirror); canvas.DrawRect(info.Rect, paint); > > >
Несколько другой подход требует меньшего объема кода. Этот подход использует метод перегрузки SKShader.CreateLinearGradient с преобразованием матрицы в качестве последнего аргумента. Этот подход является версией в примере SkiaSharpFormsDemos :
public class GradientAnimationPage : ContentPage < ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < paint.Shader = SKShader.CreateLinearGradient( new SKPoint(0, 0), info.Width < info.Height ? new SKPoint(info.Width, 0) : new SKPoint(0, info.Height), new SKColor[] < SKColors.White, SKColors.Black >, new float[] < 0, 1 >, SKShaderTileMode.Mirror, SKMatrix.MakeRotation((float)angle, info.Rect.MidX, info.Rect.MidY)); canvas.DrawRect(info.Rect, paint); > > >
Если ширина холста меньше высоты, то для двух точек градиента устанавливается значение (0, 0) и ( info.Width , 0). Преобразование поворота передано в качестве последнего аргумента для CreateLinearGradient эффективного поворота этих двух точек вокруг центра экрана.
Обратите внимание, что если угол равен 0, поворот отсутствует, а две точки градиента — это верхний левый и правый верхний угол холста. Эти точки не совпадают с вычисляемыми точками градиента, как показано в предыдущем CreateLinearGradient вызове. Но эти точки параллельны горизонтальной линии градиента, которая разделяет центр холста, и они приводят к идентичу градиента.
Радужный градиент
Страница Градиент радуги рисует радугу из левого верхнего угла холста в правый нижний угол. Но этот радужный градиент не похож на реальную радугу. Это прямой, а не кривый, но он основан на восьми цветах HSL (оттенок-насыщенность-яркость), которые определяются цикличностью через значения оттенка от 0 до 360:
SKColor[] colors = new SKColor[8]; for (int i = 0; i < colors.Length; i++) < colors[i] = SKColor.FromHsl(i * 360f / (colors.Length - 1), 100, 50); >
Этот код является частью обработчика, показанного PaintSurface ниже. Обработчик начинается с создания пути, определяющего шестистороннюю многоугольнику, простирающуюся от левого верхнего угла холста до правого нижнего угла:
public class RainbowGradientPage : ContentPage < public RainbowGradientPage () < Title = "Rainbow Gradient"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPath path = new SKPath()) < float rainbowWidth = Math.Min(info.Width, info.Height) / 2f; // Create path from upper-left to lower-right corner path.MoveTo(0, 0); path.LineTo(rainbowWidth / 2, 0); path.LineTo(info.Width, info.Height - rainbowWidth / 2); path.LineTo(info.Width, info.Height); path.LineTo(info.Width - rainbowWidth / 2, info.Height); path.LineTo(0, rainbowWidth / 2); path.Close(); using (SKPaint paint = new SKPaint()) < SKColor[] colors = new SKColor[8]; for (int i = 0; i < colors.Length; i++) < colors[i] = SKColor.FromHsl(i * 360f / (colors.Length - 1), 100, 50); >paint.Shader = SKShader.CreateLinearGradient( new SKPoint(0, rainbowWidth / 2), new SKPoint(rainbowWidth / 2, 0), colors, null, SKShaderTileMode.Repeat); canvas.DrawPath(path, paint); > > > >
Две точки градиента в методе CreateLinearGradient основаны на двух точках, определяющих этот путь: обе точки расположены близко к левому верхнему углу. Первый находится на верхнем краю холста, а второй — на левом краю холста. Ниже приведен результат:

Это интересный образ, но это не совсем намерение. Проблема заключается в том, что при создании линейного градиента линии постоянного цвета перпендикулярны линии градиента. Градиентная линия основана на точках, где фигура касается верхней и левой сторон, и эта линия обычно не перпендикулярна краям фигуры, которые простираются до нижнего правого угла. Этот подход будет работать только в том случае, если холст был квадратным.
Чтобы создать правильный градиент радуги, линия градиента должна быть перпендикулярной краю радуги. Это более сложный расчет. Необходимо определить вектор, параллельный длинной стороне фигуры. Вектор поворачивается на 90 градусов, чтобы он был перпендикулярным к этой стороне. Затем он удлиняется до ширины фигуры путем умножения на rainbowWidth . Две точки градиента вычисляются на основе точки на стороне рисунка и этой точки плюс вектор. Ниже приведен код, который отображается на странице Градиент радуги в примере SkiaSharpFormsDemos :
public class RainbowGradientPage : ContentPage < ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < ··· using (SKPath path = new SKPath()) < ··· using (SKPaint paint = new SKPaint()) < ··· // Vector on lower-left edge, from top to bottom SKPoint edgeVector = new SKPoint(info.Width - rainbowWidth / 2, info.Height) - new SKPoint(0, rainbowWidth / 2); // Rotate 90 degrees counter-clockwise: SKPoint gradientVector = new SKPoint(edgeVector.Y, -edgeVector.X); // Normalize float length = (float)Math.Sqrt(Math.Pow(gradientVector.X, 2) + Math.Pow(gradientVector.Y, 2)); gradientVector.X /= length; gradientVector.Y /= length; // Make it the width of the rainbow gradientVector.X *= rainbowWidth; gradientVector.Y *= rainbowWidth; // Calculate the two points SKPoint point1 = new SKPoint(0, rainbowWidth / 2); SKPoint point2 = point1 + gradientVector; paint.Shader = SKShader.CreateLinearGradient(point1, point2, colors, null, SKShaderTileMode.Repeat); canvas.DrawPath(path, paint); >> > >
Теперь цвета радуги выровнены по рисунку:

Цвета бесконечности
Градиент радуги также используется на странице Цвета бесконечности . Эта страница рисует знак бесконечности с помощью объекта пути, описанного в статье Три типа кривых Безье. Затем изображение окрашено с анимированным радужным градиентом, который непрерывно перебирается по изображению.
Конструктор создает объект, SKPath описывающий знак бесконечности. После создания пути конструктор также может получить прямоугольные границы пути. Затем он вычисляет значение с именем gradientCycleLength . Если градиент основан на верхнем левом и правом нижнем углах pathBounds прямоугольника, это gradientCycleLength значение является общей горизонтальной шириной шаблона градиента:
public class InfinityColorsPage : ContentPage < ··· SKCanvasView canvasView; // Path information SKPath infinityPath; SKRect pathBounds; float gradientCycleLength; // Gradient information SKColor[] colors = new SKColor[8]; ··· public InfinityColorsPage () < Title = "Infinity Colors"; // Create path for infinity sign infinityPath = new SKPath(); infinityPath.MoveTo(0, 0); // Center infinityPath.CubicTo( 50, -50, 95, -100, 150, -100); // To top of right loop infinityPath.CubicTo( 205, -100, 250, -55, 250, 0); // To far right of right loop infinityPath.CubicTo( 250, 55, 205, 100, 150, 100); // To bottom of right loop infinityPath.CubicTo( 95, 100, 50, 50, 0, 0); // Back to center infinityPath.CubicTo( -50, -50, -95, -100, -150, -100); // To top of left loop infinityPath.CubicTo(-205, -100, -250, -55, -250, 0); // To far left of left loop infinityPath.CubicTo(-250, 55, -205, 100, -150, 100); // To bottom of left loop infinityPath.CubicTo( -95, 100, - 50, 50, 0, 0); // Back to center infinityPath.Close(); // Calculate path information pathBounds = infinityPath.Bounds; gradientCycleLength = pathBounds.Width + pathBounds.Height * pathBounds.Height / pathBounds.Width; // Create SKColor array for gradient for (int i = 0; i < colors.Length; i++) < colors[i] = SKColor.FromHsl(i * 360f / (colors.Length - 1), 100, 50); >canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; > ··· >
Конструктор также создает colors массив для радуги и SKCanvasView объекта .
Переопределения OnAppearing методов и OnDisappearing выполняют дополнительные расходы на анимацию. Метод OnTimerTick анимирует поле от 0 до gradientCycleLength каждые две секунды offset :
public class InfinityColorsPage : ContentPage < ··· // For animation bool isAnimating; float offset; Stopwatch stopwatch = new Stopwatch(); ··· protected override void OnAppearing() < base.OnAppearing(); isAnimating = true; stopwatch.Start(); Device.StartTimer(TimeSpan.FromMilliseconds(16), OnTimerTick); >protected override void OnDisappearing() < base.OnDisappearing(); stopwatch.Stop(); isAnimating = false; >bool OnTimerTick() < const int duration = 2; // seconds double progress = stopwatch.Elapsed.TotalSeconds % duration / duration; offset = (float)(gradientCycleLength * progress); canvasView.InvalidateSurface(); return isAnimating; >··· >
Наконец, PaintSurface обработчик отрисовывает знак бесконечности. Так как путь содержит отрицательные и положительные координаты, окружающие центральную точку (0, 0), Translate преобразование на холсте используется для сдвига его в центр. За преобразованием Scale перевода следует преобразование, которое применяет коэффициент масштабирования, который делает знак бесконечности максимально большим, оставаясь в пределах 95 % от ширины и высоты холста.
Обратите внимание, что STROKE_WIDTH константа добавляется к ширине и высоте ограничивающего прямоугольника пути. Путь будет обводиться линией такой ширины, поэтому размер отображаемой бесконечности увеличивается на половину этой ширины на всех четырех сторонах:
public class InfinityColorsPage : ContentPage < const int STROKE_WIDTH = 50; ··· void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); // Set transforms to shift path to center and scale to canvas size canvas.Translate(info.Width / 2, info.Height / 2); canvas.Scale(0.95f * Math.Min(info.Width / (pathBounds.Width + STROKE_WIDTH), info.Height / (pathBounds.Height + STROKE_WIDTH))); using (SKPaint paint = new SKPaint()) < paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = STROKE_WIDTH; paint.Shader = SKShader.CreateLinearGradient( new SKPoint(pathBounds.Left, pathBounds.Top), new SKPoint(pathBounds.Right, pathBounds.Bottom), colors, null, SKShaderTileMode.Repeat, SKMatrix.MakeTranslation(offset, 0)); canvas.DrawPath(infinityPath, paint); >> >
Просмотрите точки, переданные в качестве первых двух аргументов . SKShader.CreateLinearGradient Эти точки основаны на исходном прямоугольнике, ограничивающем путь. Первая точка — (–250, –100), вторая — (250, 100). Внутренние по сравнению с SkiaSharp, эти точки подвергаются текущему преобразованию холста, чтобы они правильно выровняться с отображаемым знаком бесконечности.
Без последнего аргумента для CreateLinearGradient вы увидите радужный градиент, который простирается от верхнего левого знака бесконечности к нижнему правому. (На самом деле градиент простирается от левого верхнего угла до нижнего правого угла ограничивающего прямоугольника. Отрисованный знак бесконечности больше ограничивающего прямоугольника на половину STROKE_WIDTH значения со всех сторон. Так как градиент красный как в начале, так и в конце, а градиент создается с SKShaderTileMode.Repeat помощью , разница не заметна.)
С этим последним аргументом в CreateLinearGradient шаблон градиента непрерывно перемещается по изображению:

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

Перевернутый текст окрашен градиентом, который на 50 % прозрачен вверху и полностью прозрачным в нижней части. Эти уровни прозрачности связаны с альфа-значениями 0x80 и 0.
Обработчик PaintSurface на странице Градиент отражения масштабирует размер текста до 90 % от ширины холста. Затем вычисляются xText значения и yText для размещения текста, который должен быть горизонтально центрирован, но находится на базовой линии, соответствующей вертикальному центру страницы:
public class ReflectionGradientPage : ContentPage < const string TEXT = "Reflection"; public ReflectionGradientPage () < Title = "Reflection Gradient"; SKCanvasView canvasView = new SKCanvasView(); canvasView.PaintSurface += OnCanvasViewPaintSurface; Content = canvasView; >void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args) < SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); using (SKPaint paint = new SKPaint()) < // Set text color to blue paint.Color = SKColors.Blue; // Set text size to fill 90% of width paint.TextSize = 100; float width = paint.MeasureText(TEXT); float scale = 0.9f * info.Width / width; paint.TextSize *= scale; // Get text bounds SKRect textBounds = new SKRect(); paint.MeasureText(TEXT, ref textBounds); // Calculate offsets to position text above center float xText = info.Width / 2 - textBounds.MidX; float yText = info.Height / 2; // Draw unreflected text canvas.DrawText(TEXT, xText, yText, paint); // Shift textBounds to match displayed text textBounds.Offset(xText, yText); // Use those offsets to create a gradient for the reflected text paint.Shader = SKShader.CreateLinearGradient( new SKPoint(0, textBounds.Top), new SKPoint(0, textBounds.Bottom), new SKColor[] < paint.Color.WithAlpha(0), paint.Color.WithAlpha(0x80) >, null, SKShaderTileMode.Clamp); // Scale the canvas to flip upside-down around the vertical center canvas.Scale(1, -1, 0, yText); // Draw reflected text canvas.DrawText(TEXT, xText, yText, paint); > > >
Эти xText значения и yText являются теми же значениями, которые используются для отображения отраженного текста в вызове DrawText в нижней части обработчика PaintSurface . Однако непосредственно перед этим кодом вы увидите Scale вызов метода SKCanvas . Этот Scale метод масштабируется горизонтально на 1 (что ничего не делает), но вертикально на –1, что эффективно переворачивает все с ног на голову. Центр поворота устанавливается в точку (0, yText ), где yText — вертикальный центр холста, изначально вычисляемый как info.Height разделенный на 2.
Имейте в виду, что Skia использует градиент для цвета графических объектов перед преобразованием холста. После рисования неотрефлексированного текста прямоугольник смещается таким образом, textBounds чтобы он соответствовал отображаемому тексту:
textBounds.Offset(xText, yText);
Вызов CreateLinearGradient определяет градиент от верхней части этого прямоугольника к нижнему краю. Градиент находится от полностью прозрачного синего ( paint.Color.WithAlpha(0) ) до 50 % прозрачного синего ( paint.Color.WithAlpha(0x80) ). Преобразование холста переворачивает текст с ног на голову, поэтому 50 % прозрачный синий цвет начинается с базового плана и становится прозрачным в верхней части текста.
Связанные ссылки
- API SkiaSharp
- SkiaSharpFormsDemos (пример)
Использование CSS-градиентов
CSS-градиенты представлены типом данных (en-US), специальным типом (en-US), состоящим из последовательного перехода между двумя и более цветами. Вы можете выбрать один из трёх типов градиентов: линейный (создаётся с помощью функции linear-gradient() (en-US)), круговой (создаётся с помощью radial-gradient() (en-US)) и конический (создаётся с помощью функции conic-gradient() (en-US)). Вы можете также создавать повторяющиеся градиенты с помощью функций repeating-linear-gradient() (en-US), repeating-radial-gradient() (en-US) и repeating-conic-gradient() (en-US).
Градиенты могут быть использованы везде, где может быть использован тип , например в качестве фона. Так как градиенты генерируются динамически, они могут избавить от необходимости использовать файлы растровых изображений, которые ранее использовались для достижения похожих эффектов. В дополнение к этому, так как градиенты генерируются браузером, они выглядят лучше, чем растровые изображения в случае увеличения масштаба, и их размер может быть изменён на лету.
Мы начнём с того, что покажем вам линейные градиенты, затем покажем возможности, поддерживаемые всеми типами градиентов, используя линейные градиенты в качестве примера, затем перейдём к круговым, коническим и повторяющимся градиентам.
Использование линейных градиентов
Линейный градиент создаёт цветную полосу, имеющую вид прямой линии.
Обычный линейный градиент
Чтобы создать самый простой тип градиента, всё, что вам нужно – это указать два цвета. Они называются точки остановки цвета. Их должно быть, как минимум, две, но у вас может быть столько, сколько захотите.
div class="simple-linear">div>
div width: 120px; height: 120px; >
.simple-linear background: linear-gradient(blue, pink); >
Изменение направления
По умолчанию линейные градиенты идут сверху вниз. Вы можете изменить угол поворота путём задания направления.
div class="horizontal-gradient">div>
div width: 120px; height: 120px; >
.horizontal-gradient background: linear-gradient(to right, blue, pink); >
Диагональные градиенты
Вы можете даже создать градиент, проходящий диагонально, из угла в угол.
div class="diagonal-gradient">div>
div width: 200px; height: 100px; >
.diagonal-gradient background: linear-gradient(to bottom right, blue, pink); >
Использование углов
Если вы хотите больше контроля над его направлением, вы можете задать градиенту определённый угол.
div class="angled-gradient">div>
div width: 120px; height: 120px; >
.angled-gradient background: linear-gradient(70deg, blue, pink); >
При использовании угла 0deg создаётся вертикальный градиент, идущий снизу вверх, 90deg создаёт горизонтальный градиент, идущий слева направо, и так далее по часовой стрелке. Отрицательные углы идут против часовой стрелки.

Указание цветов и создание эффектов
Все типы CSS-градиентов – это диапазон позиционно-зависимых цветов. Цвета, создаваемые CSS-градиентами, могут варьироваться непрерывно с изменением позиции, создавая плавные цветовые переходы. Возможно также создавать полосы сплошных цветов, и резкие переходы между двумя цветами. Следующее примеры работают во всех градиентных функциях:
Использование более двух цветов
Вам не нужно ограничиваться двумя цветами – вы можете использовать столько, сколько хотите! По умолчанию цвета равномерно распределены по градиенту.
div class="auto-spaced-linear-gradient">div>
div width: 120px; height: 120px; >
.auto-spaced-linear-gradient background: linear-gradient(red, yellow, blue, orange); >
Расположение точек остановок цветов
Вам не нужно оставлять ваши точки остановок цветов на их исходных позициях. Чтобы подправить их расположение, вы можете не задавать каждому ничего, или задать одну или две процентные, а для круговых и линейных градиентов – абсолютные значения. Если вы зададите расположение с процентах, 0% будет представлять начальную точку, в то время как 100% будет являться конечной точкой; однако, если необходимо, вы можете использовать значения и вне этого диапазона для достижения желаемого эффекта. Если вы не будете задавать расположение, позиция этой точки остановки будет автоматически рассчитана за вас так, что первая точка остановки будет расположена на 0% , а последняя – на 100% , а все остальные точки остановки будут расположены на полпути между соседними точками остановки.
div class="multicolor-linear">div>
div width: 120px; height: 120px; >
.multicolor-linear background: linear-gradient(to left, lime 28px, red 77%, cyan); >
Создание резких переходов
Чтобы создать резкий переход между двумя цветами, т. е. получить черту вместо постепенного перехода, обе соседние точки остановки должны быть установлены в одном месте. В этом примере цвета делят точку остановки на отметке 50% , посередине градиента:
div class="striped">div>
div width: 120px; height: 120px; >
.striped background: linear-gradient(to bottom left, cyan 50%, palegoldenrod 50%); >
Подсказки градиента
По умолчанию градиент идёт плавно от одного цвета до другого. Вы можете добавить цветовую подсказку, чтобы переместить значение средней точки перехода в определённую точку градиента. В этом примере мы переместили среднюю точку перехода из отметки 50% на отметку 10%.
div class="color-hint">div> div class="simple-linear">div>
div width: 120px; height: 120px; float: left; margin-right: 10px; >
.color-hint background: linear-gradient(blue, 10%, pink); > .simple-linear background: linear-gradient(blue, pink); >
Создание цветных линий и полосок
Чтобы добавить внутрь градиента сплошную цветную область без плавного перехода, добавьте две позиции для точки остановки. Точки остановки могут быть в двух позициях, что эквивалентно двум подряд точкам остановки с тем же цветом на разных позициях. Цвет достигнет полной насыщенности на первой точке, проследует с той же насыщенностью до второй точки остановки и перейдёт в цвет следующей точки остановки через первую позицию следующей точки остановки.
div class="multiposition-stops">div> div class="multiposition-stop2">div>
div width: 120px; height: 120px; float: left; margin-right: 10px; box-sizing: border-box; >
.multiposition-stops background: linear-gradient( to left, lime 20%, red 30%, red 45%, cyan 55%, cyan 70%, yellow 80% ); background: linear-gradient( to left, lime 20%, red 30% 45%, cyan 55% 70%, yellow 80% ); > .multiposition-stop2 background: linear-gradient( to left, lime 25%, red 25%, red 50%, cyan 50%, cyan 75%, yellow 75% ); background: linear-gradient( to left, lime 25%, red 25% 50%, cyan 50% 75%, yellow 75% ); >
В первом примере выше лаймовый цвет идёт от отметки 0%, далее, как указано, до отметки 20%, сделает переход от лаймового до красного через 10% ширины градиента, достигнет сплошного красного на отметке 30%, и останется таким до 45% градиента, где он потускнеет до голубого, оставаясь таким ещё 15% градиента, и так далее.
Во втором примере каждая вторая точка остановки для каждого цвета находится на той же позиции, что и первая точка остановки соседнего цвета, создавая полосатый эффект.
В обоих примерах градиент написан дважды: первый – это метод из CSS-изображений уровня 3 использующий повторения цвета на каждой остановке, а второй пример – это метод из CSS-изображений уровня 4, где в линейном объявлении точек остановки используются множественные точки остановки с двумя значениями длин точек остановки.
Управление переходом градиента
По умолчанию градиент плавно переходит между цветами двух соседних точек остановки, а средняя точка между этими двумя точками остановки является средним значением цветового перехода. Вы можете контролировать интерполяцию или переход между двумя точками остановки добавлением его расположения в цветовой подсказке. В этом примере цвет достигает средней точки перехода от лаймового до голубого на расстоянии 20% градиента вместо стандартных 50%. Во втором примере нет такой подсказки, чтобы подчеркнуть отличие, получаемое при её использовании:
div class="colorhint-gradient">div> div class="regular-progression">div>
div width: 120px; height: 120px; float: left; margin-right: 10px; box-sizing: border-box; >
.colorhint-gradient background: linear-gradient(to top, black, 20%, cyan); > .regular-progression background: linear-gradient(to top, black, cyan); >
Перекрытие градиентов
Градиенты поддерживают прозрачность, так что вы можете накладывать фоны для получения всяких разных эффектов. Фоны накладываются снизу вверх таким образом, что первый объявленный будет лежать поверх остальных.
div class="layered-image">div>
div width: 300px; height: 150px; >
.layered-image background: linear-gradient(to right, transparent, mistyrose), url("critters.png"); >
Наслаивание градиентов
Вы можете даже наслаивать градиенты друг на друга. Если верхние градиенты не полностью непрозрачны, градиенты, лежащие под ними, тоже будут видны.
div class="stacked-linear">div>
div width: 200px; height: 200px; >
.stacked-linear background: linear-gradient( 217deg, rgba(255, 0, 0, 0.8), rgba(255, 0, 0, 0) 70.71% ), linear-gradient(127deg, rgba(0, 255, 0, 0.8), rgba(0, 255, 0, 0) 70.71%), linear-gradient(336deg, rgba(0, 0, 255, 0.8), rgba(0, 0, 255, 0) 70.71%); >
Использование круговых градиентов
Круговые градиенты схожи с линейными градиентами, за исключением того, что они создают градиентный круг по направлению от центральной точки. Вы можете указать, где должна находиться центральная точка. Вы также можете сделать её круглой или овальной.
Обычный круговой градиент
Как и в случае с линейными градиентами, всё, что вам нужно, чтобы создать круговой градиент – это два цвета. По умолчанию центр градиента находится на отметке 50% 50%, градиент становится овальным с учётом соотношения сторон содержащего его блока:
div class="simple-radial">div>
div width: 240px; height: 120px; >
.simple-radial background: radial-gradient(red, blue); >
Размещение круговых точек остановки
Опять же, как и у линейных градиентов, вы можете расположить каждую круговую точку остановки, указав значение в виде процентной или абсолютной длины.
div class="radial-gradient">div>
div width: 120px; height: 120px; >
.radial-gradient background: radial-gradient(red 10px, yellow 30%, #1e90ff 50%); >
Расположение центра градиента
Вы можете расположить центр градиента с помощью ключевых значений, процентной или абсолютной длины. Значения в виде числа или процента повторяются в случае, если указано только одно из них, иначе порядок повторения будет определяться порядком расположения, начиная слева и сверху.
div class="radial-gradient">div>
div width: 120px; height: 240px; >
.radial-gradient background: radial-gradient(at 0% 30%, red 10px, yellow 30%, #1e90ff 50%); >
Задание размеров кругового градиента
В отличие от линейных градиентов, круговому градиенту можно задавать размеры. Возможные значения включат в себя: ближайший угол, ближайшая сторона, самый дальний угол и самая дальняя сторона, самый дальний угол – значение по умолчанию.
Пример: ближайшая сторона для эллипса
В этом примере используется значение размера closest-side , которое означает, что размер определяется расстоянием от начальной точки (центра) до ближайшей стороны блока.
div class="radial-ellipse-side">div>
div width: 240px; height: 100px; >
.radial-ellipse-side background: radial-gradient( ellipse closest-side, red, yellow 10%, #1e90ff 50%, beige ); >
Пример: самый дальний угол для эллипса
Этот пример схож с предыдущим, за исключением того, что его размер указан как farthest-corner , что устанавливает размер градиента значением расстояния от начальной точки до самого дальнего угла блока.
div class="radial-ellipse-far">div>
div width: 240px; height: 100px; >
.radial-ellipse-far background: radial-gradient( ellipse farthest-corner at 90% 90%, red, yellow 10%, #1e90ff 50%, beige ); >
Пример: ближайшая сторона для круга
Этот пример использует closest-side , что задаёт размер круга как расстояние между начальной точкой (центром) и ближайшей стороной. Радиус круга – это расстояние между центром градиента и ближайшей стороной. Круг, с учётом позиционирования в точке 25% от левой стороны и 25% от низа, ближе всего к низу, так как расстояние по высоте в этом случае меньше, чем по ширине.
div class="radial-circle-close">div>
div width: 240px; height: 120px; >
.radial-circle-close background: radial-gradient( circle closest-side at 25% 75%, red, yellow 10%, #1e90ff 50%, beige ); >
Наложение круговых градиентов
Вы можете накладывать круговые градиенты так же, как линейные. Первый объявленный будет сверху, последний – снизу.
div class="stacked-radial">div>
div width: 200px; height: 200px; >
.stacked-radial background: radial-gradient( circle at 50% 0, rgba(255, 0, 0, 0.5), rgba(255, 0, 0, 0) 70.71% ), radial-gradient( circle at 6.7% 75%, rgba(0, 0, 255, 0.5), rgba(0, 0, 255, 0) 70.71% ), radial-gradient( circle at 93.3% 75%, rgba(0, 255, 0, 0.5), rgba(0, 255, 0, 0) 70.71% ) beige; border-radius: 50%; >
Использование конических градиентов
CSS-функция conic-gradient() создаёт изображение, состоящее из градиента с переходом цвета, обёрнутым вокруг центральной точки (в отличие от градиента, исходящего кругом от центральной точки). Образцом конического градиента можно назвать круговые диаграммы и цветовые круги, но он также может быть использован для создания шахматной доски (клетки) и других интересных эффектов.
Синтаксис конического градиента схож с синтаксисом кругового градиента, но с тем отличием, что точки остановки цвета располагаются вокруг градиентной дуги, вдоль длины окружности круга, а не по градиентной линии, идущей от центра градиента. Также, точки остановки цвета задаются только в процентах или градусах, абсолютные величины недопустимы.
В круговом градиенте цвета переходят от центра окружности наружу, во всех направлениях. В случае конического градиента цвета идут, как бы оборачиваясь вокруг центра круга, начиная сверху и двигаясь по часовой стрелке. Так же, как и в круговом градиенте, вы можете указать расположение центра градиента. Так же, как и в линейном градиенте, вы можете изменять угол градиента.
Обычный конический градиент
Так же, как и в случае с линейными и круговыми градиентами, всё, что вам нужно для создания конического градиента – это два цвета. По умолчанию центр градиента находится в точке 50% 50%, начало градиента направлено вверх:
div class="simple-conic">div>
div width: 120px; height: 120px; >
.simple-conic background: conic-gradient(red, blue); >
Расположение конического центра
Как и в круговом градиенте, вы можете задать расположение центра конического градиента с помощью ключевых значений, процентных или абсолютных величин с использованием ключевого слова «at».
div class="conic-gradient">div>
div width: 120px; height: 120px; >
.conic-gradient background: conic-gradient(at 0% 30%, red 10%, yellow 30%, #1e90ff 50%); >
Изменение угла
Вы можете задать угол, в котором направлено начало градиента значением типа , с предшествующим ему ключевым словом «from».
div class="conic-gradient">div>
div width: 120px; height: 120px; >
.conic-gradient background: conic-gradient( from 45deg, red, orange, yellow, green, blue, purple ); >
Использование повторяющихся градиентов
Размер повторяющейся градиентной линии или дуги – это длина от значения первой до значения последней точки остановки цвета. Если первая точка остановки содержит только цвет без указания длины до точки остановки, то используется значение по умолчанию, равное 0. Если последняя точка остановки содержит только цвет без указания длины до точки установки, то используется значение по умолчанию, равное 100%. Если ни то, ни другое не определено, то линия градиента будет равна 100%, что означает, что линейный и конический градиент не будет повторяться, а круговой градиент будет повторяться, только если радиус градиента меньше, чем расстояние между центром градиента и самым дальним углом. Если первая точка остановки определена и имеет значение больше 0, градиент будет повторяться при условии, что размер линии или дуги равен разнице между первой и последней точкой остановки, если эта разница меньше, чем 100% или 360 градусов.
Повторяющиеся линейные градиенты
В этом примере используется repeating-linear-gradient() (en-US) для создания повторяющегося градиента, идущего по прямой линии. Цветовая последовательность начинается заново с каждым повторением градиента. В данном случае градиент имеет длину 10px.
div class="repeating-linear">div>
div width: 120px; height: 120px; >
.repeating-linear background: repeating-linear-gradient( -45deg, red, red 5px, blue 5px, blue 10px ); >
Множественные повторяющиеся линейные градиенты
Так же, как и в случае с обычными линейными и круговыми градиентами, вы можете использовать множественные градиенты, один поверх другого. Это имеет смысл, только если градиенты частично прозрачны, что позволяет видеть одни градиенты сквозь прозрачные части других градиентов, этого же можно достичь при условии использования разных размеров фона (background-size), при этом возможно ещё и при разных значениях свойства background-position для каждого градиента. Мы использовали прозрачность.
В данном случае градиентные линии имеют длину 300px, 230px и 300px.
div class="multi-repeating-linear">div>
div width: 600px; height: 400px; >
.multi-repeating-linear background: repeating-linear-gradient( 190deg, rgba(255, 0, 0, 0.5) 40px, rgba(255, 153, 0, 0.5) 80px, rgba(255, 255, 0, 0.5) 120px, rgba(0, 255, 0, 0.5) 160px, rgba(0, 0, 255, 0.5) 200px, rgba(75, 0, 130, 0.5) 240px, rgba(238, 130, 238, 0.5) 280px, rgba(255, 0, 0, 0.5) 300px ), repeating-linear-gradient( -190deg, rgba(255, 0, 0, 0.5) 30px, rgba(255, 153, 0, 0.5) 60px, rgba(255, 255, 0, 0.5) 90px, rgba(0, 255, 0, 0.5) 120px, rgba(0, 0, 255, 0.5) 150px, rgba(75, 0, 130, 0.5) 180px, rgba(238, 130, 238, 0.5) 210px, rgba(255, 0, 0, 0.5) 230px ), repeating-linear-gradient(23deg, red 50px, orange 100px, yellow 150px, green 200px, blue 250px, indigo 300px, violet 350px, red 370px); >
Клетчатый градиент
Для создания клетчатого градиента мы используем несколько полупрозрачных перекрывающих друг друга градиентов. В первом объявлении фона мы внесли в список каждую остановку цвета отдельно. Во втором объявлении свойства background используется синтаксис многопозиционных остановок цвета:
div class="plaid-gradient">div>
div width: 200px; height: 200px; >
.plaid-gradient background: repeating-linear-gradient( 90deg, transparent, transparent 50px, rgba(255, 127, 0, 0.25) 50px, rgba(255, 127, 0, 0.25) 56px, transparent 56px, transparent 63px, rgba(255, 127, 0, 0.25) 63px, rgba(255, 127, 0, 0.25) 69px, transparent 69px, transparent 116px, rgba(255, 206, 0, 0.25) 116px, rgba(255, 206, 0, 0.25) 166px ), repeating-linear-gradient( 0deg, transparent, transparent 50px, rgba(255, 127, 0, 0.25) 50px, rgba(255, 127, 0, 0.25) 56px, transparent 56px, transparent 63px, rgba(255, 127, 0, 0.25) 63px, rgba(255, 127, 0, 0.25) 69px, transparent 69px, transparent 116px, rgba(255, 206, 0, 0.25) 116px, rgba(255, 206, 0, 0.25) 166px ), repeating-linear-gradient( -45deg, transparent, transparent 5px, rgba(143, 77, 63, 0.25) 5px, rgba(143, 77, 63, 0.25) 10px ), repeating-linear-gradient(45deg, transparent, transparent 5px, rgba( 143, 77, 63, 0.25 ) 5px, rgba(143, 77, 63, 0.25) 10px); background: repeating-linear-gradient( 90deg, transparent 0 50px, rgba(255, 127, 0, 0.25) 50px 56px, transparent 56px 63px, rgba(255, 127, 0, 0.25) 63px 69px, transparent 69px 116px, rgba(255, 206, 0, 0.25) 116px 166px ), repeating-linear-gradient( 0deg, transparent 0 50px, rgba(255, 127, 0, 0.25) 50px 56px, transparent 56px 63px, rgba(255, 127, 0, 0.25) 63px 69px, transparent 69px 116px, rgba(255, 206, 0, 0.25) 116px 166px ), repeating-linear-gradient( -45deg, transparent 0 5px, rgba(143, 77, 63, 0.25) 5px 10px ), repeating-linear-gradient(45deg, transparent 0 5px, rgba( 143, 77, 63, 0.25 ) 5px 10px); >
Повторяющиеся круговые градиенты
В этом примере для создания кругового градиента, повторяющегося из центральной точки, используется repeating-radial-gradient() (en-US). Цветовая последовательность начинаются заново с каждой итерацией повторения градиента.
div class="repeating-radial">div>
div width: 120px; height: 120px; >
.repeating-radial background: repeating-radial-gradient( black, black 5px, white 5px, white 10px ); >
Множественные повторяющиеся круговые градиенты
div class="multi-target">div>
div width: 250px; height: 150px; >
.multi-target background: repeating-radial-gradient( ellipse at 80% 50%, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) 15px, rgba(255, 255, 255, 0.5) 15px, rgba(255, 255, 255, 0.5) 30px ) top left no-repeat, repeating-radial-gradient( ellipse at 20% 50%, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) 10px, rgba(255, 255, 255, 0.5) 10px, rgba(255, 255, 255, 0.5) 20px ) top left no-repeat yellow; background-size: 200px 200px, 150px 150px; >
Смотрите также
- Градиентные функции: linear-gradient() (en-US), radial-gradient() (en-US), conic-gradient() (en-US), repeating-linear-gradient() (en-US), repeating-radial-gradient() (en-US), repeating-conic-gradient() (en-US)
- Типы данных CSS, связанные с градиентами: (en-US), (en-US)
- Свойства CSS, связанные с градиентами: background , background-image
- Галерея шаблонов градиентов CSS, от Lea Verou
- Библиотека градиентов CSS3, от Estelle Weyl
- Генератор градиентов CSS
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Градиенты
Узнайте, как создавать градиенты различных типов в Illustrator.
Градиент — это градуированный переход между двумя или более цветами или двумя оттенками одного цвета. Градиенты можно использовать для создания наложения цветов, добавления объема к векторным объектам, а также для добавления света и тени к иллюстрациям.

В Illustrator можно создавать, применять и изменять градиент с помощью панели «Градиент», инструмента «Градиент» или панели управления.
Типы градиентов
В Illustrator можно использовать следующие три типа градиентов:
- Линейный
Этот градиент можно использовать для перехода цветов от одной точки до другой по прямой линии.
- Радиальный
Этот градиент можно использовать для перехода цветов от одной точки до другой в виде кругового узора.
- Произвольный
Этот градиент можно использовать для создания градуированного перехода между точками цвета на форме в упорядоченной или произвольной последовательности, чтобы переход выглядел ровно и естественно. Произвольный градиент может применяться в двух режимах:- Точки. Этот режим используется для затенения области вокруг точки цвета.
- Линии. Этот режим используется для затенения области вокруг линии.
Примечание.
Точка цвета — это точка на аннотаторе градиента (для линейных или радиальных градиентов) или на объекте (для произвольного градиента), которая управляет цветом градиента. Можно изменить цвет точки цвета для настройки градиента

A. Линейный градиент B. Радиальный градиент C. Произвольный градиент (точки)
Примечание.
Линейные и радиальные градиенты можно применять на заливке и обводке объекта. Произвольный градиент можно применять только для заливки объекта.
Инструмент «Градиент» и панель «Градиент»
Для создания и изменения градиента используется инструмент «Градиент» или панель «Градиент». Используйте инструмент «Градиент», если необходимо создать или изменить градиенты непосредственно на иллюстрации и просмотреть изменения в реальном времени.
Чтобы открыть инструмент «Градиент», нажмите инструмент «Градиент» на панели инструментов.
Попробуйте в приложении
Создавайте наложения цветов за несколько простых шагов.- Выберите «Окно > Градиент».
- На панели управления дважды щелкните инструмент «Градиент».
Панель «Градиент» откроется на холсте.

A. Активный или ранее использованный градиент B. Раскрывающийся список существующих градиентов C. Цвет заливки D. Цвет обводки E. Обратный градиент F. Аннотатор градиента G. Точка цвета H. Средняя точка I. Палитра цветов J. Отображение и скрытие параметров K. Типы градиентов L. Типы обводок M. Угол N. Пропорции O. Удалить точку P. Непрозрачность Q. Положение R. Заливка или обводка (цветом) S. Точка цвета T. Распределение U. Произвольный градиент V. Режимы произвольного градиента
Инструмент «Градиент» и панель «Градиент» имеют множество одинаковых параметров. Однако некоторые задачи можно выполнить только с помощью инструмента или панели. С помощью инструмента «Градиент» и панели можно задать несколько точек цвета, их расположение и распределение. Можно также указать угол, под которым отображаются цвета, пропорции эллиптического градиента и непрозрачность каждого цвета.
Можно включить функцию рисования и редактирования в реальном времени, чтобы улучшить внешний вид объектов при работе с ними. Чтобы включить эту функцию, выполните следующие действия:
[Windows] Выберите Редактирование > Установки > Производительность > Рисование и редактирование в реальном времени.
[macOS] Выберите Illustrator > Установки > Производительность > Рисование и редактирование в реальном времени.
Аннотатор градиента
Для линейных и радиальных градиентов при нажатии инструмента «Градиент» на панели инструментов на объекте отображается аннотатор градиента. Аннотатор градиента — это шкала, на который отображаются начальная точка, конечная точка, средняя точка, а также две точки цвета для начальной и конечной точек.

A. Аннотатор градиента B. Кольцо из точек C. Наведите курсор, чтобы изменить пропорции D. Курсор поворота E. Точка для изменения размера радиального градиента F. Конечная точка (точка со стрелкой) G. Точка цвета H. Средняя точка I. Выбранная точка цвета J. Центральная точка
Аннотатор градиента можно использовать для изменения угла, положения и области линейного градиента, а также фокусной точки, центральной точки и распределения радиального градиента. После того как в объекте появится аннотатор градиента, можно использовать панель «Градиент» или аннотатор градиента, чтобы добавить новые точки цвета, задать новые цвета для отдельных точек цвета, изменить настройки непрозрачности и перетащить точки цвета в новое расположение.
Чтобы скрыть или отобразить аннотатор градиента, выберите Просмотр > Спрятать градиентный аннотатор или Просмотр > Показать градиентный аннотатор.
Для линейных и радиальных градиентов перетаскивание круглого конца ползунка (начальной точки) приводит к изменению положения центральной точки градиента, а конца со стрелкой (конечной точки) — увеличению или уменьшению диапазона. Если навести курсор на конечную точку, появится курсор поворота, с помощью которого можно изменить угол градиента.
Примечание. Произвольный градиент позволяет размещать точки цвета в любом месте объекта. Поэтому произвольный градиент не требует использования аннотатора градиента.
Применение предварительно заданного градиента
При первом применении инструмента «Градиент» по умолчанию используется Черно-белый градиент. Если градиент применялся ранее, по умолчанию применяется последний использованный градиент.
Кроме того, Illustrator содержит предварительно заданный набор градиентов, которые можно применить с помощью панели «Градиент» или «Образцы». Можно также создать градиент и сохранить его на панели «Образцы» для дальнейшего использования. Чтобы применить предварительно заданный или сохраненный градиент с панели «Градиент», выполните следующие действия:
- Выберите объект на холсте и нажмите раскрывающийся список Градиент на панели «Градиент».
Чтобы применить предварительно заданный градиент из библиотеки образцов, выполните следующие действия:
- Чтобы открыть панель «Образцы», выберите Окно >Образцы.
- На панели «Образцы» нажмите раскрывающийся список в правом верхнем углу. В списке выберите Открыть библиотеку образцов >Градиенты, затем выберите градиент, который требуется применить.
- Чтобы на панели «Образцы» отображались только образцы градиентов, нажмите раскрывающийся список Показать виды образцов и выберите Показать образцы градиентов.

Создание и применение линейных, радиальных и произвольных градиентов
В зависимости от ваших требований можно применить линейный, радиальный или произвольный градиент к иллюстрации.
- Создание и применение линейного градиента
- Создание и применение радиального градиента
- Создание и применение произвольного градиента
Создание и применение линейного градиента
Для создания линейного градиента выполните одно из следующих действий:
- Выберите инструмент «Градиент», затем нажмите объект на холсте. На панели управления или панели «Свойства» отображаются кнопки «Тип градиента». Выберите объект, затем нажмите Линейный градиент, чтобы применить линейный градиент к объекту.
- На панели «Градиент» нажмите Линейный градиент .
- На панели «Свойства» нажмите Линейный градиент в разделе Градиент.
Создание и применение радиального градиента
Для создания или применения радиального градиента выполните одно из следующих действий:
- Выберите инструмент «Градиент», затем нажмите объект на холсте. На панели управления или панели «Свойства» отображаются кнопки «Тип градиента». Выберите объект, затем нажмите Радиальный градиент, чтобы применить радиальный градиент к объекту.
- На панели «Градиент» нажмите Радиальный градиент.
- На панели «Свойства» нажмите Радиальный градиент в разделе Градиент.
Создание и применение произвольного градиента
Для создания или применения произвольного градиента выполните одно из следующих действий:
- Выберите инструмент «Градиент», затем нажмите объект на холсте. На панели управления или панели «Свойства» отображаются кнопки «Тип градиента». Выберите объект, затем нажмите Произвольный градиент, чтобы применить произвольный градиент к объекту.
- На панели «Градиент» нажмите Произвольный градиент.
- На панели «Свойства» нажмите Произвольный градиент в разделе Градиент.
После нажатия «Произвольный градиент» будут доступны следующие два параметра:
- Точки. Выберите этот параметр, чтобы создать точки цвета в виде независимых точек на объекте.
- Линии. Выберите этот параметр, чтобы создать точки цвета на отрезке линии на объекте.
Примечание.
Чтобы скопировать произвольный градиент с одного объекта на другой, используйте палитру цветов на панели инструментов.
Создание произвольного градиента в режиме точек
Для создания, изменения и удаления произвольного градиента в режиме точки выполните следующие действия:
- Чтобы добавить одну или несколько точек цвета, щелкните в любом месте внутри объекта.
- Чтобы изменить расположение точек цвета, перетащите их в нужное место.
- Чтобы удалить точку цвета, перетащите ее за пределы объекта или нажмите Удалить на панели «Градиент» или нажмите клавишу Delete.
Распределение произвольного градиента в режиме точек
Можно задать распределение точки цвета для произвольного градиента в виде точки. Распределение — это круговая область вокруг точки цвета, к которой применяется градиент. Чтобы задать распределение точки цвета, выберите точку цвета и выполните одно из следующих действий:
- На панели «Градиент» выберите или введите значение в раскрывающемся списке Распределение.
- Введите значение в раскрывающемся списке Распределение на панели управления, панели «Свойства» или панели «Градиент». Можно также использовать шкалу, которая отображается при нажатии Распределение.
По умолчанию для распределения точки цвета установлено значение 0%.
Примечание.
Распределение поддерживается только в режиме точки.
Создание произвольного градиента в режиме линий
Чтобы добавить точки цвета для произвольного градиента для линий, выполните одно из следующих действий:
- Щелкните в любом месте внутри объекта, чтобы создать первую точку цвета, которая является начальной точкой для отрезка линии.
- Нажмите для создания следующей точки цвета. Будет создана прямая линия от первой до второй точки цвета.
- Нажмите еще раз, чтобы создать дополнительные точки цвета. Прямая линия станет кривой.
Можно создать несколько отдельных отрезков линии в объекте. Чтобы создать новый отрезок линии, выполните следующие действия:
- Перетащите курсор за пределы объекта и переместите его обратно внутрь объекта, затем щелкните в любом месте, чтобы создать первую точку цвета для отрезка линии.
Примечание. Можно также перетаскивать отрезки линии и объединять их при необходимости.
Удаление выбранных точек цвета:
- Перетащите их за пределы объекта или нажмите Удалить на панели «Градиент».
Изменение расположения точек цвета:
- Перетащите точку цвета в нужное место. Отрезок линии удлиняется или сокращается при изменении расположения точек цвета. Расположение других точек цвета остается неизменным.
Примечание.
При применении градиента к выбранному объекту применяются настройки по умолчанию. Чтобы отключить эту функцию, снимите флажок Установить настройки подгонки с учетом содержимого по умолчанию в меню Редактирование > Установки > Основные (Windows) или Illustrator > Установки > Основные (macOS). Этот параметр отключен для компьютеров с 32-разрядной ОС Windows.
Изменение градиентов
Можно изменить цвет, центральную точку, непрозрачность, расположение и угол градиента с помощью инструмента «Градиент», панели «Градиент», панели управления или панели «Свойства».
Чтобы войти в режим изменения градиента напрямую, на панели «Градиент» выберите объект и нажмите кнопку Изменить градиент. Затем можно изменить такие параметры, как точки цвета, цвет, угол, непрозрачность, расположение, пропорции и т. д.

A. Оттенки одного цвета B. Два разных цвета C. Измененный угол D. Аннотатор измененного размера E. Измененное расположение

A. Два разных цвета B. Измененная центральная точка внутри кольца из точек C. Измененное расположение аннотатора градиента D. Измененные пропорции E. Измененное расположение средней точки
Добавление и изменение точек цвета
После применения градиента можно добавлять различные точки цвета на аннотатор градиента.
Добавление точек цвета:
- Поместите курсор на аннотатор градиента и при появлении значка «+» под курсором нажмите аннотатор градиента.
В месте нажатия будет добавлена точка цвета.
Чтобы удалить точку цвета, выберите точку цвета и выполните одно из следующих действий:
- Нажмите клавишу Delete.
- Нажмите кнопку Удалить на панели «Градиент».
Чтобы выбрать несколько точек цвета, удерживайте клавишу Shift и выберите точки цвета.
Для отмены выбора всех точек цвета нажмите клавишу Escape.
Примечание. При выборе точки цвета для градиента на панели управления и панели инструментов отображаются параметры для изменения точек цвета. Кроме того, параметры цвета отображаются на вкладке «Цвет» справа.
Изменение цвета
Чтобы изменить цвет точки цвета, выполните одно из следующих действий:
- Дважды нажмите точку цвета.
Откроется панель «Цвет», на которой можно выбрать цвет для применения. Выбранный цвет будет применен от текущей выделенной точки цвета до следующей точки цвета.

A. Точка цвета B. Распределение C. Непрозрачность D. Цвет E. Образцы F. Палитра цветов G. Образцы цветов
- Нажмите кнопку Образцы на панели «Цвет», чтобы выбрать цвет из доступных образцов.
- Нажмите кнопку Палитра цветов на панели «Цвет», чтобы выбрать и применить любой цвет с холста в другом месте. Нажмите клавишу Escape или Enter, чтобы выйти с палитры цветов. Палитру цветов можно открыть на панели «Цвет», «Градиент» и «Свойства».
- Откройте панель «Образцы», нажав Окна >Образцы. Нажмите заливку объекта на панели «Образцы». Выбранный цвет будет применен к выделенной точке цвета.
Изменение центральной точки, изменение размера и поворот аннотатора градиента
Начальная точка аннотатора градиента называется центральной точкой.
- Чтобы изменить центральную точку, поместите курсор на начальную точку и перетащите его.
- Чтобы изменить размер аннотатора градиента, перетащите конечную точку ближе к начальной точке или дальше от нее.
Размер аннотатора градиента не может быть изменен с помощью начальной точки (начала координат).
- Чтобы повернуть аннотатор градиента для линейного градиента, удерживайте конечную точку аннотатора градиента. Когда появится значок круговой стрелки, перетащите аннотатор и поверните его в любом направлении. На экране появится пунктирный прямоугольник, указывающий на новое расположение аннотатора.
- Чтобы повернуть аннотатор градиента для радиальных градиентов, поместите курсор на конечную точку аннотатора градиента и перетащите аннотатор, когда появится значок круговой стрелки.
Когда курсор будет помещен в пределах радиуса радиального градиента, появится пунктирное кольцо. Поверните кольцо по оси, чтобы изменить угол радиального градиента. Кроме того, на пунктирном кольце отображаются две точки. Можно нажать одну из этих точек, чтобы изменить форму кольца (пропорции), или нажать другую точку для изменения размера пунктирного кольца (распределение градиента).
Изменение расположения
Чтобы изменить расположение точек цвета и их средних точек, выполните следующие действия:
- Перетащите точки цвета вдоль ползунка градиента.
- Добавьте значение в поле Положение на панели «Градиент» (покажите пример изменения расположения точек цвета).
Изменяя среднюю точку, можно настроить деление цвета между двумя точками цвета.
Изменение угла
Чтобы изменить угол градиента, выполните следующие действия:
- Поверните аннотатор градиента на объекте.
- Выберите или введите значение в раскрывающемся списке Угол на панели «Градиент».
Изменение непрозрачности
Чтобы изменить непрозрачность точки цвета, выберите точку цвета и выполните одно из следующих действий:
- Выберите или введите значение в поле Непрозрачность на панели «Градиент» или панели управления.
- Переместите ползунок «Непрозрачность» на панели управления.
Если точка цвета имеет значение непрозрачности менее 100%, цвет отображается «в клетку» в аннотаторе градиента.