| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- using System;
- using System.IO;
- using Avalonia.Media.Imaging;
- using Avalonia.Platform;
- using Avalonia.Skia.Helpers;
- using SkiaSharp;
- namespace Avalonia.Skia
- {
- /// <summary>
- /// Immutable Skia bitmap.
- /// </summary>
- internal class ImmutableBitmap : IDrawableBitmapImpl
- {
- private readonly SKImage _image;
- /// <summary>
- /// Create immutable bitmap from given stream.
- /// </summary>
- /// <param name="stream">Stream containing encoded data.</param>
- public ImmutableBitmap(Stream stream)
- {
- using (var skiaStream = new SKManagedStream(stream))
- {
- using (var data = SKData.Create(skiaStream))
- _image = SKImage.FromEncodedData(data);
- if (_image == null)
- {
- throw new ArgumentException("Unable to load bitmap from provided data");
- }
- PixelSize = new PixelSize(_image.Width, _image.Height);
- // TODO: Skia doesn't have an API for DPI.
- Dpi = new Vector(96, 96);
- }
- }
- public ImmutableBitmap(SKImage image)
- {
- _image = image;
- PixelSize = new PixelSize(image.Width, image.Height);
- Dpi = new Vector(96, 96);
- }
- public ImmutableBitmap(ImmutableBitmap src, PixelSize destinationSize, BitmapInterpolationMode interpolationMode)
- {
- SKImageInfo info = new SKImageInfo(destinationSize.Width, destinationSize.Height, SKColorType.Bgra8888);
- SKImage output = SKImage.Create(info);
- src._image.ScalePixels(output.PeekPixels(), interpolationMode.ToSKFilterQuality());
- _image = output;
- PixelSize = new PixelSize(_image.Width, _image.Height);
- // TODO: Skia doesn't have an API for DPI.
- Dpi = new Vector(96, 96);
- }
- public ImmutableBitmap(Stream stream, int decodeSize, bool horizontal, BitmapInterpolationMode interpolationMode)
- {
- using (var skStream = new SKManagedStream(stream))
- using (var skData = SKData.Create(skStream))
- using (var codec = SKCodec.Create(skData))
- {
- var info = codec.Info;
- // get the scale that is nearest to what we want (eg: jpg returned 512)
- var supportedScale = codec.GetScaledDimensions(horizontal ? ((float)decodeSize / info.Width) : ((float)decodeSize / info.Height));
- // decode the bitmap at the nearest size
- var nearest = new SKImageInfo(supportedScale.Width, supportedScale.Height);
- var bmp = SKBitmap.Decode(codec, nearest);
- // now scale that to the size that we want
- var realScale = horizontal ? ((double)info.Height / info.Width) : ((double)info.Width / info.Height);
- SKImageInfo desired;
- if (horizontal)
- {
- desired = new SKImageInfo(decodeSize, (int)(realScale * decodeSize));
- }
- else
- {
- desired = new SKImageInfo((int)(realScale * decodeSize), decodeSize);
- }
- if (bmp.Width != desired.Width || bmp.Height != desired.Height)
- {
- var scaledBmp = bmp.Resize(desired, interpolationMode.ToSKFilterQuality());
- bmp.Dispose();
- bmp = scaledBmp;
- }
- _image = SKImage.FromBitmap(bmp);
- bmp.Dispose();
- if (_image == null)
- {
- throw new ArgumentException("Unable to load bitmap from provided data");
- }
- PixelSize = new PixelSize(_image.Width, _image.Height);
- // TODO: Skia doesn't have an API for DPI.
- Dpi = new Vector(96, 96);
- }
- }
- /// <summary>
- /// Create immutable bitmap from given pixel data copy.
- /// </summary>
- /// <param name="size">Size of the bitmap.</param>
- /// <param name="dpi">DPI of the bitmap.</param>
- /// <param name="stride">Stride of data pixels.</param>
- /// <param name="format">Format of data pixels.</param>
- /// <param name="alphaFormat">Alpha format of data pixels.</param>
- /// <param name="data">Data pixels.</param>
- public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, AlphaFormat alphaFormat, IntPtr data)
- {
- var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), alphaFormat.ToSkAlphaType());
- _image = SKImage.FromPixelCopy(imageInfo, data, stride);
- if (_image == null)
- {
- throw new ArgumentException("Unable to create bitmap from provided data");
- }
- PixelSize = size;
- Dpi = dpi;
- }
- public Vector Dpi { get; }
- public PixelSize PixelSize { get; }
- public int Version { get; } = 1;
- /// <inheritdoc />
- public void Dispose()
- {
- _image.Dispose();
- }
- /// <inheritdoc />
- public void Save(string fileName, int? quality = null)
- {
- ImageSavingHelper.SaveImage(_image, fileName);
- }
- /// <inheritdoc />
- public void Save(Stream stream, int? quality = null)
- {
- ImageSavingHelper.SaveImage(_image, stream);
- }
- /// <inheritdoc />
- public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint)
- {
- context.Canvas.DrawImage(_image, sourceRect, destRect, paint);
- }
- }
- }
|