다음을 통해 공유


픽셀 및 디바이스 독립적 단위

SkiaSharp 좌표와 Xamarin.Forms 좌표의 차이점 살펴보기

이 문서에서는 SkiaSharp 및 Xamarin.Forms에서 사용되는 좌표계의 차이점을 살펴봅니다. 두 좌표계 간에 변환하는 정보를 얻고 특정 영역을 채우는 그래픽을 그릴 수도 있습니다.

화면을 채우는 타원

한동안 프로그래밍을 Xamarin.Forms 했다면 좌표와 크기에 대한 Xamarin.Forms 느낌이 들 수 있습니다. 이전 두 문서에서 그린 원은 약간 작게 보일 수 있습니다.

이러한 원 크기와 비교하여 Xamarin.Forms 작습니다. 기본적으로 SkiaSharp는 픽셀 단위로 그리는 반면 Xamarin.Forms 기본 플랫폼에 의해 설정된 디바이스 독립적 단위에서 기본 좌표 및 크기를 그립니다. 좌표계에 대한 Xamarin.Forms 자세한 내용은 5장에서 확인할 수 있습니다. 를 사용하여 Mobile Apps를 만드는 책의 크기 처리 Xamarin.Forms

Surface Size라는 샘플 프로그램의 페이지는 SkiaSharp 텍스트 출력을 사용하여 세 가지 소스의 디스플레이 화면 크기를 표시합니다.

  • 개체의 기본 Xamarin.FormsWidthHeight 속성입니다 SKCanvasView .
  • CanvasSize 개체의 SKCanvasView 속성입니다.
  • Size 이전 두 페이지에 사용된 속성과 Height 일치하는 Width 값의 속성 SKImageInfo 입니다.

클래스는 SurfaceSizePage 이러한 값을 표시하는 방법을 보여줍니다. 생성자는 개체를 SKCanvasView 필드로 저장하므로 이벤트 처리기에서 PaintSurface 액세스할 수 있습니다.

SKCanvasView canvasView;

public SurfaceSizePage()
{
    Title = "Surface Size";

    canvasView = new SKCanvasView();
    canvasView.PaintSurface += OnCanvasViewPaintSurface;
    Content = canvasView;
}

SKCanvas 에는 6개의 다른 DrawText 메서드가 포함되어 있지만 이 DrawText 메서드는 가장 간단합니다.

public void DrawText (String text, Single x, Single y, SKPaint paint)

텍스트 문자열, 텍스트가 시작되는 X 및 Y 좌표 및 개체를 SKPaint 지정합니다. X 좌표는 텍스트의 왼쪽 위치를 지정하지만 주의해야 합니다. Y 좌표는 텍스트 기준선의 위치를 지정합니다. 줄 지어 있는 종이에 손으로 작성한 적이 있는 경우 기준선은 문자가 앉는 선이며, 아래의 하위 항목(예: g, p, q 및 y 문자의 하위 항목)입니다.

개체 SKPaint 를 사용하면 텍스트 색, 글꼴 패밀리 및 텍스트 크기를 지정할 수 있습니다. 기본적으로 TextSize 이 속성의 값은 12이며, 이로 인해 휴대폰과 같은 고해상도 디바이스에서 작은 텍스트가 생성됩니다. 가장 간단한 애플리케이션 외에는 표시할 텍스트의 크기에 대한 정보도 필요합니다. 클래스는 SKPaint 속성과 여러 MeasureText 메서드를 FontMetrics 정의하지만 덜 멋진 요구 사항을 FontSpacing 위해 속성은 연속 텍스트 줄 간격을 지정하는 데 권장되는 값을 제공합니다.

다음 PaintSurface 처리기는 40픽셀의 개체 TextSize 를 만듭니다SKPaint. 이 개체는 오름차순 위쪽에서 하위 항목의 아래쪽까지 텍스트의 원하는 세로 높이입니다. FontSpacing 개체가 SKPaint 반환하는 값은 약 47픽셀보다 약간 큽니다.

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPaint paint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 40
    };

    float fontSpacing = paint.FontSpacing;
    float x = 20;               // left margin
    float y = fontSpacing;      // first baseline
    float indent = 100;

    canvas.DrawText("SKCanvasView Height and Width:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(String.Format("{0:F2} x {1:F2}",
                                  canvasView.Width, canvasView.Height),
                    x + indent, y, paint);
    y += fontSpacing * 2;
    canvas.DrawText("SKCanvasView CanvasSize:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(canvasView.CanvasSize.ToString(), x + indent, y, paint);
    y += fontSpacing * 2;
    canvas.DrawText("SKImageInfo Size:", x, y, paint);
    y += fontSpacing;
    canvas.DrawText(info.Size.ToString(), x + indent, y, paint);
}

