Change color in vector Images - c#

I am trying to change the color of an vector image through a IValueConverter. My vector image has the following format:
Viewbox x:Key="ViewBoxName" Stretch="Uniform" x:Shared="False">
<Canvas Width="256" Height="256" ClipToBounds="True">
<Canvas />
<Canvas >
<Path Stroke="{DynamicResource GlobalColor}" StrokeThickness="10">
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="-------" />
</Path.Data>
</Path>
</Canvas>
</Canvas>
</Viewbox>
Figures value are available but i didn't want them here :)
When the parameter has a specified value I want to be able to change the GlobalColor from the viewbox to another for this image only and I want to do that inside the converter.
What I tried to do till now is to parse this viewbox and get to that color, change it and return the viewbox with the new color but on my interface the same color remains as before.
I think i need a new approach for this to work.
Regards.

Related

Drawing WPF Polygon with a stroke in solid color or transparent around

I need to create a generic triangle in WPF indicating coordinates, stroke and colors for stroke and filling area. The problem is that i want indicate as color also the Transparent for stroke, meaning than using the same coordinate, I want to draw, all inside this shape, a transparent stroke that replace for his thickness the fill color, but it seems not be possible (I found and solved with a triky the same problem for Circle and Rectangle shapes, but with Polygon it doesn't work: Drawing a WPF shape, as a Rectangle: StrokeThickness halve if Stroke is Transparent ).
The code I use now include a clip because the stroke grow part inside and part outside the coordinate profile, I need to remove outside part, and some converter to give array of points in the correct way:
<UserControl.Clip>
<PathGeometry>
<PathFigure StartPoint="{Binding Triangle.Points, Converter={StaticResource PointLocationClipConverter}}" IsClosed="True">
<PolyLineSegment Points="{Binding Triangle.Points, Converter={StaticResource PointCollectionClipConverter}}" />
</PathFigure>
</PathGeometry>
</UserControl.Clip>
<Grid x:Name="_grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Polygon Points="{Binding Triangle.Points, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource PointCollectionConverter}}" Grid.Row="0" Grid.Column="0" Margin="0,0,0,0"
Width="{Binding ActualWidth, ElementName=_grid}"
Height="{Binding ActualHeight, ElementName=_grid}"
Stroke="{Binding Triangle.BorderColorBrush}"
StrokeThickness="{Binding Triangle.Thick, Converter={StaticResource PoligonThickConverter}}"
Fill="{Binding Triangle.BackgroundBrush}" />
</Grid>
What I have at this moment is:
what I want instead is:
notice: for both example posted, the first image has solid color for Stroke and Fill area, second image has Transparent on Stroke and solid color for Fill area (and here is the problem), third image has solid color for Stroke and Transparent for Fill area. All images have same coordinates and StrokeThickness value.
Thanks for help!
Starting from #Clemens indication, I elaborate a solution with a series of transformation, without any geometric calculus. Less or more the solution is here, I will try to apply to my context, but in the end is:
<Path MouseLeftButtonUp="PathPolyline_MouseLeftButtonUp"
StrokeThickness="0" Stroke="Transparent" Fill="Gold" ClipToBounds="False">
<Path.Data>
<PathGeometry FillRule="EvenOdd" >
<PathFigure StartPoint="0,0" IsClosed="True">
<PolyLineSegment Points="50,50 0,80"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
and elaboration in C# code will do something as:
private void PathPolyline_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Brush brush = Brushes.Black;
Pen pen = new Pen(brush, 20.0); //thickness double than wanted measure: 20 to reduce 10
//
Path path = sender as Path;
PathGeometry pg = path.Data as PathGeometry;
PathGeometry pg2 = pg.GetWidenedPathGeometry(pen);
//
Transform tr = Transform.Identity;
PathGeometry pg324 = Geometry.Combine(pg, pg2, GeometryCombineMode.Intersect, tr);
pg.AddGeometry(pg324);
}

Fit Border around arbitrary Path

I have a Path based on a group of rectangle/ellipse Geometry. When I put an auto-sized Border around it, the border shrinks to fit the RectangleGeometry but does something weird with the EllipseGeometry, as shown below. Anyone know how to fix it so the Border (shown in blue) fits snugly around the whole thing?
Ultimately, I want a Border or a Panel that fits an arbitrary, runtime-generated Path (including the stroke thickness), and I need the geometry size maintained.
Sample code:
<Border BorderBrush="Blue" BorderThickness="2"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Stroke="Orange" StrokeThickness="5" Fill="Red">
<Path.Data>
<GeometryGroup>
<EllipseGeometry Center="-10,-10" RadiusX="12" RadiusY="12" />
<EllipseGeometry Center="70,0" RadiusX="70" RadiusY="10">
<EllipseGeometry.Transform>
<RotateTransform Angle="-25" CenterX="50" CenterY="0" />
</EllipseGeometry.Transform>
</EllipseGeometry>
<RectangleGeometry Rect="0,0,100,100" />
</GeometryGroup>
</Path.Data>
</Path>
</Border>
You may set the Path's Stretch property and bind its Width to the Width of the Bounds of the Geometry:
<Path ... Stretch="Uniform"
Width="{Binding Data.Bounds.Width, RelativeSource={RelativeSource Self}}">
...
</Path>
As the Geometries's Bounds do not contain the rendered Path's StrokeThickness, you may alternatively put the Border into a Canvas (which does not resize its child elements at all), and don't set the Path's Width. This may may however lead to problems when you want to center the Canvas in an outer Grid. It's actual size appears to be zero.
<Canvas>
<Border BorderBrush="Blue" BorderThickness="2">
<Path ... Stretch="Uniform">
...
</Path>
</Border>
</Canvas>

