/// <summary> /// Creates paint wrapper for given brush. /// </summary> /// <param name="brush">Source brush.</param> /// <param name="targetSize">Target size.</param> /// <returns>Paint wrapper for given brush.</returns> internal PaintWrapper CreatePaint(IBrush brush, Size targetSize) { var paint = new SKPaint { IsAntialias = true }; var paintWrapper = new PaintWrapper(paint); double opacity = brush.Opacity * _currentOpacity; if (brush is ISolidColorBrush solid) { paint.Color = new SKColor(solid.Color.R, solid.Color.G, solid.Color.B, (byte)(solid.Color.A * opacity)); return(paintWrapper); } paint.Color = new SKColor(255, 255, 255, (byte)(255 * opacity)); if (brush is IGradientBrush gradient) { ConfigureGradientBrush(ref paintWrapper, targetSize, gradient); return(paintWrapper); } var tileBrush = brush as ITileBrush; var visualBrush = brush as IVisualBrush; var tileBrushImage = default(IDrawableBitmapImpl); if (visualBrush != null) { ConfigureVisualBrush(ref paintWrapper, visualBrush, _visualBrushRenderer, ref tileBrushImage); } else { tileBrushImage = (IDrawableBitmapImpl)(tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; } if (tileBrush != null && tileBrushImage != null) { ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage); } else { paint.Color = new SKColor(255, 255, 255, 0); } return(paintWrapper); }
/// <summary> /// Configure paint wrapper for using tile brush. /// </summary> /// <param name="paintWrapper">Paint wrapper.</param> /// <param name="targetSize">Target size.</param> /// <param name="tileBrush">Tile brush to use.</param> /// <param name="tileBrushImage">Tile brush image.</param> /// <param name="interpolationMode">The bitmap interpolation mode.</param> private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) { var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height), targetSize); var intermediate = CreateRenderTarget( (int)calc.IntermediateSize.Width, (int)calc.IntermediateSize.Height, _dpi); paintWrapper.AddDisposable(intermediate); using (var context = intermediate.CreateDrawingContext(null)) { var rect = new Rect(0, 0, tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height); context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, tileBrush.BitmapInterpolationMode); context.PopClip(); } var tileTransform = tileBrush.TileMode != TileMode.None ? SKMatrix.MakeTranslation(-(float)calc.DestinationRect.X, -(float)calc.DestinationRect.Y) : SKMatrix.MakeIdentity(); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipX || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; SKShaderTileMode tileY = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipY || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; var image = intermediate.SnapshotImage(); paintWrapper.AddDisposable(image); using (var shader = image.ToShader(tileX, tileY, tileTransform)) { paintWrapper.Paint.Shader = shader; } }
internal PaintWrapper CreateAcrylicPaint(SKPaint paint, IExperimentalAcrylicMaterial material, bool disposePaint = false) { var paintWrapper = new PaintWrapper(paint, disposePaint); paint.IsAntialias = true; double opacity = _currentOpacity; var tintOpacity = material.BackgroundSource == AcrylicBackgroundSource.Digger ? material.TintOpacity : 1; const double noiseOpcity = 0.0225; var tintColor = material.TintColor; var tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, tintColor.A); if (s_acrylicNoiseShader == null) { using (var stream = typeof(DrawingContextImpl).Assembly.GetManifestResourceStream("Avalonia.Skia.Assets.NoiseAsset_256X256_PNG.png")) using (var bitmap = SKBitmap.Decode(stream)) { s_acrylicNoiseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat) .WithColorFilter(CreateAlphaColorFilter(noiseOpcity)); } } using (var backdrop = SKShader.CreateColor(new SKColor(material.MaterialColor.R, material.MaterialColor.G, material.MaterialColor.B, material.MaterialColor.A))) using (var tintShader = SKShader.CreateColor(tint)) using (var effectiveTint = SKShader.CreateCompose(backdrop, tintShader)) using (var compose = SKShader.CreateCompose(effectiveTint, s_acrylicNoiseShader)) { paint.Shader = compose; if (material.BackgroundSource == AcrylicBackgroundSource.Digger) { paint.BlendMode = SKBlendMode.Src; } return(paintWrapper); } }
/// <summary> /// Configure paint wrapper for using gradient brush. /// </summary> /// <param name="paintWrapper">Paint wrapper.</param> /// <param name="targetSize">Target size.</param> /// <param name="gradientBrush">Gradient brush.</param> private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Size targetSize, IGradientBrush gradientBrush) { var tileMode = gradientBrush.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradientBrush.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradientBrush.GradientStops.Select(s => (float)s.Offset).ToArray(); switch (gradientBrush) { case ILinearGradientBrush linearGradient: { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); var end = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint(); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) { paintWrapper.Paint.Shader = shader; } break; } case IRadialGradientBrush radialGradient: { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); var radius = (float)(radialGradient.Radius * targetSize.Width); // TODO: There is no SetAlpha in SkiaSharp //paint.setAlpha(128); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) { paintWrapper.Paint.Shader = shader; } break; } } }
/// <summary> /// Configure paint wrapper to use visual brush. /// </summary> /// <param name="paintWrapper">Paint wrapper.</param> /// <param name="visualBrush">Visual brush.</param> /// <param name="visualBrushRenderer">Visual brush renderer.</param> /// <param name="tileBrushImage">Tile brush image.</param> private void ConfigureVisualBrush(ref PaintWrapper paintWrapper, IVisualBrush visualBrush, IVisualBrushRenderer visualBrushRenderer, ref IDrawableBitmapImpl tileBrushImage) { if (_visualBrushRenderer == null) { throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl."); } var intermediateSize = visualBrushRenderer.GetRenderTargetSize(visualBrush); if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) { var intermediate = CreateRenderTarget(intermediateSize); using (var ctx = intermediate.CreateDrawingContext(visualBrushRenderer)) { ctx.Clear(Colors.Transparent); visualBrushRenderer.RenderVisualBrush(ctx, visualBrush); } tileBrushImage = intermediate; paintWrapper.AddDisposable(tileBrushImage); } }
internal PaintWrapper CreatePaint(IBrush brush, Size targetSize) { SKPaint paint = new SKPaint(); var rv = new PaintWrapper(paint); paint.IsStroke = false; // TODO: SkiaSharp does not contain alpha yet! double opacity = brush.Opacity * _currentOpacity; //paint.SetAlpha(paint.GetAlpha() * opacity); paint.IsAntialias = true; SKColor color = new SKColor(255, 255, 255, 255); var solid = brush as ISolidColorBrush; if (solid != null) color = solid.Color.ToSKColor(); paint.Color = (new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * opacity))); if (solid != null) { return rv; } var gradient = brush as GradientBrush; if (gradient != null) { var tileMode = gradient.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradient.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradient.GradientStops.Select(s => (float)s.Offset).ToArray(); var linearGradient = brush as LinearGradientBrush; if (linearGradient != null) { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); var end = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint(); // would be nice to cache these shaders possibly? var shader = SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode); paint.Shader = shader; shader.Dispose(); } else { var radialGradient = brush as RadialGradientBrush; if (radialGradient != null) { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); var radius = (float)radialGradient.Radius; // TODO: There is no SetAlpha in SkiaSharp //paint.setAlpha(128); // would be nice to cache these shaders possibly? var shader = SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode); paint.Shader = shader; shader.Dispose(); } } return rv; } var tileBrush = brush as TileBrush; if (tileBrush != null) { var helper = new TileBrushImplHelper(tileBrush, targetSize); var bitmap = new BitmapImpl((int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height); rv.AddDisposable(bitmap); using (var ctx = bitmap.CreateDrawingContext()) helper.DrawIntermediate(ctx); SKMatrix translation = SKMatrix.MakeTranslation(-(float)helper.DestinationRect.X, -(float)helper.DestinationRect.Y); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipX || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; SKShaderTileMode tileY = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipY || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; paint.Shader = SKShader.CreateBitmap(bitmap.Bitmap, tileX, tileY, translation); paint.Shader.Dispose(); } return rv; }
internal PaintWrapper CreatePaint(IBrush brush, Size targetSize) { SKPaint paint = new SKPaint(); var rv = new PaintWrapper(paint); paint.IsStroke = false; double opacity = brush.Opacity * _currentOpacity; paint.IsAntialias = true; var solid = brush as ISolidColorBrush; if (solid != null) { paint.Color = new SKColor(solid.Color.R, solid.Color.G, solid.Color.B, (byte)(solid.Color.A * opacity)); return(rv); } paint.Color = (new SKColor(255, 255, 255, (byte)(255 * opacity))); var gradient = brush as IGradientBrush; if (gradient != null) { var tileMode = gradient.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradient.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradient.GradientStops.Select(s => (float)s.Offset).ToArray(); var linearGradient = brush as ILinearGradientBrush; if (linearGradient != null) { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); var end = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint(); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) paint.Shader = shader; } else { var radialGradient = brush as IRadialGradientBrush; if (radialGradient != null) { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); var radius = (float)radialGradient.Radius; // TODO: There is no SetAlpha in SkiaSharp //paint.setAlpha(128); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) paint.Shader = shader; } } return(rv); } var tileBrush = brush as ITileBrush; var visualBrush = brush as IVisualBrush; var tileBrushImage = default(BitmapImpl); if (visualBrush != null) { if (_visualBrushRenderer != null) { var intermediateSize = _visualBrushRenderer.GetRenderTargetSize(visualBrush); if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) { var intermediate = new BitmapImpl((int)intermediateSize.Width, (int)intermediateSize.Height); using (var ctx = intermediate.CreateDrawingContext(_visualBrushRenderer)) { ctx.Clear(Colors.Transparent); _visualBrushRenderer.RenderVisualBrush(ctx, visualBrush); } rv.AddDisposable(tileBrushImage); tileBrushImage = intermediate; } } else { throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl."); } } else { tileBrushImage = (BitmapImpl)((tileBrush as IImageBrush)?.Source?.PlatformImpl); } if (tileBrush != null && tileBrushImage != null) { var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); var bitmap = new BitmapImpl((int)calc.IntermediateSize.Width, (int)calc.IntermediateSize.Height); rv.AddDisposable(bitmap); using (var context = bitmap.CreateDrawingContext(null)) { var rect = new Rect(0, 0, tileBrushImage.PixelWidth, tileBrushImage.PixelHeight); context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; context.DrawImage(tileBrushImage, 1, rect, rect); context.PopClip(); } SKMatrix translation = SKMatrix.MakeTranslation(-(float)calc.DestinationRect.X, -(float)calc.DestinationRect.Y); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipX || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; SKShaderTileMode tileY = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipY || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; using (var shader = SKShader.CreateBitmap(bitmap.Bitmap, tileX, tileY, translation)) paint.Shader = shader; } return(rv); }
/// <summary> /// Configure paint wrapper for using gradient brush. /// </summary> /// <param name="paintWrapper">Paint wrapper.</param> /// <param name="targetSize">Target size.</param> /// <param name="gradientBrush">Gradient brush.</param> private void ConfigureGradientBrush(ref PaintWrapper paintWrapper, Size targetSize, IGradientBrush gradientBrush) { var tileMode = gradientBrush.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradientBrush.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradientBrush.GradientStops.Select(s => (float)s.Offset).ToArray(); switch (gradientBrush) { case ILinearGradientBrush linearGradient: { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); var end = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint(); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) { paintWrapper.Paint.Shader = shader; } break; } case IRadialGradientBrush radialGradient: { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); var radius = (float)(radialGradient.Radius * targetSize.Width); var origin = radialGradient.GradientOrigin.ToPixels(targetSize).ToSKPoint(); if (origin.Equals(center)) { // when the origin is the same as the center the Skia RadialGradient acts the same as D2D using (var shader = SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) { paintWrapper.Paint.Shader = shader; } } else { // when the origin is different to the center use a two point ConicalGradient to match the behaviour of D2D // reverse the order of the stops to match D2D var reversedColors = new SKColor[stopColors.Length]; Array.Copy(stopColors, reversedColors, stopColors.Length); Array.Reverse(reversedColors); // and then reverse the reference point of the stops var reversedStops = new float[stopOffsets.Length]; for (var i = 0; i < stopOffsets.Length; i++) { reversedStops[i] = stopOffsets[i]; if (reversedStops[i] > 0 && reversedStops[i] < 1) { reversedStops[i] = Math.Abs(1 - stopOffsets[i]); } } // compose with a background colour of the final stop to match D2D's behaviour of filling with the final color using (var shader = SKShader.CreateCompose( SKShader.CreateColor(reversedColors[0]), SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode) )) { paintWrapper.Paint.Shader = shader; } } break; } case IConicGradientBrush conicGradient: { var center = conicGradient.Center.ToPixels(targetSize).ToSKPoint(); // Skia's default is that angle 0 is from the right hand side of the center point // but we are matching CSS where the vertical point above the center is 0. var angle = (float)(conicGradient.Angle - 90); var rotation = SKMatrix.CreateRotationDegrees(angle, center.X, center.Y); using (var shader = SKShader.CreateSweepGradient(center, stopColors, stopOffsets, rotation)) { paintWrapper.Paint.Shader = shader; } break; } } }
internal PaintWrapper CreatePaint(IBrush brush, Size targetSize) { SKPaint paint = new SKPaint(); var rv = new PaintWrapper(paint); paint.IsStroke = false; // TODO: SkiaSharp does not contain alpha yet! double opacity = brush.Opacity * _currentOpacity; //paint.SetAlpha(paint.GetAlpha() * opacity); paint.IsAntialias = true; SKColor color = new SKColor(255, 255, 255, 255); var solid = brush as ISolidColorBrush; if (solid != null) { color = solid.Color.ToSKColor(); } paint.Color = (new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * opacity))); if (solid != null) { return(rv); } var gradient = brush as GradientBrush; if (gradient != null) { var tileMode = gradient.SpreadMethod.ToSKShaderTileMode(); var stopColors = gradient.GradientStops.Select(s => s.Color.ToSKColor()).ToArray(); var stopOffsets = gradient.GradientStops.Select(s => (float)s.Offset).ToArray(); var linearGradient = brush as LinearGradientBrush; if (linearGradient != null) { var start = linearGradient.StartPoint.ToPixels(targetSize).ToSKPoint(); var end = linearGradient.EndPoint.ToPixels(targetSize).ToSKPoint(); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode)) paint.Shader = shader; } else { var radialGradient = brush as RadialGradientBrush; if (radialGradient != null) { var center = radialGradient.Center.ToPixels(targetSize).ToSKPoint(); var radius = (float)radialGradient.Radius; // TODO: There is no SetAlpha in SkiaSharp //paint.setAlpha(128); // would be nice to cache these shaders possibly? using (var shader = SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode)) paint.Shader = shader; } } return(rv); } var tileBrush = brush as TileBrush; if (tileBrush != null) { var helper = new TileBrushImplHelper(tileBrush, targetSize); var bitmap = new BitmapImpl((int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height); rv.AddDisposable(bitmap); using (var ctx = bitmap.CreateDrawingContext()) helper.DrawIntermediate(ctx); SKMatrix translation = SKMatrix.MakeTranslation(-(float)helper.DestinationRect.X, -(float)helper.DestinationRect.Y); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipX || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; SKShaderTileMode tileY = tileBrush.TileMode == TileMode.None ? SKShaderTileMode.Clamp : tileBrush.TileMode == TileMode.FlipY || tileBrush.TileMode == TileMode.FlipXY ? SKShaderTileMode.Mirror : SKShaderTileMode.Repeat; using (var shader = SKShader.CreateBitmap(bitmap.Bitmap, tileX, tileY, translation)) paint.Shader = shader; } return(rv); }