Skip to content

Instantly share code, notes, and snippets.

@dotMorten
Created November 1, 2013 21:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotMorten/7272085 to your computer and use it in GitHub Desktop.
Save dotMorten/7272085 to your computer and use it in GitHub Desktop.
A XAML based PictureMarkerSymbol for the ArcGIS Runtime .NET SDK
using Esri.ArcGISRuntime.Symbology;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
#if NETFX_CORE
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Foundation;
using Windows.UI.Xaml.Media.Imaging;
using System.Threading;
using System.Runtime.InteropServices.WindowsRuntime;
#else
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Markup;
#endif
namespace MortensGists
{
#if NETFX_CORE
[ContentProperty(Name = "Template")]
#else
[ContentProperty("Template")]
#endif
public class XamlMarkerSymbol : PictureMarkerSymbol
{
private DataTemplate m_Template;
public XamlMarkerSymbol()
{
Dpi = 96f;
}
public DataTemplate Template
{
get { return m_Template; }
set
{
if (m_Template != value)
{
m_Template = value;
Task t = RenderAsync(); //TODO: Handle fallback in case task doesn't succeed
}
}
}
/* Getting DPI (WPF):
System.Windows.Media.Matrix m =
PresentationSource.FromVisual(MyMap).CompositionTarget.TransformToDevice;
float dpi = 96f & m.M11;
*/
public float Dpi { get; set; }
private async Task RenderAsync()
{
ContentControl content = new ContentControl();
content.Content = this;
content.ContentTemplate = this.Template;
double w = this.Width / 72 * 96; //convert points to DIPs
double h = this.Height / 72 * 96; //convert points to DIPs
if (w == 0 || h == 0)
{
content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
w = content.DesiredSize.Width;
h = content.DesiredSize.Height;
}
if (w < 0.5 || h < 0.5)
{
#if NETFX_CORE
await SetSourceAsync(null as Windows.Storage.Streams.IRandomAccessStream);
#else
await SetSourceAsync(null as Stream);
#endif
return;
}
content.Arrange(new Rect(0, 0, w, h));
int pixelWidth = (int)(w * Dpi / 96); //DIPs to pixel
int pixelHeight = (int)(h * Dpi / 96); //DIPs to pixel
#if WINDOWS_PHONE
WriteableBitmap bmp = new WriteableBitmap(pixelWidth, pixelHeight);
bmp.Render(content, null);
bmp.Invalidate();
#elif NETFX_CORE
RenderTargetBitmap bmp = new RenderTargetBitmap();
await bmp.RenderAsync(content, (int)pixelWidth, (int)pixelHeight).AsTask();
var pixelBuffer = (await bmp.GetPixelsAsync().AsTask().ConfigureAwait(false)).AsStream();
byte[] pixels = new byte[pixelBuffer.Length];
pixelBuffer.Write(pixels, 0, pixels.Length);
var png = new MemoryStream().AsRandomAccessStream();
var encoder = await Windows.Graphics.Imaging.BitmapEncoder.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.PngEncoderId, png).AsTask();
encoder.SetPixelData(Windows.Graphics.Imaging.BitmapPixelFormat.Rgba8, Windows.Graphics.Imaging.BitmapAlphaMode.Straight,
(uint)pixelWidth, (uint)pixelHeight, Dpi, Dpi, pixels);
await encoder.FlushAsync().AsTask();
await SetSourceAsync(png);
#else //WPF
RenderTargetBitmap bmp = new RenderTargetBitmap(pixelWidth, pixelHeight, Dpi, Dpi, PixelFormats.Default);
bmp.Render(content);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(bmp));
using (Stream stm = new MemoryStream())
{
png.Save(stm);
stm.Seek(0, SeekOrigin.Begin);
await SetSourceAsync(stm);
}
#endif
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment