diff --git a/Directory.Packages.props b/Directory.Packages.props
index f2a02fee6..25b283216 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -32,8 +32,8 @@
-
-
+
+
@@ -72,9 +72,9 @@
-
-
-
+
+
+
@@ -84,4 +84,4 @@
-
+
\ No newline at end of file
diff --git a/src/Beutl.Engine/Graphics/BrushConstructor.cs b/src/Beutl.Engine/Graphics/BrushConstructor.cs
index 27da4933c..a1b4756dc 100644
--- a/src/Beutl.Engine/Graphics/BrushConstructor.cs
+++ b/src/Beutl.Engine/Graphics/BrushConstructor.cs
@@ -18,9 +18,6 @@ public void ConfigurePaint(SKPaint paint)
float opacity = (Brush?.Opacity ?? 0) / 100f;
paint.IsAntialias = true;
paint.BlendMode = (SKBlendMode)BlendMode;
- paint.HintingLevel = SKPaintHinting.Full;
- paint.LcdRenderText = true;
- paint.SubpixelText = true;
paint.Color = new SKColor(255, 255, 255, (byte)(255 * opacity));
@@ -194,7 +191,7 @@ private void ConfigureGradientBrush(SKPaint paint, IGradientBrush gradientBrush)
private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
{
RenderTarget? renderTarget = null;
- SKBitmap? skbitmap = null;
+ SKImage? skImage = null;
PixelSize pixelSize;
if (tileBrush is RenderSceneBrush sceneBrush)
@@ -228,7 +225,7 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
{
using (bitmap)
{
- skbitmap = bitmap.Value.ToSKBitmap();
+ skImage = bitmap.Value.ToSKImage(copy: true);
pixelSize = new(bitmap.Value.Width, bitmap.Value.Height);
}
}
@@ -237,7 +234,7 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
throw new InvalidOperationException($"'{tileBrush.GetType().Name}' not supported.");
}
- if (renderTarget == null && skbitmap == null)
+ if (renderTarget == null && skImage == null)
return;
RenderTarget? intermediate = null;
@@ -253,7 +250,7 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
SKCanvas canvas = intermediate.Value.Canvas;
using var ipaint = new SKPaint();
{
- ipaint.FilterQuality = tileBrush.BitmapInterpolationMode.ToSKFilterQuality();
+ var options = tileBrush.BitmapInterpolationMode.ToSKSamplingOptions();
canvas.Clear();
canvas.Save();
@@ -262,8 +259,8 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
if (renderTarget != null)
canvas.DrawSurface(renderTarget.Value, default, ipaint);
- else if (skbitmap != null)
- canvas.DrawBitmap(skbitmap, (SKPoint)default, ipaint);
+ else if (skImage != null)
+ canvas.DrawImage(skImage, (SKPoint)default, options, ipaint);
canvas.Restore();
}
@@ -294,8 +291,8 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
tileTransform = tileTransform.PreConcat(transform.ToSKMatrix());
}
- using (SKImage skimage = intermediate.Value.Snapshot())
- using (SKShader shader = skimage.ToShader(tileX, tileY, tileTransform))
+ using (SKImage snapshot = intermediate.Value.Snapshot())
+ using (SKShader shader = snapshot.ToShader(tileX, tileY, tileTransform))
{
paint.Shader = shader;
}
@@ -303,7 +300,7 @@ private void ConfigureTileBrush(SKPaint paint, ITileBrush tileBrush)
finally
{
renderTarget?.Dispose();
- skbitmap?.Dispose();
+ skImage?.Dispose();
intermediate?.Dispose();
}
}
diff --git a/src/Beutl.Engine/Graphics/FilterEffects/FilterEffectContext.cs b/src/Beutl.Engine/Graphics/FilterEffects/FilterEffectContext.cs
index 9f9648627..0348b5e1f 100644
--- a/src/Beutl.Engine/Graphics/FilterEffects/FilterEffectContext.cs
+++ b/src/Beutl.Engine/Graphics/FilterEffects/FilterEffectContext.cs
@@ -1,4 +1,4 @@
-using System.ComponentModel;
+using System.ComponentModel;
using System.Reactive;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -193,7 +193,17 @@ public void DisplacementMap(
AppendSkiaFilter(
data: (xChannelSelector, yChannelSelector, scale, child),
factory: static (t, input, activator)
- => SKImageFilter.CreateDisplacementMapEffect(t.xChannelSelector, t.yChannelSelector, t.scale, activator.Activate(t.child), input),
+ =>
+ {
+ var displacement = activator.Activate(t.child);
+ if (displacement != null)
+ {
+ return SKImageFilter.CreateDisplacementMapEffect(t.xChannelSelector, t.yChannelSelector, t.scale,
+ displacement, input);
+ }
+
+ return input;
+ },
transformBounds: static (data, bounds) => bounds.Inflate(data.scale / 2));
}
@@ -298,7 +308,7 @@ public void Transform(Matrix matrix, BitmapInterpolationMode bitmapInterpolation
{
AppendSkiaFilter(
(matrix, bitmapInterpolationMode),
- (data, input, _) => SKImageFilter.CreateMatrix(data.matrix.ToSKMatrix(), data.bitmapInterpolationMode.ToSKFilterQuality(), input),
+ (data, input, _) => SKImageFilter.CreateMatrix(data.matrix.ToSKMatrix(), data.bitmapInterpolationMode.ToSKSamplingOptions(), input),
(data, rect) => rect.TransformToAABB(data.matrix));
}
diff --git a/src/Beutl.Engine/Graphics/Image.cs b/src/Beutl.Engine/Graphics/Image.cs
index 7ff4835bf..92ca2cdae 100644
--- a/src/Beutl.Engine/Graphics/Image.cs
+++ b/src/Beutl.Engine/Graphics/Image.cs
@@ -146,6 +146,28 @@ public static SKBitmap ToSKBitmap(this IBitmap self)
}
}
+ public static SKImage ToSKImage(this IBitmap self, bool copy = false)
+ {
+ SKColorType? type = self switch
+ {
+ Bitmap => SKColorType.Bgra8888,
+ Bitmap => SKColorType.Argb4444,
+ Bitmap => SKColorType.Alpha8,
+ _ => null
+ };
+ if (type.HasValue)
+ {
+ return copy
+ ? SKImage.FromPixelCopy(new(self.Width, self.Height, type.Value), self.Data)
+ : SKImage.FromPixels(new(self.Width, self.Height, type.Value), self.Data);
+ }
+ else
+ {
+ using Bitmap typed = self.Convert();
+ return SKImage.FromPixelCopy(new(self.Width, self.Height, SKColorType.Bgra8888), typed.Data);
+ }
+ }
+
public static SKBitmap ToSKBitmap(this Mat self)
{
var result = new SKBitmap(new(self.Width, self.Height, SKColorType.Bgra8888));
diff --git a/src/Beutl.Engine/Graphics/SkiaSharpExtensions.cs b/src/Beutl.Engine/Graphics/SkiaSharpExtensions.cs
index 3b579d1f1..c44a8ec52 100644
--- a/src/Beutl.Engine/Graphics/SkiaSharpExtensions.cs
+++ b/src/Beutl.Engine/Graphics/SkiaSharpExtensions.cs
@@ -6,6 +6,7 @@ namespace Beutl.Graphics;
internal static class SkiaSharpExtensions
{
+ [Obsolete("Use ToSKSamplingOptions")]
public static SKFilterQuality ToSKFilterQuality(this BitmapInterpolationMode interpolationMode)
{
return interpolationMode switch
@@ -18,6 +19,18 @@ public static SKFilterQuality ToSKFilterQuality(this BitmapInterpolationMode int
};
}
+ public static SKSamplingOptions ToSKSamplingOptions(this BitmapInterpolationMode interpolationMode)
+ {
+ return interpolationMode switch
+ {
+ BitmapInterpolationMode.Default => new SKSamplingOptions(SKFilterMode.Nearest, SKMipmapMode.None),
+ BitmapInterpolationMode.LowQuality => new SKSamplingOptions(SKFilterMode.Linear, SKMipmapMode.None),
+ BitmapInterpolationMode.MediumQuality => new SKSamplingOptions(SKFilterMode.Linear, SKMipmapMode.Linear),
+ BitmapInterpolationMode.HighQuality => new SKSamplingOptions(SKCubicResampler.Mitchell),
+ _ => throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null)
+ };
+ }
+
public static SKPoint ToSKPoint(this Point p)
{
return new SKPoint(p.X, p.Y);
diff --git a/src/Beutl.Engine/Media/TextFormatting/FormattedText.cs b/src/Beutl.Engine/Media/TextFormatting/FormattedText.cs
index 51f180d22..676b33650 100644
--- a/src/Beutl.Engine/Media/TextFormatting/FormattedText.cs
+++ b/src/Beutl.Engine/Media/TextFormatting/FormattedText.cs
@@ -2,7 +2,6 @@
using System.Runtime.InteropServices;
using Beutl.Graphics;
using Beutl.Graphics.Rendering;
-using Beutl.Media.Immutable;
using Beutl.Reactive;
using SkiaSharp;
using SkiaSharp.HarfBuzz;
@@ -128,16 +127,15 @@ internal Point AddToSKPath(SKPath path, Point point)
buffer.AddUtf16(Text.AsSpan());
buffer.GuessSegmentProperties();
- using SKPaint paint = new() { TextSize = Size, Typeface = font.Typeface };
- SKShaper.Result result = shaper.Shape(buffer, paint);
+ SKShaper.Result result = shaper.Shape(buffer, font);
// create the text blob
using var builder = new SKTextBlobBuilder();
SKPositionedRunBuffer run = builder.AllocatePositionedRun(font, result.Codepoints.Length);
// copy the glyphs
- Span glyphs = run.GetGlyphSpan();
- Span positions = run.GetPositionSpan();
+ Span glyphs = run.Glyphs;
+ Span positions = run.Positions;
for (int i = 0; i < result.Codepoints.Length; i++)
{
glyphs[i] = (ushort)result.Codepoints[i];
@@ -147,7 +145,7 @@ internal Point AddToSKPath(SKPath path, Point point)
}
// build
- using SKTextBlob textBlob = builder.Build();
+ using SKTextBlob? textBlob = builder.Build();
for (int i = 0; i < glyphs.Length; i++)
{
@@ -187,7 +185,11 @@ internal SKFont ToSKFont()
{
Edging = SKFontEdging.Antialias,
Subpixel = true,
- Hinting = SKFontHinting.Full
+ Hinting = SKFontHinting.Full,
+ Embolden = true
+ //paint.HintingLevel = SKPaintHinting.Full;
+ //paint.LcdRenderText = true;
+ //paint.SubpixelText = true;
};
return font;
@@ -208,16 +210,15 @@ private void Measure()
buffer.AddUtf16(Text.AsSpan());
buffer.GuessSegmentProperties();
- using SKPaint paint = new() { TextSize = Size, Typeface = font.Typeface, };
- SKShaper.Result result = shaper.Shape(buffer, paint);
+ SKShaper.Result result = shaper.Shape(buffer, font);
// create the text blob
using var builder = new SKTextBlobBuilder();
SKPositionedRunBuffer run = builder.AllocatePositionedRun(font, result.Codepoints.Length);
var fillPath = new SKPath();
- Span glyphs = run.GetGlyphSpan();
- Span positions = run.GetPositionSpan();
+ Span glyphs = run.Glyphs;
+ Span positions = run.Positions;
CollectionsMarshal.SetCount(_pathList, result.Codepoints.Length);
Span pathList = CollectionsMarshal.AsSpan(_pathList);
for (int i = 0; i < result.Codepoints.Length; i++)
@@ -250,7 +251,7 @@ private void Measure()
// 空白で開始または、終了した場合
var bounds = new Rect(0, 0, (glyphs.Length - 1) * Spacing + result.Width, fillPath.TightBounds.Height);
Rect actualBounds = fillPath.TightBounds.ToGraphicsRect();
- SKTextBlob textBlob = builder.Build();
+ SKTextBlob? textBlob = builder.Build();
if (result.Codepoints.Length > 0)
{