Why does this image upscale from its original size? - wpf

I am having an issue with an image scaling up slightly, seemingly without explanation. The image is a 16x16 png icon but seems to be scaling slightly larger to roughly 21x21. In my application there are a dozen or so buttons on a toolbar with 16x16 png icons in them but one of them scales up so said button ends up larger than all the rest. The image in question is CollapseAll_16x.png from the Visual Studio 2019 Image Library which can be downloaded from Microsoft's website. The rest of the images are all either from the library as well or custom 16x16 images I've designed. The CollapseAll image has not been altered in any way and is the only image that is affected by this.
Below is some simplified code that shows the issue I'm describing. All images are from the VS2019 Image Library. Borders and ActualWidth added for reference. The toolbar and button set up is irrelevant to the issue as it is still happening in this example stripped-down to just the images in a stackpanel.
<StackPanel>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</StackPanel.Resources>
<Border>
<Image x:Name="collapseAll" Source="Icons/CollapseAll_16x.png"/>
</Border>
<Border>
<Image x:Name="zoomIn" Source="Icons/ZoomIn_16x.png"/>
</Border>
<Border>
<Image x:Name="zoomOut" Source="Icons/ZoomOut_16x.png"/>
</Border>
<Border>
<Image x:Name="popOut" Source="Icons/PopOut_16x.png"/>
</Border>
<Border>
<Image x:Name="close" Source="Icons/Close_16x.png"/>
</Border>
</StackPanel>
<TextBlock Text="{Binding ActualWidth, ElementName=collapseAll}"/>
<TextBlock Text="{Binding ActualWidth, ElementName=zoomIn}"/>
<TextBlock Text="{Binding ActualWidth, ElementName=zoomOut}"/>
<TextBlock Text="{Binding ActualWidth, ElementName=popOut}"/>
<TextBlock Text="{Binding ActualWidth, ElementName=close}"/>
</StackPanel>
This is the result:
I am able to prevent this unwanted scaling by adding MaxWidth=16 and/or MaxHeight=16 to the collapseAll image element. In that case all the images display the same.
So my question isn't so much how to fix this but, rather, why this particular image refuses to display at its original size.

PNG images are usually set to a default density of 96ppi to match traditional screen pixels per inch at nominal 96 DPI
Most PNGs thus contain such flags for applications to recognise and use if they use a default value. So the "Zoomin" Etc have such a marker. (0.17 inches square)
HOWEVER save this copy pasted from clipboard and it should report as null DPI and have a size of 0.5644 x 0.5644 cm; 0.22 x 0.22 inches!!
A common alternative is PDF or Jpeg default resolution of 72 pixels per inch which is 1.33% larger. And that CollapseAll icon has such a marker. (0.22 inches square) So it is "displaying" at its natural scale !
So unless ppi or DPI is defined one will be larger in the ratio of 3:4 pixels per inch. (75% or 133.3%)
there are 29 such files
AddPackage_16x.png BackgroundWorker_16x.png
CallFrom_16x.png Close_12x_16x.png
CloudDownload_16x.png CloudUpload_16x.png
CollapseAll_16x.png CPPMarkupXML_16x.png
DatabaseSchema_16x.png DeleteAllRows_16x.png
ExpandAll_16x.png ExtractConstant_16x.png
LayerMask_16x.png LinesToFile_16x.png
OpenProject_16x.png Output_16x.png
RFile_16x.png RInteractiveWindow_16x.png
R_16x.png R_ProjectSENode_16x.png
ShowCallersGraph_16x.png SortAscending_16x.png
SortDescendingFilter_16x.png StatusSuppressed_16x.png
StatusUpdate_16x.png SyncArrow_inverse_16x.png
Synchronize_16x.png Synchronize_grey_16x.png
ToggleButton_16x.png
29 File(s) 10,420 bytes

Related

RadBarCodeQr - Maintain the same distance from the image according to the image size

