SnapsToDevicePixels doesn't work with images? - c#

I've encountered a problem with bitmap images in WPF. When the image container starts on a position which is not a whole number, the image seems to not respect the value of SnapsToDevicePixels.
Example code:
<Window x:Class="BlurryImage.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="110" Width="200">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Button SnapsToDevicePixels="True">
<Image SnapsToDevicePixels="True" Source="i16.png" Stretch="None"/>
</Button>
<Button SnapsToDevicePixels="True" Margin="10.333333,0,0,0">
<Image SnapsToDevicePixels="True" Source="i16.png" Stretch="None"/>
</Button>
</StackPanel>
</Window>
(Note the value of the left margin: 10.333333.)
Here the image i16.png is a simple 16x16 bitmap in 96 DPI resolution with thin vertical lines: . (My system resolution is 96 DPI, Windows XP, .NET 4)
When I run the program, the first image is sharp, whereas the second one is blurry:
Different sources, including some here on stackoverflow, suggest different workarounds. (For example, these posts: [1], [2] and [3].) I tried the workarounds, and them seem to work. Using UseLayoutRounding="true" on the main window makes both images sharp. Using RenderOptions.BitmapScalingMode="NearestNeighbor" on the image makes it sharp, too.
The question is, why doesn't SnapsToDevicePixels="True" work without workarounds? Is it a bug in WPF or I am using it in a wrong way?

From this blog entry:
SnapsToDevicePixels
WPF anticipated that there would be cases where people wanted to align
with the pixel grid instead of using sub-pixel precision. You can set
the SnapsToDevicePixels property on any UIElement. This will cause us
to try and render to the pixel grid, but there are quite a few cases
that don't work - including images. We will be looking to improve
this in the future.
So it's just a known limitation of what SnapsToDevicePixels can do.

Related

DrawingImage is getting fuzzy and image gets bigger and cut-off when Windows scaling is set to more than 100%, for example 125%

I have an WPF usercontrol which is used in a winforms applications. WPF usercontrol is contained within an ElementHost container.
This WPF usercontrol has some images, button with images, labels, etc.
I have a dictionary with some geometries, the following is one of them.
<Geometry x:Key="hlpGeometry">F0 M22,22z M0,0z M11,22C17.0751,22 22,17.0751 22,11 22,4.92487 17.0751,0 11,0 4.92487,0 0,4.92487 0,11 0,17.0751 4.92487,22 11,22z M12.1901,16.6889L10.2662,16.6889 10.2662,18.6998 12.1901,18.6998 12.1901,16.6889z M8.18758,5.59005C7.40125,6.43439,7.00808,7.55265,7.00808,8.94484L8.72898,8.94484C8.76121,8.10695 8.89334,7.46564 9.12537,7.02091 9.53787,6.2217 10.2823,5.82209 11.3587,5.82209 12.2288,5.82209 12.8508,6.05412 13.2246,6.51818 13.6049,6.98224 13.795,7.53009 13.795,8.16173 13.795,8.61291 13.6661,9.04797 13.4083,9.46691 13.2665,9.70539 13.0796,9.9342 12.8475,10.1533L12.0741,10.9171C11.3329,11.6454 10.8527,12.2932 10.6336,12.8604 10.4144,13.4211 10.3049,14.1623 10.3049,15.084L12.0258,15.084C12.0258,14.2719 12.116,13.6596 12.2965,13.2471 12.4834,12.8281 12.8862,12.319 13.505,11.7195 14.3557,10.8945 14.9197,10.2694 15.1969,9.84396 15.4804,9.41857 15.6222,8.86427 15.6222,8.18107 15.6222,7.05314 15.2387,6.12824 14.4718,5.40636 13.7112,4.67804 12.6961,4.31388 11.4263,4.31388 10.0535,4.31388 8.9739,4.73927 8.18758,5.59005z</Geometry>
<DrawingGroup x:Key="hlpDrawingGroup" ClipGeometry="M0,0 V22 H22 V0 H0 Z">
<GeometryDrawing Brush="#FF00AA2B" Geometry="{StaticResource hlpGeometry}" />
</DrawingGroup>
<DrawingImage x:Key="ico_helpDrawingImage" Drawing="{StaticResource hlpDrawingGroup}" />
I have an WPF Image and I bound above DrawingImage to it using the Source attribute. I bind the source attribute to a property in the view model.
Something like below:
<Image x:Name="MyImage"
Height="24"
Width="24"
VerticalAlignment="Center"
Source="{Binding Path=MyIcon}"/>
It is working fine when windows is scaled to 100% but when scaled to a higher one, let's say, 125%, then the image gets fuzzy.
Also the image look like gets bigger than 24x24 and it is being cut-off when I set a scale greater than 100% (125%).
How can I make image to not get fuzzy and set image to always be the same size 24x24?
You can use the UseLayoutRounding and SnapsToDevicePixels properties.
Set the UseLayoutRounding property to true to prevent blurring caused by anti-aliasing and to tell the layout system to align elements with pixel boundaries.
RenderOptions.BitmapScalingMode is mainly for larger images to be displayed more smoothly, you can choose HighQuality.
Use high quality bitmap scaling, which is slower than LowQuality mode, but produces higher quality output.
You can check this link:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.bitmapscalingmode?redirectedfrom=MSDN&view=windowsdesktop-7.0
Code:
<Image x:Name="img" MouseWheel="img_MouseWheel"
Height="24"
Width="24"
UseLayoutRounding="True"
SnapsToDevicePixels="True"
VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality"
Source="2.jpg"/>
With images I have always found the below to always clear up the fuzzy stuff.
<Image x:Name="MyImage"
Height="24"
Width="24"
RenderOptions.BitmapScalingMode="HighQuality"
VerticalAlignment="Center"
Source="{Binding Path=MyIcon}"/>

