I'm putting together a prototype to use XAML to create PNG buttons. The basic idea is that nice, gradient image buttons can be generated from localized strings instead of having them created by any sort of graphics dept.
The most straightforward example I found actually was to build a C# assembly and call it from PHP. I converted it to pure C#. Here's what my basically working prototype looks like.
The XAML file looks like:
<UserControl
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"
mc:Ignorable="d"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Button HorizontalAlignment="Left" VerticalAlignment="Top" Content="Add To Cart" FontFamily="Arial" FontSize="11" Height="24" FontWeight="Bold" Margin="0,3,0,0">
<Button.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF3F3F3" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFDDDDDD" Offset="0.502"/>
<GradientStop Color="#FFCDCDCD" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
</Grid>
The Program.cs looks like:
class Program
{
static void Main(string[] args)
{
FileInfo xamlFile = new FileInfo("Button.xaml");
var inputXaml = File.ReadAllText(xamlFile.FullName);
Thread pngCreationThread = new Thread((ThreadStart) delegate()
{
GenImageFromXaml(inputXaml);
});
pngCreationThread.IsBackground = true;
pngCreationThread.SetApartmentState(ApartmentState.STA);
pngCreationThread.Start();
pngCreationThread.Join();
}
public static void GenImageFromXaml(string xaml)
{
var element = (FrameworkElement)XamlReader.Parse(xaml);
var pngBytes = GetPngImage(element);
using(BinaryWriter binWriter =
new BinaryWriter(File.Open(@"output.png", FileMode.Create)))
{
binWriter.Write(pngBytes);
}
}
private static byte[] GetPngImage(FrameworkElement element)
{
var size = new Size(element.Width, element.Height);
element.Measure(size);
element.Arrange(new Rect(size));
var renderTarget =
new RenderTargetBitmap((int)element.RenderSize.Width,
(int)element.RenderSize.Height,
96, 96,
PixelFormats.Pbgra32);
var sourceBrush = new VisualBrush(element);
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(
sourceBrush, null, new Rect(
new Point(0, 0),
new Point(element.RenderSize.Width,
element.RenderSize.Height)));
}
renderTarget.Render(drawingVisual);
var pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (var outputStream = new MemoryStream())
{
pngEncoder.Save(outputStream);
return outputStream.ToArray();
}
}
}
What I want is XAML files that can be used as templates and the actual string in the button swapped out. My prototype works on a basic level, rendering out an image from the input XAML file.
However, the XAML file specifies the height and width explicitly. That's going to be a problem to have the string on the button itself supplied dynamically since the width won't be known in advance and any font modifications would mess with it too.
What I'm looking for is a way to have the height and width either calculated at runtime or a straightforward way to pre-calculate them based on the text string. Any ideas?