Scaling an image with WP7 Silverlight with no smoothing algorithm applied - silverlight

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.

Related

How can I use SVG image format use as WPF image source

I want to use a SVG image format as an button image because I want these images is shown with high quality so I have decided to use SVG format.
I have searched about it and There are some people that say SVG format can be used as WPF image source.
But when I use SVG image Like this:
<Image Source="Images/hard.svg"/>
I have error.
Absolutely Microsoft website says I can use SVG file as Image source.
https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.media.imaging.svgimagesource?view=winrt-19041
How can I use SVG image format as my WPF image souse?
You have to convert svg to xaml using this library https://github.com/BerndK/SvgToXaml
Sample output:
<DrawingImage x:Key="ic_close">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="Red"
Geometry="F0 M24,24z M0,0z M5.21723,16.4509C4.64003,17.0905 4.68203,17.8189 5.21723,18.3421 5.75123,18.8653 6.65362,18.8329 7.15522,18.3421 7.52928,17.977 10.3498,15.0233 11.7599,13.5448 13.1706,15.0243 15.9893,17.977 16.3633,18.3402 16.8649,18.8298 17.7673,18.8634 18.3013,18.3402 18.8365,17.8206 18.8785,17.091 18.3013,16.4514L13.8049,11.7618 18.3013,7.07225C18.8785,6.43265 18.8365,5.70425 18.3013,5.18105 17.7673,4.65785 16.8649,4.69025 16.3633,5.18105 15.9892,5.54616 13.1687,8.49985 11.7585,9.97833 10.3479,8.4988 7.52916,5.54607 7.15523,5.18287 6.65363,4.69327 5.75123,4.65967 5.21723,5.18287 4.68203,5.70247 4.64003,6.43207 5.21723,7.07167L9.71363,11.7613 5.21723,16.4509z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
Sample usage:
<Image Width="14"
Height="14"
Source="{StaticResource ic_close}" />
If you look at the namespace of that page you linked, you will see:
Windows.UI.Xaml.Media.Imaging
Meaning this is uwp rather than wpf.
You could use SharpVectors
https://github.com/ElinamLLC/SharpVectors
Or you could manually extract the path or paths from in that svg and use those in wpf. Since this is a manual conversion that might not be attractive if there are a number of svg you wish to use or appropriate if they are somehow dynamic.
Another option to consider is xaml islands.
You could host a uwp image control in a xaml island
https://blogs.windows.com/windowsdeveloper/2018/11/02/xaml-islands-a-deep-dive-part-1/#:~:text=XAML%20Islands%20is%20a%20technology,Windows%20Forms%20and%20WPF%20technologies.
Note that this introduces a dependency on win 10 creators edition or later.
WPF renders vector based but cannot render SVG files directly. You would have to use a vector based image processing application to convert the SVG to XAML.
Generally, the XAML obtained from the exported SVG usually consists of Path or Geometry elements, which you wrap into a Viewbox for scaling.
Adobe Illustrator (not free, trial available) yields the best results. You use it to convert the SVG image to .ai file and then Blend or a plug-in to export the .ai file as XAML.
AB4D (not free, trial available) is another application which also outputs very good results and allows to export directly to XAML.
InkScape is free and works too, but the results are not very good and most of the time require manual post-processing. Complex graphics never look good out of the box.
There are more tools like SvgToXaml, but I don't remember the quality.

Get the image size right in Controls inside a Ribbon

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.

How can I render a monochrome bitmap in color in WPF?

Back in Win32 days, if I had a monochromatic bitmap, which is for all intents and purposes just a bitmap mask, I could render that bitmap onto a DeviceContext. What would happen is every pixel where there was a '0' it rendered as transparent, and every pixel where there was a '1' it rendered in the currently selected forecolor. This was very handy.
However, after a few weeks of searching, I haven't seen anything similar in WPF.
Now I was about to just roll my own MonochromeBitmapImage class, but thought if anyone would know another way to do this, it would be you all, the S.O. users, so there's my question... how, in WPF, can I render a monochrome bitmap with one value being a specificed color and the other value being transparent?
A pretty similar feature is OpacityMask for UIElement. It will display the parts that isn't transparent in the OpacityMask. It can be used with
Brushes - SolidColorBrush etc
Visuals - VisualBrush
Images - ImageBrush
etc
Here is an example with a Button using an ImageBrush
<Button Content="Opacity Mask">
<Button.OpacityMask>
<ImageBrush ImageSource="C:\OpacityRect.png"/>
</Button.OpacityMask>
</Button>
It depends if you need to use monochrome bitmaps or you just want to be able to recolor the image. If you can use any image format I would use png with alpha then you can use the image as an OpacityMask, no code necessary. By using the image as an OpacityMask you can easily change the colour, use a gradient or an ImageBrush.
<Rectangle Fill="Blue">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="..." />
</Rectangle.OpacityMask>
</Rectangle>
If you need to use 1-bit bitmaps it's quite simple to convert them to an indexed format with a custom palette. You could set the colour you want in the palette or just choose anything and use it as an OpacityMask. FormatConvertedBitmap seems to need a different format just a different palette had no effect.
public static FormatConvertedBitmap Recolor(BitmapImage b, Color c)
{
return new FormatConvertedBitmap(b, PixelFormats.Indexed2, new BitmapPalette(new List<Color>() { Colors.Transparent, c }), 0);
}
Another option would be a PixelShader it's a bit overkill for this kind of thing but for more complex manipulations they useful.

How to extend WPF hit testing zone for a Path object

