Xamarin.iOS의 핵심 그래픽

이 문서에서는 핵심 그래픽 iOS 프레임워크에 대해 설명합니다. 핵심 그래픽을 사용하여 기하 도형, 이미지 및 PDF를 그리는 방법을 보여 줍니다.

iOS에는 하위 수준 그리기 지원을 제공하는 핵심 그래픽 프레임워크가 포함되어 있습니다. 이러한 프레임워크는 UIKit 내에서 풍부한 그래픽 기능을 가능하게 합니다.

코어 그래픽은 디바이스 독립적 그래픽을 그릴 수 있는 하위 수준 2D 그래픽 프레임워크입니다. UIKit의 모든 2D 드로잉은 내부적으로 핵심 그래픽을 사용합니다.

핵심 그래픽은 다음을 비롯한 다양한 시나리오에서 그리기를 지원합니다.

기하학적 공간

시나리오에 관계없이 핵심 그래픽으로 수행되는 모든 그리기는 기하학적 공간에서 수행되므로 픽셀이 아닌 추상 지점에서 작동합니다. 기하 도형 및 그리기 상태(예: 색, 선 스타일 등)로 그릴 내용을 설명하고 핵심 그래픽은 모든 항목을 픽셀로 변환하는 것을 처리합니다. 이러한 상태는 화가의 캔버스처럼 생각할 수 있는 그래픽 컨텍스트에 추가됩니다.

이 방법에는 다음과 같은 몇 가지 이점이 있습니다.

  • 그리기 코드는 동적이 되며 런타임에 그래픽을 수정할 수 있습니다.
  • 애플리케이션 번들에서 정적 이미지의 필요성을 줄이면 애플리케이션 크기를 줄일 수 있습니다.
  • 그래픽은 장치 전체의 해상도 변경 내용에 대한 복원력이 향상됩니다.

UIView 하위 클래스에서 그리기

모든 UIView 메서드는 Draw 그려야 할 때 시스템에서 호출하는 메서드를 가지고 있습니다. 뷰에 그리기 코드를 추가하려면 다음을 수행합니다Draw.UIView

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

그리는 직접 호출해서는 안 됩니다. 이 호출은 실행 루프 처리 중에 시스템에서 호출됩니다. 뷰가 뷰 계층 구조에 추가된 후 처음으로 실행 루프를 통해 해당 Draw 메서드가 호출됩니다. 뷰를 Draw 호출하거나 SetNeedsDisplayInRect 뷰에서 그려야 하는 것으로 표시될 때 후속 호출 SetNeedsDisplay 이 발생합니다.

그래픽 코드 패턴

구현의 Draw 코드는 그리려는 내용을 설명해야 합니다. 그리기 코드는 일부 그리기 상태를 설정하고 그리기를 요청하는 메서드를 호출하는 패턴을 따릅니다. 이 패턴은 다음과 같이 일반화할 수 있습니다.

  1. 그래픽 컨텍스트를 가져옵니다.

  2. 그리기 특성을 설정합니다.

  3. 그리기 기본 형식에서 일부 기하 도형을 만듭니다.

  4. Draw 또는 Stroke 메서드를 호출합니다.

기본 그리기 예제

예를 들어 다음 코드 조각을 살펴보세요.

//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);
}

이 코드를 세분화해 보겠습니다.

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

이 줄을 사용하면 먼저 그리기에 사용할 현재 그래픽 컨텍스트를 가져옵니다. 그래픽 컨텍스트는 그리기에서 발생하는 캔버스로 생각할 수 있으며, 그리기 및 채우기 색과 같은 드로잉에 대한 모든 상태와 그릴 기하 도형을 포함할 수 있습니다.

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

그래픽 컨텍스트를 얻은 후 코드는 위에 표시된 그리기 시 사용할 몇 가지 특성을 설정합니다. 이 경우 선 너비, 스트로크 및 채우기 색이 설정됩니다. 그런 다음 모든 후속 그리기에서는 이러한 특성이 그래픽 컨텍스트의 상태에 기본 때문에 사용합니다.

