Get the image size right in Controls inside a Ribbon - wpf

I am working on a Windows application using WPF Ribbons. On these ribbons, there are controls with images, which are specified by (Large/Small)ImageSource, just like in this sample:
<Ribbon>
...
<RibbonGroup>
<RibbonToggleButton Name="NotExecutedQCButton" Margin="8,0,8,0"
Command="{Binding FilterNotExecutedCommand}"
IsChecked="{Binding NotExecutedChecked, Mode=TwoWay}"
LargeImageSource="pack://application:,,,/Sensor.UserControls;component/Icons/icons8.com/qc_notExecuted.png"
Label="Not Executed"/>
<RibbonButton Name="AllQCButton" Margin="8,0,8,0"
Command="{Binding FilterAllCommand}"
LargeImageSource="pack://application:,,,/Sensor.UserControls;component/Icons/icons8.com/qc_erase.png"
Label="Remove Filters"/>
</RibbonGroup>
...
Now when I use 48x48 pixel images here, they show up blurry and distorted. Just like here:
Images do not render correctly in WPF ribbon control
When I rescale the images to 32x32, it shows up fine. This is due to the RibbonImageSize having a fixed value which can be found here:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.ribbon.ribbonimagesize?view=netframework-4.8#System_Windows_Controls_Ribbon_RibbonImageSize_Large
According to this doc:
A Small image is typically 16x16 pixels at 96 dpi. A Large image is typically 32x32 pixels at 96 dpi.
Notice the word "typically". When doing some further research, this value seems to depend on the dpi of the monitor being used:
https://learn.microsoft.com/en-us/windows/desktop/windowsribbon/windowsribbon-imageformats
This document states that I need to provide differently scaled versions of the image to support different monitors, like this:
<Command.LargeImages>
<Image Source="res/CutLargeImage32.bmp" Id="116" Symbol="ID_CUT_LARGEIMAGE1" MinDPI="96" />
<Image Source="res/CutLargeImage40.bmp" Id="117" Symbol="ID_CUT_LARGEIMAGE2" MinDPI="120" />
<Image Source="res/CutLargeImage48.bmp" Id="118" Symbol="ID_CUT_LARGEIMAGE3" MinDPI="144" />
<Image Source="res/CutLargeImage64.bmp" Id="119" Symbol="ID_CUT_LARGEIMAGE4" MinDPI="192" />
</Command.LargeImages>
Now where do I put this code in my example? I don't have a Command in my code like in the example, and the RibbonButton or other Ribbon control elements do not have a LargeImages property.
Or better, how can I know for sure these fixed values of 16x16 or 32x32 are always being used? If I can't, how can I provide these values for the ribbon controls in my applications? Right now I'm not interested in having different sizes across monitors and I'm fine with using one hard-coded resolution for all the images (one for small, one for large) on every monitor. But now it seems that when I run my application on a machine with a different monitor, the images might be blurry. Even when I manage to specify images for all these four cases, it will not work on monitors that do not have one of these four specified DPI values.
All I want is to be sure that these images are not blurry, at least on standard modern monitors. How can I achieve this?

Or better, how can I know for sure these fixed values of 16x16 or 32x32 are always being used?
Look in the default ControlTemplate for the control. You'll find it in the System.Windows.Controls.Ribbon.dll assembly which is located in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF.
If you decompile it using a tool such as dokPeek and look at the templates in the themes folder, you will notice that the Image elements that bind to the LargeImageSource property has a fixed width and weight of 32 and that the images that display the SmallImageSource has a fixed widht and heigt of 16.
You probably want to modify the templates if you intend to display images of any other sizes.

Related

Change font size in WPF compatible with Ease of Access functions

