Skip to content

Commit 3165816

Browse files
committed
[Branches/1.1]
- Added GdiImageLayerProxy class, with test and surrogates git-tfs-id: [https://tfs.codeplex.com/tfs/TFS01]$/SharpMap/Branches/1.1;C105248
1 parent 8dd0d87 commit 3165816

7 files changed

Lines changed: 361 additions & 5 deletions

File tree

SharpMap/Layers/GdiImageLayer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using System.Runtime.Serialization;
2727
using GeoAPI.Geometries;
2828
using NetTopologySuite.Geometries;
29+
using RTools_NTS.Util;
2930
using Point = System.Drawing.Point;
3031

3132
namespace SharpMap.Layers
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Copyright 2014 - Robert Smart (www.cnl-software), Felix Obermaier (www.ivv-aachen.de)
2+
//
3+
// This file is part of SharpMap.
4+
// SharpMap is free software; you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation; either version 2 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// SharpMap is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with SharpMap; if not, write to the Free Software
16+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+
18+
using System;
19+
using System.Drawing;
20+
using System.Drawing.Imaging;
21+
using Common.Logging;
22+
using GeoAPI.Geometries;
23+
24+
namespace SharpMap.Layers
25+
{
26+
/// <summary>
27+
/// Image manipulation proxy layer
28+
/// </summary>
29+
/// <typeparam name="T">The type of the proxy layer. <see cref="ITileAsyncLayer"/> are not excluded, but are not handled in any way.</typeparam>
30+
[Serializable]
31+
public class GdiImageLayerProxy<T> : ILayer, IDisposable
32+
where T: class, ILayer
33+
{
34+
private static readonly ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
35+
36+
private readonly ColorMatrix _colorMatrix;
37+
private readonly ColorMap[] _colorMap;
38+
private readonly T _baseLayer;
39+
40+
/// <summary>
41+
/// Creates an instance of this class using the provided <paramref name="opacity"/>
42+
/// </summary>
43+
/// <param name="layer">The layer to be proxied</param>
44+
/// <param name="opacity">An opacity value in the range of [0f, 1f]. Values outside of that range will be clipped.</param>
45+
public GdiImageLayerProxy(T layer, float opacity)
46+
:this(layer, new ColorMatrix {Matrix33 = Math.Max(Math.Min(1f, opacity), 0f)})
47+
{
48+
}
49+
50+
/// <summary>
51+
/// Creates an instance of this class using the provided <paramref name="colorMatrix"/>
52+
/// </summary>
53+
/// <param name="layer">The layer to be proxied</param>
54+
/// <param name="colorMatrix">A color matrix that is to be applied upon drawing</param>
55+
public GdiImageLayerProxy(T layer, ColorMatrix colorMatrix)
56+
{
57+
if (layer is ITileAsyncLayer)
58+
{
59+
Logger.Warn("ITileAsyncLayer is not a valid layer for GdiImageLayerProxy<T>");
60+
}
61+
_baseLayer = layer;
62+
_colorMatrix = colorMatrix;
63+
}
64+
65+
/// <summary>
66+
/// Creates an instance of this class using the provided <paramref name="colorMap"/>
67+
/// </summary>
68+
/// <param name="layer">The layer to be proxied</param>
69+
/// <param name="colorMap">The color map</param>
70+
public GdiImageLayerProxy(T layer, params ColorMap[] colorMap)
71+
{
72+
if (layer is ITileAsyncLayer)
73+
{
74+
Logger.Warn("ITileAsyncLayer is not a valid layer for GdiImageLayerProxy<T>");
75+
}
76+
_baseLayer = layer;
77+
_colorMap = colorMap;
78+
}
79+
80+
/// <summary>
81+
/// Gets a value indicating the proxied base layer
82+
/// </summary>
83+
public T BaseLayer{ get { return _baseLayer; }}
84+
85+
double ILayer.MinVisible
86+
{
87+
get { return _baseLayer.MinVisible; }
88+
set { _baseLayer.MinVisible = value; }
89+
}
90+
91+
double ILayer.MaxVisible
92+
{
93+
get { return _baseLayer.MaxVisible; }
94+
set { _baseLayer.MaxVisible = value; }
95+
}
96+
97+
bool ILayer.Enabled
98+
{
99+
get { return _baseLayer.Enabled; }
100+
set { _baseLayer.Enabled = value; }
101+
}
102+
103+
string ILayer.LayerName
104+
{
105+
get { return _baseLayer.LayerName; }
106+
set { _baseLayer.LayerName = value; }
107+
}
108+
109+
Envelope ILayer.Envelope
110+
{
111+
get { return _baseLayer.Envelope; }
112+
}
113+
114+
int ILayer.SRID
115+
{
116+
get { return _baseLayer.SRID; }
117+
set { _baseLayer.SRID = value; }
118+
}
119+
120+
int ILayer.TargetSRID
121+
{
122+
get { return _baseLayer.TargetSRID; }
123+
}
124+
125+
string ILayer.Proj4Projection
126+
{
127+
get { return _baseLayer.Proj4Projection; }
128+
set { _baseLayer.Proj4Projection = value; }
129+
}
130+
131+
void ILayer.Render(Graphics g, Map map)
132+
{
133+
if (_baseLayer is ITileAsyncLayer)
134+
{
135+
Logger.Warn("ITileAsyncLayer is not a valid layer for GdiImageLayerProxy<T>. -> Skipping");
136+
_baseLayer.Render(g, map);
137+
return;
138+
}
139+
140+
var s = map.Size;
141+
using (var img = new Bitmap(s.Width, s.Height, PixelFormat.Format32bppArgb))
142+
{
143+
using (var gg = Graphics.FromImage(img))
144+
{
145+
_baseLayer.Render(gg, map);
146+
}
147+
148+
using (var ia = CreateImageAttributes())
149+
{
150+
g.DrawImage(img, new Rectangle(0, 0, s.Width, s.Height),
151+
0, 0, s.Width, s.Height, GraphicsUnit.Pixel, ia);
152+
}
153+
}
154+
}
155+
156+
private ImageAttributes CreateImageAttributes()
157+
{
158+
var ia = new ImageAttributes();
159+
if (_colorMatrix != null)
160+
{
161+
ia.SetColorMatrix(_colorMatrix);
162+
}
163+
else if (_colorMap != null)
164+
{
165+
ia.SetRemapTable(_colorMap);
166+
}
167+
return ia;
168+
}
169+
170+
public void Dispose()
171+
{
172+
if (_baseLayer is IDisposable)
173+
{
174+
((IDisposable)_baseLayer).Dispose();
175+
}
176+
}
177+
}
178+
}

SharpMap/SharpMap.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
<Compile Include="Geometries\GeoAPIEx.cs" />
191191
<Compile Include="Layers\DuplicateLayerException.cs" />
192192
<Compile Include="Layers\GdiImageLayer.cs" />
193+
<Compile Include="Layers\GdiImageLayerProxy.cs" />
193194
<Compile Include="Layers\IAsyncLayer.cs" />
194195
<Compile Include="Layers\ILayer.cs" />
195196
<Compile Include="Layers\ICanQueryLayer.cs" />

SharpMap/Utilities/Surrogates.Helper.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Drawing;
33
using System.Drawing.Drawing2D;
4+
using System.Drawing.Imaging;
45
using System.Runtime.Serialization;
56

67
namespace SharpMap.Utilities
@@ -182,5 +183,68 @@ object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info,
182183
}
183184

