Поделиться через


Основы растрового изображения в SkiaSharp

Загрузите растровые изображения из различных источников и отобразите их.

Поддержка растровых карт в SkiaSharp довольно обширна. В этой статье рассматриваются только основные сведения о загрузке растровых изображений и их отображении:

Отображение двух растровых изображений

Гораздо более глубокое исследование растровых карт можно найти в разделе SkiaSharp Bitmaps.

Растровое изображение SkiaSharp — это объект типа SKBitmap. Существует множество способов создания растрового изображения, но эта статья ограничивается SKBitmap.Decode методом, который загружает растровое изображение из объекта .NET Stream .

Страница "Базовые растровые карты" в программе SkiaSharpFormsDemos демонстрирует загрузку растровых карт из трех разных источников:

  • Из Интернета
  • Из ресурса, внедренного в исполняемый файл
  • Из библиотеки фотографий пользователя

Три SKBitmap объекта для этих трех источников определяются как поля в BasicBitmapsPage классе:

public class BasicBitmapsPage : ContentPage
{
    SKCanvasView canvasView;
    SKBitmap webBitmap;
    SKBitmap resourceBitmap;
    SKBitmap libraryBitmap;

    public BasicBitmapsPage()
    {
        Title = "Basic Bitmaps";

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

Загрузка растрового изображения из Интернета

Чтобы загрузить растровое изображение на основе URL-адреса, можно использовать HttpClient класс. Необходимо создать экземпляр только одного экземпляра HttpClient и повторно использовать его, поэтому сохраните его как поле:

HttpClient httpClient = new HttpClient();

При использовании HttpClient с приложениями iOS и Android необходимо задать свойства проекта, как описано в документах по протоколу TLS 1.2.

Так как с оператором await удобнее всего использовать оператор HttpClient, код не может быть выполнен в конструкторе BasicBitmapsPage . Вместо этого это часть OnAppearing переопределения. URL-адрес здесь указывает на область на веб-сайте Xamarin с некоторыми примерами растровых изображений. Пакет на веб-сайте позволяет добавить спецификацию для изменения размера растрового изображения к определенной ширине:

protected override async void OnAppearing()
{
    base.OnAppearing();

    // Load web bitmap.
    string url = "https://developer.xamarin.com/demo/IMG_3256.JPG?width=480";

    try
    {
        using (Stream stream = await httpClient.GetStreamAsync(url))
        using (MemoryStream memStream = new MemoryStream())
        {
            await stream.CopyToAsync(memStream);
            memStream.Seek(0, SeekOrigin.Begin);

            webBitmap = SKBitmap.Decode(memStream);
            canvasView.InvalidateSurface();
        };
    }
    catch
    {
    }
}

Операционная система Android вызывает исключение при использовании Stream возвращаемого в GetStreamAsync методе SKBitmap.Decode , так как она выполняет длинную операцию в основном потоке. По этой причине содержимое растрового файла копируется в MemoryStream объект с помощью CopyToAsync.

Статический SKBitmap.Decode метод отвечает за декодирование растровых файлов. Он работает с форматами растровых изображений JPEG, PNG и GIF и сохраняет результаты во внутреннем формате SkiaSharp. На этом этапе SKCanvasView необходимо недействительно разрешить PaintSurface обработчику обновлять дисплей.

Загрузка ресурса растрового изображения

С точки зрения кода самый простой подход к загрузке растровых изображений — это включение ресурса растрового изображения непосредственно в приложении. Программа SkiaSharpFormsDemos содержит папку с именем Media , содержащую несколько растровых файлов, включая один именованный monkey.png. Для растровых изображений, хранящихся в виде ресурсов программы, необходимо использовать диалоговое окно "Свойства ", чтобы предоставить файлу действие сборки внедренного ресурса!

Каждый внедренный ресурс содержит идентификатор ресурса, состоящий из имени проекта, папки и имени файла, подключенного по периодам: SkiaSharpFormsDemos.Media.monkey.png. Вы можете получить доступ к этому ресурсу, указав этот идентификатор ресурса в качестве аргумента к GetManifestResourceStream методу Assembly класса:

string resourceID = "SkiaSharpFormsDemos.Media.monkey.png";
Assembly assembly = GetType().GetTypeInfo().Assembly;

using (Stream stream = assembly.GetManifestResourceStream(resourceID))
{
    resourceBitmap = SKBitmap.Decode(stream);
}

Этот Stream объект можно передать непосредственно в SKBitmap.Decode метод.

Загрузка растрового изображения из библиотеки фотографий

Кроме того, пользователь может загрузить фотографию из библиотеки рисунков устройства. Этот объект не предоставляется самостоятельно Xamarin.Forms . Для задания требуется служба зависимостей, например описанная в статье Выбор фотографии из библиотеки рисунков.

Файл IPhotoLibrary.cs в проекте SkiaSharpFormsDemos и три файла PhotoLibrary.cs в проектах платформы были адаптированы из этой статьи. Кроме того, файл Android MainActivity.cs был изменен, как описано в статье, и проект iOS получил разрешение на доступ к библиотеке фотографий с двумя строками в нижней части файла info.plist .

Конструктор BasicBitmapsPage добавляет в TapGestureRecognizerSKCanvasView уведомление о касаниях. При получении касания Tapped обработчик получает доступ к службе зависимостей выбора рисунков и вызовам PickPhotoAsync. Stream Если возвращается объект, он передается методуSKBitmap.Decode:

// Add tap gesture recognizer
TapGestureRecognizer tapRecognizer = new TapGestureRecognizer();
tapRecognizer.Tapped += async (sender, args) =>
{
    // Load bitmap from photo library
    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();

    using (Stream stream = await photoLibrary.PickPhotoAsync())
    {
        if (stream != null)
        {
            libraryBitmap = SKBitmap.Decode(stream);
            canvasView.InvalidateSurface();
        }
    }
};
canvasView.GestureRecognizers.Add(tapRecognizer);

Обратите внимание, что Tapped обработчик также вызывает InvalidateSurface метод SKCanvasView объекта. Это создает новый вызов обработчика PaintSurface .

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

Обработчику PaintSurface необходимо отобразить три растровых изображения. Обработчик предполагает, что телефон находится в книжном режиме и делит холст вертикально на три равные части.

Первый растровый рисунок отображается с самым DrawBitmap простым методом. Все, что необходимо указать, — координаты X и Y, в которых должен размещаться верхний левый угол растрового изображения:

public void DrawBitmap (SKBitmap bitmap, Single x, Single y, SKPaint paint = null)

SKPaint Хотя определен параметр, он имеет значение null по умолчанию и его можно игнорировать. Пиксели растрового изображения просто передаются в пиксели поверхности отображения с сопоставлением "один к одному". Вы увидите приложение для этого SKPaint аргумента в следующем разделе о SkiaSharp Transparency.

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

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

    canvas.Clear();

    if (webBitmap != null)
    {
        float x = (info.Width - webBitmap.Width) / 2;
        float y = (info.Height / 3 - webBitmap.Height) / 2;
        canvas.DrawBitmap(webBitmap, x, y);
    }
    ...
}

Остальные две растровые карты отображаются с версией DrawBitmap с параметром SKRect :

public void DrawBitmap (SKBitmap bitmap, SKRect dest, SKPaint paint = null)

Третья версия имеет два SKRect аргумента для указания прямоугольного подмножества отображаемого растрового изображения, но эта версия DrawBitmap не используется в этой статье.

Ниже приведен код для отображения растрового изображения, загруженного из внедренного растрового изображения ресурса:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    if (resourceBitmap != null)
    {
        canvas.DrawBitmap(resourceBitmap,
            new SKRect(0, info.Height / 3, info.Width, 2 * info.Height / 3));
    }
    ...
}

