Двухмерной графики в Xamarin.iOSCore Graphics in Xamarin.iOS

В этой статье рассматриваются платформы iOS двухмерной графики. В этом примере показано использование Core Graphics для рисования geometry, изображения и PDF-файлы.This article discusses the Core Graphics iOS frameworks. It shows how to use Core Graphics to draw geometry, images and PDFs.

включает в себя iOS двухмерной графики framework и обеспечивает поддержку низкого уровня рисования.iOS includes the Core Graphics framework to provide low-level drawing support. Эти платформы являются обеспечивают широкие возможности графического в UIKit.These frameworks are what enable the rich graphical capabilities within UIKit.

Двухмерной графики — это платформа низкого уровня двумерной графики, которая позволяет рисования аппаратно независимая графика.Core Graphics is a low-level 2D graphics framework that allows drawing device independent graphics. Все 2D, рисование в UIKit внутри использует двухмерной графики.All 2D drawing in UIKit uses Core Graphics internally.

Двухмерной графики поддерживает рисование в ряде сценариев, в том числе:Core Graphics supports drawing in a number of scenarios including:

Геометрические пространстваGeometric Space

Независимо от сценария все операции рисования, выполненные с двухмерной графики выполняется геометрические пробел, это означает, что он работает в абстрактный точек, а не в точках.Regardless of the scenario, all drawing done with Core Graphics is done in geometric space, meaning it works in abstract points rather than pixels. Вы описываете желаемого рисоваться с точки зрения геометрии и Рисование состояния, таких как цвета, стили линий, т. д. и двухмерной графики обрабатывает все преобразования в пикселях.You describe what you want drawn in terms of geometry and drawing state such as colors, line styles, etc. and Core Graphics handles translating everything into pixels. Такое состояние добавляется в контекст графики, который можно рассматривать как холст по образцу.Such state is added to a graphics context, which you can think of like a painter’s canvas.

Существует несколько преимуществ такого подхода:There are a few benefits to this approach:

  • Код становится динамические, а впоследствии можно изменить графики во время выполнения.Drawing code becomes dynamic, and can subsequently modify graphics at runtime.
  • Снижая потребность в статические изображения в пакете приложения можно уменьшить размер приложения.Reducing the need for static images in the application bundle can reduce application size.
  • Графики становятся более устойчивым к Изменение разрешения на устройствах.Graphics become more resilient to resolution changes across devices.

Рисование в подкласс UIViewDrawing in a UIView Subclass

Каждый UIView имеет Draw метод, который вызывается системой, когда он должен быть нарисован.Every UIView has a Draw method that is called by the system when it needs to be drawn. Чтобы добавить код рисования к представлению, подкласс UIView и переопределить Draw:To add drawing code to a view, subclass UIView and override Draw:

public class TriangleView : UIView
{
    public override void Draw (CGRect rect)
    {
        base.Draw (rect);
    }
}

Draw никогда не должен вызываться напрямую.Draw should never be called directly. Вызывается системой во время выполнения цикла обработки.It is called by the system during run loop processing. В первый раз с помощью выполнения цикла после добавления представления иерархии представлений, его Draw вызывается метод.The first time through the run loop after a view is added to the view hierarchy, its Draw method is called. Последующие вызовы Draw возникать, когда представление помечается как нуждающийся в рисуется с помощью вызова SetNeedsDisplay или SetNeedsDisplayInRect в представлении.Subsequent calls to Draw occur when the view is marked as needing to be drawn by calling either SetNeedsDisplay or SetNeedsDisplayInRect on the view.

Шаблон для кода графикиPattern for Graphics Code

Код в Draw реализации должны описывать изложить формируемого.The code in the Draw implementation should describe what it wants drawn. Код рисования соответствует шаблону, в котором он задает некоторое состояние, рисования и вызывает метод для запроса, он рисуется.The drawing code follows a pattern in which it sets some drawing state and calls a method to request it be drawn. Этот шаблон можно обобщить следующим образом:This pattern can be generalized as follows:

  1. Получите контекст графики.Get a graphics context.

  2. Задайте атрибуты рисования.Set up drawing attributes.

  3. Создание некоторых геометрических объектов из графических примитивов.Create some geometry from drawing primitives.

  4. Вызовите метод Draw или рисования штрихов.Call a Draw or Stroke method.

Пример базовых средств рисованияBasic Drawing Example

Например рассмотрим следующий фрагмент кода:For example, consider the following code snippet:

//get graphics context
using (CGContext g = UIGraphics.GetCurrentContext ()) {
            
    //set up drawing attributes
    g.SetLineWidth (10);
    UIColor.Blue.SetFill ();
    UIColor.Red.SetStroke ();

    //create geometry
    var path = new CGPath ();

    path.AddLines (new CGPoint[]{
    new CGPoint (100, 200),
    new CGPoint (160, 100), 
    new CGPoint (220, 200)});

    path.CloseSubpath ();

    //add geometry to graphics context and draw it
    g.AddPath (path);       
    g.DrawPath (CGPathDrawingMode.FillStroke);
}

Давайте разобьем следующий код:Let's break this code down:

using (CGContext g = UIGraphics.GetCurrentContext ()) {
...
}

С помощью этой строки он получает текущим графическим контекстом, используемый для рисования.With this line, it first gets the current graphics context to use for drawing. Можно считать контекста графики canvas, рисование передачах, содержащий все данные о состоянии о рисунком, таких как штриха и цвета заливки, а также геометрии для рисования.You can think of a graphics context as the canvas that drawing happens on, containing all the state about the drawing, such as stroke and fill colors, as well as the geometry to draw.

g.SetLineWidth (10);
UIColor.Blue.SetFill ();
UIColor.Red.SetStroke ();

После получения графического контекста в коде настраивается некоторые атрибуты отображения, показано выше.After getting a graphics context the code sets up some attributes to use when drawing, shown above. В этом случае устанавливаются цвета линий ширины, штриха и заливки.In this case the line width, stroke and fill colors are set. Все последующие операции рисования будет использовать эти атрибуты, так как они сохраняются в состоянии графического контекста.Any subsequent drawing will then use these attributes because they are maintained in the graphics context's state.

Создание геометрического объекта в коде используется CGPath, что позволяет графический контур, описываемый из линий и кривых.To create geometry the code uses a CGPath, which allows a graphics path to be described from lines and curves. В этом случае путь добавляет линий, соединяющих массив точек, чтобы сложить треугольника.In this case, the path adds lines connecting an array of points to make up a triangle. Как показано ниже используется двухмерной графики в системе координат для рисования представления, где источником является в левом верхнем углу с положительным x-direct вправо, а оси y положительные вниз:As displayed below Core Graphics uses a coordinate system for view drawing, where the origin is in the upper left, with positive x-direct to the right and the positive-y direction down:

var path = new CGPath ();

path.AddLines (new CGPoint[]{
new CGPoint (100, 200),
new CGPoint (160, 100), 
new CGPoint (220, 200)});

path.CloseSubpath ();

После создания пути он добавляется к контексту графики, таким образом, вызов AddPath и DrawPath соответственно можно создать его.Once the path is created, it's added to the graphics context so that calling AddPath and DrawPath respectively can draw it.

Ниже показано результирующее представление:The resulting view is shown below:

Создание градиента заливкиCreating Gradient Fills

Также доступны широкие формы отрисовки.Richer forms of drawing are also available. Например Core Graphics позволяет создавать градиентные заливки и применение контуров обрезки.For example, Core Graphics allows creating gradient fills and applying clipping paths. Чтобы нарисовать градиентную заливку путь из предыдущего примера, сначала путь должен быть задан в качестве контура обрезки:To draw a gradient fill inside the path from the previous example, first the path needs to be set as the clipping path:

// add the path back to the graphics context so that it is the current path
g.AddPath (path);
// set the current path to be the clipping path
g.Clip ();

Параметр по текущему пути, как контур обрезки ограничивает все последующие операции рисования в геометрический путь, например, следующий код, который рисует линейного градиента:Setting the current path as the clipping path constrains all subsequent drawing within the geometry of the path, such as the following code, which draws a linear gradient:

// the color space determines how Core Graphics interprets color information
    using (CGColorSpace rgb = CGColorSpace.CreateDeviceRGB()) {
        CGGradient gradient = new CGGradient (rgb, new CGColor[] {
        UIColor.Blue.CGColor,
        UIColor.Yellow.CGColor
    });

// draw a linear gradient
    g.DrawLinearGradient (
        gradient, 
        new CGPoint (path.BoundingBox.Left, path.BoundingBox.Top), 
        new CGPoint (path.BoundingBox.Right, path.BoundingBox.Bottom), 
        CGGradientDrawingOptions.DrawsBeforeStartLocation);
    }

Эти изменения позволяют градиентную заливку, как показано ниже:These changes produce a gradient fill as shown below:

Изменение строки шаблоновModifying Line Patterns

Атрибуты рисования строк можно также изменить при помощи двухмерной графики.The drawing attributes of lines can also be modified with Core Graphics. Это включает в себя изменение ширины и stroke цвет линии, а также шаблон линии, как показано в следующем коде:This includes changing the line width and stroke color, as well as the line pattern itself, as seen in the following code:

