Friday, 25 November 2011

How to inline Images in a FlowDocument

Introduction

Sometimes you want to deploy, share or load just a plain XAML file containing a FlowDocument. Then you want to put in some inline images. HTML provides a functionality to express the image as Base64 encoded CDATA section, but WPF does not have such a functionality.

I found a solution how to do this, by creating a custom InlineImage element, that does the trick. The following example shows how to do it.

 
<FlowDocument>
    <InlineImage Width="100" Height="100" Stretch="Fill">
        <![CDATA[iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAB3RJTUUH2AQP
        SFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAAnOSURBVHjaxVcLcBvVFT1vV
        ki3Hju3GCQnGjkObONQkJkxCSIHQQGnIdEr5TFs+LaGl7RRCSUvDp8nglH4mDGQ6EwZIm=]]>
    </InlineImage>
</FlowDocument>
 
 

Implementation of the InlineImage Control

 
namespace XamlInlineImageDemo
{
 
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation",
 "XamlInlineImageDemo")]
 
[ContentProperty("Base64Source")]
public class InlineImage : BlockUIContainer
{
    #region DependencyProperty 'Width'
 
    /// <summary>
    /// Gets or sets the width.
    /// </summary>
    public double Width
    {
        get { return (double)GetValue(WidthProperty); }
        set { SetValue(WidthProperty, value); }
    }
 
    /// <summary>
    /// Registers a dependency property to get or set the width
    /// </summary>
    public static readonly DependencyProperty WidthProperty =
        DependencyProperty.Register("Width", typeof(double),
        typeof(InlineImage),
        new FrameworkPropertyMetadata(Double.NaN));
 
    #endregion
 
    #region DependencyProperty 'Height'
 
    /// <summary>
    /// Gets or sets the height.
    /// </summary>
    public double Height
    {
        get { return (double)GetValue(HeightProperty); }
        set { SetValue(HeightProperty, value); }
    }
 
    /// <summary>
    /// Registers a dependency property to get or set the height
    /// </summary>
    public static readonly DependencyProperty HeightProperty =
        DependencyProperty.Register("Height", typeof(double),
        typeof(InlineImage),
        new FrameworkPropertyMetadata(Double.NaN));
 
    #endregion
 
    #region DependencyProperty 'Stretch'
 
    /// <summary>
    /// Gets or sets the stretch behavior.
    /// </summary>
    public Stretch Stretch
    {
        get { return (Stretch)GetValue(StretchProperty); }
        set { SetValue(StretchProperty, value); }
    }
 
    /// <summary>
    /// Registers a dependency property to get or set the stretch behavior
    /// </summary>
    public static readonly DependencyProperty StretchProperty =
        DependencyProperty.Register("Stretch", typeof(Stretch),
        typeof(InlineImage),
        new FrameworkPropertyMetadata(Stretch.Uniform));
 
    #endregion
 
    #region DependencyProperty 'StretchDirection'
 
    /// <summary>
    /// Gets or sets the stretch direction.
    /// </summary>
    public StretchDirection StretchDirection
    {
        get { return (StretchDirection)GetValue(StretchDirectionProperty); }
        set { SetValue(StretchDirectionProperty, value); }
    }
 
    /// <summary>
    /// Registers a dependency property to get or set the stretch direction
    /// </summary>
    public static readonly DependencyProperty StretchDirectionProperty =
        DependencyProperty.Register("StretchDirection", typeof(StretchDirection), 
        typeof(InlineImage), 
        new FrameworkPropertyMetadata(StretchDirection.Both));
 
    #endregion
 
    #region DependencyProperty 'Base64Source'
 
    /// <summary>
    /// Gets or sets the base64 source.
    /// </summary>
    public string Base64Source
    {
        get { return (string)GetValue(Base64SourceProperty); }
        set { SetValue(Base64SourceProperty, value); }
    }
 
    /// <summary>
    /// Registers a dependency property to get or set the base64 source
    /// </summary>
    public static readonly DependencyProperty Base64SourceProperty =
        DependencyProperty.Register("Base64Source", typeof(string), typeof(InlineImage),
        new FrameworkPropertyMetadata(null, OnBase64SourceChanged));
 
    #endregion
 
    #region Private Members
 
    private static void OnBase64SourceChanged(DependencyObject sender, 
        DependencyPropertyChangedEventArgs e)
    {
        var inlineImage = (InlineImage)sender;
        var stream = new MemoryStream(Convert.FromBase64String(inlineImage.Base64Source));
 
        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.StreamSource = stream;
        bitmapImage.EndInit();
 
        var image =new Image {
            Source = bitmapImage, 
            Stretch = inlineImage.Stretch,
            StretchDirection = inlineImage.StretchDirection,
             };
 
        if (!double.IsNaN(inlineImage.Width))
        {
            image.Width = inlineImage.Width;
        }
 
        if (!double.IsNaN(inlineImage.Height))
        {
            image.Height = inlineImage.Height;
        }
 
        inlineImage.Child = image;
    }
 
    #endregion
 
  }
}
 
 

No comments:

Post a Comment