I have control of RadBarCodeQR and I want that it maintains an equal spacing from its parent for any text bound to it.
When RadBarCodeQR is bound to an empty string:
And when RadBarCodeQRbound to "ssssssssssssssssss":
My Code:
<Grid>
<StackPanel VerticalAlignment="Center">
<TextBox
Text="{Binding QrCode, UpdateSourceTrigger=PropertyChanged}"
Width="300"
Height="30"
Margin="20"/>
<telerik:RadBarcodeQR
Height="100"
Width="100"
Text="{Binding QrCode, UpdateSourceTrigger=PropertyChanged}"
Foreground="Black"
UseLayoutRounding="True">
<telerik:RadBarcodeQR.Style>
<Style TargetType="telerik:RadBarcodeQR">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="telerik:RadBarcodeQR">
<Grid
x:Name="PART_RadBarcodeQR"
Background="White"
Margin="15">
<Image
x:Name="ImageQrCode"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</telerik:RadBarcodeQR.Style>
</telerik:RadBarcodeQR>
</StackPanel>
</Grid>
I do not think that it is possible to maintain an equal spacing around the control. The QR code comes in different sizes and has a mandatory margin as stated in the documentation. This is given the by specification and not maintaining it can lead to unreadable QR codes.
There are a total of 40 versions available in the QRCode, from 21 by 21 modules to 177 by 177 modules, increasing in steps of 4 modules per side. Naturally, higher versions are used to encode larger amounts of data: [...]
Additionally, around each QR code, there is an obligatory 4-modules-wide white space area: [...]
The control will render an image of the QR code, as you can see from the control template. This image contains a white margin varying in thickness depending on the QR code size. The Margin and Padding do not affect this. That being said, your change to the control template - setting Margin="15" - breaks the default drawing behavior that at least draws the margin required by the specification.
Consequently, you should remove your custom control template. Layout rounding should not be necessary, as the control is optimized to display a QR code anyway. The UpdateSourceTrigger is only needed for controls that actually change the source property, this control does not, it only reads the value.
<telerik:RadBarcodeQR
Text="{Binding QrCode}"
Foreground="Black"
Background="White"
Height="100"
Width="100"/>
You seem to be using the old RadBarcodeQR which is deprecated. You can use RadBarcode instead:
<telerik:RadBarcode Value="{Binding QrCode}"
Height="100"
Width="100">
<telerik:RadBarcode.Symbology>
<telerik:QRCode />
</telerik:RadBarcode.Symbology>
</telerik:RadBarcode>
If you want to have an additional fixed-size space, you can add a Padding to it.

ZIndex for one canvas over an adjacent canvas

I'm trying to render a row of interlocking arrows, like this:
Each arrow represents a step in a workflow, and the color of each arrow is determined by its step's position in the workflow. While the example above has 3 colors (before, current, after), so far I've implemented only 2 colors (before/current, after) and that's fine for the purposes of this question. I've got an IMultiValueConverter to handle those colors.
The workflow steps are represented as a StepStruct which has a Step property (set manually, more on this later), and a VmFunc property which returns the view model for that step. My current IMultiValueConverter uses the index of the step in the list of steps, rather than the actual Step value.
My problem is the arrows. Initially I have each step as a canvas rendering a simple rectangle, and that's easy to get working. But to make the arrow, I've used a PolyLine that I want to position at the right of the canvas, indeed starting at the right of one canvas and overflowing into the next.
I can't get the Panel.ZIndex to work in such a way that a canvas's arrow is visible overflowing into its right-hand neighbor.
My code is pasted below. Of note:
I've bound the Polyline's Panel.Zindex (which I've read affects its parent canvas's z-index) to the StepStruct's Step property, and I've set the Step values so that each step's value is less than the value of the step to its left, which should show left steps over the right step.
I've commented a line setting the Canvas.Left property of each PolyLine. When I uncomment this line (and move it into place), the Polyline indeed moves over to the right side of the canvas, but it's invisible, which I imagine is because it's hidden behind the canvas to its right. (I've confirmed this by changing the PolyLine to start with negative x-values, so you can see the part that's not blocked by the neighboring canvas. This is not pictured.)
I've rendered each canvas's Step as text, and those TextBlocks all have an identical z-index (40) so that they're in front of some PolyLines and behind others, which shows that the PolyLine does have its z-index set right, at least within its own canvas.
<Border Grid.Row="0" BorderBrush="{StaticResource BackgroundBlack}" BorderThickness="2">
<!--Progress bar-->
<ItemsControl ItemsSource="{Binding StepViewModels}" Grid.Row="0" x:Name="progressBar">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas Height="24">
<Canvas.Style>
<Style TargetType="Canvas">
<Setter Property="Background" Value="{StaticResource BackgroundDarkGrey}"/>
<Style.Triggers>
<DataTrigger>
<DataTrigger.Binding>
<!-- the binding. this part works so I'm omitting the code -->
</DataTrigger.Binding>
<DataTrigger.Value>True</DataTrigger.Value>
<Setter Property="Background" Value="{StaticResource DisabledGrey}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Canvas.Style>
<Polyline Points="0,-1 20,11 0,25" Stroke="{StaticResource BackgroundBlack}" StrokeThickness="2"
Fill="{Binding Background, RelativeSource={RelativeSource AncestorType=Canvas}}"
Panel.ZIndex="{Binding Step}"
/>
<!--Canvas.Left="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Canvas}}"-->
<TextBlock Text="{Binding Step}" FontWeight="ExtraBlack" Panel.ZIndex="40" Foreground="Pink" FontSize="20" Canvas.Left="8"/>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
The result (with the Canvas.Left still commented)
How do I get the arrows to render at the end of one canvas and atop the next, as desired?
(I could of course keep it this way and make it work but the bindings would be very annoying and complicated, needing to bind each arrow to the color of the previous canvas; or rather do some kind of conversion involving IndexOf - 1)
For ZIndex:
Each item is wrapped by a ContentPresenter, this is done by the ItemContainerGenerator inside this ItemsControl instance.
So you need to edit the container to get a new ZIndex(via a ContentPresenter style and a binding for example).
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Panel.ZIndex" Value="{Binding XXX}" />
</Style>
</ItemsControl.ItemContainerStyle>
For the shape:
I would recommend using a Path control with a predefined shape geometry like:
"M 0,0 L30,0 L34,5 L30,10 L0,10 z"
and have a negative margin at the end like Margin="0,0,-4,0"