이 메서드는 X 좌표 20(왼쪽에 약간의 여백)과 Y 좌표를 사용하여 텍스트의 fontSpacing첫 번째 줄을 시작합니다. 이 좌표는 표시 화면 맨 위에 있는 첫 번째 텍스트 줄의 전체 높이를 표시하는 데 필요한 것보다 약간 더 큽니다. 호출할 DrawText때마다 Y 좌표가 1~2씩 증가합니다 fontSpacing.

실행 중인 프로그램은 다음과 같습니다.

스크린샷은 두 개의 모바일 장치에서 실행되는 Surface Size 앱을 보여줍니다.

CanvasSize 수 있듯이 값의 SKCanvasView 속성과 Size 속성 SKImageInfo 은 픽셀 차원을 보고할 때 일관성이 있습니다. 속성 및 Width 속성 SKCanvasViewHeight Xamarin.Forms 속성이며 플랫폼에서 정의한 디바이스 독립적 단위로 보기의 크기를 보고합니다.

왼쪽의 iOS 7 시뮬레이터에는 디바이스 독립적 단위당 2픽셀이 있고 중앙의 Android Nexus 5에는 단위당 3픽셀이 있습니다. 따라서 앞에서 보여 준 간단한 원은 플랫폼에 따라 크기가 다릅니다.

디바이스 독립적 단위로 완전히 작업하려면 해당 속성을 IgnorePixelScaling SKCanvasView true하여 작업을 수행할 수 있습니다. 그러나 결과가 마음에 들지 않을 수 있습니다. SkiaSharp는 디바이스 독립적 단위의 보기 크기와 동일한 픽셀 크기로 더 작은 디바이스 화면에서 그래픽을 렌더링합니다. 예를 들어 SkiaSharp는 Nexus 5에서 360 x 512 픽셀의 디스플레이 화면을 사용합니다. 그런 다음, 해당 이미지를 크기로 확장하여 눈에 띄는 비트맵 jaggies를 생성합니다.

동일한 이미지 해상도를 유지하기 위해 두 좌표계 간에 변환하는 고유한 간단한 함수를 작성하는 것이 더 좋습니다.

메서드 SKCanvas 외에도 DrawCircle 타원을 그리는 두 가지 DrawOval 메서드를 정의합니다. 타원은 단일 반지름이 아닌 두 개의 반지름으로 정의됩니다. 이러한 반경을 주 반경부 반지름이라고 합니다. 이 메서드는 DrawOval X 및 Y 축에 두 개의 radii 병렬로 타원을 그립니다. (X 및 Y축과 평행하지 않은 축으로 타원을 그려야 하는 경우 문서에서 설명한 대로 회전 변환을 사용할 수 있습니다.원호를 그리는 세 가지 방법 문서에서 설명한 대로 회전 변환 또는 그래픽 경로). 메서드의 DrawOval 이 오버로드는 두 개의 radii 매개 변수 rx 의 이름을 지정하고 X 및 ry Y 축과 병렬임을 나타냅니다.

public void DrawOval (Single cx, Single cy, Single rx, Single ry, SKPaint paint)

디스플레이 화면을 채우는 줄임표를 그릴 수 있나요? 타원 채우기 페이지에서 방법을 보여 줍니다. PaintSurface EllipseFillPage.xaml.cs 클래스의 이벤트 처리기는 전체 줄임표 및 yRadius 디스플레이 화면 내의 윤곽선에 맞게 스트로크 너비 xRadius 의 절반을 뺍니다.

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    float strokeWidth = 50;
    float xRadius = (info.Width - strokeWidth) / 2;
    float yRadius = (info.Height - strokeWidth) / 2;

    SKPaint paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Blue,
        StrokeWidth = strokeWidth
    };
    canvas.DrawOval(info.Width / 2, info.Height / 2, xRadius, yRadius, paint);
}

여기서 실행 중입니다.

스크린샷은 두 개의 모바일 디바이스에서 실행되는 타원 채우기 앱을 보여줍니다.

다른 DrawOval 메서드에는 SKRect 인수가 있는데, 이 사각형은 왼쪽 위 모서리와 오른쪽 아래 모서리의 X 및 Y 좌표를 기준으로 정의됩니다. 타원은 직사각형을 채웁니다. 이는 다음과 같이 타원 채우기 페이지에서 사용할 수 있음을 시사합니다.

SKRect rect = new SKRect(0, 0, info.Width, info.Height);
canvas.DrawOval(rect, paint);

그러나 네 면의 타원 윤곽선 가장자리가 모두 잘립니다. 이 작업을 올바르게 수행하려면 다음을 기준으로 strokeWidth 모든 SKRect 생성자 인수를 조정해야 합니다.

SKRect rect = new SKRect(strokeWidth / 2,
                         strokeWidth / 2,
                         info.Width - strokeWidth / 2,
                         info.Height - strokeWidth / 2);
canvas.DrawOval(rect, paint);