Растровое изображение растянуто до измерений прямоугольника, поэтому обезьяна горизонтально растянута на этих снимках экрана:

Тройной снимок экрана страницы

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

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    if (libraryBitmap != null)
    {
        float scale = Math.Min((float)info.Width / libraryBitmap.Width,
                               info.Height / 3f / libraryBitmap.Height);

        float left = (info.Width - scale * libraryBitmap.Width) / 2;
        float top = (info.Height / 3 - scale * libraryBitmap.Height) / 2;
        float right = left + scale * libraryBitmap.Width;
        float bottom = top + scale * libraryBitmap.Height;
        SKRect rect = new SKRect(left, top, right, bottom);
        rect.Offset(0, 2 * info.Height / 3);

        canvas.DrawBitmap(libraryBitmap, rect);
    }
    else
    {
        using (SKPaint paint = new SKPaint())
        {
            paint.Color = SKColors.Blue;
            paint.TextAlign = SKTextAlign.Center;
            paint.TextSize = 48;

            canvas.DrawText("Tap to load bitmap",
                info.Width / 2, 5 * info.Height / 6, paint);
        }
    }
}

Если растровое изображение еще не загружено из библиотеки рисунков, else блок отображает некоторый текст, чтобы побудить пользователя коснуться экрана.

Вы можете отображать растровые изображения с различными степенью прозрачности, а в следующей статье о skiaSharp Transparency описывается, как.