I am working on a simple WPF app that needs to be accessible for people with impaired vision.
I am testing my app with the Windows 10 -> Settings -> Ease of Access -> Display -> Make text Bigger slider setting.
I have some section titles (TextBlock) that I want to have a bigger font than the rest of the labels and text in the window. However, if I use the FontSize attribute to make it bigger it is no longer affected by changes to the system text size. Thus, while all other text that hasn't FontSize set gets bigger, the ones that do remain at their fixed size.
Is there a simple way to make some text relatively bigger than the rest while not setting a specific font size value?
Is there a simple way to make some text relatively bigger than the rest while not setting a specific font size value?
I am afraid there is no support for relative font sizes in WPF but you could try to apply a ScaleTransform:
<TextBlock Text="Bigger">
<TextBlock.RenderTransform>
<ScaleTransform ScaleX="1.2" ScaleY="1.2" />
</TextBlock.RenderTransform>
</TextBlock>
This achieved exactly what I wanted. It is not the prettiest, but it works well.
https://github.com/dotnet/wpf/issues/3701

Can't get Silverlight Media Framework SMFPlayer to show film full screen or correct aspect ratio

I am using the latest version of the Silverlight Media Framework on Windows Phone 8. I have got both standard MP4's and DRM encrypted MWV media to play successfully.
However, neither will play to the full extent of the screen.
The standard MP4's play with the correct aspect ratio, but don't fill the available area. Some film do, so I imagine that some have a lower resolution than the phone, so play smaller. It would be good to get even lower resolution films to play to full screen.
The DRM films fill the screen vertically, but are 'squished' horizontally (in a 4:3 aspect ratio). These are supposed to be wide screen movies (!
I have tried a few things, such as setting the play item to the height and width of the player
item.VideoHeight = player.ActualHeight;
item.VideoWidth = player.ActualWidth;
item.VideoStretchMode = Stretch.Uniform;
This didn't work. Nor did setting the following in the player xaml!
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
I am using the simplest implementation in XAML at the moment.
<core:SMFPlayer
Name="player"
IsEnabled="True"
Grid.Row="0"
CaptionsVisibility="Disabled"
VolumeLevel="50"
Visibility="{Binding DisplayError, ConverterParameter=true, Converter={StaticResource BoolToVisibilityConverter}}"
/>
Can someone help? I need to be able to force all media playback to play as full screen as possible while maintaining aspect ratio and not clipping.
Are there any properties of the SMF I can set to get films to play as large as possible and preserve aspect ratios?
You want your containers, not just your video, to have Stretch="Uniform" set. That is, either Grid, SMFPlayer, etc... I'm not sure exactly which element will need to have that, it depends on your XAML.
This should do what you want: fill as much as possible the screen, while retaining aspect ratio, without cropping. There is another mode if you want to 'zoom', ie crop so screen is always filled: Stretch="UniformToFill".

How can I create an opacity mask in wpf that doesn't scale?

Ok, I've created a PNG-24 with transparency. It's basically a grayscale image that uses 'colors' in between black and transparent instead of black and white. I did this so I can use this as the Opacity Mask of a colored rectangle, thus rendering the image in whatever color I want using only a single graphic.
However, for the life of me, I can't get WPF to stop anti-aliasing the da*n image!!
I've set 'SnapesToDevicePixels' on the rectangle to which the brush is applied... I've set the ImageBrush's Scale to 'None'... I've set its ViewPort and the ViewBox to absolute units and sized them exactly to the source image. But no matter what I try, WPF still insists on trying to smooth things out! This is VERY frustrating!!!
So... anyone know how to use an image as an opacity mask but not lose the pixel-precise drawing that we have done? I just want WPF to render the damn thing as we drew it, period!
I have tried to reproduce your problem. Simply like this:
<Rectangle Width="200" Height="200" Fill="Red">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/mask.png"/>
</Rectangle.OpacityMask>
</Rectangle>
mask.png contains a simple diagonal mask, like that half of rectange is visible and other half is 100% transparent.
And recrangle is rendering pixel perfect (and aliased, as you want).
I think, that you may a DPI setting, that is not native to your monitor, and WPF just can`t render images correctly.
GOT IT! It's a layout issue that for some reason, there's no easy way to change. However, there's a value you can set called UseLayoutRounding that fixes it. I just set it at the root level (for this fauxample, a grid...)
<Grid UseLayoutRounding="True">
....
</Grid>
...and BAM! Works like a charm! "Sort of" like a 'SnapsToDevicePixels' but for positioning of elements (i.e. it rounds all layout-related values like left, width, etc. whereas SnapsToDevicePixels snaps the layout to the on-screen pixels when rendering.)
M

Scaling an image with WP7 Silverlight with no smoothing algorithm applied

I have some images (32x32 .png) that I want to display in my Windows Phone 7 application. Right, now, I am able to scale them, etc... I was wondering if there was a way to scale them without any smoothing algorithms applied (so when I double the image size, it creates a blocky image look).
Right now in my XAML I have the following:
<Image Height="64" Width="64" Margin="12,0,9,0" Name="{Binding itemName}"
Stretch="Uniform" VerticalAlignment="Center" Source="{Binding imageName}" />
Where imageName is just a path to the .png images. Is there a simple way to do this in just XAML, or should I be loading the image into a different format to play with it in the code (while keeping the transparency of the png).
Thanks in advance,
-Jeff
Theres currently no way to do this in XAML. The only way to achieve a nearest neighbor scaling without any interpolation (smoothing) is the open source library WriteableBitmapEx.
http://writeablebitmapex.codeplex.com
First load the PNG into a WriteableBitmap, then use the Resize extension method the WriteableBitmapEx provides. Use the NearestNeighbor as value for the last parameter of the method. Then assign the return value of the Resize method to the Source property of your Image control.
You can wrap this functionality in an IValueConverter implementation so you can use it in XAML.

Why everything in WPF is blurry?

Can someone explain why everything in WPF is blurry? Is this something that can be fixed?
The reason for this is the anti-aliasing system which spreads the line over multiple pixels if it doesn't align with physical device pixels.
WPF is resoultion independent. This means you specify the size of an user interface element in inches, not in pixels. A logical unit in WPF is 1/96 of an inch. This scale is chosen, because most screens have a resolution of 96dpi. So in most cases 1 logical unit matches to 1 physical pixel. But if the screen resolution changes, this rule is no longer valid.
All WPF controls provide a property SnapsToDevicePixels. If set to true, the control ensures the all edges are drawn excactly on physical device pixels. But unfortunately this feature is only available on control level.
Source: Draw lines excactly on physical device pixels
Quick Fix:
Use these options on every Container from root to your blurry control
UseLayoutRounding="True"
RenderOptions.BitmapScalingMode="NearestNeighbor"
SnapsToDevicePixels="True"
RenderOptions.ClearTypeHint="Enabled"
Explanation:
UseLayoutRounding=true fixes subpixel layout problems. They often occur because e.g. Effects resize controls to be something between pixels.
RenderOptions.BitmapScalingMode=NearestNeighbor fixes blurry sampling of bitmaps. Bitmaps are used when effects or other techniques are used. When they are reapplied to the container or control they might end up inbetween pixels and therefore interpolate the pixels of the bitmap.
SnapsToDevicePixels="True" fixes vertical and horizontal polygons, lines and rectangles being rendered inbetween pixels
RenderOptions.ClearTypeHint="Enabled" reenables cleartype on text. It is disabled very easily by effects or whenever the renderer does not know the exact background of a text.
You should use it on every Container because sometimes, e.g. by data templates these options are defaulted again for the sub controls.
I spent a couple of hours trying to figure out the cause of the blurriness on custom panels. On these custom panels we are using a drop shadow border effect. The drop shadow was the culprit. It actually causes blurry text if the panels are placed side by side. I don't have a high enough reputation to make a comment so I am answering the question.
UseLayoutRounding="True"
was the fix for my problems as answered by ecreif. although I did not need the other lines of code in his answer, I added them anyways.
The following worked for us when facing similar issue:-
Right Click and open the Properties Window for the executable.
Under "Compatibility" tab, click on "Change High DPI Settings" button then check the "Override High DPI scaling behavior" checkbox at "Application" drop-down selection.
Click on Apply/Ok buttons to save the settings then relaunch app.
P.S.: These settings could be deployed to User system via Windows Registry entry.

Resources