Best way to use a vector image in Viewport3D? - c#

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.

Related

Mandatory Use of Setting x:Shared="False" Not Possible

This Question might be Very Similar to Questions such as Error when using x:Shared="False" resources in external assembly in WPF but I have not been able to find a Solution that I can Relate to or rather get an Idea of How to Solve this.
Why I have mentioned Mandatory Use in the title is I have not been able to find an alternative way to solve my problem other than the with the use of Setting X:shared to false.
My problem is that in a particular view that has Icons , for Elements of Similar Type Icons seem to be sharing hence even if there are two or more types the Icon will only be rendered with one Item
This Question is justified in these Stack oveerflow Questions as well
Content Only being shown in a Single element at a given time
WPF: Can use StaticResource only once
I would Really appreciate any help/suggestions to overcome this
A complication is the numerous colours you have there. The trend nowadays is to simpler icons with just a background and foreground. Which you can "just" use one path and geometry for.
Seeing as how this is several shapes and several colours, you could use a DrawingImage.
I did this example in a usercontrol, it's roughly like one of your icons.
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
mc:Ignorable="PresentationOptions"
>
<UserControl.Resources>
<DrawingImage x:Key='icon' PresentationOptions:Freeze="True">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M17,17A5,5,0,0,1,12,22A5,5,0,0,1,7,17C7,15.36,7.79,13.91,9,13L9,5A3,3,0,0,1,12,2A3,3,0,0,1,15,5L15,13C16.21,13.91,17,15.36,17,17 M11,8L11,14.17C9.83,14.58,9,15.69,9,17A3,3,0,0,0,12,20A3,3,0,0,0,15,17C15,15.69,14.17,14.58,13,14.17L13,8 11,8z"
Brush="Wheat"
>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Green"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Geometry="M17,18L12,15.82 7,18 7,5 17,5 M17,3L7,3A2,2,0,0,0,5,5L5,21 12,18 19,21 19,5C19,3.89,18.1,3,17,3z"
Brush="Lavender"
>
<GeometryDrawing.Pen>
<Pen Thickness="1" Brush="Red"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</UserControl.Resources>
<Grid>
<StackPanel>
<Image Width="12" Height="12" Source="{StaticResource icon}"/>
<Image Width="12" Height="12" Source="{StaticResource icon}"/>
</StackPanel>
</Grid>
</UserControl>
I might look at using DataTemplates to create the icons, if for any reason x:Shared is a problem. A DataTemplate instantiates a copy of the content when it's applied, so sharing is a non-issue.
Resource:
<DataTemplate x:Key="FileSystemIcon">
<Canvas Width="12" Height="12">
<Path
Stroke="Black"
Fill="White"
Data="M20,4L4,4A2,2,0,0,0,2,6L2,18A2,2,0,0,0,4,20L20,20A2,2,0,0,0,22,18L22,6A2,2,0,0,0,20,4 M20,18L4,18 4,8 12,13 20,8 20,18 M20,6L12,11 4,6 4,6 20,6 20,6z"
/>
</Canvas>
</DataTemplate>
Usage:
<UserControl ContentTemplate="{StaticResource FileSystemIcon}" />

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);
}

Using Vector images as an image source. WPF , 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.

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>

round robin image rotation what is the best way to do in WPF

I am looking to find the best way to do this in wpf. I already asked this question and got an answer which implement it in opencv. round robin image rotation what is the best way to do in opencv
What is the best way to do this in wpf.
Apparently I can create a writableBitmap and copy the pixels manually, but I don't think it is the best way to do this.
Edit 1
To clarify what I am asking: I like to implement the same algorithm that suggested in this SO question (round robin image rotation what is the best way to do in opencv) using WPF.
What is the best way to do this in WPF which is efficient (memory and speed).
You can use an ImageBrush to draw on a rectangle and adjust the ViewPort property of the brush to slide the image. If you wanted to do an animation with this, here is a sample XAML in WPF which uses animation to automatically adjust the viewport property of the brush and perform a slide animation. Hope this is helpful.
<Window x:Class="TestWpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Rectangle>
<Rectangle.Fill>
<DrawingBrush x:Name="MyBrush" Viewport="0,0,1,1" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<GeometryGroup>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<ImageBrush ImageSource="lSXfX.png" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<RectAnimation
Storyboard.TargetName="MyBrush"
Storyboard.TargetProperty="Viewport"
From="0 0 1 1" To="1 0 1 1" Duration="0:0:10"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Grid>
</Window>

Categories