기하 도형을 만들기 위해 코드는 선과 곡선에서 그래픽 경로를 설명할 수 있는 선을 사용합니다 CGPath. 이 경우 경로는 점 배열을 연결하는 선을 추가하여 삼각형을 구성합니다. 아래 표시된 것처럼 코어 그래픽은 원점이 왼쪽 위에 있고 오른쪽에 양의 x-direct가 있고 아래쪽에 양수 방향이 있는 보기 그리기에 좌표계를 사용합니다.

var path = new CGPath ();

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

path.CloseSubpath ();

경로가 만들어지면 호출 AddPath 하고 DrawPath 각각 그릴 수 있도록 그래픽 컨텍스트에 추가됩니다.

결과 보기는 다음과 같습니다.

The sample output triangle

그라데이션 채우기 만들기

다양한 형태의 드로잉도 사용할 수 있습니다. 예를 들어 핵심 그래픽을 사용하면 그라데이션 채우기를 만들고 클리핑 경로를 적용할 수 있습니다. 이전 예제에서 경로 내부에 그라데이션 채우기를 그리려면 먼저 경로를 클리핑 경로로 설정해야 합니다.

// 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 ();

현재 경로를 클리핑 경로로 설정하면 선형 그라데이션을 그리는 다음 코드와 같이 경로의 기하 도형 내에서 모든 후속 그리기를 제한합니다.

// 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);
    }

이러한 변경은 아래와 같이 그라데이션 채우기를 생성합니다.

The example with a gradient fill

선 패턴 수정

핵심 그래픽을 사용하여 선의 그리기 특성을 수정할 수도 있습니다. 여기에는 다음 코드와 같이 선 너비 및 스트로크 색과 선 패턴 자체를 변경하는 것이 포함됩니다.

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

그리기 작업 전에 이 코드를 추가하면 아래와 같이 대시 사이의 간격이 4개인 파선 스트로크 길이가 10단위입니다.

Adding this code before any drawing operations results in dashed strokes

Xamarin.iOS에서 통합 API를 사용하는 경우 배열 형식은 Math.PI nfloat로 명시적으로 캐스팅되어야 합니다.

이미지 및 텍스트 그리기

코어 그래픽은 보기의 그래픽 컨텍스트에서 경로를 그리는 것 외에도 이미지 및 텍스트 그리기를 지원합니다. 이미지를 그리려면 다음을 CGImage 만들어 호출에 DrawImage 전달하기만 하면 됩니다.

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

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

그러나 아래와 같이 거꾸로 그려진 이미지가 생성됩니다.

An image drawn upside down

그 이유는 이미지 그리기의 핵심 그래픽 원점이 왼쪽 아래에 있는 반면 보기의 원점은 왼쪽 위에 있기 때문입니다. 따라서 이미지를 올바르게 표시하려면 원본을 수정해야 하며, 이는 CTM(현재 변환 매트릭스)을 수정하여 수행할 수 있습니다. CTM은 지점이 있는 위치(사용자 공간이라고도 함)를 정의합니다. CTM을 y 방향으로 반전하고 음수 y 방향으로 범위의 높이로 이동하면 이미지가 대칭 이동할 수 있습니다.

그래픽 컨텍스트에는 CTM을 변환하는 도우미 메서드가 있습니다. 이 경우 ScaleCTM 아래와 같이 드로잉을 "대칭 이동"하고 TranslateCTM 왼쪽 위로 이동합니다.

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 sample image displayed upright

Important

그래픽 컨텍스트의 변경 내용은 모든 후속 그리기 작업에 적용됩니다. 따라서 CTM이 변환되면 추가 그리기에 영향을 미칩니다. 예를 들어 CTM 변환 후 삼각형을 그린 경우 거꾸로 나타납니다.

이미지에 텍스트 추가

경로 및 이미지와 마찬가지로 핵심 그래픽을 사용하여 텍스트를 그리려면 일부 그래픽 상태를 설정하고 그리는 메서드를 호출하는 것과 동일한 기본 패턴이 포함됩니다. 텍스트의 경우 텍스트를 표시하는 메서드는 .입니다 ShowText. 이미지 그리기 예제에 추가된 경우 다음 코드는 핵심 그래픽을 사용하여 일부 텍스트를 그립니다.

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");
}

보듯이 텍스트 그리기의 그래픽 상태를 설정하는 것은 그리기 기하 도형과 비슷합니다. 그러나 텍스트 그리기의 경우 텍스트 그리기 모드와 글꼴도 적용됩니다. 이 경우 그림자 적용은 경로 그리기에 대해 동일하게 작동하지만 그림자도 적용됩니다.

결과 텍스트는 아래와 같이 이미지와 함께 표시됩니다.

The resulting text is displayed with the image

메모리 기반 이미지

코어 그래픽은 보기의 그래픽 컨텍스트에 그리는 것 외에도 메모리 지원 이미지 그리기(화면 끄기라고도 함)를 지원합니다. 이렇게 하려면 다음이 필요합니다.

  • 메모리 내 비트맵에서 백업되는 그래픽 컨텍스트 만들기
  • 그리기 상태 설정 및 그리기 명령 실행
  • 컨텍스트에서 이미지 가져오기
  • 컨텍스트 제거

뷰에서 Draw 컨텍스트를 제공하는 메서드와 달리 이 경우 다음 두 가지 방법 중 하나로 컨텍스트를 만듭니다.

  1. 호출 UIGraphics.BeginImageContext (또는 BeginImageContextWithOptions)

  2. 새 만들기 CGBitmapContextInstance

CGBitmapContextInstance 는 사용자 지정 이미지 조작 알고리즘을 사용하는 경우와 같이 이미지 비트로 직접 작업할 때 유용합니다. 다른 모든 경우에는 사용 BeginImageContext 하거나 BeginImageContextWithOptions.

이미지 컨텍스트가 있으면 그리기 코드를 추가하는 것은 하위 클래스에 있는 UIView 것과 같습니다. 예를 들어 삼각형을 그리기 위해 이전에 사용한 코드 예제는 아래와 같이 메모리 대신 메모리의 이미지에 UIView그리는 데 사용할 수 있습니다.

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이미지에서 이미지를 캡처하는 것입니다. 예를 들어 다음 코드는 뷰의 계층을 비트맵 컨텍스트로 렌더링하고 뷰에서 만듭니다 UIImage .

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 그리기

핵심 그래픽은 이미지 외에도 PDF 드로잉을 지원합니다. 이미지와 마찬가지로 메모리에서 PDF를 렌더링하고 PDF를 읽어 렌더링할 수 있습니다 UIView.

UIView의 PDF

Core Graphics는 파일에서 PDF를 읽고 클래스를 사용하여 CGPDFDocument 보기에서 렌더링할 수도 있습니다. 이 클래스는 CGPDFDocument 코드에서 PDF를 나타내며 페이지를 읽고 그리는 데 사용할 수 있습니다.

예를 들어 하위 클래스의 다음 코드 UIView 는 파일에서 다음으로 CGPDFDocumentPDF를 읽습니다.

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하여 렌더링할 수 있습니다.

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

메모리 내 PDF의 경우 호출 BeginPDFContext하여 PDF 컨텍스트를 만들어야 합니다. PDF로 그리기는 페이지로 세분화됩니다. 각 페이지는 호출 BeginPDFPage 로 시작하고 그 사이에 그래픽 코드를 사용하여 호출 EndPDFContent하여 완료됩니다. 또한 이미지 그리기와 마찬가지로 메모리 지원 PDF 드로잉은 이미지와 마찬가지로 CTM을 수정하여 고려할 수 있는 왼쪽 아래의 원점도 사용합니다.

다음 코드는 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 수 있습니다.

요약

이 문서에서는 Core Graphics 프레임워크를 통해 제공되는 그래픽 기능을 살펴보았습니다. 코어 그래픽을 사용하여 메모리 지원 그래픽 컨텍스트뿐만 아니라 컨텍스트 UIView, 내에서 기하 도형, 이미지 및 PDF를 그리는 방법을 알아보았습니다.