Why is my image being displayed larger? - c#

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.

Related

How to properly align Canvas with the underlying Image?

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!

Wrong images loaded

I was developing an UWP app. I am using UWP "Image" control to show images in my app. All images are loaded properly most of the time. But occasionally few images not loading properly. Sometimes it is loaded in cropped version and sometimes loaded a black box which is never set from app. My code to set image:
XAML:
<Image x:Name="FavoritePen"
Source="{Binding FavPenSource, Mode=OneWay}"
Height="44"
Width="44"
Margin="0,10,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"/>
CS:
private string favPenSource =
"ms-appx:///Assets/Images/NoteList/ic_main_tb_favorite_on.svg";
public string FavPenSource
{
get
{
return favPenSource;
}
set
{
SetProperty(ref favPenSource, value);
}
}
Black box loaded:
Wrong image loaded with cropped version:
Additionally, this is a very rare case, may be 1/100 frequency.
I googled and tried many solutions but it didn't help. I found that some people faced same issue but didn't find a proper solution yet. (Issue_1 , Issue_2, Issue_3 , Issue_4)
Can anyone please help me to solve the issue!!
Add View Box element, This is the x, y coordinates of the image inside the element along with the height and width. The default size is 300×150 size. Since I do not see the full container source, check if the SVG element is not beyond the parent container. You can remove the Horizontal/Vertical Alignment.
Sometimes it is loaded in cropped version and sometimes loaded a black box which is never set from app. My code to set image:
The problem is the svg file has been specified height and width property, when you render them with fix size image control, the svg content will display beyond the bound.
For this problem, please edit svg content and set it's height and width property as auto
<svg width="auto" height="auto" viewBox="0 0 469 476" version="1.1" xmlns="http://www.w3.org/2000/svg">

Wpf shared image memory

I want to optimize the memory usage in my WPF app.
I want to load from the disk an jpg image and show it with its real size.
And then I want to show 5 cropped square section of the original image loaded from the disk.
(No resize is applied on any image).
I want to do all this by loading the original image once and sharing that data among the image controls, in such a way that no memory is wasted and all controls fetch data from the same memory location.
I tried by using a memory stream object but in the end due to some convertions between bitmap and bitmapimage I ended up copying the data.
I found an interesting way to crop an image from a BitmapImage here that I think will solve your problem. Doing it this way, you can display all of your images just using a single BitmapImage
In your xaml your full resolution image would just be a regular image element, but your cropped images would be a rectangle element using an image brush with a specific viewbox. Just define the rectangle with the height and width of the cropped image that you want, and then the viewbox is defined as "x y width height" (in my example it is "10 20 100 200") and remember that x starts at 0 for left and is positive moving right, and y starts at 0 for the top and is positive moving down.
<Image Source="{Binding Image}"></Image>
<Rectangle Height="200" Width="100">
<Rectangle.Fill>
<ImageBrush ViewboxUnits="Absolute" Viewbox="10,20,100,200" ImageSource="{Binding Image}"></ImageBrush>
</Rectangle.Fill>
</Rectangle>
Note that the binding for the Image and the ImageBrush are the same, so you only need to define Image once, and it is used across both elements.

Stretch image to fill available width / height (separately)

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.

WP7 development, change size of Image control from the code

I am developing picture viewer application and I want to add new function to it.
Till this time, I have fixed size of Image control in the XAML
Height="422" Width="444",but I want to use all possible space on the page and it is Width="447" Height="585"
<StackPanel Height="422" Width="444">
<Image Height="414" HorizontalAlignment="Center" Margin="9,6,0,0" Name="image2" Stretch="Uniform" VerticalAlignment="Center" Width="441" />
</StackPanel>
Code behind
var stream = new IsolatedStorageFileStream(path, FileMode.Open, _file);
var image = new BitmapImage();
image.SetSource(stream);
stream.Close();
if (image1 != null) image1.Source = image;
So, my question is:
How I can set the size of the Image control from the code behind, so the picture will fit to the Width="447" Height="585" size, I have both portrait and landscape oriented pictures?
I need to have portrait and landscape orientation support, so when orientation is change I would like to picture fit to new size Width="585" Height="447", how I can manage that? (I guess if I will find solution to the first, than only think I need is right event to handle this) Similar to this (http://stackoverflow.com/questions/6857142/handling-size-of-image-after-orientation-change-wp7), but I need to see some code t in order to understand.
Please, post some code or link to the tutorial, in order to prevent “classic” dialog where one person now how to do it and think it is simple and other person have now idea how it work.
You can directly change the size of image control through it's Width and Height properties.
image2.Width = "447";
image2.Height = 585;
If you want to fit in your picture in the Image Control properly then you can use property Stretch
image2.Stretch = Stretch.UnifromToFill;
For handling the orientation change handle the OrientationChanged event of your page and do the image manipulation inside it
Try this one,
when change the orientation then the following event is reaised.
private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if (this.Orientation == PageOrientation.Portrait)
{
optionsup.VerticalOffset = 447;
optionsup.HorizontalOffset = 585;
}
else
{
optionsup.VerticalOffset = 585;
optionsup.HorizontalOffset = 447;
}
}
initially orientation is PortraitUp then
optionsup.VerticalOffset = 447;
optionsup.HorizontalOffset = 585;
I poor in english, if any mistakes dont mind.
Thanks for your answers guys, I did it this way: I have made <Image Height="Auto" Width="Auto" and Name="image1" Stretch="UniformToFill"/> So, the Silverlight will do all job for me.

Categories