// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Runtime.Serialization;
namespace SharpMap.Utilities
{
///
/// Helper class for serializing System.Drawing.Pen and System.Drawing.Brush
///
public partial class Surrogates
{
///
/// Gets the surrogate selecteds for System.Drawing.Pen and System.Drawing.Brush
///
/// SurrogateSelector
public static SurrogateSelector GetSurrogateSelectors()
{
var sc = new StreamingContext(StreamingContextStates.All);
var ss = new SurrogateSelector();
ss.AddSurrogate(typeof (Pen), sc, new PenSurrogate());
ss.AddSurrogate(typeof (Brush), sc, new BrushSurrogate());
ss.AddSurrogate(typeof(SolidBrush), sc, new SolidBrushSurrogate());
ss.AddSurrogate(typeof(TextureBrush), sc, new TextureBrushSurrogate());
ss.AddSurrogate(typeof(HatchBrush), sc, new HatchBrushSurrogate());
ss.AddSurrogate(typeof(LinearGradientBrush), sc, new LinearGradientBrushSurrogate());
ss.AddSurrogate(typeof(AdjustableArrowCap), sc, new AdjustableArrowCapSurrogate());
#pragma warning disable 612,618
ss.AddSurrogate(typeof(CustomLineCap), sc, new CustomLineCapSurrogate());
#pragma warning restore 612,618
ss.AddSurrogate(typeof(GraphicsPath), sc, new GraphicsPathSurrogate());
ss.AddSurrogate(typeof(Blend), sc, new BlendSurrogate());
ss.AddSurrogate(typeof(ColorBlend), sc, new ColorBlendSurrogate());
ss.AddSurrogate(typeof(Matrix), sc, new MatrixSurrogate());
ss.AddSurrogate(typeof(StringFormat), sc, new StringFormatSurrogate());
ss.AddSurrogate(typeof(ImageFormat), sc, new ImageFormatSurrogate());
ss.AddSurrogate(typeof(ColorMap), sc, new ColorMapSurrogate());
ss.AddSurrogate(typeof(ColorMatrix), sc, new ColorMatrixSurrogate());
return ss;
}
#region Nested type: StringFormatSurrogate
///
/// Surrogate class to serialize
///
private class ImageFormatSurrogate : ISerializationSurrogate
{
[Serializable]
public class ImageFormatRef : IObjectReference, ISerializable
{
private readonly ImageFormat _format;
public ImageFormatRef(SerializationInfo info, StreamingContext context)
{
var guid = (Guid)info.GetValue("guid", typeof (Guid));
_format = new ImageFormat(guid);
}
public object GetRealObject(StreamingContext context)
{
return _format;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotSupportedException();
}
}
///
/// Populates the provided SerializationInfo with the data needed to serialize the object.
///
/// The object to serialize.
/// The SerializationInfo to populate with data.
/// The destination for this serialization.
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
info.SetType(typeof(ImageFormatRef));
var sf = (ImageFormat)obj;
info.AddValue("guid", sf.Guid);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
var @if = (ImageFormat)obj;
return null;
}
}
#endregion
#region Nested type: StringFormatSurrogate
///
/// Surrogate class to serialize
///
private class StringFormatSurrogate : ISerializationSurrogate
{
[Serializable]
public class StringFormatRef: IObjectReference, ISerializable
{
private readonly StringFormat _format;
public StringFormatRef(SerializationInfo info, StreamingContext context)
{
var sf = _format = new StringFormat();
sf.Alignment = (StringAlignment)info.GetInt32("Alignment");
var dsl = info.GetInt32("DigitSubstitutionLanguage");
var dsm = (StringDigitSubstitute)info.GetInt32("DigitSubstitutionMethod");
sf.FormatFlags = (StringFormatFlags)info.GetInt32("FormatFlags");
sf.HotkeyPrefix = (HotkeyPrefix)info.GetInt32("HotkeyPrefix");
sf.LineAlignment = (StringAlignment)info.GetInt32("LineAlignment");
sf.Trimming = (StringTrimming)info.GetInt32("Trimming");
var firstTabStop = info.GetSingle("FirstTabStop");
var tabStops = (float[])info.GetValue("TabStops", typeof(float[]));
sf.SetTabStops(firstTabStop, tabStops);
sf.SetDigitSubstitution(dsl, dsm);
}
public object GetRealObject(StreamingContext context)
{
return _format;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotSupportedException();
}
}
///
/// Populates the provided SerializationInfo with the data needed to serialize the object.
///
/// The object to serialize.
/// The SerializationInfo to populate with data.
/// The destination for this serialization.
public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
info.SetType(typeof(StringFormatRef));
var sf = (StringFormat) obj;
info.AddValue("Alignment", (int)sf.Alignment);
info.AddValue("DigitSubstitutionLanguage", sf.DigitSubstitutionLanguage);
info.AddValue("DigitSubstitutionMethod", (int)sf.DigitSubstitutionMethod);
info.AddValue("FormatFlags", (int)sf.FormatFlags);
info.AddValue("HotkeyPrefix", (int) sf.HotkeyPrefix);
info.AddValue("LineAlignment", sf.LineAlignment);
info.AddValue("Trimming", sf.Trimming);
float firstTabStop;
var tabStops = sf.GetTabStops(out firstTabStop);
info.AddValue("FirstTabStop", firstTabStop);
info.AddValue("TabStops", tabStops);
}
public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
var sf = (StringFormat) obj;
return null;
}
}
#endregion
#region Nested type: PenSurrogate
///
/// Surrogate class used for serializing System.Drawing.Pen
///
public class PenSurrogate : ISerializationSurrogate
{
///
/// Serialization utility class
///
[Serializable]
public class PenRef : IObjectReference, ISerializable
{
private readonly Pen _pen;
///
/// Serialization constructor
///
/// The serialization info
/// The streaming context
public PenRef(SerializationInfo info, StreamingContext context)
{
var penType = (PenType) info.GetInt32("PenType");
var width = info.GetSingle("Width");
switch (penType)
{
case PenType.SolidColor:
_pen = new Pen((Color)info.GetValue("Color", typeof(Color)), width);
break;
default:
var brush = (Brush) info.GetValue("Brush", typeof (Brush));
_pen = new Pen(brush, width);
break;
}
_pen.Alignment = (PenAlignment)info.GetInt32("Alignment");
var ca = (float[]) info.GetValue("CompoundArray", typeof (float[]));
if (ca!= null && ca.Length > 0)
_pen.CompoundArray = ca;
LineCap lineCap;
CustomLineCap custonLineCap;
DeserializeLineCap(info, "Start", out lineCap, out custonLineCap);
_pen.StartCap = lineCap;
if (custonLineCap != null) _pen.CustomStartCap = custonLineCap;
DeserializeLineCap(info, "End", out lineCap, out custonLineCap);
_pen.EndCap = lineCap;
if (custonLineCap != null) _pen.CustomEndCap = custonLineCap;
/*
info.AddValue("DashCap", (int)pen.DashCap);
info.AddValue("DashOffset", pen.DashOffset);
info.AddValue("DashPattern", pen.DashPattern);
info.AddValue("DashStyle", (int)pen.DashStyle);
*/
_pen.DashCap = (DashCap)info.GetInt32("DashCap");
_pen.DashOffset = info.GetSingle("DashOffset");
var dashStyle = (DashStyle)info.GetInt32("DashStyle");
if (dashStyle == DashStyle.Custom)
_pen.DashPattern = (float[])info.GetValue("DashPattern", typeof(float[]));
else
_pen.DashStyle = dashStyle;
_pen.LineJoin = (LineJoin)info.GetInt32("LineJoin");
_pen.MiterLimit = info.GetSingle("MiterLimit");
_pen.Transform = (Matrix)info.GetValue("Transform", typeof(Matrix));
System.Diagnostics.Debug.Assert(penType == _pen.PenType);
}
private static void DeserializeLineCap(SerializationInfo info, string label, out LineCap lineCap, out CustomLineCap customLineCap)
{
lineCap = (LineCap)info.GetInt32(label + "Cap");
customLineCap = null;
if (lineCap != LineCap.Custom)
return;
customLineCap = (CustomLineCap)info.GetValue("Custom" + label + "Cap", typeof(CustomLineCap));
}
object IObjectReference.GetRealObject(StreamingContext context)
{
return _pen;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotSupportedException();
}
}
#region ISerializationSurrogate Members
///
/// Populates the provided SerializationInfo with the data needed to serialize the object.
///
/// The object to serialize.
/// The SerializationInfo to populate with data.
/// The destination for this serialization.
public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
{
info.SetType(typeof(PenRef));
var pen = (Pen) obj;
info.AddValue("PenType", pen.PenType);
info.AddValue("Width", pen.Width);
if (pen.PenType == PenType.SolidColor)
info.AddValue("Color", pen.Color);
else
info.AddValue("Brush", pen.Brush);
info.AddValue("Alignment", (int)pen.Alignment);
info.AddValue("CompoundArray", pen.CompoundArray);
var clp = pen.StartCap == LineCap.Custom ? pen.CustomStartCap : null;
SerializeLineCap(info, "Start", pen.StartCap, clp);
clp = pen.EndCap == LineCap.Custom ? pen.CustomEndCap : null;
SerializeLineCap(info, "End",pen.EndCap, clp);
info.AddValue("DashCap", (int)pen.DashCap);
info.AddValue("DashOffset", pen.DashOffset);
info.AddValue("DashStyle", (int)pen.DashStyle);
if (pen.DashStyle == DashStyle.Custom)
info.AddValue("DashPattern", pen.DashPattern);
info.AddValue("LineJoin", (int)pen.LineJoin);
info.AddValue("MiterLimit", pen.MiterLimit);
info.AddValue("Transform", pen.Transform);
}
private static void SerializeLineCap(SerializationInfo info, string label, LineCap lineCap,
CustomLineCap customLineCap)
{
if (lineCap == LineCap.Custom)
{
if (CustomEndCapSerializable(customLineCap))
{
info.AddValue(label + "Cap", (int)lineCap);
info.AddValue("Custom" + label + "Cap", customLineCap);
}
else
info.AddValue(label+"Cap", (int)LineCap.Round);
}
else
info.AddValue(label+"Cap", (int)lineCap);
}
private static bool CustomEndCapSerializable(CustomLineCap clp)
{
if (clp == null)
return false;
if (clp is AdjustableArrowCap)
return true;
return clp.GetType().IsSerializable;
}
///
/// Populates the object using the information in the SerializationInfo
///
/// The object to populate.
/// The information to populate the object.
/// The source from which the object is deserialized.
/// The surrogate selector where the search for a compatible surrogate begins.
///
public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context,
ISurrogateSelector selector)
{
throw new NotSupportedException();
}
#endregion
}
#endregion
#region Nested type: AdjustableArrowCapSurrogate
///
/// Surrogate class used to serialize
///
public class AdjustableArrowCapSurrogate : ISerializationSurrogate
{
///
/// Object reference class for
///
[Serializable]
public class AdjustableArrowCapRef : IObjectReference, ISerializable
{
private readonly AdjustableArrowCap _aac;
///
/// Serialization constructor
///
/// The serialization info
/// The streaming context
public AdjustableArrowCapRef(SerializationInfo info, StreamingContext context)
{
var aac = _aac = new AdjustableArrowCap(info.GetSingle("Width"), info.GetSingle("Height"));
aac.BaseCap = (LineCap)info.GetInt32("BaseCap");
aac.BaseInset = info.GetSingle("BaseInset");
aac.Filled = info.GetBoolean("Filled");
aac.MiddleInset = info.GetSingle("MiddleInset");
aac.StrokeJoin = (LineJoin)info.GetInt32("StrokeJoin");
aac.WidthScale = info.GetSingle("WidthScale");
}
object IObjectReference.GetRealObject(StreamingContext context)
{
return _aac;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotSupportedException();
}
}
void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
var aac = (AdjustableArrowCap) obj;
info.SetType(typeof(AdjustableArrowCapRef));
info.AddValue("Width", aac.Width);
info.AddValue("Height", aac.Height);
info.AddValue("BaseCap", (int)aac.BaseCap);
info.AddValue("BaseInset", aac.BaseInset);
info.AddValue("Filled", aac.Filled);
info.AddValue("MiddleInset", aac.MiddleInset);
info.AddValue("StrokeJoin", (int)aac.StrokeJoin);
info.AddValue("WidthScale", aac.WidthScale);
}
object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
throw new NotSupportedException();
}
}
#endregion
#region Nested type: CustomLineCapSurrogate
///
/// Surrogate class used to serialize objects
///
/// Unfortunately this does not work, since the
//[Obsolete("Does not work since there is no way to get a hold of the GraphicsPath that make up this object")]
public class CustomLineCapSurrogate : ISerializationSurrogate
{
///
/// Serialization utility class
///
[Serializable]
public class CustomLineCapRef : IObjectReference, ISerializable
{
private readonly CustomLineCap _clp;
///
/// Serialization constructor
///
///
///
public CustomLineCapRef(SerializationInfo info, StreamingContext context)
{
var baseCap = (LineCap) info.GetInt32("BaseCap");
var baseInset = info.GetSingle("BaseInset");
var fillPath = (GraphicsPath) info.GetValue("FillPath", (typeof (GraphicsPath)));
var strokePath = (GraphicsPath)info.GetValue("StrokePath", (typeof(GraphicsPath)));
var startCap = (LineCap)info.GetInt32("StartCap");
var endCap = (LineCap)info.GetInt32("StartCap");
_clp = new CustomLineCap(fillPath, strokePath, baseCap, baseInset);
_clp.StrokeJoin = (LineJoin) info.GetInt32("StrokeJoin");
_clp.WidthScale = info.GetSingle("WidthScale");
_clp.SetStrokeCaps(startCap, endCap);
}
object IObjectReference.GetRealObject(StreamingContext context)
{
return _clp;
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotSupportedException();
}
}
void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
{
var clp = (CustomLineCap)obj;
info.SetType(typeof(CustomLineCapRef));
info.AddValue("BaseCap", clp.BaseCap);
info.AddValue("BaseInset", clp.BaseInset);
//FillPath
//No way to get this!
//StrokePath
//No way to get this!
LineCap startCap, endCap;
clp.GetStrokeCaps(out startCap, out endCap);
info.AddValue("StartCap", (int)startCap);
info.AddValue("EndCap", (int)endCap);
info.AddValue("StrokeJoin", (int)clp.StrokeJoin);
info.AddValue("WidthScale", clp.WidthScale);
}
object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
{
throw new NotSupportedException();
}
}
#endregion
}
}