Win2D:如何在可缩放的圆圈内绘制中心图像
Win2D: How to draw a center image inside a circle scalable
我正在尝试使用 C# 中的 Win2D 在圆圈内绘制缩放图像,但我没有这样做。
我的尝试是例如:
CanvasBitmap image;
bool resourcesLoaded = false;
public Other() {
this.InitializeComponent();
}
void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args) {
if( resourcesLoaded ) {
var halfWidth = sender.ActualWidth / 2;
var halfHeight = sender.ActualHeight / 2;
double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / 96.0;
double pixelWidth = halfWidth * displayScaling;
double pixelHeight = halfHeight * displayScaling;
var scaleEffect = new ScaleEffect() {
Source = image,
Scale = new Vector2() {
X = ( float ) ( pixelHeight / image.Size.Height ),
Y = ( float ) ( pixelHeight / image.Size.Height ),
}
};
var blurEffect = new GaussianBlurEffect() {
Source = scaleEffect,
BlurAmount = 5f
};
args.DrawingSession.FillCircle( new System.Numerics.Vector2() { X = ( float ) halfWidth, Y = (float) halfHeight },
(float) halfHeight/2,
new CanvasImageBrush( sender, blurEffect ) {
SourceRectangle = new Rect(0,0, scaleEffect.GetBounds(sender).Width, scaleEffect.GetBounds( sender ).Height)
} );
}
}
private void canvasControl_CreateResources(CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) {
args.TrackAsyncAction( CreateResources( sender ).AsAsyncAction() );
}
private async Task CreateResources(CanvasControl sender) {
image = await CanvasBitmap.LoadAsync( canvasControl, new Uri( "ms-appx:///Imgs/test.jpg" ) );
resourcesLoaded = true;
sender.Invalidate();
}
发生的事情是图像似乎是在 window 的 X=0 和 Y=0 位置绘制的(canvas 使用所有 window),所以我的圆圈在 window 的中间,然后只有一点图像被绘制,我希望我的图像放在圆圈的中心。
所以问题是:
- 我的体重秤做得对吗?为什么要除以 96?我可以从系统中读取这个吗?
- 是否可以只模糊图像的边缘?
- 如何在圆心绘制图像?
谢谢
我想我已经解决了我的问题,首先,可能的问题的答案是:
- 我的秤做得对吗?
在下一个示例代码中现在是(比例必须同时使用,with 和 height)
- 为什么要除以 96?我可以从系统中读取吗?
96是DPI,所以我们需要得到你的系统当前使用的DPI,我们可以调用CanvasControl.Dpi找出
- 以及如何在圆心绘制图像?
最好显示代码来回答这个问题,但基本上的想法是在 CanvasCommandList 中完成所有操作,然后在 window 上的任何需要的地方绘制 CanvasCommandList:
CanvasCommandList cl;
CanvasBitmap image;
bool resourcesLoaded = false;
private void canvasControl_CreateResources(CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) {
args.TrackAsyncAction( CreateResources( sender ).AsAsyncAction() );
}
private async Task CreateResources(CanvasControl sender) {
image = await CanvasBitmap.LoadAsync( canvasControl, new Uri( "ms-appx:///Imgs/test.jpg" ) );
int ratio = 6;
var newImgWidth = image.Size.Width / ratio;
var newImgHeight = image.Size.Height / ratio;
double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / sender.Dpi;
double pixelWidth = newImgWidth * displayScaling;
double pixelHeight = newImgHeight * displayScaling;
cl = new CanvasCommandList( sender );
using( CanvasDrawingSession clds = cl.CreateDrawingSession() ) {
var scaleEffect = new ScaleEffect() {
Source = image,
Scale = new Vector2() {
X = ( float ) ( pixelWidth / image.Size.Width ),
Y = ( float ) ( pixelHeight / image.Size.Height ),
}
};
var blurEffect = new GaussianBlurEffect() {
Source = scaleEffect,
BlurAmount = 5f
};
//don't now why but we need to do this in order to have the correct bounds size
clds.DrawImage( blurEffect, 0, 0, new Rect( 0, 0, newImgWidth, newImgHeight ), 0.05f );
//now draw the circle
clds.FillCircle( ( float ) newImgWidth / 2, ( float ) newImgHeight / 2,
( float ) ( newImgWidth > newImgHeight ? newImgHeight : newImgWidth ) / 2,
new CanvasImageBrush( sender, scaleEffect ) {
SourceRectangle = new Rect( 0, 0, newImgWidth, newImgHeight )
} );
}
resourcesLoaded = true;
}
void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args) {
if( resourcesLoaded ) {
//cell (0,0)
args.DrawingSession.DrawImage( cl,
0,
0 );
args.DrawingSession.DrawRectangle( new Rect(
0, 0,
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Red, 3 );
//cell (0,1)
args.DrawingSession.DrawImage( cl,
( float ) ( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( float ) ( 0 ) );
args.DrawingSession.DrawRectangle( new Rect(
( sender.ActualWidth - cl.GetBounds( sender ).Width ), 0,
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Green, 3 );
//cell (1,0)
args.DrawingSession.DrawImage( cl, ( float ) ( 0 ),
( float ) ( sender.ActualHeight - cl.GetBounds( sender ).Height ) );
args.DrawingSession.DrawRectangle( new Rect(
( 0 ),
( sender.ActualHeight - cl.GetBounds( sender ).Height ),
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Yellow, 3 );
//cell (1,1)
args.DrawingSession.DrawImage( cl,
( float ) ( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( float ) ( sender.ActualHeight - cl.GetBounds( sender ).Height ) );
args.DrawingSession.DrawRectangle( new Rect(
( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( sender.ActualHeight - cl.GetBounds( sender ).Height ),
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Orange, 3 );
}
}
这在 window 的每个角落正确地绘制了 4 个圆形图像,正如预期和期望的那样,我认为这可能是一个错误的唯一问题是,如果你只在 CanvasCommandList 中绘制圆形这个边界是预期的一半,为此我需要绘制所有褪色的图像只是为了确保边界正确如预期......也许有更好的解决方案但这是我找到的最好的解决方案。
我正在尝试使用 C# 中的 Win2D 在圆圈内绘制缩放图像,但我没有这样做。
我的尝试是例如:
CanvasBitmap image;
bool resourcesLoaded = false;
public Other() {
this.InitializeComponent();
}
void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args) {
if( resourcesLoaded ) {
var halfWidth = sender.ActualWidth / 2;
var halfHeight = sender.ActualHeight / 2;
double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / 96.0;
double pixelWidth = halfWidth * displayScaling;
double pixelHeight = halfHeight * displayScaling;
var scaleEffect = new ScaleEffect() {
Source = image,
Scale = new Vector2() {
X = ( float ) ( pixelHeight / image.Size.Height ),
Y = ( float ) ( pixelHeight / image.Size.Height ),
}
};
var blurEffect = new GaussianBlurEffect() {
Source = scaleEffect,
BlurAmount = 5f
};
args.DrawingSession.FillCircle( new System.Numerics.Vector2() { X = ( float ) halfWidth, Y = (float) halfHeight },
(float) halfHeight/2,
new CanvasImageBrush( sender, blurEffect ) {
SourceRectangle = new Rect(0,0, scaleEffect.GetBounds(sender).Width, scaleEffect.GetBounds( sender ).Height)
} );
}
}
private void canvasControl_CreateResources(CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) {
args.TrackAsyncAction( CreateResources( sender ).AsAsyncAction() );
}
private async Task CreateResources(CanvasControl sender) {
image = await CanvasBitmap.LoadAsync( canvasControl, new Uri( "ms-appx:///Imgs/test.jpg" ) );
resourcesLoaded = true;
sender.Invalidate();
}
发生的事情是图像似乎是在 window 的 X=0 和 Y=0 位置绘制的(canvas 使用所有 window),所以我的圆圈在 window 的中间,然后只有一点图像被绘制,我希望我的图像放在圆圈的中心。
所以问题是: - 我的体重秤做得对吗?为什么要除以 96?我可以从系统中读取这个吗? - 是否可以只模糊图像的边缘? - 如何在圆心绘制图像?
谢谢
我想我已经解决了我的问题,首先,可能的问题的答案是:
- 我的秤做得对吗?
在下一个示例代码中现在是(比例必须同时使用,with 和 height)
- 为什么要除以 96?我可以从系统中读取吗?
96是DPI,所以我们需要得到你的系统当前使用的DPI,我们可以调用CanvasControl.Dpi找出
- 以及如何在圆心绘制图像?
最好显示代码来回答这个问题,但基本上的想法是在 CanvasCommandList 中完成所有操作,然后在 window 上的任何需要的地方绘制 CanvasCommandList:
CanvasCommandList cl;
CanvasBitmap image;
bool resourcesLoaded = false;
private void canvasControl_CreateResources(CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) {
args.TrackAsyncAction( CreateResources( sender ).AsAsyncAction() );
}
private async Task CreateResources(CanvasControl sender) {
image = await CanvasBitmap.LoadAsync( canvasControl, new Uri( "ms-appx:///Imgs/test.jpg" ) );
int ratio = 6;
var newImgWidth = image.Size.Width / ratio;
var newImgHeight = image.Size.Height / ratio;
double displayScaling = DisplayInformation.GetForCurrentView().LogicalDpi / sender.Dpi;
double pixelWidth = newImgWidth * displayScaling;
double pixelHeight = newImgHeight * displayScaling;
cl = new CanvasCommandList( sender );
using( CanvasDrawingSession clds = cl.CreateDrawingSession() ) {
var scaleEffect = new ScaleEffect() {
Source = image,
Scale = new Vector2() {
X = ( float ) ( pixelWidth / image.Size.Width ),
Y = ( float ) ( pixelHeight / image.Size.Height ),
}
};
var blurEffect = new GaussianBlurEffect() {
Source = scaleEffect,
BlurAmount = 5f
};
//don't now why but we need to do this in order to have the correct bounds size
clds.DrawImage( blurEffect, 0, 0, new Rect( 0, 0, newImgWidth, newImgHeight ), 0.05f );
//now draw the circle
clds.FillCircle( ( float ) newImgWidth / 2, ( float ) newImgHeight / 2,
( float ) ( newImgWidth > newImgHeight ? newImgHeight : newImgWidth ) / 2,
new CanvasImageBrush( sender, scaleEffect ) {
SourceRectangle = new Rect( 0, 0, newImgWidth, newImgHeight )
} );
}
resourcesLoaded = true;
}
void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args) {
if( resourcesLoaded ) {
//cell (0,0)
args.DrawingSession.DrawImage( cl,
0,
0 );
args.DrawingSession.DrawRectangle( new Rect(
0, 0,
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Red, 3 );
//cell (0,1)
args.DrawingSession.DrawImage( cl,
( float ) ( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( float ) ( 0 ) );
args.DrawingSession.DrawRectangle( new Rect(
( sender.ActualWidth - cl.GetBounds( sender ).Width ), 0,
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Green, 3 );
//cell (1,0)
args.DrawingSession.DrawImage( cl, ( float ) ( 0 ),
( float ) ( sender.ActualHeight - cl.GetBounds( sender ).Height ) );
args.DrawingSession.DrawRectangle( new Rect(
( 0 ),
( sender.ActualHeight - cl.GetBounds( sender ).Height ),
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Yellow, 3 );
//cell (1,1)
args.DrawingSession.DrawImage( cl,
( float ) ( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( float ) ( sender.ActualHeight - cl.GetBounds( sender ).Height ) );
args.DrawingSession.DrawRectangle( new Rect(
( sender.ActualWidth - cl.GetBounds( sender ).Width ),
( sender.ActualHeight - cl.GetBounds( sender ).Height ),
cl.GetBounds( sender ).Width, cl.GetBounds( sender ).Height ), Windows.UI.Colors.Orange, 3 );
}
}
这在 window 的每个角落正确地绘制了 4 个圆形图像,正如预期和期望的那样,我认为这可能是一个错误的唯一问题是,如果你只在 CanvasCommandList 中绘制圆形这个边界是预期的一半,为此我需要绘制所有褪色的图像只是为了确保边界正确如预期......也许有更好的解决方案但这是我找到的最好的解决方案。