How are the semi-transparent blur windows in OSX and W10 Start Menu created?

I'm currently working on a window that focuses on some elements on screen while blurring the rest of the area.
Using common methods like the WindowCompositionAttribute and the others are not suitable for this situation as there are limitations to it and it doesn't meet the standards regarding the intensity of the blur, contrast and colors which should be strict.
What i have managed to solve my problem was building an image stream with a light image encoder to enhance performance but then that wasn't enough. So, i thought of writing a motion detection algorithm to only steam when there's motion, but it still didn't change the performance drops.
What i need is something like those of the native OSX windows and Windows 10 Start Menu, so how are they created and run efficiently without any heavy load on the performance?
To create a new Window from scratch you have to set WindowsStyle to none (AllowTransparency="True" can be set only along with WindowsStyle="None") and from there build the style of the window.
However, you will face several issues if you follow this approach:
-no buttons (minimize, close)
-no support for fullscreen (taskbar issues)
I would suggest you to have a base view and include the other views inside the main view(which has the blur effect).
The blur effect could be obtained easily by doing something like below:
<Grid>
<Grid Margin="5" Background="#FF3782DC">
<!--<Grid.Background>
<Image Source="test.png"></Image>
</Grid.Background>-->
<Grid.Effect>
<BlurEffect Radius="100" />
</Grid.Effect>
</Grid>
<TextBlock
x:Name="textBlock"
Height="61"
Margin="136,82,211,0"
VerticalAlignment="Top"
Text="test"
TextWrapping="Wrap" />
</Grid>
I've set a color for the background, but you could set an image as background and by default it would be blurred (here you should set a binding and every time the view changes, you have to take a snapshot of the screen and set the source of the Image). However you will probably have some performance issues, but with a good encoder (JPEGencoder) it will be fast enough.
Hope that helps you!

Circular CaptureElement camera stream in Windows 10

