Thursday 25 August 2011

Convert Text to Path in Xaml

In Expression Blend you can convert any object to a path:  Object Menu > Path > Convert to Path.

Or you can download my WPF app

ClickOnce installer http://stevenhollidge.com/blog-source-code/clickonce/text2path/Text2Path.html
Source code https://github.com/stevenh77/Text2Path

 

Screenshot

image

The Code

<Controls:MetroWindow x:Class="Text2Path.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Text2Path"
Height="500"
Width="660"
ShowMinButton="False"
ShowMaxRestoreButton="False"
ShowIconOnTitleBar="true"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro">

<Controls:MetroWindow.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="Resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style TargetType="ComboBox">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Margin" Value="10"/>
</Style>

<Style TargetType="TextBox">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="30" />
</Style>

<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Margin" Value="10"/>
<Setter Property="Height" Value="30" />
</Style>

</ResourceDictionary>

</Controls:MetroWindow.Resources>

<Controls:MetroWindow.WindowCommands>
<Controls:WindowCommands>
<Button x:Name="BlogButton" Content="blog" Click="BlogButton_Click" />
</Controls:WindowCommands>
</Controls:MetroWindow.WindowCommands>

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>

<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="100" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>

<TextBlock Text="Text:" Grid.Column="0" Grid.Row="0" />
<TextBox x:Name="TextTextBlock" Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="3" />
<Button x:Name="ConvertButton" Grid.Column="4" Grid.Row="0" Content="Convert" Click="ConvertButton_Click" VerticalAlignment="Top" Margin="10"/>

<TextBlock Text="Culture:" Grid.Column="0" Grid.Row="1" />
<ComboBox x:Name="CultureComboBox" Grid.Column="1" Grid.Row="1" />

<TextBlock Text="Direction:" Grid.Column="2" Grid.Row="1" />
<ComboBox x:Name="DirectionComboBox" Grid.Column="3" Grid.Row="1" IsReadOnly="True" />

<TextBlock Text="Font:" Grid.Column="0" Grid.Row="2" />
<ComboBox x:Name="FontComboBox" Grid.Column="1" Grid.Row="2" />

<TextBlock Text="Font Size:" Grid.Column="2" Grid.Row="2" />
<ComboBox x:Name="FontSizeComboBox" Grid.Column="3" Grid.Row="2" />

<TextBlock Text="Result:" Grid.Row="3" VerticalAlignment="Top" Visibility="Collapsed"/>
<Path x:Name="OutputPath" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3"
Stroke="Black" Fill="Black"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>

<TextBlock x:Name="PathTextBlock" Text="Path:" Grid.Row="4" VerticalAlignment="Top" Visibility="Collapsed"/>
<TextBox x:Name="OutputTextBox" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="4"
IsReadOnly="True"
VerticalAlignment="Stretch"
Visibility="Collapsed"
TextWrapping="WrapWithOverflow"
FontSize="12"
Height="180"/>

<Button x:Name="CopyButton" Visibility="Collapsed" Grid.Column="4" Grid.Row="4" Content="Copy" Click="CopyButton_Click" VerticalAlignment="Top" Margin="10"/>
<TextBlock x:Name="ClipboardResponse" Grid.Column="4" Grid.Row="4" VerticalAlignment="Top" HorizontalAlignment="Center" FontSize="12" Foreground="Red" Margin="0,60,0,0"/>

</Grid>
</Controls:MetroWindow>


 

using System;
using System.Collections;
using System.Drawing.Text;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace Text2Path
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Populate();
SetDefaults();
}

private void Populate()
{
CultureComboBox.ItemsSource = Helper.GetAvailableCultures();
DirectionComboBox.ItemsSource = Helper.GetDirections();
FontComboBox.ItemsSource = Helper.GetFonts();
FontSizeComboBox.ItemsSource = Helper.GetFontSizes();
}

private void SetDefaults()
{
TextTextBlock.Text = "Convert this text!";
CultureComboBox.SelectedItem = "en-US";
DirectionComboBox.SelectedItem = "Left to right";
FontComboBox.SelectedItem = "Segoe UI";
FontSizeComboBox.SelectedItem = "48";
}

private void ConvertButton_Click(object sender, RoutedEventArgs e)
{
try
{
this.Cursor = Cursors.Wait;

var path = Helper.Text2Path(TextTextBlock.Text,
CultureComboBox.Text,
(DirectionComboBox.Text == "Left to right"),
FontComboBox.Text,
Int32.Parse(FontSizeComboBox.Text));

OutputTextBox.Text = string.Format("<Path Stroke={0}Black{0} Fill={0}Black{0} Data={0}{1}{0} />", '"', path);
PathTextBlock.Visibility = Visibility.Visible;
CopyButton.Visibility = Visibility.Visible;

OutputPath.Data = Geometry.Parse(path);
}
catch (Exception ex)
{
OutputTextBox.Text = ex.Message;
}
finally
{
OutputTextBox.Visibility = Visibility.Visible;
this.Cursor = Cursors.Arrow;
}
}

private void BlogButton_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Process.Start("http://stevenhollidge.blogspot.com");
}

private void CopyButton_Click(object sender, RoutedEventArgs e)
{
try
{
Clipboard.SetData(DataFormats.Text, OutputTextBox.Text);
ClipboardResponse.Text = "Success";
}
catch
{
ClipboardResponse.Text = "Failed";
}
}
}

public class Helper
{
public static string Text2Path(String text, string culture, bool leftToRight, string font, int fontSize)
{
if (culture == "") culture = "en-us";

var ci = new CultureInfo(culture);
var fd = leftToRight ? FlowDirection.LeftToRight : FlowDirection.RightToLeft;
var ff = new FontFamily(font);
var tf = new Typeface(ff, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
var t = new FormattedText(text, ci, fd, tf, fontSize, Brushes.Black);
var g = t.BuildGeometry(new Point(0, 0));
var p = g.GetFlattenedPathGeometry();

return p.ToString();
}

public static IEnumerable GetAvailableCultures()
{
return CultureInfo.GetCultures(CultureTypes.SpecificCultures | CultureTypes.NeutralCultures)
.Select(x => x.Name)
.ToList();
}

public static IEnumerable GetDirections()
{
return new [] {"Left to right", "Right to left" };
}

public static IEnumerable GetFonts()
{
return new InstalledFontCollection().Families.Select(font => font.Name).ToList();
}

public static IEnumerable GetFontSizes()
{
return new [] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 26, 28, 36, 48, 72 }.Select(x => x.ToString());
}
}
}

No comments:

Post a Comment