A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

148 lines
4.7 KiB

using System;
using System.IO;
using Avalonia.Platform;
using Avalonia.Rendering;
using SkiaSharp;
namespace Avalonia.Skia
{
class BitmapImpl : IRenderTargetBitmapImpl, IWritableBitmapImpl
{
private Vector _dpi;
public SKBitmap Bitmap { get; private set; }
public BitmapImpl(SKBitmap bm)
{
Bitmap = bm;
PixelHeight = bm.Height;
PixelWidth = bm.Width;
_dpi = new Vector(96, 96);
}
static void ReleaseProc(IntPtr address, object ctx)
{
((IUnmanagedBlob) ctx).Dispose();
}
private static readonly SKBitmapReleaseDelegate ReleaseDelegate = ReleaseProc;
public BitmapImpl(int width, int height, Vector dpi, PixelFormat? fmt = null)
{
PixelHeight = height;
PixelWidth = width;
_dpi = dpi;
var colorType = fmt?.ToSkColorType() ?? SKImageInfo.PlatformColorType;
var runtimePlatform = AvaloniaLocator.Current?.GetService<IRuntimePlatform>();
var runtime = runtimePlatform?.GetRuntimeInfo();
if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux)
colorType = SKColorType.Bgra8888;
if (runtimePlatform != null)
{
Bitmap = new SKBitmap();
var nfo = new SKImageInfo(width, height, colorType, SKAlphaType.Premul);
var plat = AvaloniaLocator.Current.GetService<IRuntimePlatform>();
var blob = plat.AllocBlob(nfo.BytesSize);
Bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, null, ReleaseDelegate, blob);
}
else
Bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Premul);
Bitmap.Erase(SKColor.Empty);
}
public void Dispose()
{
Bitmap.Dispose();
}
public int PixelWidth { get; private set; }
public int PixelHeight { get; private set; }
public IntPtr GetPixels()
{
return Bitmap.GetPixels();
}
class BitmapDrawingContext : DrawingContextImpl
{
private readonly SKSurface _surface;
public BitmapDrawingContext(SKBitmap bitmap, Vector dpi, IVisualBrushRenderer visualBrushRenderer)
: this(CreateSurface(bitmap), dpi, visualBrushRenderer)
{
CanUseLcdRendering = false;
}
private static SKSurface CreateSurface(SKBitmap bitmap)
{
IntPtr length;
var rv = SKSurface.Create(bitmap.Info, bitmap.GetPixels(out length), bitmap.RowBytes);
if (rv == null)
throw new Exception("Unable to create Skia surface");
return rv;
}
public BitmapDrawingContext(SKSurface surface, Vector dpi, IVisualBrushRenderer visualBrushRenderer)
: base(surface.Canvas, dpi, visualBrushRenderer)
{
_surface = surface;
}
public override void Dispose()
{
base.Dispose();
_surface.Dispose();
}
}
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
return new BitmapDrawingContext(Bitmap, _dpi, visualBrushRenderer);
}
public void Save(Stream stream)
{
IntPtr length;
using (var image = SKImage.FromPixels(Bitmap.Info, Bitmap.GetPixels(out length), Bitmap.RowBytes))
using (var data = image.Encode())
{
data.SaveTo(stream);
}
}
public void Save(string fileName)
{
using (var stream = File.Create(fileName))
Save(stream);
}
class BitmapFramebuffer : ILockedFramebuffer
{
private SKBitmap _bmp;
public BitmapFramebuffer(SKBitmap bmp)
{
_bmp = bmp;
_bmp.LockPixels();
}
public void Dispose()
{
_bmp.UnlockPixels();
_bmp = null;
}
public IntPtr Address => _bmp.GetPixels();
public int Width => _bmp.Width;
public int Height => _bmp.Height;
public int RowBytes => _bmp.RowBytes;
public Vector Dpi { get; } = new Vector(96, 96);
public PixelFormat Format => _bmp.ColorType.ToPixelFormat();
}
public ILockedFramebuffer Lock() => new BitmapFramebuffer(Bitmap);
}
}