TreeView/ScrollView rendering bug with bitmaps?

There is a WPF (.NET 3.5) TreeView, which contains bitmaps.
Nothing special:
<ControlTemplate x:Key="ctrlOutputTree" TargetType="{x:Type vo:OutputTreeView}">
<TreeView x:Name="OutputTree" ItemContainerStyle="{DynamicResource TreeViewItemStyle}"
KeyboardNavigation.TabNavigation="Cycle" SnapsToDevicePixels="True" MouseDown="OutputTree_MouseDown"
Loaded="OutputTree_Loaded" RenderOptions.BitmapScalingMode="NearestNeighbor">
<TreeView.Resources>
<Style TargetType="TreeViewItem">
<EventSetter Event="RequestBringIntoView" Handler="OutputTree_RequestBringIntoView"/>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.Resources>
<TreeViewItem ItemsSource="{Binding Converter={StaticResource featureDiffsSourceCreator},Mode=OneWay}"
IsExpanded="True" Margin="0,4,0,0"
KeyDown="AttrDiffTreeviewItem_KeyDown">
</TreeViewItem>
</TreeView>
</ControlTemplate>
TreeViewItems:
<ControlTemplate x:Key="ImageTemplate">
<Image VerticalAlignment="Top" Margin="3,1,0,0"
RenderOptions.BitmapScalingMode="NearestNeighbor"
RenderOptions.EdgeMode="Aliased"
Stretch="None">
<Image.Source>
<!-- <BitmapImage UriSource="c:\\imageBMP_test.bmp" />-->
<MultiBinding Converter="{StaticResource imageConverter}">
<Binding Path=....
</MultiBinding>
</Image.Source>
</v:Image>
</ControlTemplate>
The bitmaps are generated as BitmapSource in imageConverter (from native control).
System::Drawing::Bitmap^ b = System::Drawing::Image::FromHbitmap((IntPtr)aBmp);
IntPtr hb = b->GetHbitmap();
System::Windows::Media::Imaging::BitmapSource^ bs =
System::Windows::Interop::Imaging::CreateBitmapSourceFromHBitmap(hb,
System::IntPtr::Zero,
Int32Rect(0,0,nWidth,nHeight),
BitmapSizeOptions::FromEmptyOptions());
It displays all fine, but when we scroll the tree, sometimes bitmaps becomes distorted. Mostly close to the bottom. Sometimes we need to resize the tree to happen, but it happens sooner or later.
ItemX is text, and the table next to it is the bitmap.
After this, when it's wrong, if I scroll the tree with the scrollbar-position-thumb, just 1 pixel up/down, it becomes sharp and good again.
But if I scroll with up/down arrows on the scrollbar, bitmaps remain invalid for a few click (then goes away)
If I replace the BitmapSource generation in XAML MultiBinding/imageConverter --> <BitmapImage UriSource="c:\\imageBMP_test.bmp" , then don't experience this issue. (I have to take care the imageBMP_test.bmp to be 24 bits & 96DPI, otherwise also not good)
If I change the BitmapSource generation to read from file (24 or 32bit bmp with 96dpi):
System::Drawing::Bitmap^ b = gcnew System::Drawing::Bitmap("c:\\imageBMP24_96dpi_small.bmp");
IntPtr hb = b->GetHbitmap();
System::Windows::Media::Imaging::BitmapSource^ bs =
System::Windows::Interop::Imaging::CreateBitmapSourceFromHBitmap(hb,
System::IntPtr::Zero,
Int32Rect(0,0,nWidth,nHeight),
BitmapSizeOptions::FromEmptyOptions());
Then after some scrolling, I got this:
Any help, idea would be appreciated.
What I tried:
Checked, generated 'BitmapSource' is 96 DPI.
Saved into file all generated 'BitmapSource' - all were fine, while they were distorted on the screen.
I am out of ideas, seems it's a WPF bug? Or maybe video driver? (nvidia quadro/laptop/win7 64bit)
SO IN SHORT
TreeView displays bitmap loaded from file specified in XAML: OK (very small glitches here also sometimes, but those are acceptable)
TreeView displays bitmap from BitmapSource generated: FAILS sometimes (during scroll)
I found a solution.
Have no clue why it works, but seems to solve the problem:
if in the imageConverter (in a native control) I return BitmapImage^ instead of BitmapSource^, it's ok.
Very strange, but I just create BitmapImage from the BitmapSource, return that, and no problems.
WPF is horrible...