How can I make multiple Path elements inside a Canvas scale to fit its parent?

I have created a series of shapes in Illustrator, and exported them to an .ai file. When I import this file in Blend for Visual Studio, I get something that looks like this:
<Canvas x:Name="ManyPaths" Grid.Row="0">
<Path Data="F1M0,53.135L0.004,102.44 22.03,151.59 55.042,0z" Fill="#FF8B1A34" Height="151.59" Canvas.Left="0.017" Stretch="None" Canvas.Top="182.406" Width="55.042"/>
<Path Data="F1M0.003,34.152L22.027,49.15 0,0z" Fill="#FF991937" Height="49.15" Canvas.Left="0.02" Stretch="None" Canvas.Top="284.846" Width="22.027"/>
</Canvas>
There are numerous Paths, I won't list them all here for brevity. When put together, they make a fixed size rectangle. I would like to use this rectangle at the top of my app as the header image. I can resize the Canvas element in Blend, but I cannot get the collective Paths to fit the Canvas, and be resized along with it. Since I'm designing for various size screens, I would like the header image to scale. I have tried nesting it in a Grid, but that doesn't work.
Looks like the traditional way to do Paths in C# is
<Path Grid.Row="1" Stroke="Black" StrokeThickness="2" Fill="Green">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="100,100">
<QuadraticBezierSegment Point1="165,25" Point2="225,100" />
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
I'm not sure if there is a means to convert the first format to the second, but I would like to reuse my .ai files if possible, instead of recreating them from scratch.
There is no need to convert to the second format. Using the Data attribute is more concise and often clearer.
You can wrap your Canvas in a ViewBox to let it scale to its container. The Stretch attribute can control if it stretches uniformly or distorts (you probably want uniform)
<Viewbox Stretch="Uniform" Grid.Row="0">
<Grid x:Name="ManyPaths" >
<Path Data="F1M0,53.135L0.004,102.44 22.03,151.59 55.042,0z" Fill="#FF8B1A34" Height="151.59" Canvas.Left="0.017" Stretch="None" Canvas.Top="182.406" Width="55.042"/>
<Path Data="F1M0.003,34.152L22.027,49.15 0,0z" Fill="#FF991937" Height="49.15" Canvas.Left="0.02" Stretch="None" Canvas.Top="284.846" Width="22.027"/>
</Grid>
</Viewbox>

InkPresenter draw only in transparent area

I have an InkPresenter and this image with a transparent background. I want my strokes to be drawn only in the transparent area and ignore the black border of the shape. How is it possible?
here is an example using WPF, same applies to InkPresenter, you can use InkPresenter.Clip property to define the clip region
<Border BorderBrush="Green"
BorderThickness="1"
Width="200"
Height="200">
<Grid>
<InkCanvas>
<InkCanvas.Clip>
<EllipseGeometry RadiusX="98"
RadiusY="98"
Center="100,100" />
</InkCanvas.Clip>
</InkCanvas>
<Ellipse Stroke="Blue"
StrokeThickness="2" />
</Grid>
</Border>
result
I was able to solve my problem using Opacity Mask:
<InkPresenter.OpacityMask>
<ImageBrush ImageSource="{Binding ImageMask}" />
</InkPresenter.OpacityMask>

Resize polygon in to fill in Canvas

How can i resize Polygon which is placed in Canvas so it fills that canvas?
I don't want to change values of polygon points, I just want it to be displayed inside of canvas in case polygon coordinates are too large, too small or out of screen.
Came across this problem recently and worked out a solid solution:
<Canvas x:Name="CanvasName">
<Polygon Points="{Binding Path=PointCollectionName}" Stretch="Fill" Fill="Black"
Width={Binding ElementName=CanvasName, Path=ActualWidth}"
Height={Binding ElementName=CanvasName, Path=AcutalHeight}"/>
</Canvas>
Do you have the chance to replace the Canvas with a Grid? If so just set the Stretch attribute of the polygon, e.g. Uniform keeps the aspect ratio:
<Grid Width="297" Height="159">
<Polygon Points="10,110 110,110 110,10" Fill="Blue" Stretch="Uniform" />
</Grid>

Categories

Resources