Some modifications to the OxyPlot library to back-port to .NET 2.0. Added the LINQBridge library for the LINQ based code in OxyPlot (the original .NET LINQ is not available in .NET 2.0).
1 // --------------------------------------------------------------------------------------------------------------------
2 // <copyright file="GraphicsRenderContext.cs" company="OxyPlot">
3 // The MIT License (MIT)
5 // Copyright (c) 2012 Oystein Bjorke
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be included
16 // in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 // The graphics render context.
29 // --------------------------------------------------------------------------------------------------------------------
30 namespace OxyPlot.WindowsForms
33 using System.Collections.Generic;
35 using System.Drawing.Drawing2D;
36 using System.Drawing.Imaging;
43 /// The graphics render context.
45 internal class GraphicsRenderContext : RenderContextBase
48 /// The font size factor.
50 private const float FontsizeFactor = 0.8f;
53 /// The GDI+ drawing surface.
58 /// Initializes a new instance of the <see cref="GraphicsRenderContext"/> class.
60 public GraphicsRenderContext()
65 /// Sets the graphics target.
67 /// <param name="graphics">The graphics surface.</param>
68 public void SetGraphicsTarget(Graphics graphics)
74 /// Draws the ellipse.
76 /// <param name="rect">The rect.</param>
77 /// <param name="fill">The fill.</param>
78 /// <param name="stroke">The stroke.</param>
79 /// <param name="thickness">The thickness.</param>
80 public override void DrawEllipse(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
85 this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
88 if (stroke == null || thickness <= 0)
93 using (var pen = new Pen(this.ToColor(stroke), (float)thickness))
95 this.g.SmoothingMode = SmoothingMode.HighQuality;
96 this.g.DrawEllipse(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
103 /// <param name="points">The points.</param>
104 /// <param name="stroke">The stroke.</param>
105 /// <param name="thickness">The thickness.</param>
106 /// <param name="dashArray">The dash array.</param>
107 /// <param name="lineJoin">The line join.</param>
108 /// <param name="aliased">if set to <c>true</c> [aliased].</param>
109 public override void DrawLine(
110 IList<ScreenPoint> points,
114 OxyPenLineJoin lineJoin,
117 if (stroke == null || thickness <= 0 || points.Count < 2)
122 this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality;
123 using (var pen = new Pen(this.ToColor(stroke), (float)thickness))
126 if (dashArray != null)
128 pen.DashPattern = this.ToFloatArray(dashArray);
133 case OxyPenLineJoin.Round:
134 pen.LineJoin = LineJoin.Round;
136 case OxyPenLineJoin.Bevel:
137 pen.LineJoin = LineJoin.Bevel;
140 // The default LineJoin is Miter
143 this.g.DrawLines(pen, this.ToPoints(points));
148 /// Draws the polygon.
150 /// <param name="points">The points.</param>
151 /// <param name="fill">The fill.</param>
152 /// <param name="stroke">The stroke.</param>
153 /// <param name="thickness">The thickness.</param>
154 /// <param name="dashArray">The dash array.</param>
155 /// <param name="lineJoin">The line join.</param>
156 /// <param name="aliased">if set to <c>true</c> [aliased].</param>
157 public override void DrawPolygon(
158 IList<ScreenPoint> points,
163 OxyPenLineJoin lineJoin,
166 if (points.Count < 2)
171 this.g.SmoothingMode = aliased ? SmoothingMode.None : SmoothingMode.HighQuality;
173 PointF[] pts = this.ToPoints(points);
176 this.g.FillPolygon(this.ToBrush(fill), pts);
179 if (stroke != null && thickness > 0)
181 using (var pen = new Pen(this.ToColor(stroke), (float)thickness))
184 if (dashArray != null)
186 pen.DashPattern = this.ToFloatArray(dashArray);
191 case OxyPenLineJoin.Round:
192 pen.LineJoin = LineJoin.Round;
194 case OxyPenLineJoin.Bevel:
195 pen.LineJoin = LineJoin.Bevel;
198 // The default LineJoin is Miter
201 this.g.DrawPolygon(pen, pts);
207 /// The draw rectangle.
209 /// <param name="rect">
212 /// <param name="fill">
215 /// <param name="stroke">
218 /// <param name="thickness">
221 public override void DrawRectangle(OxyRect rect, OxyColor fill, OxyColor stroke, double thickness)
225 this.g.FillRectangle(
226 this.ToBrush(fill), (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
229 if (stroke == null || thickness <= 0)
234 using (var pen = new Pen(this.ToColor(stroke), (float)thickness))
236 this.g.DrawRectangle(pen, (float)rect.Left, (float)rect.Top, (float)rect.Width, (float)rect.Height);
246 /// <param name="text">
249 /// <param name="fill">
252 /// <param name="fontFamily">
255 /// <param name="fontSize">
258 /// <param name="fontWeight">
261 /// <param name="rotate">
264 /// <param name="halign">
267 /// <param name="valign">
270 /// <param name="maxSize">
271 /// The maximum size of the text.
273 public override void DrawText(
281 HorizontalAlignment halign,
282 VerticalAlignment valign,
285 var fs = FontStyle.Regular;
286 if (fontWeight >= 700)
291 using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs))
293 using (var sf = new StringFormat { Alignment = StringAlignment.Near })
295 var size = this.g.MeasureString(text, font);
298 if (size.Width > maxSize.Value.Width)
300 size.Width = (float)maxSize.Value.Width;
303 if (size.Height > maxSize.Value.Height)
305 size.Height = (float)maxSize.Value.Height;
310 if (halign == HorizontalAlignment.Center)
312 dx = -size.Width / 2;
315 if (halign == HorizontalAlignment.Right)
321 sf.LineAlignment = StringAlignment.Near;
322 if (valign == VerticalAlignment.Middle)
324 dy = -size.Height / 2;
327 if (valign == VerticalAlignment.Bottom)
332 this.g.TranslateTransform((float)p.X, (float)p.Y);
333 if (Math.Abs(rotate) > double.Epsilon)
335 this.g.RotateTransform((float)rotate);
338 this.g.TranslateTransform(dx, dy);
340 var layoutRectangle = new RectangleF(0, 0, size.Width, size.Height);
341 this.g.DrawString(text, font, this.ToBrush(fill), layoutRectangle, sf);
343 this.g.ResetTransform();
349 /// The measure text.
351 /// <param name="text">The text.</param>
352 /// <param name="fontFamily">The font family.</param>
353 /// <param name="fontSize">The font size.</param>
354 /// <param name="fontWeight">The font weight.</param>
355 /// <returns>The size of the text.</returns>
356 public override OxySize MeasureText(string text, string fontFamily, double fontSize, double fontWeight)
360 return OxySize.Empty;
363 var fs = FontStyle.Regular;
364 if (fontWeight >= 700)
369 using (var font = new Font(fontFamily, (float)fontSize * FontsizeFactor, fs))
371 var size = this.g.MeasureString(text, font);
372 return new OxySize(size.Width, size.Height);
377 /// Converts a fill color to a System.Drawing.Brush.
379 /// <param name="fill">
385 private Brush ToBrush(OxyColor fill)
389 return new SolidBrush(this.ToColor(fill));
396 /// Converts a color to a System.Drawing.Color.
402 /// The System.Drawing.Color.
404 private Color ToColor(OxyColor c)
406 return Color.FromArgb(c.A, c.R, c.G, c.B);
410 /// Converts a double array to a float array.
418 private float[] ToFloatArray(double[] a)
425 var r = new float[a.Length];
426 for (int i = 0; i < a.Length; i++)
435 /// Converts a list of point to an array of PointF.
437 /// <param name="points">
441 /// An array of points.
443 private PointF[] ToPoints(IList<ScreenPoint> points)
450 var r = new PointF[points.Count()];
452 foreach (ScreenPoint p in points)
454 r[i++] = new PointF((float)p.X, (float)p.Y);
460 public override void CleanUp()
462 var imagesToRelease = imageCache.Keys.Where(i => !imagesInUse.Contains(i));
463 foreach (var i in imagesToRelease)
465 var image = this.GetImage(i);
467 imageCache.Remove(i);
473 public override OxyImageInfo GetImageInfo(OxyImage source)
475 var image = this.GetImage(source);
476 return image == null ? null : new OxyImageInfo { Width = (uint)image.Width, Height = (uint)image.Height, DpiX = image.HorizontalResolution, DpiY = image.VerticalResolution };
479 public override void DrawImage(OxyImage source, uint srcX, uint srcY, uint srcWidth, uint srcHeight, double x, double y, double w, double h, double opacity, bool interpolate)
481 var image = this.GetImage(source);
484 ImageAttributes ia = null;
487 var cm = new ColorMatrix
493 Matrix44 = (float)opacity
496 ia = new ImageAttributes();
497 ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
500 g.InterpolationMode = interpolate ? InterpolationMode.HighQualityBicubic : InterpolationMode.NearestNeighbor;
501 int sx = (int)Math.Round(x);
502 int sy = (int)Math.Round(y);
503 int sw = (int)Math.Round(x + w) - sx;
504 int sh = (int)Math.Round(y + h) - sy;
505 g.DrawImage(image, new Rectangle(sx, sy, sw, sh), srcX, srcY, srcWidth, srcHeight, GraphicsUnit.Pixel, ia);
509 private HashSet<OxyImage> imagesInUse = new HashSet<OxyImage>();
511 private Dictionary<OxyImage, Image> imageCache = new Dictionary<OxyImage, Image>();
514 private Image GetImage(OxyImage source)
521 if (!this.imagesInUse.Contains(source))
523 this.imagesInUse.Add(source);
527 if (this.imageCache.TryGetValue(source, out src))
535 using (var ms = new MemoryStream(source.GetData()))
537 btm = Image.FromStream(ms);
540 this.imageCache.Add(source, btm);
547 public override bool SetClip(OxyRect rect)
549 this.g.SetClip(rect.ToRect(false));
553 public override void ResetClip()