Using Vector images as an image source. WPF , C# - c#

i'm working on a project including loads of images. the thing is, like the title says, i have to convert all my vector images to png before i can use them as a image source.
I have vector images created in illustrator. I have them in the .ai project file , how do i go from here ?
My goal is to be able to do this :
<Image Width="70" Height="70" Source="MyVectorImage"/>

If you want to get the ImageSource from a geometry path image into your cs file, you can put the drawingImage into a resource file: Icons.xaml:
<DrawingImage x:Key="hazelnut">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<GeometryGroup>
<PathGeometry Figures="M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z ">
<PathGeometry.Transform>
<TransformGroup>
<ScaleTransform
CenterX="23"
CenterY="20"
ScaleX="0.45"
ScaleY="0.45" />
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
And add in you App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/Icons.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
And use it in your cs file like:
ImageSource image = ResourcePathToImageSource("hazelnut");
private ImageSource ResourcePathToImageSource(string resourcesName)
{
return (DrawingImage)Application.Current.TryFindResource(resourcesName);
}

You can use a DrawingImage as the Image's Source. DrawingImage uses a Geometry (i.e. vector graphics) instead of a bitmap.
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Thickness="2" Brush="Black"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="100,100,100,100"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
You can of course also bind the Source property to a view model property of type ImageSource, which contains a DrawingImage that you would create from your original vector data.

Related

How to reuse a static GeometryDrawing in a DrawingImage using xaml

If I define in app.xaml a GeometryDrawing like this:
<GeometryDrawing x:Key="ReuseThis"
Pen="..."
Brush="..."
Geometry="..."/>
How can I then use it later in a DrawingImage like this:
<DrawingImage x:Key="FullImage">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing reuse it here somehow"{StaticResource ReuseThis}"/>
<Geometrydrawing ...>
<Geometrydrawing ...>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
I'm trying to avoid copying and pasting that GeometryDrawing in a bunch of DrawingImages I have.
Thanks
You can use the StaticResource Markup Extension in XAML Object Element Syntax:
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<StaticResource ResourceKey="ReuseThis"/>
<GeometryDrawing .../>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>

WPF pixel gridlines

I'm trying to draw a grid on my canvas in which:
The lines are always one pixel thick
The size of the square tile are expressed in pixel or in other words the distance between each horizontal and vertical lines is in pixels and maybe binded to the code behind so that I can change it at run time.
This is my first attempt, but maybe I'm using the wrong controls.
<Canvas Panel.ZIndex="0" x:Name="TileCanvas">
<Grid Panel.ZIndex="5">
<Rectangle Width="{Binding ElementName=TileCanvas, Path=ActualWidth}" Height="{Binding ElementName=TileCanvas, Path=ActualHeight}"
Stroke="Black" StrokeThickness="0">
<Rectangle.Fill>
<DrawingBrush ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Viewport>
<MultiBinding Converter="{StaticResource RectConverter}">
<...>
</MultiBinding>
</DrawingBrush.Viewport>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</DrawingGroup>
</DrawingBrush.Drawing>
<DrawingBrush.Transform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</DrawingBrush.Transform>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
This solution allows me to vary the size of each tile, but:
I didn't find the way to fix the line thickness to one pixel
When I change the DrawingBrush.Viewport with the converter I do enlarge the tile (Great!) but the thickness of the lines increase (boo).
I had a very similar problem.
You can use a single geometry and if you want to avoid thickness increase\decrease you have to express the thickness in terms of the tile width by a ratio like thickness = 1/tileWidth. If you change that size of your tile with a WPF control you can use a converter to update the thickness accordingly.
<GeometryDrawing Geometry="M10,0 L10,10 0,10 10,10 10,0Z" Brush="Green" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<GeometryDrawing.Pen>
<Pen Thickness="{Binding ElementName=[TILE SIZE CONTROL VAL], Converter={StaticResource RatioConverter}}"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (1 / (double)value);
}

Best way to use a vector image in Viewport3D?

I was able to display a vector image with standard WPF like this.
<Image >
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="#8F8E8F" Thickness="1" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<LineGeometry StartPoint="0,0" EndPoint="0,10"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
Unfortunately I was not able to do the same inside a Viewport3D element.
I created a VisualBrush from the Image and added it to the DiffuseMaterial of my 3D Model.
I also tried it via a DrawingBrush. Unfortunately the vector image gets renderd to a standard bitmap at some point of the pre-render processed. (that is what i think).
Is it even possible to display a vector image inside a Viewport3D?
Thank you for help in advance.

Binding to Generic UI Element / XAML Interface