Wherever you look in Windows 10, there are circles. It's fairly easy to make images circular, but camera is a bit different. Is there a simple XAML way to clip the camera stream in a CaptureElement to make it a circle?
I tried putting it in a border, but CaptureElement doesn't care about its borders. I also tried using the Clip property, but it can only clip to RectangleGeometry.
One way would certainly be to grab CaptureElement frames, transforming them to images (frame by frame) and applying to Image element, and then clipping the image, but it seems like that would have awful performance.
Is there something in the framework to make this really simple, but I'm not seeing it?
Well after seeing that might be the background is always black of the Canvas DirectX the only way I see is:
1.- Clip a rectangle with an ellipse in Inkscape for instance.
2.- Copy to Expression Design and Ctrl-Shift-C (to copy XAML)
3.- Place inside a ViewBox only the path generated
<Grid Width="300" Height="300">
<CaptureElement Name="PreviewControl" Stretch="Uniform" Width="280" Height="280" />
<Viewbox Width="280" Height="280">
<Path Width="813.701" Height="813.701" Canvas.Left="-33.3503" Canvas.Top="-45.3503" Stretch="Fill" Fill="#FF800080" Data="F1 M -33.3503,-45.3503L -33.3503,768.35L 780.35,768.35L 780.35,-45.3503L -33.3503,-45.3503 Z M 373.54,158.095C 485.863,158.095 576.985,249.137 576.985,361.54C 576.985,473.863 485.863,564.985 373.54,564.985C 261.137,564.985 170.095,473.863 170.095,361.54C 170.095,249.137 261.137,158.095 373.54,158.095 Z "/>
</Viewbox>
</Grid>
With that you can place an image in the path or a solid color, that's the only way I see to do it. Hope it helps

Grid tilt effect like Windows 8 Start Screen

I'm trying to create a tile in WPF that looks like the tiles of the Windows 8 Start screen.
Actually, the problem is that I don't know how to make the tilt effect of the Windows 8 tiles ( the click effect ).
I tried different transformations such as matrix transofmration, but this is not what I want.
Explanation in image :
Default style:
Here is my code
<Grid >
<Grid.LayoutTransform>
<MatrixTransform>
<MatrixTransform.Matrix >
<Matrix OffsetX="5" OffsetY="5" M11="1" M12="0.1"></Matrix></MatrixTransform.Matrix>
</MatrixTransform>
</Grid.LayoutTransform>
<Grid.Background>
<ImageBrush ImageSource="/MaCollectivitéWPF;component/src/Img/Home/Porte Document-petite.jpg" Stretch="UniformToFill" >
</ImageBrush>
</Grid.Background>
It's almost what I want but I only want the bottom to be tilted.
I've take a look at the 3D controls but I think it's to complicated for what I'm looking for.
Is there a solution with Layout Transformation I would not have seen yet ?
I think you want to pinch Greg Schechter's Planerator for tilting.
Your use case is exactly the one in the article, so I doubt you'd need to change anything. I've not tried it myself, but it seems to reduce tilting the plane to fairly easy xaml. Worth a look at least.
<pl:Planerator RotationY="35">
<StackPanel Orientation="Horizontal" ... >
<StackPanel>
<Label FontSize="24" Content=" " Foreground="#FF000000"/>
<Border ... >
<MediaElement x:Name="myMediaElement" />
</Border>
</StackPanel>
<ListBox ... />
</StackPanel>
</pl:Planerator>

Tint a partially transparent image in WPF

How can I tint/colorize an image in WPF (using MVVM) without sacrificing performance? A purely XAML solution would be ideal, as modifying bitmaps in the code will cause performance loss with lots of changing images. The image is made up of more than simple shapes, so it is not possible using a path.
Unlike WinForms/GDI+, WPF does not seem to contain any easy ways to colorize/tint an image as it is being rendered. Two ideas for accomplishing this are, using a shader, or overlaying a colored rectangle over the image.
I decided to try the rectangle route and found that it works. Basically, all you need to do is overlay a colored rectangle over your image, and use an OpacityMask to restrict the color fill to a certain area. OpacityMask is primarily used with paths, but it can take any kind of brush, including an ImageBrush. This means you can use your image as a "stencil" for the colored fill.
Example: (Taken from my application where a user can "highlight" a section of a map, the actual image looks like this)
Before Overlay & Mask
After Overlay & Mask
Here is all of the required XAML for this:
<Image
Source="{Binding MyImage}"
Width="150"
Height="150" />
<Rectangle Width="150" Height="150">
<Rectangle.Fill>
<SolidColorBrush Color="{Binding Color}"/>
</Rectangle.Fill>
<Rectangle.OpacityMask>
<ImageBrush ImageSource="{Binding MyImage}"/>
</Rectangle.OpacityMask>
</Rectangle>
To bind the color to a brush as I did, use a ColorToBrushConverter.

Categories