Основы растрового изображения в 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
добавляет в TapGestureRecognizer
SKCanvasView
уведомление о касаниях. При получении касания 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 описывается, как.