//use a dashed line
g.SetLineDash (0, new nfloat[] { 10, 4 * (nfloat)Math.PI });

Добавив этот код перед рисования результатов операций в long, пунктирные обводки 10 единиц для работы с 4 единицы интервала между тире, как показано ниже:Adding this code before any drawing operations results in dashed strokes 10 units long, with 4 units of spacing between dashes, as shown below:

Обратите внимание, что при использовании на единый API в Xamarin.iOS, тип массива должна быть nfloatи также должен быть явно приведен к Math.PI.Note that when using the Unified API in Xamarin.iOS, the array type needs to be an nfloat, and also needs to be explicitly cast to Math.PI.

Рисование изображений и текстаDrawing Images and Text

Помимо рисования пути в контексте графического представления, Core Graphics также поддерживает рисования текста и изображений.In addition to drawing paths in a view's graphics context, Core Graphics also supports drawing images and text. Для рисования изображения, просто создайте CGImage и передать его в DrawImage вызова:To draw an image, simply create a CGImage and pass it to a DrawImage call:

public override void Draw (CGRect rect)
{
    base.Draw (rect);

    using(CGContext g = UIGraphics.GetCurrentContext ()){
        g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
    }
}

Тем не менее в результате получается изображения, нарисованного сверху вниз, как показано ниже:However, this produces an image drawn upside down, as shown below:

Причиной этого является origin Core Graphics для рисования изображения находится в левом нижнем, а представление расположен в левом верхнем углу.The reason for this is Core Graphics origin for image drawing is in the lower left, while the view has its origin in the upper left. Таким образом, чтобы правильно отображать изображения, источника должно быть изменено, что можно сделать, изменив текущую матрицу преобразования (CTM).Therefore, to display the image correctly, the origin needs to be modified, which can be accomplished by modifying the Current Transformation Matrix (CTM). CTM определяет места проживания точек, называемых также пространства пользователя.The CTM defines where points live, also known as user space. Инверсия CTM по оси y и сдвигая его границы высота по оси y отрицательное можно перевернуть изображение.Inverting the CTM in the y direction and shifting it by the bounds’ height in the negative y direction can flip the image.

Графический контекст содержит вспомогательные методы для преобразования CTM.The graphics context has helper methods to transform the CTM. В этом случае ScaleCTM «отражение» Рисование и TranslateCTM переходит в левый верхний угол, как показано ниже:In this case, ScaleCTM "flips" the drawing and TranslateCTM shifts it to the upper left, as shown below:

public override void Draw (CGRect rect)
{
    base.Draw (rect);
    
    using (CGContext g = UIGraphics.GetCurrentContext ()) {

        // scale and translate the CTM so the image appears upright
        g.ScaleCTM (1, -1);
        g.TranslateCTM (0, -Bounds.Height);
        g.DrawImage (rect, UIImage.FromFile ("MyImage.png").CGImage);
}   

Полученное изображение отображается вертикально:The resulting image is then displayed upright:

Важно!

Изменения графического контекста применяются для всех последующих операций рисования.Changes to the graphics context apply to all subsequent drawing operations. Таким образом когда CTM преобразуется, изменения затронут все дополнительные рисование.Therefore, when the CTM is transformed, it will affect any additional drawing. Например если после преобразования CTM нарисованную треугольник, может показаться сверху вниз.For example, if you drew the triangle after the CTM transformation, it would appear upside down.

Добавление текста в образеAdding Text to the Image

Как пути и изображения, рисование текста с графикой Core включает тот же базовый шаблон настройки некоторых состояние графики и вызов метода для рисования.As with paths and images, drawing text with Core Graphics involves the same basic pattern of setting some graphics state and calling a method to draw. В случае с текстом, метод для отображения текста — ShowText.In the case of text, the method to display text is ShowText. При добавлении к образу, рисование пример, приведенный ниже Рисует текст с помощью двухмерной графики:When added to the image drawing example, the following code draws some text using Core Graphics:

public override void Draw (RectangleF rect)
{
    base.Draw (rect);
    
    // image drawing code omitted for brevity ...

    // translate the CTM by the font size so it displays on screen
    float fontSize = 35f;
    g.TranslateCTM (0, fontSize);

    // set general-purpose graphics state
    g.SetLineWidth (1.0f);
    g.SetStrokeColor (UIColor.Yellow.CGColor);
    g.SetFillColor (UIColor.Red.CGColor);
    g.SetShadow (new CGSize (5, 5), 0, UIColor.Blue.CGColor);

    // set text specific graphics state
    g.SetTextDrawingMode (CGTextDrawingMode.FillStroke);
    g.SelectFont ("Helvetica", fontSize, CGTextEncoding.MacRoman);

    // show the text
    g.ShowText ("Hello Core Graphics");
}

Как вы видите, состояние графики для рисования текста задается аналогично рисованию geometry.As you can see, setting the graphics state for text drawing is similar to drawing geometry. Тем не менее рисования текста, также применяются рисования режим и шрифт текста.For text drawing however, the text drawing mode and the font are applied as well. В этом случае тень также применяется, несмотря на то, что применение shadows работает так же, для пути рисования.In this case, a shadow is also applied, although applying shadows works the same for path drawing.

Получившийся текст отображается с изображением, как показано ниже:The resulting text is displayed with the image as shown below:

Образы на основе памятиMemory-Backed Images

Помимо рисования для представления графического контекста двухмерной графики поддерживает рисование памяти на базе образов, также известный как рисование вне экрана.In addition to drawing to a view's graphics context, Core Graphics supports drawing memory backed images, also known as drawing off-screen. Для этого необходимо:Doing so requires:

  • Создание графического контекста, поддерживаемый обработки в памяти растрового изображенияCreating a graphics context that is backed by an in memory bitmap
  • Установка состояния, рисования и выдача команд рисованияSetting drawing state and issuing drawing commands
  • Получение изображения из контекстаGetting the image from the context
  • Удаление контекстаRemoving the context

В отличие от Draw метод, где контекст предоставляется путем представления, в этом случае создании контекста в одном из двух способов:Unlike the Draw method, where the context is supplied by the view, in this case you create the context in one of two ways:

  1. Путем вызова UIGraphics.BeginImageContext (или BeginImageContextWithOptions)By calling UIGraphics.BeginImageContext (or BeginImageContextWithOptions)

  2. При создании нового CGBitmapContextInstanceBy creating a new CGBitmapContextInstance

CGBitmapContextInstance полезно при работе непосредственно с биты изображения, например для случаев, когда используется алгоритм обработки пользовательского образа.CGBitmapContextInstance is useful when you are working directly with the image bits, such as for cases where you are using a custom image manipulation algorithm. Во всех остальных случаях следует использовать BeginImageContext или BeginImageContextWithOptions.In all other cases, you should use BeginImageContext or BeginImageContextWithOptions.

Получив контекст изображения, добавив код отрисовки — так же, как он находится в UIView подкласс.Once you have an image context, adding drawing code is just like it is in a UIView subclass. Например, в примере выше используется для рисования треугольник можно использовать для рисования изображения в памяти, а не в UIView, как показано ниже:For example, the code example used earlier to draw a triangle can be used to draw to an image in memory instead of in a UIView, as shown below:

UIImage DrawTriangle ()
{
    UIImage triangleImage;

    //push a memory backed bitmap context on the context stack
    UIGraphics.BeginImageContext (new CGSize (200.0f, 200.0f));

    //get graphics context
    using(CGContext g = UIGraphics.GetCurrentContext ()){

        //set up drawing attributes
        g.SetLineWidth(4);
        UIColor.Purple.SetFill ();
        UIColor.Black.SetStroke ();

        //create geometry
        path = new CGPath ();

        path.AddLines(new CGPoint[]{
            new CGPoint(100,200),
            new CGPoint(160,100), 
            new CGPoint(220,200)});

        path.CloseSubpath();

        //add geometry to graphics context and draw it
        g.AddPath(path);
        g.DrawPath(CGPathDrawingMode.FillStroke);

        //get a UIImage from the context
        triangleImage = UIGraphics.GetImageFromCurrentImageContext ();
    }
    
    return triangleImage;
}

Обычно документа на основе памяти растрового изображения используется для записи образа из любого UIView.A common use of drawing to a memory-backed bitmap is to capture an image from any UIView. Например, следующий код подготавливают слой представления на контекст растрового изображения и создает UIImage от него:For example, the following code renders a view's layer to a bitmap context and creates a UIImage from it:

UIGraphics.BeginImageContext (cellView.Frame.Size);

//render the view's layer in the current context
anyView.Layer.RenderInContext (UIGraphics.GetCurrentContext ());

//get a UIImage from the context
UIImage anyViewImage = UIGraphics.GetImageFromCurrentImageContext ();
UIGraphics.EndImageContext ();

Рисование PDF-файлыDrawing PDFs

Помимо образов Core Graphics поддерживает рисование PDF.In addition to images, Core Graphics supports PDF drawing. Например, изображения, вы может визуализации PDF-ФАЙЛ в памяти, а также чтение PDF-ФАЙЛ для подготовки к просмотру в UIView.Like images, you can render a PDF in memory as well as read a PDF for rendering in a UIView.

PDF-ФАЙЛ в UIViewPDF in a UIView

Графики Core также поддерживает чтение PDF-ФАЙЛ из файла и отображения его в представление с использованием CGPDFDocument класса.Core Graphics also supports reading a PDF from a file and rendering it in a view using the CGPDFDocument class. CGPDFDocument Класс представляет PDF-ФАЙЛ, в коде и может использоваться для чтения и рисования страницы.The CGPDFDocument class represents a PDF in code, and can be used to read and draw pages.

Например, следующий код в UIView подкласс PDF-ФАЙЛ, считывает из файла в CGPDFDocument:For example, the following code in a UIView subclass reads a PDF from a file into a CGPDFDocument:

public class PDFView : UIView
{
    CGPDFDocument pdfDoc;

    public PDFView ()
    {
        //create a CGPDFDocument from file.pdf included in the main bundle
        pdfDoc = CGPDFDocument.FromFile ("file.pdf");
    }
  
     public override void Draw (Rectangle rect)
    {
        ...
    }
}

Draw Можно затем использовать метод CGPDFDocument необходимо считать страницу в CGPDFPage и визуализировать его путем вызова DrawPDFPage, как показано ниже:The Draw method can then use the CGPDFDocument to read a page into CGPDFPage and render it by calling DrawPDFPage, as shown below:

public override void Draw (CGRect rect)
{
    base.Draw (rect);
        
    //flip the CTM so the PDF will be drawn upright
    using (CGContext g = UIGraphics.GetCurrentContext ()) {
        g.TranslateCTM (0, Bounds.Height);
        g.ScaleCTM (1, -1);
        
        // render the first page of the PDF
        using (CGPDFPage pdfPage = pdfDoc.GetPage (1)) {
            
        //get the affine transform that defines where the PDF is drawn
        CGAffineTransform t = pdfPage.GetDrawingTransform (CGPDFBox.Crop, rect, 0, true);
        
        //concatenate the pdf transform with the CTM for display in the view
        g.ConcatCTM (t);
        
        //draw the pdf page
        g.DrawPDFPage (pdfPage);
        }
    }
}

PDF-ФАЙЛ на основе памятиMemory-Backed PDF

Для PDF-документ в памяти, необходимо создать контекст PDF путем вызова BeginPDFContext.For an in-memory PDF, you need to create a PDF context by calling BeginPDFContext. Документ в PDF более детализированные на страницы.Drawing to PDF is granular to pages. Каждая страница, начатую посредством вызова BeginPDFPage и завершается путем вызова метода EndPDFContent, с помощью графического кода между ними.Each page is started by calling BeginPDFPage and completed by calling EndPDFContent, with the graphics code in between. Кроме того как с помощью рисования изображения памяти скопированный PDF, рисование использует источник в нижнем левом углу, который может быть включен, только изменив CTM для, например с изображениями.Also, as with image drawing, memory backed PDF drawing uses an origin in the lower left, which can be accounted by modifying the CTM just like with images.

Ниже показано, как для рисования текста в документ PDF:The following code shows how to draw text to a PDF:

//data buffer to hold the PDF
NSMutableData data = new NSMutableData ();

//create a PDF with empty rectangle, which will configure it for 8.5x11 inches
UIGraphics.BeginPDFContext (data, CGRect.Empty, null);

//start a PDF page
UIGraphics.BeginPDFPage ();
       
using (CGContext g = UIGraphics.GetCurrentContext ()) {
    g.ScaleCTM (1, -1);
    g.TranslateCTM (0, -25);      
    g.SelectFont ("Helvetica", 25, CGTextEncoding.MacRoman);
    g.ShowText ("Hello Core Graphics");
    }
    
//complete a PDF page
UIGraphics.EndPDFContent ();

Получившийся текст рисуется в формат PDF, которые затем содержатся в NSData , могут сохраняться, отправленного, полученный по электронной почте и т. д.The resulting text is drawn to the PDF, which is then contained in an NSData that can be saved, uploaded, emailed, etc.

СводкаSummary

В этой статье мы рассмотрели возможности графики, предоставляемого двухмерной графики framework.In this article we looked at the graphics capabilities provided via the Core Graphics framework. Мы узнали, как использовать Core Graphics для рисования geometry, изображения и PDF-файлы в контексте UIView, а также с контекстами графики на основе памяти.We saw how to use Core Graphics to draw geometry, images and PDFs within the context of a UIView, as well as to memory-backed graphics contexts.