Skip to content

Instantly share code, notes, and snippets.

@robmikh
Created April 6, 2016 22:31
Show Gist options
  • Save robmikh/8c74f176349d31fd02f58a25b9508b9a to your computer and use it in GitHub Desktop.
Save robmikh/8c74f176349d31fd02f58a25b9508b9a to your computer and use it in GitHub Desktop.
Custom Image Control using Composition
using Robmikh.Util.CompositionImageLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Hosting;
namespace ControlSample.Helpers
{
public static class CompositionHelper
{
private static Compositor _compositor;
public static Compositor Compositor
{
get
{
if (_compositor == null)
{
_compositor = ElementCompositionPreview.GetElementVisual(Window.Current.Content).Compositor;
}
return _compositor;
}
}
private static IImageLoader _imageLoader;
public static IImageLoader ImageLoader
{
get
{
if (_imageLoader == null)
{
_imageLoader = ImageLoaderFactory.CreateImageLoader(Compositor);
}
return _imageLoader;
}
}
}
}
using ControlSample.Helpers;
using Robmikh.Util.CompositionImageLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;
namespace ControlSample.Controls
{
public class ImageVisual : UserControl
{
private static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(Uri), typeof(ImageVisual), new PropertyMetadata(null, SourcePropertyChanged));
private SpriteVisual _visual;
private IManagedSurface _surface;
private CompositionSurfaceBrush _imageBrush;
public SpriteVisual Visual
{
get { return _visual; }
}
public CompositionSurfaceBrush ImageBrush
{
get { return _imageBrush; }
}
public Uri Source
{
get { return (Uri)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public ImageVisual()
{
InitComposition();
SizeChanged += ImageVisual_SizeChanged;
}
private void ImageVisual_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
if (_visual != null)
{
_visual.Size = new Vector2((float)ActualWidth, (float)ActualHeight);
}
}
private void InitComposition()
{
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
_visual = compositor.CreateSpriteVisual();
_visual.Size = new Vector2((float)ActualWidth, (float)ActualHeight);
_surface = CompositionHelper.ImageLoader.CreateManagedSurfaceFromUri(Source);
_imageBrush = compositor.CreateSurfaceBrush(_surface.Surface);
_visual.Brush = _imageBrush;
ElementCompositionPreview.SetElementChildVisual(this, _visual);
}
private void UpdateImage(Uri newImageUri)
{
if (_surface != null)
{
var ignored = _surface.RedrawSurface(newImageUri);
}
}
private static void SourcePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var control = obj as ImageVisual;
var oldUri = args.OldValue as Uri;
var newUri = args.NewValue as Uri;
if (control != null && !newUri.Equals(oldUri))
{
control.UpdateImage(newUri);
}
}
}
}
<Page
x:Class="ControlSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ControlSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:ControlSample.Controls"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<controls:ImageVisual x:Name="ImageVisualControl" Width="480" Height="176.5" Source="http://ncmedia.azureedge.net/ncmedia/2014/10/MSFT_logo_rgb_C-Gray.png" />
<Button HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0, 0, 10, 10" Content="Invert Image" Click="Button_Click" />
</Grid>
</Page>
using Microsoft.Graphics.Canvas.Effects;
using Robmikh.Util.CompositionImageLoader;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Effects;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace ControlSample
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var visual = ImageVisualControl.Visual;
var imageBrush = ImageVisualControl.ImageBrush;
var currentBrush = visual.Brush;
var compositor = visual.Compositor;
if (currentBrush is CompositionSurfaceBrush)
{
IGraphicsEffect graphicsEffect = new InvertEffect
{
Name = "invertEffect",
Source = new CompositionEffectSourceParameter("image")
};
var effectFactory = compositor.CreateEffectFactory(graphicsEffect);
var effectBrush = effectFactory.CreateBrush();
effectBrush.SetSourceParameter("image", imageBrush);
visual.Brush = effectBrush;
}
else if (currentBrush is CompositionEffectBrush)
{
visual.Brush = imageBrush;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment