Reputation: 1940
i'm trying to draw a scaled image inside a circle using Win2D in c# and i'm failing on doing this.
My tries are for example:
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();
}
And what happen is that the image seems to be draw in X=0 and Y=0 position of the window (the canvas uses all window), so my circle is in the middle of the window then only a bit of the image is paint and i wanted that my image be placed on the center of the circle.
So the questions are: - is my scale correctly done? why divide by 96? can i read this from the system? - is it possible to blur only the edges of the image? - and how can i draw my image in the center of the circle?
Thanks
Upvotes: 0
Views: 739
Reputation: 1940
I think i managed to correct my problem, first the answers to may questions are:
in the next sample code now they are (the scale must use both, with and height)
96 is the DPI, so we need to get the current DPI used by your system, we can call CanvasControl.Dpi to find out
well is better to show the code to answer this one, but basically the idea is to do everything inside a CanvasCommandList and then draw the CanvasCommandList wherever desired on the window:
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 );
}
}
This draws 4 circle images correctly in each corner of the window as expected and desired, the only problem that i think that is a bug probably, is that if you only draw the Circle in the CanvasCommandList the bounds of this are half of what is expected, for this i need to draw the all image faded only to ensure that the bounds are correctly as expected... maybe there is a better solution but this is the best one that i found.
Upvotes: 0