184185
#endregion
186+
187+
#region "Nested type: ColorMapSurrogate"
188+
/// <summary>
189+
/// Surrogate class for <see cref="T:System.Drawing.Imaging.ColorMap"/>
190+
/// </summary>
191+
public class ColorMapSurrogate : ISerializationSurrogate
192+
{
193+
194+
void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
195+
{
196+
var colorMap = (ColorMap)obj;
197+
info.AddValue("old", colorMap.OldColor);
198+
info.AddValue("new", colorMap.NewColor);
199+
}
200+
201+
object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
202+
{
203+
var blend = (ColorMap)obj;
204+
blend.OldColor = (Color)info.GetValue("old", typeof(Color));
205+
blend.NewColor = (Color)info.GetValue("new", typeof(Color));
206+
return null;
207+
}
208+
}
209+
#endregion
210+
211+
#region "Nested type: ColorMapSurrogate"
212+
/// <summary>
213+
/// Surrogate class for <see cref="T:System.Drawing.Imaging.ColorMap"/>
214+
/// </summary>
215+
public class ColorMatrixSurrogate : ISerializationSurrogate
216+
{
217+
218+
void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
219+
{
220+
var colorMatrix = (ColorMatrix)obj;
221+
info.AddValue("cm", ToFloatArray(colorMatrix));
222+
}
223+
224+
object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
225+
{
226+
var colorMatrix = (ColorMatrix)obj;
227+
var floatArray = (float[]) info.GetValue("cm", typeof (float[]));
228+
for (var i = 0; i < floatArray.Length; i++)
229+
{
230+
colorMatrix[i/5, i%5] = floatArray[i];
231+
}
232+
return null;
233+
}
234+
235+
private static float[] ToFloatArray(ColorMatrix matrix)
236+
{
237+
return new[]
238+
{
239+
matrix.Matrix00, matrix.Matrix01, matrix.Matrix02, matrix.Matrix03, matrix.Matrix04,
240+
matrix.Matrix10, matrix.Matrix11, matrix.Matrix12, matrix.Matrix13, matrix.Matrix14,
241+
matrix.Matrix20, matrix.Matrix21, matrix.Matrix22, matrix.Matrix23, matrix.Matrix24,
242+
matrix.Matrix30, matrix.Matrix31, matrix.Matrix32, matrix.Matrix33, matrix.Matrix34,
243+
matrix.Matrix40, matrix.Matrix41, matrix.Matrix42, matrix.Matrix43, matrix.Matrix44
244+
};
245+
}
246+
}
247+
#endregion
248+
185249
}
186250
}

SharpMap/Utilities/Surrogates.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public static SurrogateSelector GetSurrogateSelectors()
5353
ss.AddSurrogate(typeof(Matrix), sc, new MatrixSurrogate());
5454
ss.AddSurrogate(typeof(StringFormat), sc, new StringFormatSurrogate());
5555
ss.AddSurrogate(typeof(ImageFormat), sc, new ImageFormatSurrogate());
56+
ss.AddSurrogate(typeof(ColorMap), sc, new ColorMapSurrogate());
57+
ss.AddSurrogate(typeof(ColorMatrix), sc, new ColorMatrixSurrogate());
5658
return ss;
5759
}
5860

UnitTests/Layers/GdiImageLayerTest.cs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,23 @@
55
using System.IO;
66
using GeoAPI.Geometries;
77
using NUnit.Framework;
8+
using SharpMap;
89
using SharpMap.Layers;
910

1011
namespace UnitTests.Layers
1112
{
1213
public class GdiImageLayerTest
1314
{
14-
private static string CreateImage(Size size, Point? origin = null)
15+
internal static string CreateImage(Size size, Point? origin = null)
1516
{
16-
var img = new Bitmap(size.Width, size.Height);
17+
var img = new Bitmap(size.Width, size.Height, PixelFormat.Format32bppArgb);
1718
var tmpFile = Path.ChangeExtension(Path.GetTempFileName(), ".png");
19+
20+
using (var g = Graphics.FromImage(img))
21+
{
22+
g.FillRectangle(Brushes.Red, new Rectangle(0, 0, size.Width, size.Height));
23+
}
24+
1825
img.Save(tmpFile, ImageFormat.Png);
1926

2027
CreateWorldFile(tmpFile, size, origin);
@@ -43,7 +50,7 @@ private static void CreateWorldFile(string imageFile, Size size, Point? origin)
4350
}
4451
}
4552

46-
private static void DeleteTmpFiles(string imageFile)
53+
internal static void DeleteTmpFiles(string imageFile)
4754
{
4855
if (File.Exists(imageFile))
4956
{
@@ -98,7 +105,65 @@ public void TestGdiImageLayer2()
98105

99106
DeleteTmpFiles(imageFile);
100107
}
108+
}
109+
110+
public class GdiImageLayerProxyTest
111+
{
112+
[Test]
113+
public void TestTransparency()
114+
{
115+
var tmpFile = GdiImageLayerTest.CreateImage(new Size(300, 300), new Point(10, 10));
116+
using(var l = new GdiImageLayer(tmpFile))
117+
using (var pl = new GdiImageLayerProxy<GdiImageLayer>(l, 0.3f))
118+
using (var m = new Map(new Size(450, 450)))
119+
{
120+
m.Layers.Add(pl);
121+
m.ZoomToExtents();
122+
using (var img = (Bitmap)m.GetMap())
123+
{
124+
var color = img.GetPixel(225, 225);
125+
Assert.AreEqual((byte)Math.Round(0.3f*255, MidpointRounding.AwayFromZero), color.A);
126+
}
127+
}
128+
GdiImageLayerTest.DeleteTmpFiles(tmpFile);
129+
}
101130

102-
131+
[Test, Ignore("not yet implemented")]
132+
public void TestColorMatrix()
133+
{
134+
var tmpFile = GdiImageLayerTest.CreateImage(new Size(300, 300), new Point(10, 10));
135+
using (var l = new GdiImageLayer(tmpFile))
136+
using (var pl = new GdiImageLayerProxy<GdiImageLayer>(l, 0.3f))
137+
using (var m = new Map(new Size(450, 450)))
138+
{
139+
m.Layers.Add(pl);
140+
m.ZoomToExtents();
141+
using (var img = (Bitmap)m.GetMap())
142+
{
143+
var color = img.GetPixel(225, 225);
144+
Assert.AreEqual((byte)Math.Round(0.3f * 255, MidpointRounding.AwayFromZero), color.A);
145+
}
146+
}
147+
GdiImageLayerTest.DeleteTmpFiles(tmpFile);
148+
}
149+
150+
[Test]
151+
public void TestColorMap()
152+
{
153+
var tmpFile = GdiImageLayerTest.CreateImage(new Size(300, 300), new Point(10, 10));
154+
using (var l = new GdiImageLayer(tmpFile))
155+
using (var pl = new GdiImageLayerProxy<GdiImageLayer>(l, new ColorMap{OldColor = Color.Red, NewColor = Color.MistyRose}))
156+
using (var m = new Map(new Size(450, 450)))
157+
{
158+
m.Layers.Add(pl);
159+
m.ZoomToExtents();
160+
using (var img = (Bitmap)m.GetMap())
161+
{
162+
var color = img.GetPixel(225, 225);
163+
Assert.AreEqual(Color.MistyRose, color);
164+
}
165+
}
166+
GdiImageLayerTest.DeleteTmpFiles(tmpFile);
167+
}
103168
}
104169
}

0 commit comments

Comments
 (0)