Is it any way to fill available width / height with image in xaml?
I need something like UniformToFill, but where I can control stretch direction (width or height)
Assume I have have following code:
<UniformGrid Columns="2" Rows="2">
<Image Source="Desert1.jpg" Stretch="Uniform"/> //
<Image Source="Desert2.jpg" Stretch="UniformToFill"/> //
<Image Source="Desert3.jpg" />
<Image Source="Desert4.jpg" />
</UniformGrid>
EDIT:
for examle (width): if image is half as wide as I want to show, I don't care about height and just scale x2 image height and width. So image must fit width, and don't care about height. It's desired behaviour, but if it's not possible - ok. So you can rethink question as IF it possible, HOW can I do it in xaml.
Also all images may have different width and height
I think that you might be able to get the effect you desire in certain conditions. If your images are all bigger than the size that they will be displayed, you could possibly use this:
<Image Source="Desert.jpg" Stretch="UniformToFill" StretchDirection="DownOnly" />
A ViewBox has the same Stretch properties as an Image and there is a good example of the differences between the different combinations in the How to: Apply Stretch Properties to the Contents of a Viewbox article on MSDN.
This might be what you are looking for...
TransformedBitmap
Here is a static method I made in an ImageUtility class.
public static TransformedBitmap GetScaledBitmapImageSprite(BitmapSource src, double x_scale, double y_scale)
{
return (new TransformedBitmap(src, new ScaleTransform(x_scale, y_scale)));
{
The x_scale and y_scale are doubles in the form of:
desired_width / original_width
Maybe a little different than what you are looking for but I think it can get you started on the right track.
You can store your TransformedBitmap in memory and apply new transforms through:
TransformedBitmap x = new TransformedBitmap();
x.Transform = new ScaleTransform(x,y);
You should use
<Image Source="{Binding Image}" Stretch="Fill"/>
like if you use Stretch="UnifrmtoFill" then it will change both length and width in a ratio or I say both together.
so if you use
Stretch="Fill", it gives you chance to change either height or width at a time whatever is changed.
Related
My application detects a foreign object (blob, cluster etc) in the live webcam image and displays object's outline on top of the image. To achieve that I employ Image and Canvas elements as follows:
<Border x:Name="ViewportBorder" Grid.Column="0" Grid.Row="1" BorderThickness="3" Background="AliceBlue" BorderBrush="Red">
<Grid>
<Image x:Name="videoPlayer" Stretch="Uniform" MouseDown="videoPlayer_MouseDown"></Image>
<Canvas x:Name="ObjectsCanvas"></Canvas>
</Grid>
</Border>
Border element in the above XAML is used just to draw a thick red line border around the Grid containing videoPlayer and ObjectsCanvas. Stretch="Uniform" is set to preserve image aspect ratio while being able it to stretch when application window gets maximized.
Every time the new frame arrives from the camera videoPlayer.Source gets updated with frame's bitmap whereas blob detection method yields a list of coordinates used for drawing a Polyline. The Polyline object is then added to ObjectsCanvas to be shown on top of the actual image frame.
Here's a part which draws the blob and adds it to the ObjectsCanvas.Children:
private void DrawBlob(List<Point> corners)
{
this.Dispatcher.Invoke(() =>
{
var myPolyline = new Polyline();
myPolyline.Stroke = System.Windows.Media.Brushes.Yellow;
myPolyline.StrokeThickness = 4;
myPolyline.FillRule = FillRule.EvenOdd;
myPolyline.Points = corners;
Canvas.SetLeft(myPolyline, 0);
Canvas.SetTop(myPolyline, 0);
ObjectsCanvas.Children.Clear(); // remove any old blob polyline
ObjectsCanvas.Children.Add(myPolyline); // add new polyline
});
}
When running the application I observe imperfect overlap of the blob object (thick yellow polyline), it gets somewhat right-shifted as shown in the image below.
Observed imperfection is not due to blob detection algorithm! I verified that by drawing the polylines of very same coordinates using old-fashion GDI methods on the actual bitmap.
It gets worse when I maximize the application window, an action causing videoPlayer to stretch:
I tried setting HorizontalAlignment and VerticalAlignment properties of ObjectsCanvas to Stretch but that does not help. Is there any method to align canvas exactly with the actual displayed image region?
I could get back to drawing the polylines using GDI, but I think it's a shame doing so in WPF...
I think I found a solution.
So, in order to stretch your canvas up to your image size you could wrap your canvas in ViewvBox control and bind your Canvas.Height and Canvas.Width to the image source's Height and Width like so:
<Grid>
<Image x:Name="MyFrame" Stretch="Uniform" />
<Viewbox Stretch="Uniform">
<Canvas
x:Name="MyCanvas"
Width="{Binding ElementName=MyFrame, Path=Source.Width}"
Height="{Binding ElementName=MyFrame, Path=Source.Height}">
<Canvas.Background>
<SolidColorBrush Opacity="0" Color="White" />
</Canvas.Background>
</Canvas>
</Viewbox>
</Grid>
However you need to set your Canvas.Background (you can make it transparent like in the example above), or ViewvBox will hide all of the canvas children otherwise.
Here are some screenshots of it working with a yellow polyline:
One more thing to note here - the coordinates of your polyline should be relative to image resolution.
Hope that helps!
<StackPanel x:Name="rootStackPanel" Background="{ThemeResource SystemControlAcrylicWindowBrush}" Padding="0,48">
<Rectangle x:Name="sampleRectangle" Width="200" Height="300" Fill="DeepPink" DoubleTapped="Rectangle_DoubleTapped" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<CompositeTransform TranslateY="-100"/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="otherRectangle" Width="200" Height="200" Fill="Cyan"/>
</StackPanel>
I want to achieve a dynamic look, where, when the pink rectangle is moved upward, the blue rectangle takes up the left over space. Such that it is always touching the pink rectangle.
I have tried manipulating offsets and scale properties provided by visual layer but the actual height is not affected by any of the property, as a result the other rectangle just stays in the original position. Now I am trying to achieve that effect using storyboards animation. But as you can see, the translation property (and the scale property as well) doesn't effect the actual container of the control somehow but rather makes the content in it move to whatever translation.
So, what properties do I need to manipulate to achieve the effect where the other rectangle inside the stackpanel moves dynamically with the changes to the first rectangle?
I know adjusting width or height property would result in what I am trying to achieve but for more complex scenarios where there might be a textbox rather than simple rectangle that is being animated, there is sort of a weird animation of the placeholder text(shrinking of text), which is something I don't want!
So, what properties do I need to manipulate to achieve the effect where the other rectangle inside the stackpanel moves dynamically with the changes to the first rectangle?
You could use Microsoft.Toolkit.Uwp.UI.Animations.Behaviors to realize this feature directly. Before animate your rectangle, you need to get the absolute position of the each rectangle like the follow.
var scgt = sampleRectangle.TransformToVisual(Window.Current.Content);
Point screenCoords = scgt.TransformPoint(new Point(0, 0));
var ddv = otherRectangle.TransformToVisual(Window.Current.Content);
Point Res = ddv.TransformPoint(new Point(0, 0));
If you want pink rectangle to move upward, you could Offset offsetY value
sampleRectangle.Offset(offsetX: 0, offsetY: -(float)screenCoords.Y - (float)sampleRectangle.Height, duration: 2500).Start();
And then animate otherRectangle like the follow
otherRectangle.Offset(offsetX: -(float)Res.X, offsetY: -(float)Res.Y).Scale(scaleX: 2, scaleY: 2).Start();
You need keep scaleX equal with scaleY when you scale TextBox.Otherwise, the TextBox will be deformed.
Since the creators update came out, uwp can use svg images as briefly explained here (minute 3).
I have this svg (48x48) and i can use it fine, if (and only if) i set the image's width&height to 48 and the strech to none:
<Image Source="ms-appx:///Assets//check.svg" Height="48" Width="48" Stretch="None"/>
If i set the stretch to fill, the image disappears. If i increase the width and height i can see that the icon is pinned to the upper left corner of the image (screenshot with a different svg but same size). Isn't Stretch=Fill and a fixed height/width the intended way to scale an image?
It looks to my as if the stretching algorithm does not grasp that my svg is supposed to be 48x48. Am i doing it wrong, or are there workarounds?
Okay, so here is how I solved this!
YouTube Video for this!
Open the SVG file
The SVG file Width and Height - set these to auto!
I've been having the same issue all morning and was about to completely give up on Svg support, seems mad that you can't get a scalable format to scale properly...
But, I had one more go and I think I've worked this out.
It seems that you need to tell the SvgImageSource to rasterize at the SVG's original design size and then get the Image to scale it. Not sure it's a particularly helpful approach, but certainly solves it as of build 15063.
<Image Width="24" Stretch="Uniform" VerticalAlignment="Center">
<Image.Source>
<SvgImageSource UriSource="ms-appx:///Assets/salesorder.folder.plain.svg"
RasterizePixelHeight="48"
RasterizePixelWidth="48" />
</Image.Source>
</Image>
So if the SVG was 48x48 we turn it into a bitmap at 48x48 using the RasterizePixelHeight and RasterizePixelWidth values and then the image scales that to 24x24.
Hope that helps.
Update
I just re-read your question and realised that you were looking to increase the scale whereas I've been working to decrease it. Looks as though the technique still works, but as you scale up you're going to lose any sharpness of image due to the bitmap scale process. I think this points to a fundamental flaw in the current implementation. They seem to be rendering the svg as a bitmap, and we have to tell it the original size to get it to render properly, and then they allow the bitmap code to do the rest of the work.
I think it's somewhat debateable whether this is true support or an odd half way house. Somewhere someone suggested that Adobe Illustrator can generate XAML paths, I think I'm going to look at that to see whether I can get a better quality output, shame though because I really like Inkscape :-(
For me, it worked with modifying SVG file like this:
Add appropriate preserveAspectRatio property to svg tag. For me it was "xMinYMin meet".
Set viewbox property of svg tag to this template "0 0 ActualHeight ActualWidth", in my case it was "0 0 1050 805".
Set height and width of svg tag to "auto".
Now svg element is relative to Height, Width and Stretch properties you provide in your XAML page or view.
It might be needed to rebuild the project for XAML Designer to take effect.
SVG File:
<svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 1050 805" width="auto" height="auto" ... > ... </svg>
XAML File:
<Image
Width="200"
Source="ms-appx:///Assets/Photos/Illustrations/sample.svg"
Stretch="UniformToFill" />
For me it works only if you set RasterizePixelHeight and RasterizePixelWidth to the svg original resolution (e.g. document properties in Inkscape).
For me it worked without setting those Properties, but adding preserveAspectRatio="xMinYMin" to the <svg ...> tag and deleting width and height from the <svg ...> tag.
I'm trying to display an image on a splash screen and it's being stretched upon display. The image I'm trying to display is a simple bmp file. Any ideas why?
In SplashWindow.xaml:
<Window ... SizeToContent="WidthAndHeight">
<Grid>
...
<Image Grid.Row="0" Source="{Binding SplashImage}"></Image>
</Grid>
</Window>
In SplashViewModel.cs
public ImageSource SplashImage
{
get
{
return ImageUtilities.GetImageSource(_splashImageFilenameString);
}
}
From ImageUtilities.cs
public static ImageSource GetImageSource(string imageFilename)
{
BitmapFrame bitmapFrame = null;
if(!string.IsNullOrEmpty(imageFilename))
{
if(File.Exists(imageFilename))
{
bitmapFrame = BitmapFrame.Create(new Uri(imageFilename));
}
else
{
Debug.Assert(false, "File " + imageFilename + " does not exist.");
}
}
return bitmapFrame;
}
In your XAML, set the "Stretch" property to "None" (I believe it defaults to "Fill"):
<Image Grid.Row="0" Source="{Binding SplashImage}" Stretch="None"></Image>
You can also explicitly set the Width and Height properties if you like.
typically you want:
<Image Source="{Binding ImagePath}" Stretch="Uniform" />
this value will enlarge the image as much as possible while still fitting entirely within your parent control. It will not distort it, it will maintain the source's aspect ratio. If you use
Stretch="None"
it will display the image (or what fits of the image, it will clip) at it's native size which is not always what you want.
Anyhow, you have some choices but setting Stretch to what you want will effect the way the image stretches or not.
WPF doesn't display things in pixels (at least not on the surface). WPF displays things in device-independent units, specifically 1/96ths of an inch.
Image files have DPI/resolution information in their metadata which tells the computer how big that image is in inches. If your image file has been programmed to say it is 8 inches wide, that's going to be equal to 768 units in WPF, regardless of how many pixels the image is.
You can use an image editing program like Photoshop or equivalent to change the DPI of your image, or just give it an explicit Width and Height when you display it in WPF.
I'm running into a problem of "jitters" when moving the X, Y coordinates of controls. Basically, I got an animation to work two different ways: 1) TranslateTransform of the X property, and 2) A Timer that calls Canvas.SetLeft. Both of which cause the image to move, but not smoothly.
XAML:
<Canvas Margin="0" Name="CanvasContainer">
<Canvas Margin="0" Name="FirstCanvas" Background="White">
<Image Name="FirstImage" Opacity="1" Margin="0,0,0,0" Canvas.Left="0" Canvas.Top="0" Source="someImage.png" />
</Canvas>
<Canvas Margin="0" Name="SecondCanvas" Background="DarkOrange">
<Image Name="SecondImage" Opacity="1" Margin="0,0,0,0" Canvas.Left="0" Canvas.Top="0" Source="anotherImage.png" />
</Canvas>
</Canvas>
TranslateTransform:
private void StartMovement(double startX, double endX, double milliseconds = 1000)
{
GuiDispatcher.Invoke(DispatcherPriority.Normal, new Action<Canvas, double, double, double>(MoveTo), Canvas, startX, endX, milliseconds);
}
private void MoveTo(Canvas canvas, double startX, double endX, double milliseconds)
{
canvas.RenderTransform = new TranslateTransform();
var animation = new DoubleAnimation(startX, endX, TimeSpan.FromMilliseconds(milliseconds));
canvas.RenderTransform.BeginAnimation(TranslateTransform.XProperty, animation);
}
Is there a better method for accomplishing this, or do I have something set up wrong? Any help would be appreciated.
Either of those methods are generally fine for animations in WPF. If the image isn't moving smoothly, I have a few of questions.
How big is the image?
Large images take longer to render, and will therefore not animate as well.
Are you rendering the image at its native resolution?
Like large images, scaling can slow down the render, as it takes longer to calculate the rendered pixels.
How good is your graphics card? And are your drivers up to date?
WPF uses your graphics card to render, unless it isn't good enough. If it has to fallback to software rendering, everything gets sluggish.
How far is the image moving?
The further the image moves, the fewer frames will be drawn per second, which could leave to the appearance of the animation being jerky.
If it is a framerate issue because the image is moving too far too quickly, you can increase the desired framerate by setting the Timeline.DesiredFrameRate property:
Timeline.SetDesiredFrameRate(animation, 120);;
In WPF, the default target framerate is 60, and is by no means guaranteed. But one of the primary uses for this attached property is to decrease horizontal tearing, so it might help.