Wpf hit testing is pretty good but the only method I found to extend the hit zone is to put a transparent padding area around your object. I can't find any method to add a transparent area arround a Path object. The path is very thin and I would like to enable hit testing if the user clicks near the path. I can't find any method to extend the path object with a transparent area like the image below :
alt text http://img175.imageshack.us/img175/6741/linepadding.png
I tried to used a partially transparent stroke brush but I ran into the problem described here : How can I draw a "soft" line in WPF (presumably using a LinearGradientBrush)?
I also tried to put an adorner over my line but because of WPF anti-aliasing algorithms, the position is way off when I zoom in my canvas and interfere with other objects hit-testing in a bad way.
Any suggestion to extend the hit testing zone would be highly appreciated.
Thanks,
Kumar
Path.Data is a geometry object. The Geometry class has several methods that can help you hit test with tolerance:
GetFlattenedPathGeometry(Double, ToleranceType)
GetOutlinedPathGeometry(Double, ToleranceType)
GetRenderBounds(Pen, Double, ToleranceType)
I think GetRenderBounds will work best for you.
Once you have the geometry (plus a little width) you can call
geometry.FillContains(Point, Double, ToleranceType)
or
geometry.StrokeContains(Pen, Point, Double, ToleranceType)
Out of all of that you should tune the desired hit from your hit test;
You can wrap the Path inside a transparent Border.
In WPF you can create another path with its geometry databound to the first (using Element Binding), but with transparent brush and increased thickness.
Something more or less like this:
<Path x:Name="backPath" Data="{Binding Data, ElementName=mainPath}" StrokeThickness="10" Stroke="Transparent"/>
<Path x:Name="mainPath" Data="{Binding DataFromViewModel}" StrokeThickness="1" Stroke="Red"/>
Note that the main path comes after in XAML, so that it is rendered on top.

In WPF, What is the best way to create toolbar buttons so that the images are properly scaled?

Specifically, I'm looking to use the 16*16 32-bit png images included with the VS2008ImageLibrary. I've tried manually setting the Height and Width attributes of the image, adjusting margins and padding, adjusting Stretch and RenderOptions. My attempts to create toolbar buttons have all led to either Improper Scaling (blurry icons), the bottom row of pixels on the icon being truncated, or the toolbar button being improperly sized - not to mention the disappearing icons already mentioned Here. Has anyone found the best way to make standard, VisualStudio/WinForms-style toolbar buttons that display properly in WPF?
First, change the image resolution to 96DPI, this can done with the free Paint.net ( http://www.getpaint.net ) by opening the file, Selecting Image->Canvas Size from the menu and adjusting the "resolution" to 96 and saving.
If this doesn't help you can then use the solution I wrote about in my blog here http://www.nbdtech.com/blog/archive/2008/11/20/blurred-images-in-wpf.aspx
Best way would be using Vector graphics instead of png. I know the following is not exactly what you asked for, but imho there is no way for better looking icons. Also it would help you get rid off margins and paddings. (Ok, if you want to use photos you're screwed)
Bad News is you probably need to repaint all your icons. You could do this using MS Expression Blend(it's capable to save painted Images as .xaml) or you make them on our own with a texteditor.
I prefer the Border.Background instead of the Image.Source for placing the icon, this allows me to put text over the image. This would look samething like that:
<Window.Resources>
<ResourceDictionary Source="Resources/Icons.xaml"/>
</Window.Resources>
<!--
...
-->
<Button>
<Border Background="{StaticResource IconName}" Height="16" Width="16" />
</Button>
The best workaround I can come up with is this:
<Image x:Key="TB_NewIcon" Source="Toolbar Images/NewDocumentHS.png" Height="16" Width="16" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
...
<Button Command="ApplicationCommands.New" Content="{StaticResource TB_NewIcon}" Padding="2,2,2,1"/>
Or Alternatively:
<BitmapImage x:Key="TB_NewIcon" UriSource="Toolbar Images\NewDocumentHS.png"/>
...
<Button Command="ApplicationCommands.New" Padding="2,2,2,1">
<Image Source="{StaticResource TB_NewIcon}" Height="16" Width="16" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Button>
For the Button Tag, the Padding attribute is needed to ensure that the image isn't truncated at a height of 15 pixels, and that the button isn't resized to fit the image. Alternatively, we could specify Padding="1", but then we must manually set Height="21" and Width="22" to ensure the button isn't resized to fit the image
On the Image Tab, the Height and Width are needed to ensure that the image isn't stretched. SnapsToDevicePixels and RenderOptions.BitMapScalingMode are both needed to ensure that there is no blurring. I can't promise that this will work nicely for all resolutions.
Note:
For the NewDocumentHS.png icon, the one that causes the most issues,as it takes up the full 16 pixels of height, you may want to adjust the padding to "1,1,3,2", so that the bottom aligns more properly with other icons.
You may want to consider trying a new property available now in WPF4.
Leave the RenderOptions.BitmapScalingMode to HighQuality or just don't declare it.
On your root element (i.e. your main window) add this property: UseLayoutRounding="True".
A property previously only available in Silverlight has now fixed all Bitmap sizing woes. :)
Please Note - a few of the effects layout rounding
can have on exact layout:
width and or height of elements may grow or shrink by at most 1 pixel
placement of an object can move by at most 1 pixel
centered elements can be vertically or horizontally off center by at most
1 pixel
More info found here: http://blogs.msdn.com/text/archive/2009/08/27/layout-rounding.aspx

Resources