Show different background for transparent buttons

We have a design requirement such that transparent buttons (with white text) are overlayed on a scenic background image. But here's the hard part, and my dilemma...
While the background image should be clear and visible OUTSIDE the image borders, the area INSIDE the buttons (the overlayed area) should be a blurred area of the background image. The idea is to make it easier for users to see the white text inside the button.
I'm a novice in XAML and even more unfamiliar with how to perform such complex styling. I have a starting point for the overlay layout, but this code does not attempt to solve the problem. It's simply a button over an image.
Any ideas or help on how to blur the area under the image?
<Grid Margin="0,0,0,12" Visibility="{Binding SignedIn, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=False}">
<Image Source="backgroundImage.png" Height="136" Stretch="Fill" HorizontalAlignment="Stretch" />
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Button x:Uid="SignInBtn" Content="SIGN IN" Style="{StaticResource TransparentButtonStyle}" HorizontalAlignment="Center" Command="{Binding SignInCommand}" IsEnabled="{Binding LoadingResults, Converter={StaticResource NotBoolConverter}}" />
</StackPanel>
</Grid>
There's no straightforward way to do this in a Windows Phone 8.1 app. Image effects are not supported in either Windows Phone Silverlight or in Windows.UI.Xaml.
The typical and easy solution would be to dim (rather than blur) the image by setting the Button's background to a partially transparent brush.
<Button Background="#7F000000" </Button>
If you want to put a bit more work into it you can crop the area of the bitmap behind the button, run your blur transform on it (take a look at the Lumia Imaging SDK) and then set the new, blurred image to the button.
Consider using Effects.
In addition, see if you can leverage this example:
<Style TargetType="Window">
<Setter Property="Background">
<Setter.Value>
<VisualBrush>
<VisualBrush.Visual>
<Image Source="Images\myImage.png">
<Image.Effect>
<BlurEffect Radius="20"/>
</Image.Effect>
</Image>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
...

wpf histogram fidelity degrades when resized smaller

I've developed a simple Histogram control that shows the distribution of grayscale colors (1 to 256 bins) in a live image. The control renders rectangles in an ItemsControl whose ItemsContainer is a ViewBox. Everything is working fine for the most part, however when I resize the grid column (using a GridSplitter) that is hosting the control the fidelity of my histogram begins to degrade.
Here's a couple shots of the histogram at its initial state, and then when it has been resized horizontally (notice the dark vertical lines in the forest of green rectangles...it gets worse the smaller I go):
Here's the XAML that renders the histogram:
<ItemsControl x:Name="_Histogram" Margin="1,3"
ItemsSource="{Binding HistogramCollection}"
VerticalAlignment="Bottom">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Grid>
<Viewbox Stretch="Fill" MaxHeight="100" >
<ItemsPresenter />
</Viewbox>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle Fill="LimeGreen"
Stretch="Fill"
Height="{Binding Bin}"
MinWidth="1"
StrokeThickness="0"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
RenderOptions.EdgeMode="Aliased"
UseLayoutRounding="True"
MouseEnter="Rectangle_MouseEnter"
MouseLeave="Rectangle_MouseLeave"
/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Any thoughts? My guess is that WPF is throwing out some Visuals in order to evenly distribute the rest.
I've experimented with using a Polygon in lieu of ItemsControl and Rectangles to distribute my bin points and the behavior goes away, however, I need the ability to MouseOver the histogram and show a popup (among other things, e.g. select a range of bins and update properties in my ViewModel). If you know of a way, using the Polygon approach, that I can hover in the green area and determine that I'm over a specific bin I'm definitely open to that.
UPDATE:
Removing RenderOptions.EdgeMode="Aliased" on the Rectangle XAML seems to solve the problem of black line glitches. Though it does render somewhat pale in the Designer (using d:DesignData), but it seems to render fine at runtime. I'm going to hold off on marking as "Answered" until others have had a chance to chime in. I'm really interested in the polygon approach because I get a crisper histogram when resizing to a larger width (the wider I make the histogram, the more pixelated the peaks get, i.e. the peaks are flat because of the width of the rectangle, which presents as a jagged plot instead of smooth curved plot). If only Point had a mouse over handler :D.

Resources