I have a DrawingImage that I use as a Vector image placeholder.
Further on, there are styles that take that respective DrawingImage and use it as an image in my UserControl custom button.
So far everything was fine, but I just came to realize that my current approach has caused my DrawingImages to be non-reusable, since they have their Brush property hard-bound to the control, they are used in, as follows:
<DrawingImage x:Key="addIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Path=ImageBrush, ElementName=addButton}" Geometry="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z" />
<GeometryDrawing Brush="{Binding Path=ImageBrush, ElementName=addButton}" Geometry="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
Now, I was trying to come up with a way to have them bound not directly to the Element, but to some kind of a generic Element (similairly as interfaces work) so that the code would be sure that anything that is bound to it, has got the Brush Dependency property.
So far, i failed to find it.
I have also tried by searching through an ancestor, still no luck.
Is there a more or less common practice to binding to unknown Elements, that have certain dependency properties, without exposing them directly?
In fact, there is no way to do directly what you ask. The reason is that when you define DrawingImage as a resource and then use it as a source for image, then no copies of the resource are created, but instead of this each image looks at the same resource. Therefore, the DrawingImage can not have a parent in the visual tree at all, so there is just no control to bind to.
There are two options here. One is to use a Geometry as a resource, not a DrawingImage. Then you can create some DrawingImage resources referencing to this Geometry and using different colors. Or do not use DrawingImage at all, but use the Geometry directly (for example, through the Path). Actually, there are so many ways how to use and combine Geometry resources. I give just few examples here:
<Window x:Class="FlipControlApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<PathGeometry x:Key="addIconGeometry" Figures="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z"/>
<PathGeometry x:Key="iconBorderGeometry" Figures="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z"/>
<GeometryGroup x:Key="addIconWithBorderGeometry">
<StaticResource ResourceKey="iconBorderGeometry"/>
<StaticResource ResourceKey="addIconGeometry"/>
</GeometryGroup>
<DrawingImage x:Key="addIconBlack">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Black" Geometry="{StaticResource addIconWithBorderGeometry}" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
<UniformGrid Columns="2">
<Button Name="addButton0" Width="100" Height="100">
<Image Source="{StaticResource addIconBlack}"/>
</Button>
<Button Width="100" Height="100" Foreground="Blue">
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="{StaticResource addIconGeometry}" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Button>
<Button Width="100" Height="100" Foreground="Green">
<Grid>
<Path Data="{StaticResource iconBorderGeometry}" Fill="Pink" Stretch="Uniform"/>
<Path Data="{StaticResource addIconGeometry}" Fill="Purple" Stretch="Uniform" Margin="15"/>
</Grid>
</Button>
<Button x:Name="addBtn" Width="100" Height="100" Foreground="Green">
<Path Fill="{Binding Foreground, ElementName=addBtn}" Stretch="Uniform">
<Path.Data>
<CombinedGeometry Geometry1="{StaticResource iconBorderGeometry}" Geometry2="{StaticResource addIconGeometry}"/>
</Path.Data>
</Path>
</Button>
</UniformGrid>
</Window>
Another option is to use whole Image as resource with a Brush binding to the some ancestors property. But in this case, it is necessary to use the attribute x:Shared and hence the resource must be declared in the compiled resource dictionary (for details see x:Shared).
Create resource:
<ResourceDictionary>
<Image x:Key="addIconImage2" x:Shared="False">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z" />
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</ResourceDictionary>
Then use it:
<Button Name="addButton3" Width="100" Height="100"
Content="{StaticResource addIconImage}" Foreground="Red"/>
<Button Name="addButton4" Width="100" Height="100"
Content="{StaticResource addIconImage}" Foreground="Green"/>
Each time you reference to it, new copy will be created.
But the first way is more flexible.

How to use DrawingBrush as Window.Icon?

I have a DLL that has a ResourceDictionary containing a XAML image:
<DrawingBrush x:Key="imgFoo" ViewboxUnits="Absolute" Viewbox="0,0,128,128">
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square" EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M 56.5625 ... 64.03125 45.46875 z"
FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
Is it possible to use this DrawingBrush as Window.Icon?
using StaticResource or DynamicResource doesn't work:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="{DynamicResource imgFoo}">
The only thing I found is using Window.Resources like this:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="{DynamicResource imgFoo}">
<Window.Resources>
<DrawingImage x:Key="imgFoo">
<DrawingImage.Drawing>
<GeometryDrawing Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square"
EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M 56.5625 ... 64.03125 45.46875 z"
FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
But this uses only a part of the DrawingBrush from the DLL file and creates duplicate XAML code.
Any suggestions on how I could use that DrawingBrush directly?
You could split the resource declaration into two parts and declare the GeometryDrawing and the DrawingBrush separately:
<GeometryDrawing x:Key="imgFooDrawing" Brush="#FF111111">
<GeometryDrawing.Pen>
<Pen LineJoin="Miter" StartLineCap="Square" EndLineCap="Square"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M10,64 L64,10 118,64 64,118Z" FillRule="NonZero"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<DrawingBrush x:Key="imgFoo" ViewboxUnits="Absolute" Viewbox="0,0,128,128"
Drawing="{StaticResource imgFooDrawing}">
</DrawingBrush>
Now you could directly reuse the GeometryDrawing in a DrawingImage that is used as the Window's Icon:
<Window.Icon>
<DrawingImage Drawing="{DynamicResource imgFooDrawing}"/>
</Window.Icon>
In case you can't change the Resource DLL, you could bind the DrawingImage's Drawing property to the Drawing property of the DrawingBrush.
This would however require an ugly workaround because you can't use a DynamicResource as binding source. You may set the Tag property of the Window to the DrawingBrush, and then create a RelativeSource/FindAncestor binding:
<Window ... Tag="{DynamicResource imgFoo}">
<Window.Icon>
<DrawingImage Drawing="{Binding Tag.Drawing,
RelativeSource={RelativeSource AncestorType=Window}}"/>
</Window.Icon>
</Window>

Categories