ASCU_ALL/PrintPDF/PdfSharp/Drawing/XGraphics.cs
2021-05-25 17:00:45 +05:00

5313 lines
194 KiB
C#
Raw Permalink Blame History

#region PDFsharp - A .NET library for processing PDF
//
// Authors:
// Stefan Lange
//
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
#if GDI
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using GdiPoint = System.Drawing.Point;
using GdiSize = System.Drawing.Size;
using GdiRect = System.Drawing.Rectangle;
using GdiPointF = System.Drawing.PointF;
using GdiSizeF = System.Drawing.SizeF;
using GdiRectF = System.Drawing.RectangleF;
using GdiMatrix = System.Drawing.Drawing2D.Matrix;
#endif
#if WPF
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using PdfSharp.Windows;
using SysPoint = System.Windows.Point;
using SysSize = System.Windows.Size;
using SysRect = System.Windows.Rect;
using SysMatrix = System.Windows.Media.Matrix;
using WpfBrush = System.Windows.Media.Brush;
using WpfPen = System.Windows.Media.Pen;
#if !SILVERLIGHT
using WpfBrushes = System.Windows.Media.Brushes;
#endif
#endif
#if NETFX_CORE
using Windows.UI.Xaml.Media;
using SysPoint = Windows.Foundation.Point;
using SysSize = Windows.Foundation.Size;
using SysRect = Windows.Foundation.Rect;
#endif
#if UWP
using System.Numerics;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Geometry;
using SysPoint = Windows.Foundation.Point;
using SysSize = Windows.Foundation.Size;
using SysRect = Windows.Foundation.Rect;
#endif
using PdfSharp.Pdf;
using PdfSharp.Drawing.Pdf;
using PdfSharp.Internal;
using PdfSharp.Pdf.Advanced;
#pragma warning disable 1587
// ReSharper disable UseNullPropagation
// ReSharper disable RedundantNameQualifier
// ReSharper disable UseNameofExpression
namespace PdfSharp.Drawing // #??? Clean up
{
/// <summary>
/// Holds information about the current state of the XGraphics object.
/// </summary>
[Flags]
enum InternalGraphicsMode
{
DrawingGdiGraphics,
DrawingPdfContent,
DrawingBitmap,
}
/// <summary>
/// Represents a drawing surface for a fixed size page.
/// </summary>
public sealed class XGraphics : IDisposable
{
#if CORE
// TODO: Implement better concept of a measure context.
#endif
#if GDI
/// <summary>
/// Initializes a new instance of the XGraphics class.
/// </summary>
/// <param name="gfx">The gfx.</param>
/// <param name="size">The size.</param>
/// <param name="pageUnit">The page unit.</param>
/// <param name="pageDirection">The page direction.</param>
XGraphics(Graphics gfx, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
if (gfx == null)
{
// MigraDoc comes here when creating a MeasureContext.
try
{
Lock.EnterGdiPlus();
gfx = Graphics.FromHwnd(IntPtr.Zero); // BUG: Use measure image
}
finally { Lock.ExitGdiPlus(); }
}
_gsStack = new GraphicsStateStack(this);
TargetContext = XGraphicTargetContext.GDI;
_gfx = gfx;
_drawGraphics = true;
_pageSize = new XSize(size.Width, size.Height);
_pageUnit = pageUnit;
switch (pageUnit)
{
case XGraphicsUnit.Point:
_pageSizePoints = new XSize(size.Width, size.Height);
break;
case XGraphicsUnit.Inch:
_pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height));
break;
case XGraphicsUnit.Millimeter:
_pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height));
break;
case XGraphicsUnit.Centimeter:
_pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height));
break;
case XGraphicsUnit.Presentation:
_pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height));
break;
default:
throw new NotImplementedException("unit");
}
_pageDirection = pageDirection;
Initialize();
}
#endif
#if WPF && !SILVERLIGHT
/// <summary>
/// Initializes a new instance of the XGraphics class.
/// </summary>
/// <param name="dc">The drawing context.</param>
/// <param name="size">The size.</param>
/// <param name="pageUnit">The page unit.</param>
/// <param name="pageDirection">The page direction.</param>
XGraphics(DrawingContext dc, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
if (dc == null)
{
//throw new ArgumentNullException("dc");
_dv = new DrawingVisual();
dc = _dv.RenderOpen();
}
_gsStack = new GraphicsStateStack(this);
TargetContext = XGraphicTargetContext.WPF;
_dc = dc;
_drawGraphics = true;
_pageSize = new XSize(size.Width, size.Height);
_pageUnit = pageUnit;
switch (pageUnit)
{
case XGraphicsUnit.Point:
_pageSizePoints = new XSize(size.Width, size.Height);
break;
case XGraphicsUnit.Inch:
_pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height));
break;
case XGraphicsUnit.Millimeter:
_pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height));
break;
case XGraphicsUnit.Centimeter:
_pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height));
break;
case XGraphicsUnit.Presentation:
_pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height));
break;
default:
throw new NotImplementedException("unit");
}
_pageDirection = pageDirection;
Initialize();
}
#endif
#if WPF
/// <summary>
/// Initializes a new instance of the XGraphics class.
/// </summary>
/// <param name="canvas">The canvas.</param>
/// <param name="size">The size.</param>
/// <param name="pageUnit">The page unit.</param>
/// <param name="pageDirection">The page direction.</param>
XGraphics(Canvas canvas, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
//throw new ArgumentNullException("canvas");
if (canvas == null)
canvas = new Canvas();
#if !SILVERLIGHT
// Create DrawingVisual as container for the content of the page.
_dv = new DrawingVisual();
// Create a host that shows the visual.
VisualPresenter vp = new VisualPresenter();
vp.Children.Add(_dv);
// The canvas only contains the host of the DrawingVisual.
canvas.Children.Add(vp);
_dc = _dv.RenderOpen();
TargetContext = XGraphicTargetContext.WPF;
//////VisualBrush brush = new VisualBrush(_dv);
////////brush.ViewboxUnits = BrushMappingMode.
//////brush.Viewport=new Rect(new Point(), size.ToSize());
//////brush.Viewbox=new Rect(new Point(), size.ToSize());
////////brush.Viewport=new Rect(new Point(), (Size)size);
//////brush.AutoLayoutContent = true;
//////canvas.Background = brush;
#else
_dc = new AgDrawingContext(canvas);
#endif
_gsStack = new GraphicsStateStack(this);
TargetContext = XGraphicTargetContext.WPF;
_drawGraphics = true;
_pageSize = new XSize(size.Width, size.Height);
_pageUnit = pageUnit;
switch (pageUnit)
{
case XGraphicsUnit.Point:
_pageSizePoints = new XSize(size.Width, size.Height);
break;
case XGraphicsUnit.Inch:
_pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height));
break;
case XGraphicsUnit.Millimeter:
_pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height));
break;
case XGraphicsUnit.Centimeter:
_pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height));
break;
case XGraphicsUnit.Presentation:
_pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height));
break;
default:
throw new NotImplementedException("unit");
}
_pageDirection = pageDirection;
Initialize();
}
#endif
#if UWP
/// <summary>
/// Initializes a new instance of the XGraphics class.
/// </summary>
/// <param name="canvasDrawingSession">The canvas.</param>
/// <param name="size">The size.</param>
/// <param name="pageUnit">The page unit.</param>
/// <param name="pageDirection">The page direction.</param>
XGraphics(CanvasDrawingSession canvasDrawingSession, XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
if (canvasDrawingSession == null)
throw new ArgumentNullException("canvasDrawingSession");
_cds = canvasDrawingSession;
_gsStack = new GraphicsStateStack(this);
TargetContext = XGraphicTargetContext.WPF;
_drawGraphics = true;
_pageSize = new XSize(size.Width, size.Height);
_pageUnit = pageUnit;
switch (pageUnit)
{
case XGraphicsUnit.Point:
_pageSizePoints = new XSize(size.Width, size.Height);
break;
case XGraphicsUnit.Inch:
_pageSizePoints = new XSize(XUnit.FromInch(size.Width), XUnit.FromInch(size.Height));
break;
case XGraphicsUnit.Millimeter:
_pageSizePoints = new XSize(XUnit.FromMillimeter(size.Width), XUnit.FromMillimeter(size.Height));
break;
case XGraphicsUnit.Centimeter:
_pageSizePoints = new XSize(XUnit.FromCentimeter(size.Width), XUnit.FromCentimeter(size.Height));
break;
case XGraphicsUnit.Presentation:
_pageSizePoints = new XSize(XUnit.FromPresentation(size.Width), XUnit.FromPresentation(size.Height));
break;
default:
throw new NotImplementedException("unit");
}
_pageDirection = pageDirection;
Initialize();
}
#endif
/// <summary>
/// Initializes a new instance of the XGraphics class for drawing on a PDF page.
/// </summary>
XGraphics(PdfPage page, XGraphicsPdfPageOptions options, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
if (page == null)
throw new ArgumentNullException("page");
if (page.Owner == null)
throw new ArgumentException("You cannot draw on a page that is not owned by a PdfDocument object.", "page");
if (page.RenderContent != null)
throw new InvalidOperationException("An XGraphics object already exists for this page and must be disposed before a new one can be created.");
if (page.Owner.IsReadOnly)
throw new InvalidOperationException("Cannot create XGraphics for a page of a document that cannot be modified. Use PdfDocumentOpenMode.Modify.");
_gsStack = new GraphicsStateStack(this);
PdfContent content = null;
switch (options)
{
case XGraphicsPdfPageOptions.Replace:
page.Contents.Elements.Clear();
goto case XGraphicsPdfPageOptions.Append;
case XGraphicsPdfPageOptions.Prepend:
content = page.Contents.PrependContent();
break;
case XGraphicsPdfPageOptions.Append:
content = page.Contents.AppendContent();
break;
}
page.RenderContent = content;
#if CORE
TargetContext = XGraphicTargetContext.CORE;
#endif
#if GDI
// HACK: This does not work with #MediumTrust
//_gfx = Graphics.FromHwnd(IntPtr.Zero); // _gfx should not be necessary anymore.
_gfx = null;
TargetContext = XGraphicTargetContext.GDI;
#endif
#if WPF && !SILVERLIGHT
_dv = new DrawingVisual();
_dc = _dv.RenderOpen();
TargetContext = XGraphicTargetContext.WPF;
#endif
#if SILVERLIGHT
_dc = new AgDrawingContext(new Canvas());
TargetContext = XGraphicTargetContext.WPF;
#endif
#if GDI && WPF
TargetContext = PdfSharp.Internal.TargetContextHelper.TargetContext;
#endif
_renderer = new PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer(page, this, options);
_pageSizePoints = new XSize(page.Width, page.Height);
switch (pageUnit)
{
case XGraphicsUnit.Point:
_pageSize = new XSize(page.Width, page.Height);
break;
case XGraphicsUnit.Inch:
_pageSize = new XSize(XUnit.FromPoint(page.Width).Inch, XUnit.FromPoint(page.Height).Inch);
break;
case XGraphicsUnit.Millimeter:
_pageSize = new XSize(XUnit.FromPoint(page.Width).Millimeter, XUnit.FromPoint(page.Height).Millimeter);
break;
case XGraphicsUnit.Centimeter:
_pageSize = new XSize(XUnit.FromPoint(page.Width).Centimeter, XUnit.FromPoint(page.Height).Centimeter);
break;
case XGraphicsUnit.Presentation:
_pageSize = new XSize(XUnit.FromPoint(page.Width).Presentation, XUnit.FromPoint(page.Height).Presentation);
break;
default:
throw new NotImplementedException("unit");
}
_pageUnit = pageUnit;
_pageDirection = pageDirection;
Initialize();
}
/// <summary>
/// Initializes a new instance of the XGraphics class used for drawing on a form.
/// </summary>
XGraphics(XForm form)
{
if (form == null)
throw new ArgumentNullException("form");
_form = form;
form.AssociateGraphics(this);
_gsStack = new GraphicsStateStack(this);
#if CORE
TargetContext = XGraphicTargetContext.CORE;
_drawGraphics = false;
if (form.Owner != null)
_renderer = new XGraphicsPdfRenderer(form, this);
_pageSize = form.Size;
Initialize();
#endif
#if GDI && !WPF
try
{
Lock.EnterGdiPlus();
TargetContext = XGraphicTargetContext.GDI;
// If form.Owner is null create a meta file.
if (form.Owner == null)
{
MemoryStream stream = new MemoryStream();
// BUG: This Windows 1.0 technique issued an exception under Microsoft Azure. // #???
using (Graphics refgfx = Graphics.FromHwnd(IntPtr.Zero))
{
IntPtr hdc = refgfx.GetHdc();
#if true_
// This code comes from my C++ RenderContext and checks some confusing details in connection
// with metafiles.
// Display | LaserJet
// DPI 96 : 120 | 300
// physical device size in MM ---------------------------------------------
int horzSizeMM = NativeMethods.GetDeviceCaps(hdc, NativeMethods.HORZSIZE); // = 360 : 360 | 198 (not 210)
int vertSizeMM = NativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTSIZE); // = 290 : 290 | 288 (hot 297)
// Cool:
// My monitor is a Sony SDM-N80 and its size is EXACTLY 360mm x 290mm!!
// It is an 18.1" Flat Panel LCD from 2002 and these are the values
// an older display drivers reports in about 2003:
// Display
// DPI 96 : 120
// --------------
// 330 : 254
// 254 : 203
// Obviously my ATI driver reports the exact size of the monitor.
// device size in pixel
int horzSizePixel = NativeMethods.GetDeviceCaps(hdc, NativeMethods.HORZRES); // = 1280 : 1280 | 4676
int vertSizePixel = NativeMethods.GetDeviceCaps(hdc, NativeMethods.VERTRES); // = 1024 : 1024 | 6814
// 'logical' device resolution in DPI
int logResX = NativeMethods.GetDeviceCaps(hdc, NativeMethods.LOGPIXELSX); // = 96 : 120 | 600
int logResY = NativeMethods.GetDeviceCaps(hdc, NativeMethods.LOGPIXELSY); // = 96 : 120 | 600
// now we can get the 'physical' device resolution...
float phyResX = horzSizePixel / (horzSizeMM / 25.4f); // = 98.521210 : 128.00000 | 599.85052
float phyResY = vertSizePixel / (vertSizeMM / 25.4f); // = 102.40000 : 128.12611 | 600.95691
// ...and rescale the size of the meta rectangle.
float magicX = logResX / phyResX; // = 0.97440946 : 0.93750000 | 1.0002491
float magicY = logResY / phyResY; // = 0.93750000 : 0.93657720 | 0.99840766
// use A4 page in point
// adjust size of A4 page so that meta file fits with DrawImage...
//GdiRectF rcMagic = new GdiRectF(0, 0, magicX * form.Width, magicY * form.Height);
//m_PreviewMetafile = new Metafile(hdc, rcMagic, MetafileFrameUnitPoint,
// EmfTypeEmfPlusOnly, L"some description");
#endif
GdiRectF rect = new GdiRectF(0, 0, form.PixelWidth, form.PixelHeight);
Metafile = new Metafile(stream, hdc, rect, MetafileFrameUnit.Pixel); //, EmfType.EmfPlusOnly);
// Petzold disposes the refgfx object, although the hdc is in use of the metafile
refgfx.ReleaseHdc(hdc);
} // refgfx.Dispose();
_gfx = Graphics.FromImage(Metafile);
_gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
_drawGraphics = true;
}
else
{
Metafile = null;
_gfx = Graphics.FromHwnd(IntPtr.Zero);
}
if (form.Owner != null)
_renderer = new PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer(form, this);
_pageSize = form.Size;
}
finally { Lock.ExitGdiPlus(); }
Initialize();
#endif
#if WPF && !GDI
TargetContext = XGraphicTargetContext.WPF;
#if !SILVERLIGHT
// If form.Owner is null create a meta file.
if (form.Owner == null)
{
_dv = new DrawingVisual();
_dc = _dv.RenderOpen();
_drawGraphics = true;
}
else
{
_dv = new DrawingVisual();
_dc = _dv.RenderOpen();
}
if (form.Owner != null)
_renderer = new PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer(form, this);
_pageSize = form.Size;
Initialize();
#else
throw new NotImplementedException(); // AGHACK
//Initialize();
#endif
#endif
}
/// <summary>
/// Creates the measure context. This is a graphics context created only for querying measures of text.
/// Drawing on a measure context has no effect.
/// </summary>
public static XGraphics CreateMeasureContext(XSize size, XGraphicsUnit pageUnit, XPageDirection pageDirection)
{
#if CORE
//throw new InvalidOperationException("No measure context in CORE build.");
PdfDocument dummy = new PdfDocument();
PdfPage page = dummy.AddPage();
//XGraphics gfx = new XGraphics(((System.Drawing.Graphics)null, size, pageUnit, pageDirection);
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append, pageUnit, pageDirection);
return gfx;
#endif
#if GDI && !WPF
//XGraphics gfx = new XGraphics((System.Drawing.Graphics)null, size, pageUnit, pageDirection);
XGraphics gfx = new XGraphics((System.Drawing.Graphics)null, size, pageUnit, pageDirection);
return gfx;
#endif
#if WPF && !SILVERLIGHT
XGraphics gfx = new XGraphics((System.Windows.Media.DrawingContext)null, size, pageUnit, pageDirection);
return gfx;
#endif
#if SILVERLIGHT
XGraphics gfx = new XGraphics(new Canvas(), size, pageUnit, pageDirection);
return gfx;
#endif
#if NETFX_CORE || UWP // NETFX_CORE_TODO
return null;
#endif
}
#if GDI
/// <summary>
/// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object.
/// </summary>
public static XGraphics FromGraphics(Graphics graphics, XSize size)
{
// Creating a new instance is by design.
return new XGraphics(graphics, size, XGraphicsUnit.Point, XPageDirection.Downwards);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object.
/// </summary>
public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit)
{
// Creating a new instance is by design.
return new XGraphics(graphics, size, unit, XPageDirection.Downwards);
}
///// <summary>
///// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object.
///// </summary>
//public static XGraphics FromGraphics(Graphics graphics, XSize size, XPageDirection pageDirection)
//{
// // Creating a new instance is by design.
// return new XGraphics(graphics, size, XGraphicsUnit.Point, pageDirection);
//}
///// <summary>
///// Creates a new instance of the XGraphics class from a System.Drawing.Graphics object.
///// </summary>
//public static XGraphics FromGraphics(Graphics graphics, XSize size, XGraphicsUnit unit, XPageDirection pageDirection)
//{
// // Creating a new instance is by design.
// return new XGraphics(graphics, size, XGraphicsUnit.Point, pageDirection);
//}
#endif
#if WPF && !SILVERLIGHT
/// <summary>
/// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object.
/// </summary>
public static XGraphics FromDrawingContext(DrawingContext drawingContext, XSize size, XGraphicsUnit unit)
{
return new XGraphics(drawingContext, size, unit, XPageDirection.Downwards);
}
#endif
#if WPF
/// <summary>
/// Creates a new instance of the XGraphics class from a System.Windows.Media.DrawingContext object.
/// </summary>
public static XGraphics FromCanvas(Canvas canvas, XSize size, XGraphicsUnit unit)
{
return new XGraphics(canvas, size, unit, XPageDirection.Downwards);
}
#endif
#if UWP
/// <summary>
/// Creates a new instance of the XGraphics class from a Microsoft.Graphics.Canvas.CanvasDrawingSession object.
/// </summary>
public static XGraphics FromCanvasDrawingSession(CanvasDrawingSession drawingSession, XSize size, XGraphicsUnit unit)
{
return new XGraphics(drawingSession, size, unit, XPageDirection.Downwards);
}
#endif
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page)
{
return new XGraphics(page, XGraphicsPdfPageOptions.Append, XGraphicsUnit.Point, XPageDirection.Downwards);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XGraphicsUnit unit)
{
return new XGraphics(page, XGraphicsPdfPageOptions.Append, unit, XPageDirection.Downwards);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XPageDirection pageDirection)
{
return new XGraphics(page, XGraphicsPdfPageOptions.Append, XGraphicsUnit.Point, pageDirection);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XGraphicsPdfPageOptions options)
{
return new XGraphics(page, options, XGraphicsUnit.Point, XPageDirection.Downwards);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XGraphicsPdfPageOptions options, XPageDirection pageDirection)
{
return new XGraphics(page, options, XGraphicsUnit.Point, pageDirection);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XGraphicsPdfPageOptions options, XGraphicsUnit unit)
{
return new XGraphics(page, options, unit, XPageDirection.Downwards);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Pdf.PdfPage object.
/// </summary>
public static XGraphics FromPdfPage(PdfPage page, XGraphicsPdfPageOptions options, XGraphicsUnit unit, XPageDirection pageDirection)
{
return new XGraphics(page, options, unit, pageDirection);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XPdfForm object.
/// </summary>
public static XGraphics FromPdfForm(XPdfForm form)
{
if (form.Gfx != null)
return form.Gfx;
return new XGraphics(form);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XForm object.
/// </summary>
public static XGraphics FromForm(XForm form)
{
if (form.Gfx != null)
return form.Gfx;
return new XGraphics(form);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XForm object.
/// </summary>
public static XGraphics FromImage(XImage image)
{
return FromImage(image, XGraphicsUnit.Point);
}
/// <summary>
/// Creates a new instance of the XGraphics class from a PdfSharp.Drawing.XImage object.
/// </summary>
public static XGraphics FromImage(XImage image, XGraphicsUnit unit)
{
if (image == null)
throw new ArgumentNullException("image");
XBitmapImage bmImage = image as XBitmapImage;
if (bmImage != null)
{
#if CORE
return null;
#endif
#if GDI && !WPF
Graphics gfx = Graphics.FromImage(image._gdiImage);
image.XImageState = image.XImageState | XImageState.UsedInDrawingContext;
return new XGraphics(gfx, new XSize(image.PixelWidth, image.PixelHeight), unit, XPageDirection.Downwards);
#endif
#if WPF && !GDI
DiagnosticsHelper.ThrowNotImplementedException("WPF image");
return null;
#endif
#if NETFX_CORE
DiagnosticsHelper.ThrowNotImplementedException("NETFX_CORE image");
return null;
#endif
}
return null;
}
/// <summary>
/// Internal setup.
/// </summary>
void Initialize()
{
_pageOrigin = new XPoint();
double pageHeight = _pageSize.Height;
PdfPage targetPage = PdfPage;
XPoint trimOffset = new XPoint();
if (targetPage != null && targetPage.TrimMargins.AreSet)
{
pageHeight += targetPage.TrimMargins.Top.Point + targetPage.TrimMargins.Bottom.Point;
trimOffset = new XPoint(targetPage.TrimMargins.Left.Point, targetPage.TrimMargins.Top.Point);
}
XMatrix matrix = new XMatrix();
#if CORE
// Nothing to do here.
Debug.Assert(TargetContext == XGraphicTargetContext.CORE);
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterFontFactory();
if (_gfx != null)
matrix = _gfx.Transform;
if (_pageUnit != XGraphicsUnit.Point)
{
switch (_pageUnit)
{
case XGraphicsUnit.Inch:
matrix.ScalePrepend(XUnit.InchFactor);
break;
case XGraphicsUnit.Millimeter:
matrix.ScalePrepend(XUnit.MillimeterFactor);
break;
case XGraphicsUnit.Centimeter:
matrix.ScalePrepend(XUnit.CentimeterFactor);
break;
case XGraphicsUnit.Presentation:
matrix.ScalePrepend(XUnit.PresentationFactor);
break;
}
if (_gfx != null)
_gfx.Transform = (GdiMatrix)matrix;
}
}
finally { Lock.ExitFontFactory(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
if (_pageUnit != XGraphicsUnit.Presentation)
{
switch (_pageUnit)
{
case XGraphicsUnit.Point:
matrix.ScalePrepend(XUnit.PointFactorWpf);
break;
case XGraphicsUnit.Inch:
matrix.ScalePrepend(XUnit.InchFactorWpf);
break;
case XGraphicsUnit.Millimeter:
matrix.ScalePrepend(XUnit.MillimeterFactorWpf);
break;
case XGraphicsUnit.Centimeter:
matrix.ScalePrepend(XUnit.CentimeterFactorWpf);
break;
}
if (!matrix.IsIdentity)
{
#if !SILVERLIGHT
MatrixTransform transform = new MatrixTransform((SysMatrix)matrix);
_dc.PushTransform(transform);
#else
MatrixTransform transform2 = new MatrixTransform();
transform2.Matrix = (SysMatrix)matrix;
_dc.PushTransform(transform2);
#endif
}
}
}
#endif
if (_pageDirection != XPageDirection.Downwards)
matrix.Prepend(new XMatrix(1, 0, 0, -1, 0, pageHeight));
if (trimOffset != new XPoint())
matrix.TranslatePrepend(trimOffset.X, -trimOffset.Y);
DefaultViewMatrix = matrix;
_transform = new XMatrix();
}
/// <summary>
/// Releases all resources used by this object.
/// </summary>
public void Dispose()
{
Dispose(true);
}
void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
if (disposing)
{
// Dispose managed resources.
if (_associatedImage != null)
{
_associatedImage.DisassociateWithGraphics(this);
_associatedImage = null;
}
}
if (_form != null)
_form.Finish();
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
// GDI+ requires this to disassociate it from metafiles.
if (_gfx != null)
_gfx.Dispose();
_gfx = null;
Metafile = null;
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (_dc != null)
{
_dc.Close();
#if !SILVERLIGHT
// Free resources. Only needed when running on a server, but does no harm with desktop applications.
// Needed on server, but causes harm with WPF desktop application. So now what?
//_dc.Dispatcher.InvokeShutdown();
_dv = null;
#endif
}
#endif
_drawGraphics = false;
if (_renderer != null)
{
_renderer.Close();
_renderer = null;
}
}
}
bool _disposed;
/// <summary>
/// Internal hack for MigraDoc. Will be removed in further releases.
/// Unicode support requires a global refactoring of MigraDoc and will be done in further releases.
/// </summary>
// ReSharper disable once InconsistentNaming
// ReSharper disable once ConvertToAutoProperty
public PdfFontEncoding MUH // MigraDoc Unicode Hack...
{
get { return _muh; }
set { _muh = value; }
}
PdfFontEncoding _muh;
/// <summary>
/// A value indicating whether GDI+ or WPF is used as context.
/// </summary>
internal XGraphicTargetContext TargetContext;
/// <summary>
/// Gets or sets the unit of measure used for page coordinates.
/// CURRENTLY ONLY POINT IS IMPLEMENTED.
/// </summary>
public XGraphicsUnit PageUnit
{
get { return _pageUnit; }
//set
//{
// // TODO: other page units
// if (value != XGraphicsUnit.Point)
// throw new NotImplementedException("PageUnit must be XGraphicsUnit.Point in current implementation.");
//}
}
readonly XGraphicsUnit _pageUnit;
/// <summary>
/// Gets or sets the a value indicating in which direction y-value grow.
/// </summary>
public XPageDirection PageDirection
{
get { return _pageDirection; }
set
{
// Is there really anybody who needs the concept of XPageDirection.Upwards?
if (value != XPageDirection.Downwards)
throw new NotImplementedException("PageDirection must be XPageDirection.Downwards in current implementation.");
}
}
readonly XPageDirection _pageDirection;
/// <summary>
/// Gets the current page origin. Setting the origin is not yet implemented.
/// </summary>
public XPoint PageOrigin
{
get { return _pageOrigin; }
set
{
// Is there really anybody who needs to set the page origin?
if (value != new XPoint())
throw new NotImplementedException("PageOrigin cannot be modified in current implementation.");
}
}
XPoint _pageOrigin;
/// <summary>
/// Gets the current size of the page.
/// </summary>
public XSize PageSize
{
get { return _pageSize; }
//set
//{
// //TODO
// throw new NotImplementedException("PageSize cannot be modified in current implementation.");
//}
}
XSize _pageSize;
XSize _pageSizePoints;
#region Drawing
// ----- DrawLine -----------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws a line connecting two Point structures.
/// </summary>
public void DrawLine(XPen pen, GdiPoint pt1, GdiPoint pt2)
{
// Because of overloading the cast is NOT redundant.
DrawLine(pen, (double)pt1.X, (double)pt1.Y, (double)pt2.X, (double)pt2.Y);
}
#endif
#if WPF
/// <summary>
/// Draws a line connecting two Point structures.
/// </summary>
public void DrawLine(XPen pen, SysPoint pt1, SysPoint pt2)
{
DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
}
#endif
#if GDI
/// <summary>
/// Draws a line connecting two GdiPointF structures.
/// </summary>
public void DrawLine(XPen pen, GdiPointF pt1, GdiPointF pt2)
{
DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
}
#endif
/// <summary>
/// Draws a line connecting two XPoint structures.
/// </summary>
public void DrawLine(XPen pen, XPoint pt1, XPoint pt2)
{
DrawLine(pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
}
/// <summary>
/// Draws a line connecting the two points specified by coordinate pairs.
/// </summary>
public void DrawLine(XPen pen, double x1, double y1, double x2, double y2)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawLine(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawLine(pen.RealizeWpfPen(), new SysPoint(x1, y1), new SysPoint(x2, y2));
#endif
#if UWP
_cds.DrawLine(new Vector2((float)x1, (float)x2), new Vector2((float)x2, (float)y2), Colors.Red, (float)pen.Width);
#endif
}
if (_renderer != null)
_renderer.DrawLines(pen, new[] { new XPoint(x1, y1), new XPoint(x2, y2) });
}
// ----- DrawLines ----------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws a series of line segments that connect an array of points.
/// </summary>
public void DrawLines(XPen pen, GdiPoint[] points)
{
DrawLines(pen, MakePointFArray(points, 0, points.Length));
}
#endif
#if WPF || NETFX_CORE
/// <summary>
/// Draws a series of line segments that connect an array of points.
/// </summary>
public void DrawLines(XPen pen, SysPoint[] points)
{
DrawLines(pen, XGraphics.MakeXPointArray(points, 0, points.Length));
}
#endif
#if GDI
/// <summary>
/// Draws a series of line segments that connect an array of points.
/// </summary>
public void DrawLines(XPen pen, GdiPointF[] points)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (points == null)
throw new ArgumentNullException("points");
if (points.Length < 2)
throw new ArgumentException(PSSR.PointArrayAtLeast(2), "points");
if (_drawGraphics)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawLines(pen.RealizeGdiPen(), points);
}
finally { Lock.ExitGdiPlus(); }
}
if (_renderer != null)
_renderer.DrawLines(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
/// <summary>
/// Draws a series of line segments that connect an array of points.
/// </summary>
public void DrawLines(XPen pen, XPoint[] points)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (points == null)
throw new ArgumentNullException("points");
if (points.Length < 2)
throw new ArgumentException(PSSR.PointArrayAtLeast(2), "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawLines(pen.RealizeGdiPen(), XGraphics.MakePointFArray(points));
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
#if !SILVERLIGHT
PolyLineSegment seg = new PolyLineSegment(XGraphics.MakePointArray(points), true);
#else
Point[] pts = XGraphics.MakePointArray(points);
PointCollection collection = new PointCollection();
foreach (Point point in pts)
collection.Add(point);
PolyLineSegment seg = new PolyLineSegment();
seg.Points = collection;
#endif
PathFigure figure = new PathFigure();
figure.IsFilled = false;
figure.StartPoint = new SysPoint(points[0].X, points[0].Y);
figure.Segments.Add(seg);
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(null, pen.RealizeWpfPen(), geo);
}
#endif
#if UWP
var pathBuilder = new CanvasPathBuilder(_cds.Device);
pathBuilder.BeginFigure((float)points[0].X, (float)points[0].Y, CanvasFigureFill.DoesNotAffectFills);
int length = points.Length;
for (int idx = 1; idx < length; idx++)
pathBuilder.AddLine((float)points[idx].X, (float)points[idx].Y);
pathBuilder.EndFigure(CanvasFigureLoop.Open);
var geometry = CanvasGeometry.CreatePath(pathBuilder);
_cds.DrawGeometry(geometry, Colors.Red);
#endif
}
if (_renderer != null)
_renderer.DrawLines(pen, points);
}
/// <summary>
/// Draws a series of line segments that connect an array of x and y pairs.
/// </summary>
public void DrawLines(XPen pen, double x, double y, params double[] value)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (value == null)
throw new ArgumentNullException("value");
int length = value.Length;
XPoint[] points = new XPoint[length / 2 + 1];
points[0].X = x;
points[0].Y = y;
for (int idx = 0; idx < length / 2; idx++)
{
points[idx + 1].X = value[2 * idx];
points[idx + 1].Y = value[2 * idx + 1];
}
DrawLines(pen, points);
}
// ----- DrawBezier ---------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws a B<>zier spline defined by four points.
/// </summary>
public void DrawBezier(XPen pen, GdiPoint pt1, GdiPoint pt2, GdiPoint pt3, GdiPoint pt4)
{
// ReSharper disable RedundantCast because it is required
DrawBezier(pen, (double)pt1.X, (double)pt1.Y, (double)pt2.X, (double)pt2.Y,
(double)pt3.X, (double)pt3.Y, (double)pt4.X, (double)pt4.Y);
// ReSharper restore RedundantCast
}
#endif
#if WPF
/// <summary>
/// Draws a B<>zier spline defined by four points.
/// </summary>
public void DrawBezier(XPen pen, SysPoint pt1, SysPoint pt2, SysPoint pt3, SysPoint pt4)
{
DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
}
#endif
#if GDI
/// <summary>
/// Draws a B<>zier spline defined by four points.
/// </summary>
public void DrawBezier(XPen pen, GdiPointF pt1, GdiPointF pt2, GdiPointF pt3, GdiPointF pt4)
{
DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
}
#endif
/// <summary>
/// Draws a B<>zier spline defined by four points.
/// </summary>
public void DrawBezier(XPen pen, XPoint pt1, XPoint pt2, XPoint pt3, XPoint pt4)
{
DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
}
/// <summary>
/// Draws a B<>zier spline defined by four points.
/// </summary>
public void DrawBezier(XPen pen, double x1, double y1, double x2, double y2,
double x3, double y3, double x4, double y4)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawBezier(pen.RealizeGdiPen(), (float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3, (float)x4, (float)y4);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
#if !SILVERLIGHT
BezierSegment seg = new BezierSegment(new SysPoint(x2, y2), new SysPoint(x3, y3), new SysPoint(x4, y4), true);
#else
BezierSegment seg = new BezierSegment();
seg.Point1 = new SysPoint(x2, y2);
seg.Point2 = new SysPoint(x3, y3);
seg.Point3 = new SysPoint(x4, y4);
#endif
PathFigure figure = new PathFigure();
figure.StartPoint = new SysPoint(x1, y1);
figure.Segments.Add(seg);
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(null, pen.RealizeWpfPen(), geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawBeziers(pen,
new XPoint[] { new XPoint(x1, y1), new XPoint(x2, y2), new XPoint(x3, y3), new XPoint(x4, y4) });
}
// ----- DrawBeziers --------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws a series of B<>zier splines from an array of points.
/// </summary>
public void DrawBeziers(XPen pen, GdiPoint[] points)
{
DrawBeziers(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
#if WPF
/// <summary>
/// Draws a series of B<>zier splines from an array of points.
/// </summary>
public void DrawBeziers(XPen pen, SysPoint[] points)
{
DrawBeziers(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
#if GDI
/// <summary>
/// Draws a series of B<>zier splines from an array of points.
/// </summary>
public void DrawBeziers(XPen pen, GdiPointF[] points)
{
DrawBeziers(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
/// <summary>
/// Draws a series of B<>zier splines from an array of points.
/// </summary>
public void DrawBeziers(XPen pen, XPoint[] points)
{
if (pen == null)
throw new ArgumentNullException("pen");
int count = points.Length;
if (count == 0)
return;
if ((count - 1) % 3 != 0)
throw new ArgumentException("Invalid number of points for bezier curves. Number must fulfill 4+3n.", "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawBeziers(pen.RealizeGdiPen(), MakePointFArray(points));
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
PathFigure figure = new PathFigure();
figure.StartPoint = new SysPoint(points[0].X, points[0].Y);
for (int idx = 1; idx < count; idx += 3)
{
#if !SILVERLIGHT
BezierSegment seg = new BezierSegment(
new SysPoint(points[idx].X, points[idx].Y),
new SysPoint(points[idx + 1].X, points[idx + 1].Y),
new SysPoint(points[idx + 2].X, points[idx + 2].Y), true);
#else
BezierSegment seg = new BezierSegment();
seg.Point1 = new SysPoint(points[idx].X, points[idx].Y);
seg.Point2 = new SysPoint(points[idx + 1].X, points[idx + 1].Y);
seg.Point3 = new SysPoint(points[idx + 2].X, points[idx + 2].Y);
#endif
figure.Segments.Add(seg);
}
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(null, pen.RealizeWpfPen(), geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawBeziers(pen, points);
}
// ----- DrawCurve ----------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws a cardinal spline through a specified array of points.
/// </summary>
public void DrawCurve(XPen pen, GdiPoint[] points)
{
DrawCurve(pen, MakePointFArray(points, 0, points.Length), 0.5);
}
/// <summary>
/// Draws a cardinal spline through a specified array of point using a specified tension.
/// The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, GdiPoint[] points, int offset, int numberOfSegments, double tension)
{
DrawCurve(pen, MakePointFArray(points, offset, numberOfSegments), tension);
}
#endif
#if WPF
/// <summary>
/// Draws a cardinal spline through a specified array of points.
/// </summary>
public void DrawCurve(XPen pen, SysPoint[] points)
{
DrawCurve(pen, MakeXPointArray(points, 0, points.Length), 0.5);
}
/// <summary>
/// Draws a cardinal spline through a specified array of point. The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, SysPoint[] points, int offset, int numberOfSegments)
{
DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a cardinal spline through a specified array of points.
/// </summary>
public void DrawCurve(XPen pen, GdiPointF[] points)
{
DrawCurve(pen, MakeXPointArray(points, 0, points.Length), 0.5);
}
#endif
/// <summary>
/// Draws a cardinal spline through a specified array of points.
/// </summary>
public void DrawCurve(XPen pen, XPoint[] points)
{
DrawCurve(pen, points, 0.5);
}
#if GDI
/// <summary>
/// Draws a cardinal spline through a specified array of points using a specified tension.
/// </summary>
public void DrawCurve(XPen pen, GdiPoint[] points, double tension)
{
DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension);
}
#endif
#if WPF
/// <summary>
/// Draws a cardinal spline through a specified array of points using a specified tension.
/// </summary>
public void DrawCurve(XPen pen, SysPoint[] points, double tension)
{
DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension);
}
/// <summary>
/// Draws a cardinal spline through a specified array of point using a specified tension.
/// The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, SysPoint[] points, int offset, int numberOfSegments, double tension)
{
DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), tension);
}
#endif
#if GDI
/// <summary>
/// Draws a cardinal spline through a specified array of points using a specified tension.
/// </summary>
public void DrawCurve(XPen pen, GdiPointF[] points, double tension)
{
DrawCurve(pen, MakeXPointArray(points, 0, points.Length), tension);
}
/// <summary>
/// Draws a cardinal spline through a specified array of point. The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, GdiPointF[] points, int offset, int numberOfSegments)
{
DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), 0.5);
}
/// <summary>
/// Draws a cardinal spline through a specified array of point using a specified tension.
/// The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, GdiPointF[] points, int offset, int numberOfSegments, double tension)
{
DrawCurve(pen, MakeXPointArray(points, offset, numberOfSegments), tension);
}
#endif
/// <summary>
/// Draws a cardinal spline through a specified array of point using a specified tension.
/// The drawing begins offset from the beginning of the array.
/// </summary>
public void DrawCurve(XPen pen, XPoint[] points, int offset, int numberOfSegments, double tension)
{
XPoint[] points2 = new XPoint[numberOfSegments];
Array.Copy(points, offset, points2, 0, numberOfSegments);
DrawCurve(pen, points2, tension);
}
/// <summary>
/// Draws a cardinal spline through a specified array of points using a specified tension.
/// </summary>
public void DrawCurve(XPen pen, XPoint[] points, double tension)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (points == null)
throw new ArgumentNullException("points");
int count = points.Length;
if (count < 2)
throw new ArgumentException("DrawCurve requires two or more points.", "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawCurve(pen.RealizeGdiPen(), MakePointFArray(points), (float)tension);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
tension /= 3;
PathFigure figure = new PathFigure();
figure.StartPoint = new SysPoint(points[0].X, points[0].Y);
if (count == 2)
{
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension));
}
else
{
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[2], tension));
for (int idx = 1; idx < count - 2; idx++)
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension));
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[count - 1], tension));
}
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(null, pen.RealizeWpfPen(), geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawCurve(pen, points, tension);
}
// ----- DrawArc ------------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws an arc representing a portion of an ellipse.
/// </summary>
public void DrawArc(XPen pen, Rectangle rect, double startAngle, double sweepAngle)
{
// Because of overloading the cast is NOT redundant.
DrawArc(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle);
}
#endif
#if GDI
/// <summary>
/// Draws an arc representing a portion of an ellipse.
/// </summary>
public void DrawArc(XPen pen, GdiRectF rect, double startAngle, double sweepAngle)
{
DrawArc(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
#endif
/// <summary>
/// Draws an arc representing a portion of an ellipse.
/// </summary>
public void DrawArc(XPen pen, XRect rect, double startAngle, double sweepAngle)
{
DrawArc(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>
/// Draws an arc representing a portion of an ellipse.
/// </summary>
public void DrawArc(XPen pen, double x, double y, double width, double height, double startAngle, double sweepAngle)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (Math.Abs(sweepAngle) >= 360)
{
DrawEllipse(pen, x, y, width, height);
}
else
{
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
SysPoint startPoint;
ArcSegment seg = GeometryHelper.CreateArcSegment(x, y, width, height, startAngle, sweepAngle, out startPoint);
PathFigure figure = new PathFigure();
figure.StartPoint = startPoint;
figure.Segments.Add(seg);
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(null, pen.RealizeWpfPen(), geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawArc(pen, x, y, width, height, startAngle, sweepAngle);
}
}
// ----- DrawRectangle ------------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, Rectangle rect)
{
// Because of overloading the cast is NOT redundant.
DrawRectangle(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, GdiRectF rect)
{
DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, XRect rect)
{
DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, double x, double y, double width, double height)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
_dc.DrawRectangle(null, pen.RealizeWpfPen(), new Rect(x, y, width, height));
}
#endif
#if UWP
if (TargetContext == XGraphicTargetContext.UWP)
{
_cds.DrawRectangle((float)x, (float)y, (float)width, (float)height, pen.Color.ToUwpColor());
}
#endif
}
if (_renderer != null)
_renderer.DrawRectangle(pen, null, x, y, width, height);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XBrush brush, Rectangle rect)
{
// Because of overloading the cast is NOT redundant.
DrawRectangle(brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XBrush brush, GdiRectF rect)
{
DrawRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XBrush brush, XRect rect)
{
DrawRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XBrush brush, double x, double y, double width, double height)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawRectangle(brush.RealizeWpfBrush(), null, new Rect(x, y, width, height));
#endif
#if UWP
if (TargetContext == XGraphicTargetContext.UWP)
{
_cds.DrawRectangle((float)x, (float)y, (float)width, (float)height, brush.RealizeCanvasBrush());
}
#endif
}
if (_renderer != null)
_renderer.DrawRectangle(null, brush, x, y, width, height);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, XBrush brush, Rectangle rect)
{
// Because of overloading the cast is NOT redundant.
DrawRectangle(pen, brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, XBrush brush, GdiRectF rect)
{
DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, XBrush brush, XRect rect)
{
DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws a rectangle.
/// </summary>
public void DrawRectangle(XPen pen, XBrush brush, double x, double y, double width, double height)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillRectangle(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height);
if (pen != null)
_gfx.DrawRectangle(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawRectangle(
brush != null ? brush.RealizeWpfBrush() : null,
pen != null ? pen.RealizeWpfPen() : null,
new Rect(x, y, width, height));
#endif
}
if (_renderer != null)
_renderer.DrawRectangle(pen, brush, x, y, width, height);
}
// ----- DrawRectangles -----------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, GdiRect[] rectangles)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(pen, null, rectangles);
}
#endif
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, GdiRectF[] rectangles)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(pen, null, rectangles);
}
#endif
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, XRect[] rectangles)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(pen, null, rectangles);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XBrush brush, GdiRect[] rectangles)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(null, brush, rectangles);
}
#endif
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XBrush brush, GdiRectF[] rectangles)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(null, brush, rectangles);
}
#endif
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XBrush brush, XRect[] rectangles)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (rectangles == null)
throw new ArgumentNullException("rectangles");
DrawRectangles(null, brush, rectangles);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, XBrush brush, Rectangle[] rectangles)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (rectangles == null)
throw new ArgumentNullException("rectangles");
if (_drawGraphics)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles);
if (pen != null)
_gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles);
}
finally { Lock.ExitGdiPlus(); }
}
if (_renderer != null)
{
int count = rectangles.Length;
for (int idx = 0; idx < count; idx++)
{
Rectangle rect = rectangles[idx];
_renderer.DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
}
}
#endif
#if GDI
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, XBrush brush, GdiRectF[] rectangles)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (rectangles == null)
throw new ArgumentNullException("rectangles");
if (_drawGraphics)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillRectangles(brush.RealizeGdiBrush(), rectangles);
if (pen != null)
_gfx.DrawRectangles(pen.RealizeGdiPen(), rectangles);
}
finally { Lock.ExitGdiPlus(); }
}
if (_renderer != null)
{
int count = rectangles.Length;
for (int idx = 0; idx < count; idx++)
{
GdiRectF rect = rectangles[idx];
_renderer.DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
}
}
#endif
/// <summary>
/// Draws a series of rectangles.
/// </summary>
public void DrawRectangles(XPen pen, XBrush brush, XRect[] rectangles)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (rectangles == null)
throw new ArgumentNullException("rectangles");
int count = rectangles.Length;
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
GdiRectF[] rects = MakeRectangleFArray(rectangles, 0, rectangles.Length);
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillRectangles(brush.RealizeGdiBrush(), rects);
if (pen != null)
_gfx.DrawRectangles(pen.RealizeGdiPen(), rects);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null;
WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null;
for (int idx = 0; idx < count; idx++)
{
XRect rect = rectangles[idx];
_dc.DrawRectangle(wpfBrush, wpfPen, new SysRect(new SysPoint(rect.X, rect.Y), new SysSize(rect.Width, rect.Height)));
}
}
#endif
}
if (_renderer != null)
{
for (int idx = 0; idx < count; idx++)
{
XRect rect = rectangles[idx];
_renderer.DrawRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
}
}
// ----- DrawRoundedRectangle -----------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, Rectangle rect, GdiSize ellipseSize)
{
DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
#if WPF
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, Rect rect, SysSize ellipseSize)
{
DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, GdiRectF rect, SizeF ellipseSize)
{
DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XRect rect, XSize ellipseSize)
{
DrawRoundedRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, double x, double y, double width, double height, double ellipseWidth, double ellipseHeight)
{
if (pen == null)
throw new ArgumentNullException("pen");
DrawRoundedRectangle(pen, null, x, y, width, height, ellipseWidth, ellipseHeight);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XBrush brush, Rectangle rect, GdiSize ellipseSize)
{
DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
#if WPF
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XBrush brush, Rect rect, SysSize ellipseSize)
{
DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XBrush brush, GdiRectF rect, SizeF ellipseSize)
{
DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XBrush brush, XRect rect, XSize ellipseSize)
{
DrawRoundedRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XBrush brush, double x, double y, double width, double height, double ellipseWidth, double ellipseHeight)
{
if (brush == null)
throw new ArgumentNullException("brush");
DrawRoundedRectangle(null, brush, x, y, width, height, ellipseWidth, ellipseHeight);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XBrush brush, Rectangle rect, GdiSize ellipseSize)
{
// ReSharper disable RedundantCast because it is required
DrawRoundedRectangle(pen, brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height,
(double)ellipseSize.Width, (double)ellipseSize.Height);
// ReSharper restore RedundantCast
}
#endif
#if WPF
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XBrush brush, Rect rect, SysSize ellipseSize)
{
DrawRoundedRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
#if GDI
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XBrush brush, GdiRectF rect, SizeF ellipseSize)
{
DrawRoundedRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
#endif
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XBrush brush, XRect rect, XSize ellipseSize)
{
DrawRoundedRectangle(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, ellipseSize.Width, ellipseSize.Height);
}
/// <summary>
/// Draws a rectangles with round corners.
/// </summary>
public void DrawRoundedRectangle(XPen pen, XBrush brush, double x, double y, double width, double height,
double ellipseWidth, double ellipseHeight)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
XGraphicsPath path = new XGraphicsPath();
path.AddRoundedRectangle(x, y, width, height, ellipseWidth, ellipseHeight);
DrawPath(pen, brush, path);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
_dc.DrawRoundedRectangle(
brush != null ? brush.RealizeWpfBrush() : null,
pen != null ? pen.RealizeWpfPen() : null,
new Rect(x, y, width, height), ellipseWidth / 2, ellipseHeight / 2);
}
#endif
}
if (_renderer != null)
_renderer.DrawRoundedRectangle(pen, brush, x, y, width, height, ellipseWidth, ellipseHeight);
}
// ----- DrawEllipse --------------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, Rectangle rect)
{
DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, GdiRectF rect)
{
DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, XRect rect)
{
DrawEllipse(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, double x, double y, double width, double height)
{
if (pen == null)
throw new ArgumentNullException("pen");
// No DrawArc defined?
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
double radiusX = width / 2;
double radiusY = height / 2;
_dc.DrawEllipse(null, pen.RealizeWpfPen(), new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY);
}
#endif
}
if (_renderer != null)
_renderer.DrawEllipse(pen, null, x, y, width, height);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XBrush brush, Rectangle rect)
{
DrawEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XBrush brush, GdiRectF rect)
{
DrawEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XBrush brush, XRect rect)
{
DrawEllipse(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XBrush brush, double x, double y, double width, double height)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
double radiusX = width / 2;
double radiusY = height / 2;
_dc.DrawEllipse(brush.RealizeWpfBrush(), null, new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY);
}
#endif
}
if (_renderer != null)
_renderer.DrawEllipse(null, brush, x, y, width, height);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, XBrush brush, Rectangle rect)
{
DrawEllipse(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, XBrush brush, GdiRectF rect)
{
DrawEllipse(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, XBrush brush, XRect rect)
{
DrawEllipse(pen, brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws an ellipse defined by a bounding rectangle.
/// </summary>
public void DrawEllipse(XPen pen, XBrush brush, double x, double y, double width, double height)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillEllipse(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height);
if (pen != null)
_gfx.DrawArc(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, 0, 360);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
double radiusX = width / 2;
double radiusY = height / 2;
_dc.DrawEllipse(
brush != null ? brush.RealizeWpfBrush() : null,
pen != null ? pen.RealizeWpfPen() : null,
new SysPoint(x + radiusX, y + radiusY), radiusX, radiusY);
}
#endif
#if UWP
//var cds = new CanvasDrawingSession();
//cds.DrawCachedGeometry();
if (TargetContext == XGraphicTargetContext.UWP)
{
var radiusX = (float)width / 2;
var radiusY = (float)height / 2;
//var geometry = CanvasGeometry.CreateEllipse(_cds.Device, (float)x + radiusX, (float)y + radiusY, radiusX, radiusY);
if (brush != null)
_cds.FillEllipse((float)x + radiusX, (float)y + radiusY, radiusX, radiusY, Colors.Blue);
if (pen != null)
_cds.DrawEllipse((float)x + radiusX, (float)y + radiusY, radiusX, radiusY, pen.Color.ToUwpColor());
}
#endif
}
if (_renderer != null)
_renderer.DrawEllipse(pen, brush, x, y, width, height);
}
// ----- DrawPolygon --------------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, GdiPoint[] points)
{
DrawPolygon(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
#if WPF
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, SysPoint[] points)
{
DrawPolygon(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, GdiPointF[] points)
{
DrawPolygon(pen, MakeXPointArray(points, 0, points.Length));
}
#endif
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, XPoint[] points)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (points == null)
throw new ArgumentNullException("points");
if (points.Length < 2)
throw new ArgumentException(PSSR.PointArrayAtLeast(2), "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawPolygon(pen.RealizeGdiPen(), MakePointFArray(points));
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
_dc.DrawGeometry(null, pen.RealizeWpfPen(), GeometryHelper.CreatePolygonGeometry(MakePointArray(points), XFillMode.Alternate, true));
}
#endif
}
if (_renderer != null)
_renderer.DrawPolygon(pen, null, points, XFillMode.Alternate); // XFillMode is ignored
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XBrush brush, GdiPoint[] points, XFillMode fillmode)
{
DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
#if WPF
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XBrush brush, SysPoint[] points, XFillMode fillmode)
{
DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XBrush brush, GdiPointF[] points, XFillMode fillmode)
{
DrawPolygon(brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XBrush brush, XPoint[] points, XFillMode fillmode)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (points == null)
throw new ArgumentNullException("points");
if (points.Length < 2)
throw new ArgumentException(PSSR.PointArrayAtLeast(2), "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.FillPolygon(brush.RealizeGdiBrush(), MakePointFArray(points), (FillMode)fillmode);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawGeometry(brush.RealizeWpfBrush(), null, GeometryHelper.CreatePolygonGeometry(MakePointArray(points), fillmode, true));
#endif
}
if (_renderer != null)
_renderer.DrawPolygon(null, brush, points, fillmode);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode)
{
DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
#if WPF
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode)
{
DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
#if GDI
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode)
{
DrawPolygon(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode);
}
#endif
/// <summary>
/// Draws a polygon defined by an array of points.
/// </summary>
public void DrawPolygon(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
if (points == null)
throw new ArgumentNullException("points");
if (points.Length < 2)
throw new ArgumentException(PSSR.PointArrayAtLeast(2), "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
GdiPointF[] pts = MakePointFArray(points);
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillPolygon(brush.RealizeGdiBrush(), pts, (FillMode)fillmode);
if (pen != null)
_gfx.DrawPolygon(pen.RealizeGdiPen(), pts);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null;
WpfPen wpfPen = brush != null ? pen.RealizeWpfPen() : null;
_dc.DrawGeometry(wpfBrush, wpfPen, GeometryHelper.CreatePolygonGeometry(MakePointArray(points), fillmode, true));
}
#endif
}
if (_renderer != null)
_renderer.DrawPolygon(pen, brush, points, fillmode);
}
// ----- DrawPie ------------------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, Rectangle rect, double startAngle, double sweepAngle)
{
// ReSharper disable RedundantCast because it is required
DrawPie(pen, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle);
// ReSharper restore RedundantCast
}
#endif
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, GdiRectF rect, double startAngle, double sweepAngle)
{
DrawPie(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
#endif
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, XRect rect, double startAngle, double sweepAngle)
{
DrawPie(pen, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, double x, double y, double width, double height, double startAngle, double sweepAngle)
{
if (pen == null)
throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
DrawPie(pen, null, x, y, width, height, startAngle, sweepAngle);
#endif
}
if (_renderer != null)
_renderer.DrawPie(pen, null, x, y, width, height, startAngle, sweepAngle);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XBrush brush, Rectangle rect, double startAngle, double sweepAngle)
{
// Because of overloading the cast is NOT redundant.
DrawPie(brush, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height, startAngle, sweepAngle);
}
#endif
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XBrush brush, GdiRectF rect, double startAngle, double sweepAngle)
{
DrawPie(brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
#endif
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XBrush brush, XRect rect, double startAngle, double sweepAngle)
{
DrawPie(brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle)
{
if (brush == null)
throw new ArgumentNullException("brush", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
DrawPie(null, brush, x, y, width, height, startAngle, sweepAngle);
#endif
}
if (_renderer != null)
_renderer.DrawPie(null, brush, x, y, width, height, startAngle, sweepAngle);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, XBrush brush, Rectangle rect, double startAngle, double sweepAngle)
{
DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
#endif
#if GDI
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, XBrush brush, GdiRectF rect, double startAngle, double sweepAngle)
{
DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
#endif
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, XBrush brush, XRect rect, double startAngle, double sweepAngle)
{
DrawPie(pen, brush, rect.X, rect.Y, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>
/// Draws a pie defined by an ellipse.
/// </summary>
public void DrawPie(XPen pen, XBrush brush, double x, double y, double width, double height, double startAngle, double sweepAngle)
{
if (pen == null && brush == null)
throw new ArgumentNullException("pen", PSSR.NeedPenOrBrush);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillPie(brush.RealizeGdiBrush(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle);
if (pen != null)
_gfx.DrawPie(pen.RealizeGdiPen(), (float)x, (float)y, (float)width, (float)height, (float)startAngle, (float)sweepAngle);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null;
WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null;
SysPoint center = new SysPoint(x + width / 2, y + height / 2);
SysPoint startArc;
ArcSegment arc = GeometryHelper.CreateArcSegment(x, y, width, height, startAngle, sweepAngle, out startArc);
PathFigure figure = new PathFigure();
figure.StartPoint = center;
#if !SILVERLIGHT
LineSegment seg = new LineSegment(startArc, true);
#else
LineSegment seg = new LineSegment { Point = startArc };
#endif
figure.Segments.Add(seg);
figure.Segments.Add(arc);
figure.IsClosed = true;
PathGeometry geo = new PathGeometry();
geo.Figures.Add(figure);
_dc.DrawGeometry(wpfBrush, wpfPen, geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawPie(pen, brush, x, y, width, height, startAngle, sweepAngle);
}
// ----- DrawClosedCurve ----------------------------------------------------------------------
// ----- stroke -----
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, GdiPoint[] points)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, SysPoint[] points)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, GdiPointF[] points)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XPoint[] points)
{
DrawClosedCurve(pen, null, points, XFillMode.Alternate, 0.5);
}
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, GdiPoint[] points, double tension)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, SysPoint[] points, double tension)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, GdiPointF[] points, double tension)
{
DrawClosedCurve(pen, null, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, tension);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XPoint[] points, double tension)
{
DrawClosedCurve(pen, null, points, XFillMode.Alternate, tension);
}
// ----- fill -----
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPoint[] points)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, SysPoint[] points)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPointF[] points)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, XPoint[] points)
{
DrawClosedCurve(null, brush, points, XFillMode.Alternate, 0.5);
}
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, SysPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPointF[] points, XFillMode fillmode)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(null, brush, points, fillmode, 0.5);
}
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPoint[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, SysPoint[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, GdiPointF[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(null, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XBrush brush, XPoint[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(null, brush, points, fillmode, tension);
}
// ----- stroke and fill -----
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), XFillMode.Alternate, 0.5);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points)
{
DrawClosedCurve(pen, brush, points, XFillMode.Alternate, 0.5);
}
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, 0.5);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode)
{
DrawClosedCurve(pen, brush, points, fillmode, 0.5);
}
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPoint[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
#if WPF
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, SysPoint[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
#if GDI
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, GdiPointF[] points, XFillMode fillmode, double tension)
{
DrawClosedCurve(pen, brush, MakeXPointArray(points, 0, points.Length), fillmode, tension);
}
#endif
/// <summary>
/// Draws a closed cardinal spline defined by an array of points.
/// </summary>
public void DrawClosedCurve(XPen pen, XBrush brush, XPoint[] points, XFillMode fillmode, double tension)
{
if (pen == null && brush == null)
{
// ReSharper disable once NotResolvedInText
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
}
int count = points.Length;
if (count == 0)
return;
if (count < 2)
throw new ArgumentException("Not enough points.", "points");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillClosedCurve(brush.RealizeGdiBrush(), MakePointFArray(points), (FillMode)fillmode, (float)tension);
if (pen != null)
{
// The fillmode is not used by DrawClosedCurve.
_gfx.DrawClosedCurve(pen.RealizeGdiPen(), MakePointFArray(points), (float)tension, (FillMode)fillmode);
}
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
tension /= 3; // Simply tried out. Not proofed why it is correct.
PathFigure figure = new PathFigure();
figure.IsClosed = true;
figure.StartPoint = new SysPoint(points[0].X, points[0].Y);
if (count == 2)
{
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[0], points[0], points[1], points[1], tension));
}
else
{
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 1], points[0], points[1], points[2], tension));
for (int idx = 1; idx < count - 2; idx++)
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[idx - 1], points[idx], points[idx + 1], points[idx + 2], tension));
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 3], points[count - 2], points[count - 1], points[0], tension));
figure.Segments.Add(GeometryHelper.CreateCurveSegment(points[count - 2], points[count - 1], points[0], points[1], tension));
}
PathGeometry geo = new PathGeometry();
geo.FillRule = fillmode == XFillMode.Alternate ? FillRule.EvenOdd : FillRule.Nonzero;
geo.Figures.Add(figure);
WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null;
WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null;
_dc.DrawGeometry(wpfBrush, wpfPen, geo);
}
#endif
}
if (_renderer != null)
_renderer.DrawClosedCurve(pen, brush, points, tension, fillmode);
}
// ----- DrawPath -----------------------------------------------------------------------------
// ----- stroke -----
/// <summary>
/// Draws a graphical path.
/// </summary>
public void DrawPath(XPen pen, XGraphicsPath path)
{
if (pen == null)
throw new ArgumentNullException("pen");
if (path == null)
throw new ArgumentNullException("path");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.DrawPath(pen.RealizeGdiPen(), path._gdipPath);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawGeometry(null, pen.RealizeWpfPen(), path._pathGeometry);
#endif
}
if (_renderer != null)
_renderer.DrawPath(pen, null, path);
}
// ----- fill -----
/// <summary>
/// Draws a graphical path.
/// </summary>
public void DrawPath(XBrush brush, XGraphicsPath path)
{
if (brush == null)
throw new ArgumentNullException("brush");
if (path == null)
throw new ArgumentNullException("path");
if (_drawGraphics)
{
#if GDI
// $TODO THHO Lock???
if (TargetContext == XGraphicTargetContext.GDI)
_gfx.FillPath(brush.RealizeGdiBrush(), path._gdipPath);
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
_dc.DrawGeometry(brush.RealizeWpfBrush(), null, path._pathGeometry);
#endif
}
if (_renderer != null)
_renderer.DrawPath(null, brush, path);
}
// ----- stroke and fill -----
/// <summary>
/// Draws a graphical path.
/// </summary>
public void DrawPath(XPen pen, XBrush brush, XGraphicsPath path)
{
if (pen == null && brush == null)
{
// ReSharper disable once NotResolvedInText
throw new ArgumentNullException("pen and brush", PSSR.NeedPenOrBrush);
}
if (path == null)
throw new ArgumentNullException("path");
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (brush != null)
_gfx.FillPath(brush.RealizeGdiBrush(), path._gdipPath);
if (pen != null)
_gfx.DrawPath(pen.RealizeGdiPen(), path._gdipPath);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
WpfBrush wpfBrush = brush != null ? brush.RealizeWpfBrush() : null;
WpfPen wpfPen = pen != null ? pen.RealizeWpfPen() : null;
_dc.DrawGeometry(wpfBrush, wpfPen, path._pathGeometry);
}
#endif
}
if (_renderer != null)
_renderer.DrawPath(pen, brush, path);
}
// ----- DrawString ---------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, GdiPointF point)
{
DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), XStringFormats.Default);
}
#endif
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, XPoint point)
{
DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), XStringFormats.Default);
}
#if GDI
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, GdiPointF point, XStringFormat format)
{
DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), format);
}
#endif
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, XPoint point, XStringFormat format)
{
DrawString(s, font, brush, new XRect(point.X, point.Y, 0, 0), format);
}
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, double x, double y)
{
DrawString(s, font, brush, new XRect(x, y, 0, 0), XStringFormats.Default);
}
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, double x, double y, XStringFormat format)
{
DrawString(s, font, brush, new XRect(x, y, 0, 0), format);
}
#if GDI
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, GdiRectF layoutRectangle)
{
DrawString(s, font, brush, new XRect(layoutRectangle), XStringFormats.Default);
}
#endif
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, XRect layoutRectangle)
{
DrawString(s, font, brush, layoutRectangle, XStringFormats.Default);
}
#if GDI
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string s, XFont font, XBrush brush, GdiRectF layoutRectangle, XStringFormat format)
{
DrawString(s, font, brush, new XRect(layoutRectangle), format);
}
#endif
/// <summary>
/// Draws the specified text string.
/// </summary>
public void DrawString(string text, XFont font, XBrush brush, XRect layoutRectangle, XStringFormat format)
{
if (text == null)
throw new ArgumentNullException("text");
if (font == null)
throw new ArgumentNullException("font");
if (brush == null)
throw new ArgumentNullException("brush");
if (format != null && format.LineAlignment == XLineAlignment.BaseLine && layoutRectangle.Height != 0)
throw new InvalidOperationException("DrawString: With XLineAlignment.BaseLine the height of the layout rectangle must be 0.");
if (text.Length == 0)
return;
if (format == null)
format = XStringFormats.Default;
// format cannot be null below this line.
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
// Was font created with font resolver?
if (font.GdiFont == null)
throw new InvalidOperationException("This font cannot be used by GDI+.");
try
{
Lock.EnterGdiPlus();
GdiRectF rect = layoutRectangle.ToRectangleF();
if (format.LineAlignment == XLineAlignment.BaseLine)
{
double lineSpace = font.GetHeight(); //old: font.GetHeight(this);
int cellSpace = font.FontFamily.GetLineSpacing(font.Style);
int cellAscent = font.FontFamily.GetCellAscent(font.Style);
int cellDescent = font.FontFamily.GetCellDescent(font.Style);
double cyAscent = lineSpace * cellAscent / cellSpace;
cyAscent = lineSpace * font.CellAscent / font.CellSpace;
rect.Offset(0, (float)-cyAscent);
}
//_gfx.DrawString(text, font.Realize_GdiFont(), brush.RealizeGdiBrush(), rect,
// format != null ? format.RealizeGdiStringFormat() : null);
_gfx.DrawString(text, font.GdiFont, brush.RealizeGdiBrush(), rect,
format.RealizeGdiStringFormat());
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
#if !SILVERLIGHT
double x = layoutRectangle.X;
double y = layoutRectangle.Y;
double lineSpace = font.GetHeight(); // old: font.GetHeight(this);
double cyAscent = lineSpace * font.CellAscent / font.CellSpace;
double cyDescent = lineSpace * font.CellDescent / font.CellSpace;
bool bold = (font.Style & XFontStyle.Bold) != 0;
bool italic = (font.Style & XFontStyle.Italic) != 0;
bool strikeout = (font.Style & XFontStyle.Strikeout) != 0;
bool underline = (font.Style & XFontStyle.Underline) != 0;
//GlyphRun glyphRun=new GlyphRun(font.GlyphTypeface , 0,);
#if DEBUG_
if (font.WpfTypeface.FontFamily.Source == "Segoe UI Light")
GetType();
#endif
FormattedText formattedText = FontHelper.CreateFormattedText(text, font.WpfTypeface, font.Size, brush.RealizeWpfBrush());
//formattedText.SetTextDecorations(TextDecorations.OverLine);
switch (format.Alignment)
{
case XStringAlignment.Near:
// nothing to do, this is the default
//formattedText.TextAlignment = TextAlignment.Left;
break;
case XStringAlignment.Center:
x += layoutRectangle.Width / 2;
formattedText.TextAlignment = TextAlignment.Center;
break;
case XStringAlignment.Far:
x += layoutRectangle.Width;
formattedText.TextAlignment = TextAlignment.Right;
break;
}
if (PageDirection == XPageDirection.Downwards)
{
switch (format.LineAlignment)
{
case XLineAlignment.Near:
//y += cyAscent;
break;
case XLineAlignment.Center:
// TODO use CapHeight. PDFlib also uses 3/4 of ascent
y += -formattedText.Baseline + (cyAscent * 1 / 3) + layoutRectangle.Height / 2;
//y += -formattedText.Baseline + (font.Size * font.Metrics.CapHeight / font.unitsPerEm / 2) + layoutRectangle.Height / 2;
break;
case XLineAlignment.Far:
y += -formattedText.Baseline - cyDescent + layoutRectangle.Height;
break;
case XLineAlignment.BaseLine:
y -= formattedText.Baseline;
break;
}
}
else
{
// TODOWPF: make unit test
switch (format.LineAlignment)
{
case XLineAlignment.Near:
//y += cyDescent;
break;
case XLineAlignment.Center:
// TODO use CapHeight. PDFlib also uses 3/4 of ascent
//y += -(cyAscent * 3 / 4) / 2 + rect.Height / 2;
break;
case XLineAlignment.Far:
//y += -cyAscent + rect.Height;
break;
case XLineAlignment.BaseLine:
// nothing to do
break;
}
}
// BoldSimulation and ItalicSimulation is done only in PDF, not in UI.
if (underline)
{
formattedText.SetTextDecorations(TextDecorations.Underline);
//double underlinePosition = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlinePosition / font.cellSpace;
//double underlineThickness = lineSpace * realizedFont.FontDescriptor.descriptor.UnderlineThickness / font.cellSpace;
//DrawRectangle(null, brush, x, y - underlinePosition, width, underlineThickness);
}
if (strikeout)
{
formattedText.SetTextDecorations(TextDecorations.Strikethrough);
//double strikeoutPosition = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutPosition / font.cellSpace;
//double strikeoutSize = lineSpace * realizedFont.FontDescriptor.descriptor.StrikeoutSize / font.cellSpace;
//DrawRectangle(null, brush, x, y - strikeoutPosition - strikeoutSize, width, strikeoutSize);
}
//_dc.DrawText(formattedText, layoutRectangle.Location.ToPoint());
_dc.DrawText(formattedText, new SysPoint(x, y));
#else
_dc.DrawString(this, text, font, brush, layoutRectangle, format);
#endif
}
#endif
}
if (_renderer != null)
_renderer.DrawString(text, font, brush, layoutRectangle, format);
}
// ----- MeasureString ------------------------------------------------------------------------
/// <summary>
/// Measures the specified string when drawn with the specified font.
/// </summary>
public XSize MeasureString(string text, XFont font, XStringFormat stringFormat)
{
if (text == null)
throw new ArgumentNullException("text");
if (font == null)
throw new ArgumentNullException("font");
if (stringFormat == null)
throw new ArgumentNullException("stringFormat");
#if true
return FontHelper.MeasureString(text, font, stringFormat);
#else
#if GDI && !WPF
//XSize gdiSize; // #MediumTrust
//if (_gfx != null)
// gdiSize = XSize.FromSizeF(_gfx.MeasureString(text, font.Realize_GdiFont(), new GdiPointF(0, 0), stringFormat.RealizeGdiStringFormat()));
//else
// gdiSize = FontHelper.MeasureString(text, font, XStringFormats.Default); // TODO 4STLA: Why is parameter stringFormat not used here?
#if DEBUG_
XSize edfSize = FontHelper.MeasureString(text, font, XStringFormats.Default);
//Debug.Assert(gdiSize == edfSize, "Measure string failed.");
if (gdiSize != edfSize)
{
double dx = Math.Abs(gdiSize.Width - edfSize.Width);
double dy = Math.Abs(gdiSize.Height - edfSize.Height);
Debug.Assert(dx < .05 * gdiSize.Width, "MeasureString: width differs.");
Debug.Assert(dy < .05 * gdiSize.Height, "MeasureString: height differs.");
}
#endif
return FontHelper.MeasureString(text, font, XStringFormats.Default);
#endif
#if WPF && !GDI
#if !SILVERLIGHT
#if DEBUG
FormattedText formattedText = FontHelper.CreateFormattedText(text, font.WpfTypeface, font.Size, WpfBrushes.Black);
XSize size1 = FontHelper.MeasureString(text, font, null);
XSize size2 = new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height);
//Debug.Assert(Math.Abs((size1.Height - size2.Height) * 10) < 1.0);
return size1;
#else
// Same as above, but without code needed for Debug.Assert.
XSize size1 = FontHelper.MeasureString(text, font, null);
return size1;
#endif
#else
// Use the WPF code also for Silverlight.
XSize size1 = FontHelper.MeasureString(text, font, null);
return size1;
#endif
#endif
#if WPF && GDI
#if true_
if (TargetContext == XGraphicTargetContext.GDI)
{
XSize gdiSize = XSize.FromSizeF(_gfx.MeasureString(text, font.Realize_GdiFont(), new GdiPointF(0, 0), stringFormat.RealizeGdiStringFormat()));
#if DEBUG
#if GDI
{
//Debug.WriteLine(gdiSize);
XSize edfSize = FontHelper14.MeasureStringGdi(_gfx, text, font, XStringFormats.Default);
//Debug.WriteLine(edfSize);
//Debug.Assert(gdiSize == edfSize, "Measure string failed.");
if (gdiSize.Width != edfSize.Width)
{
Debug.WriteLine(String.Format("Width: {0}, {1} : {2}", gdiSize.Width, edfSize.Width, gdiSize.Width / edfSize.Width));
}
if (gdiSize.Height != edfSize.Height)
{
Debug.WriteLine(String.Format("Height: {0}, {1}", gdiSize.Height, edfSize.Height));
}
//double lineSpace = font.GetHeight(this);
//int cellSpace = font.cellSpace; // font.FontFamily.GetLineSpacing(font.Style);
//int cellAscent = font.cellAscent; // font.FontFamily.GetCellAscent(font.Style);
//int cellDescent = font.cellDescent; // font.FontFamily.GetCellDescent(font.Style);
//double cyAscent = lineSpace * cellAscent / cellSpace;
//double cyDescent = lineSpace * cellDescent / cellSpace;
}
#endif
#if WPF
{
//Debug.WriteLine(gdiSize);
XSize edfSize = FontHelper14.MeasureStringWpf(text, font, XStringFormats.Default);
//Debug.WriteLine(edfSize);
//Debug.Assert(gdiSize == edfSize, "Measure string failed.");
if (gdiSize.Width != edfSize.Width)
{
Debug.WriteLine(String.Format("Width: {0}, {1} : {2}", gdiSize.Width, edfSize.Width, gdiSize.Width / edfSize.Width));
}
if (gdiSize.Height != edfSize.Height)
{
Debug.WriteLine(String.Format("Height: {0}, {1}", gdiSize.Height, edfSize.Height));
}
//double lineSpace = font.GetHeight(this);
//int cellSpace = font.cellSpace; // font.FontFamily.GetLineSpacing(font.Style);
//int cellAscent = font.cellAscent; // font.FontFamily.GetCellAscent(font.Style);
//int cellDescent = font.cellDescent; // font.FontFamily.GetCellDescent(font.Style);
//double cyAscent = lineSpace * cellAscent / cellSpace;
//double cyDescent = lineSpace * cellDescent / cellSpace;
}
#endif
#endif
return gdiSize;
}
if (TargetContext == XGraphicTargetContext.WPF)
{
//double h = font.Height;
//FormattedText formattedText = new FormattedText(text, new CultureInfo("en-us"),
// FlowDirection.LeftToRight, font.typeface, font.Size, WpfBrushes.Black);
FormattedText formattedText = FontHelper.CreateFormattedText(text, font.Typeface, font.Size, WpfBrushes.Black);
XSize wpfSize = new XSize(formattedText.WidthIncludingTrailingWhitespace, formattedText.Height);
#if DEBUG
Debug.WriteLine(wpfSize);
#endif
return wpfSize;
}
Debug.Assert(false);
return XSize.Empty;
#else
XSize size23 = FontHelper.MeasureString(text, font, XStringFormats.Default);
return size23;
#endif
#endif
#if CORE || NETFX_CORE || UWP
XSize size = FontHelper.MeasureString(text, font, XStringFormats.Default);
return size;
#endif
#endif
}
/// <summary>
/// Measures the specified string when drawn with the specified font.
/// </summary>
public XSize MeasureString(string text, XFont font)
{
return MeasureString(text, font, XStringFormats.Default);
}
// ----- DrawImage ----------------------------------------------------------------------------
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, GdiPoint point)
{
DrawImage(image, point.X, point.Y);
}
#endif
#if WPF
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, SysPoint point)
{
DrawImage(image, point.X, point.Y);
}
#endif
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, GdiPointF point)
{
DrawImage(image, point.X, point.Y);
}
#endif
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, XPoint point)
{
DrawImage(image, point.X, point.Y);
}
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, double x, double y)
{
if (image == null)
throw new ArgumentNullException("image");
CheckXPdfFormConsistence(image);
double width = image.PointWidth;
double height = image.PointHeight;
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (image._gdiImage != null)
{
InterpolationMode interpolationMode = InterpolationMode.Invalid;
if (!image.Interpolate)
{
interpolationMode = _gfx.InterpolationMode;
_gfx.InterpolationMode = InterpolationMode.NearestNeighbor;
}
_gfx.DrawImage(image._gdiImage, (float)x, (float)y, (float)width, (float)height);
if (!image.Interpolate)
_gfx.InterpolationMode = interpolationMode;
}
else
{
DrawMissingImageRect(new XRect(x, y, width, height));
//_gfx.DrawRectangle(Pens.Red, (float)x, (float)y, (float)width, (float)height);
//_gfx.DrawLine(Pens.Red, (float)x, (float)y, (float)(x + width), (float)(y + height));
//_gfx.DrawLine(Pens.Red, (float)(x + width), (float)y, (float)x, (float)(y + height));
}
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
if (image._wpfImage != null)
{
_dc.DrawImage(image._wpfImage, new Rect(x, y, image.PointWidth, image.PointHeight));
}
else
{
DrawMissingImageRect(new XRect(x, y, width, height));
}
}
#endif
}
if (_renderer != null)
_renderer.DrawImage(image, x, y, image.PointWidth, image.PointHeight);
//image.Width * 72 / image.HorizontalResolution,
//image.Height * 72 / image.HorizontalResolution);
}
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, Rectangle rect)
{
// Because of overloading the cast is NOT redundant.
DrawImage(image, (double)rect.X, (double)rect.Y, (double)rect.Width, (double)rect.Height);
}
#endif
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, GdiRectF rect)
{
DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height);
}
#endif
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, XRect rect)
{
DrawImage(image, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, double x, double y, double width, double height)
{
if (image == null)
throw new ArgumentNullException("image");
CheckXPdfFormConsistence(image);
if (_drawGraphics)
{
// THHO4STLA: Platform-independent images cannot be drawn here, can they? => They can. Lazy create platform-dependent image and draw that.
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (image._gdiImage != null)
{
InterpolationMode interpolationMode = InterpolationMode.Invalid;
if (!image.Interpolate)
{
interpolationMode = _gfx.InterpolationMode;
_gfx.InterpolationMode = InterpolationMode.NearestNeighbor;
}
_gfx.DrawImage(image._gdiImage, (float)x, (float)y, (float)width, (float)height);
if (!image.Interpolate)
_gfx.InterpolationMode = interpolationMode;
}
else
{
XImage placeholder = null;
XPdfForm pdfForm = image as XPdfForm;
if (pdfForm != null)
{
//XPdfForm pf = pdfForm;
if (pdfForm.PlaceHolder != null)
placeholder = pdfForm.PlaceHolder;
}
if (placeholder != null)
_gfx.DrawImage(placeholder._gdiImage, (float)x, (float)y, (float)width,
(float)height);
else
{
DrawMissingImageRect(new XRect(x, y, width, height));
}
}
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
if (image._wpfImage != null)
{
//InterpolationMode interpolationMode = InterpolationMode.Invalid;
//if (!image.Interpolate)
//{
// interpolationMode = gfx.InterpolationMode;
// gfx.InterpolationMode = InterpolationMode.NearestNeighbor;
//}
_dc.DrawImage(image._wpfImage, new Rect(x, y, width, height));
//if (!image.Interpolate)
// gfx.InterpolationMode = interpolationMode;
}
else
{
XImage placeholder = null;
if (image is XPdfForm)
{
XPdfForm pf = image as XPdfForm;
if (pf.PlaceHolder != null)
placeholder = pf.PlaceHolder;
}
if (placeholder != null)
_dc.DrawImage(placeholder._wpfImage, new Rect(x, y, width, height));
else
DrawMissingImageRect(new XRect(x, y, width, height));
}
}
#endif
}
if (_renderer != null)
_renderer.DrawImage(image, x, y, width, height);
}
// TODO: calculate destination size
//public void DrawImage(XImage image, double x, double y, GdiRectF srcRect, XGraphicsUnit srcUnit)
//public void DrawImage(XImage image, double x, double y, XRect srcRect, XGraphicsUnit srcUnit)
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, Rectangle destRect, Rectangle srcRect, XGraphicsUnit srcUnit)
{
XRect destRectX = new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height);
XRect srcRectX = new XRect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height);
DrawImage(image, destRectX, srcRectX, srcUnit);
}
#endif
#if GDI
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, GdiRectF destRect, GdiRectF srcRect, XGraphicsUnit srcUnit)
{
XRect destRectX = new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height);
XRect srcRectX = new XRect(srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height);
DrawImage(image, destRectX, srcRectX, srcUnit);
}
#endif
/// <summary>
/// Draws the specified image.
/// </summary>
public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit srcUnit)
{
if (image == null)
throw new ArgumentNullException("image");
CheckXPdfFormConsistence(image);
if (_drawGraphics)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
if (image._gdiImage != null)
{
InterpolationMode interpolationMode = InterpolationMode.Invalid;
if (!image.Interpolate)
{
interpolationMode = _gfx.InterpolationMode;
_gfx.InterpolationMode = InterpolationMode.NearestNeighbor;
}
GdiRectF destRectF = new GdiRectF((float)destRect.X, (float)destRect.Y,
(float)destRect.Width, (float)destRect.Height);
GdiRectF srcRectF = new GdiRectF((float)srcRect.X, (float)srcRect.Y,
(float)srcRect.Width, (float)srcRect.Height);
_gfx.DrawImage(image._gdiImage, destRectF, srcRectF, GraphicsUnit.Pixel);
if (!image.Interpolate)
_gfx.InterpolationMode = interpolationMode;
}
else
{
DrawMissingImageRect(new XRect(destRect.X, destRect.Y, destRect.Width, destRect.Height));
}
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
if (image._wpfImage != null)
{
//InterpolationMode interpolationMode = InterpolationMode.Invalid;
//if (!image.Interpolate)
//{
// interpolationMode = gfx.InterpolationMode;
// //gfx.InterpolationMode = InterpolationMode.NearestNeighbor;
//}
// HACK: srcRect is ignored
//double x = destRect.X;
//double y = destRect.Y;
_dc.DrawImage(image._wpfImage, new SysRect(destRect.X, destRect.Y, destRect.Width, destRect.Height));
//if (!image.Interpolate)
// gfx.InterpolationMode = interpolationMode;
}
else
{
DrawMissingImageRect(destRect);
}
}
#endif
}
if (_renderer != null)
_renderer.DrawImage(image, destRect, srcRect, srcUnit);
}
//TODO?
//public void DrawImage(XImage image, Rectangle destRect, double srcX, double srcY, double srcWidth, double srcHeight, GraphicsUnit srcUnit);
//public void DrawImage(XImage image, Rectangle destRect, double srcX, double srcY, double srcWidth, double srcHeight, GraphicsUnit srcUnit);
void DrawMissingImageRect(XRect rect)
{
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
float x = (float)rect.X;
float y = (float)rect.Y;
float width = (float)rect.Width;
float height = (float)rect.Height;
_gfx.DrawRectangle(Pens.Red, x, y, width, height);
_gfx.DrawLine(Pens.Red, x, y, x + width, y + height);
_gfx.DrawLine(Pens.Red, x + width, y, x, y + height);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
double x = rect.X;
double y = rect.Y;
double width = rect.Width;
double height = rect.Height;
#if !SILVERLIGHT
WpfPen pen = new WpfPen(WpfBrushes.Red, 1);
#else
WpfPen pen = new WpfPen();
pen.Brush = new SolidColorBrush(Colors.Red);
pen.Thickness = 1;
#endif
_dc.DrawRectangle(null, pen, new Rect(x, y, width, height));
_dc.DrawLine(pen, new SysPoint(x, y), new SysPoint(x + width, y + height));
_dc.DrawLine(pen, new SysPoint(x + width, y), new SysPoint(x, y + height));
}
#endif
}
/// <summary>
/// Checks whether drawing is allowed and disposes the XGraphics object, if necessary.
/// </summary>
void CheckXPdfFormConsistence(XImage image)
{
XForm xForm = image as XForm;
if (xForm != null)
{
// Force disposing of XGraphics that draws the content
xForm.Finish();
// ReSharper disable once MergeSequentialChecks
if (_renderer != null && (_renderer as XGraphicsPdfRenderer) != null)
{
if (xForm.Owner != null && xForm.Owner != ((XGraphicsPdfRenderer)_renderer).Owner)
throw new InvalidOperationException(
"A XPdfForm object is always bound to the document it was created for and cannot be drawn in the context of another document.");
if (xForm == ((XGraphicsPdfRenderer)_renderer)._form)
throw new InvalidOperationException(
"A XPdfForm cannot be drawn on itself.");
}
}
}
// ----- DrawBarCode --------------------------------------------------------------------------
/// <summary>
/// Draws the specified bar code.
/// </summary>
public void DrawBarCode(BarCodes.BarCode barcode, XPoint position)
{
barcode.Render(this, XBrushes.Black, null, position);
}
/// <summary>
/// Draws the specified bar code.
/// </summary>
public void DrawBarCode(BarCodes.BarCode barcode, XBrush brush, XPoint position)
{
barcode.Render(this, brush, null, position);
}
/// <summary>
/// Draws the specified bar code.
/// </summary>
public void DrawBarCode(BarCodes.BarCode barcode, XBrush brush, XFont font, XPoint position)
{
barcode.Render(this, brush, font, position);
}
// ----- DrawMatrixCode -----------------------------------------------------------------------
/// <summary>
/// Draws the specified data matrix code.
/// </summary>
public void DrawMatrixCode(BarCodes.MatrixCode matrixcode, XPoint position)
{
matrixcode.Render(this, XBrushes.Black, position);
}
/// <summary>
/// Draws the specified data matrix code.
/// </summary>
public void DrawMatrixCode(BarCodes.MatrixCode matrixcode, XBrush brush, XPoint position)
{
matrixcode.Render(this, brush, position);
}
#endregion
// --------------------------------------------------------------------------------------------
#region Save and Restore
/// <summary>
/// Saves the current state of this XGraphics object and identifies the saved state with the
/// returned XGraphicsState object.
/// </summary>
public XGraphicsState Save()
{
XGraphicsState xState = null;
#if CORE || NETFX_CORE
if (TargetContext == XGraphicTargetContext.CORE || TargetContext == XGraphicTargetContext.NONE)
{
xState = new XGraphicsState();
InternalGraphicsState iState = new InternalGraphicsState(this, xState);
iState.Transform = _transform;
_gsStack.Push(iState);
}
else
{
Debug.Assert(false, "XGraphicTargetContext must be XGraphicTargetContext.CORE.");
}
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
xState = new XGraphicsState(_gfx != null ? _gfx.Save() : null);
InternalGraphicsState iState = new InternalGraphicsState(this, xState);
iState.Transform = _transform;
_gsStack.Push(iState);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
xState = new XGraphicsState();
InternalGraphicsState iState = new InternalGraphicsState(this, xState);
iState.Transform = _transform;
_gsStack.Push(iState);
}
#endif
if (_renderer != null)
_renderer.Save(xState);
return xState;
}
/// <summary>
/// Restores the state of this XGraphics object to the state represented by the specified
/// XGraphicsState object.
/// </summary>
public void Restore(XGraphicsState state)
{
if (state == null)
throw new ArgumentNullException("state");
#if CORE
if (TargetContext == XGraphicTargetContext.CORE)
{
_gsStack.Restore(state.InternalState);
_transform = state.InternalState.Transform;
}
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gsStack.Restore(state.InternalState);
if (_gfx != null)
_gfx.Restore(state.GdiState);
_transform = state.InternalState.Transform;
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
_gsStack.Restore(state.InternalState);
_transform = state.InternalState.Transform;
}
#endif
if (_renderer != null)
_renderer.Restore(state);
}
/// <summary>
/// Restores the state of this XGraphics object to the state before the most recently call of Save.
/// </summary>
public void Restore()
{
if (_gsStack.Count == 0)
throw new InvalidOperationException("Cannot restore without preceding save operation.");
Restore(_gsStack.Current.State);
}
/// <summary>
/// Saves a graphics container with the current state of this XGraphics and
/// opens and uses a new graphics container.
/// </summary>
public XGraphicsContainer BeginContainer()
{
return BeginContainer(new XRect(0, 0, 1, 1), new XRect(0, 0, 1, 1), XGraphicsUnit.Point);
}
#if GDI
/// <summary>
/// Saves a graphics container with the current state of this XGraphics and
/// opens and uses a new graphics container.
/// </summary>
public XGraphicsContainer BeginContainer(Rectangle dstrect, Rectangle srcrect, XGraphicsUnit unit)
{
return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit);
}
#endif
#if GDI
/// <summary>
/// Saves a graphics container with the current state of this XGraphics and
/// opens and uses a new graphics container.
/// </summary>
public XGraphicsContainer BeginContainer(GdiRectF dstrect, GdiRectF srcrect, XGraphicsUnit unit)
{
return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit);
}
#endif
#if WPF
/// <summary>
/// Saves a graphics container with the current state of this XGraphics and
/// opens and uses a new graphics container.
/// </summary>
public XGraphicsContainer BeginContainer(Rect dstrect, Rect srcrect, XGraphicsUnit unit)
{
return BeginContainer(new XRect(dstrect), new XRect(dstrect), unit);
}
#endif
/// <summary>
/// Saves a graphics container with the current state of this XGraphics and
/// opens and uses a new graphics container.
/// </summary>
public XGraphicsContainer BeginContainer(XRect dstrect, XRect srcrect, XGraphicsUnit unit)
{
// TODO: unit
if (unit != XGraphicsUnit.Point)
throw new ArgumentException("The current implementation supports XGraphicsUnit.Point only.", "unit");
XGraphicsContainer xContainer = null;
#if CORE
if (TargetContext == XGraphicTargetContext.CORE)
xContainer = new XGraphicsContainer();
#endif
#if GDI
// _gfx can be null if drawing applies to PDF page only.
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
xContainer = new XGraphicsContainer(_gfx != null ? _gfx.Save() : null);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
xContainer = new XGraphicsContainer();
#endif
InternalGraphicsState iState = new InternalGraphicsState(this, xContainer);
iState.Transform = _transform;
_gsStack.Push(iState);
if (_renderer != null)
_renderer.BeginContainer(xContainer, dstrect, srcrect, unit);
XMatrix matrix = new XMatrix();
double scaleX = dstrect.Width / srcrect.Width;
double scaleY = dstrect.Height / srcrect.Height;
matrix.TranslatePrepend(-srcrect.X, -srcrect.Y);
matrix.ScalePrepend(scaleX, scaleY);
matrix.TranslatePrepend(dstrect.X / scaleX, dstrect.Y / scaleY);
AddTransform(matrix, XMatrixOrder.Prepend);
return xContainer;
}
/// <summary>
/// Closes the current graphics container and restores the state of this XGraphics
/// to the state saved by a call to the BeginContainer method.
/// </summary>
public void EndContainer(XGraphicsContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_gsStack.Restore(container.InternalState);
#if CORE
// nothing to do
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI && _gfx != null)
{
try
{
Lock.EnterGdiPlus();
_gfx.Restore(container.GdiState);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
// nothing to do
#endif
_transform = container.InternalState.Transform;
if (_renderer != null)
_renderer.EndContainer(container);
}
/// <summary>
/// Gets the current graphics state level. The default value is 0. Each call of Save or BeginContainer
/// increased and each call of Restore or EndContainer decreased the value by 1.
/// </summary>
public int GraphicsStateLevel
{
get { return _gsStack.Count; }
}
#endregion
// --------------------------------------------------------------------------------------------
#region Properties
/// <summary>
/// Gets or sets the smoothing mode.
/// </summary>
/// <value>The smoothing mode.</value>
public XSmoothingMode SmoothingMode
{
get
{
#if CORE
// nothing to do
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI &&
_gfx != null)
{
try
{
Lock.EnterGdiPlus();
return (XSmoothingMode)_gfx.SmoothingMode;
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
// nothing to do
#endif
return _smoothingMode;
}
set
{
_smoothingMode = value;
#if CORE
// nothing to do
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI &&
_gfx != null)
{
try
{
Lock.EnterGdiPlus();
_gfx.SmoothingMode = (SmoothingMode)value;
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF
// nothing to do
#endif
}
}
XSmoothingMode _smoothingMode;
//public Region Clip { get; set; }
//public GdiRectF ClipBounds { get; }
//public CompositingMode CompositingMode { get; set; }
//public CompositingQuality CompositingQuality { get; set; }
//public float DpiX { get; }
//public float DpiY { get; }
//public InterpolationMode InterpolationMode { get; set; }
//public bool IsClipEmpty { get; }
//public bool IsVisibleClipEmpty { get; }
//public float PageScale { get; set; }
//public GraphicsUnit PageUnit { get; set; }
//public PixelOffsetMode PixelOffsetMode { get; set; }
//public Point RenderingOrigin { get; set; }
//public SmoothingMode SmoothingMode { get; set; }
//public int TextContrast { get; set; }
//public TextRenderingHint TextRenderingHint { get; set; }
//public Matrix Transform { get; set; }
//public GdiRectF VisibleClipBounds { get; }
#endregion
// --------------------------------------------------------------------------------------------
#region Transformation
/// <summary>
/// Applies the specified translation operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void TranslateTransform(double dx, double dy)
{
AddTransform(XMatrix.CreateTranslation(dx, dy), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified translation operation to the transformation matrix of this object
/// in the specified order.
/// </summary>
public void TranslateTransform(double dx, double dy, XMatrixOrder order)
{
XMatrix matrix = new XMatrix();
matrix.TranslatePrepend(dx, dy);
AddTransform(matrix, order);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void ScaleTransform(double scaleX, double scaleY)
{
AddTransform(XMatrix.CreateScaling(scaleX, scaleY), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object
/// in the specified order.
/// </summary>
public void ScaleTransform(double scaleX, double scaleY, XMatrixOrder order)
{
XMatrix matrix = new XMatrix();
matrix.ScalePrepend(scaleX, scaleY);
AddTransform(matrix, order);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
// ReSharper disable once InconsistentNaming
public void ScaleTransform(double scaleXY)
{
ScaleTransform(scaleXY, scaleXY);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object
/// in the specified order.
/// </summary>
// ReSharper disable once InconsistentNaming
public void ScaleTransform(double scaleXY, XMatrixOrder order)
{
ScaleTransform(scaleXY, scaleXY, order);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void ScaleAtTransform(double scaleX, double scaleY, double centerX, double centerY)
{
AddTransform(XMatrix.CreateScaling(scaleX, scaleY, centerX, centerY), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified scaling operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void ScaleAtTransform(double scaleX, double scaleY, XPoint center)
{
AddTransform(XMatrix.CreateScaling(scaleX, scaleY, center.X, center.Y), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified rotation operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void RotateTransform(double angle)
{
AddTransform(XMatrix.CreateRotationRadians(angle * Const.Deg2Rad), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified rotation operation to the transformation matrix of this object
/// in the specified order. The angle unit of measure is degree.
/// </summary>
public void RotateTransform(double angle, XMatrixOrder order)
{
XMatrix matrix = new XMatrix();
matrix.RotatePrepend(angle);
AddTransform(matrix, order);
}
/// <summary>
/// Applies the specified rotation operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void RotateAtTransform(double angle, XPoint point)
{
AddTransform(XMatrix.CreateRotationRadians(angle * Const.Deg2Rad, point.X, point.Y), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified rotation operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// </summary>
public void RotateAtTransform(double angle, XPoint point, XMatrixOrder order)
{
AddTransform(XMatrix.CreateRotationRadians(angle * Const.Deg2Rad, point.X, point.Y), order);
}
/// <summary>
/// Applies the specified shearing operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// ShearTransform is a synonym for SkewAtTransform.
/// Parameter shearX specifies the horizontal skew which is measured in degrees counterclockwise from the y-axis.
/// Parameter shearY specifies the vertical skew which is measured in degrees counterclockwise from the x-axis.
/// </summary>
public void ShearTransform(double shearX, double shearY)
{
AddTransform(XMatrix.CreateSkewRadians(shearX * Const.Deg2Rad, shearY * Const.Deg2Rad), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified shearing operation to the transformation matrix of this object
/// in the specified order.
/// ShearTransform is a synonym for SkewAtTransform.
/// Parameter shearX specifies the horizontal skew which is measured in degrees counterclockwise from the y-axis.
/// Parameter shearY specifies the vertical skew which is measured in degrees counterclockwise from the x-axis.
/// </summary>
public void ShearTransform(double shearX, double shearY, XMatrixOrder order)
{
AddTransform(XMatrix.CreateSkewRadians(shearX * Const.Deg2Rad, shearY * Const.Deg2Rad), order);
}
/// <summary>
/// Applies the specified shearing operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// ShearTransform is a synonym for SkewAtTransform.
/// Parameter shearX specifies the horizontal skew which is measured in degrees counterclockwise from the y-axis.
/// Parameter shearY specifies the vertical skew which is measured in degrees counterclockwise from the x-axis.
/// </summary>
public void SkewAtTransform(double shearX, double shearY, double centerX, double centerY)
{
AddTransform(XMatrix.CreateSkewRadians(shearX * Const.Deg2Rad, shearY * Const.Deg2Rad, centerX, centerY), XMatrixOrder.Prepend);
}
/// <summary>
/// Applies the specified shearing operation to the transformation matrix of this object by
/// prepending it to the object's transformation matrix.
/// ShearTransform is a synonym for SkewAtTransform.
/// Parameter shearX specifies the horizontal skew which is measured in degrees counterclockwise from the y-axis.
/// Parameter shearY specifies the vertical skew which is measured in degrees counterclockwise from the x-axis.
/// </summary>
public void SkewAtTransform(double shearX, double shearY, XPoint center)
{
AddTransform(XMatrix.CreateSkewRadians(shearX * Const.Deg2Rad, shearY * Const.Deg2Rad, center.X, center.Y), XMatrixOrder.Prepend);
}
/// <summary>
/// Multiplies the transformation matrix of this object and specified matrix.
/// </summary>
public void MultiplyTransform(XMatrix matrix)
{
AddTransform(matrix, XMatrixOrder.Prepend);
}
/// <summary>
/// Multiplies the transformation matrix of this object and specified matrix in the specified order.
/// </summary>
public void MultiplyTransform(XMatrix matrix, XMatrixOrder order)
{
AddTransform(matrix, order);
}
/// <summary>
/// Gets the current transformation matrix.
/// The transformation matrix cannot be set. Instead use Save/Restore or BeginContainer/EndContainer to
/// save the state before Transform is called and later restore to the previous transform.
/// </summary>
public XMatrix Transform
{
get { return _transform; }
}
/// <summary>
/// Applies a new transformation to the current transformation matrix.
/// </summary>
void AddTransform(XMatrix transform, XMatrixOrder order)
{
XMatrix matrix = _transform;
matrix.Multiply(transform, order);
_transform = matrix;
matrix = DefaultViewMatrix;
matrix.Multiply(_transform, XMatrixOrder.Prepend);
#if CORE
if (TargetContext == XGraphicTargetContext.CORE)
{
GetType();
// TODO: _gsStack...
}
#endif
#if GDI
if (TargetContext == XGraphicTargetContext.GDI)
{
if (_gfx != null)
{
try
{
Lock.EnterGdiPlus();
_gfx.Transform = (GdiMatrix)matrix;
}
finally { Lock.ExitGdiPlus(); }
}
}
#endif
#if WPF
if (TargetContext == XGraphicTargetContext.WPF)
{
#if !SILVERLIGHT
MatrixTransform mt = new MatrixTransform(transform.ToWpfMatrix());
#else
MatrixTransform mt = new MatrixTransform();
mt.Matrix = transform.ToWpfMatrix();
#endif
if (order == XMatrixOrder.Append)
mt = (MatrixTransform)mt.Inverse;
_gsStack.Current.PushTransform(mt);
}
#endif
if (_renderer != null)
_renderer.AddTransform(transform, XMatrixOrder.Prepend);
}
//public void TransformPoints(CoordinateSpace destSpace, CoordinateSpace srcSpace, Point[] points)
//{
//}
//
//public void TransformPoints(CoordinateSpace destSpace, CoordinateSpace srcSpace, GdiPointF[] points)
//{
//}
#endregion
// --------------------------------------------------------------------------------------------
#region Clipping
#if GDI
/// <summary>
/// Updates the clip region of this XGraphics to the intersection of the
/// current clip region and the specified rectangle.
/// </summary>
public void IntersectClip(Rectangle rect)
{
XGraphicsPath path = new XGraphicsPath();
path.AddRectangle(rect);
IntersectClip(path);
}
#endif
#if GDI
/// <summary>
/// Updates the clip region of this XGraphics to the intersection of the
/// current clip region and the specified rectangle.
/// </summary>
public void IntersectClip(GdiRectF rect)
{
XGraphicsPath path = new XGraphicsPath();
path.AddRectangle(rect);
IntersectClip(path);
}
#endif
/// <summary>
/// Updates the clip region of this XGraphics to the intersection of the
/// current clip region and the specified rectangle.
/// </summary>
public void IntersectClip(XRect rect)
{
XGraphicsPath path = new XGraphicsPath();
path.AddRectangle(rect);
IntersectClip(path);
}
/// <summary>
/// Updates the clip region of this XGraphics to the intersection of the
/// current clip region and the specified graphical path.
/// </summary>
public void IntersectClip(XGraphicsPath path)
{
if (path == null)
throw new ArgumentNullException("path");
if (_drawGraphics)
{
#if GDI && !WPF
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.SetClip(path._gdipPath, CombineMode.Intersect);
}
finally { Lock.ExitGdiPlus(); }
}
#endif
#if WPF && !GDI
if (TargetContext == XGraphicTargetContext.WPF)
_gsStack.Current.PushClip(path._pathGeometry);
#endif
#if GDI && WPF
if (TargetContext == XGraphicTargetContext.GDI)
{
try
{
Lock.EnterGdiPlus();
_gfx.SetClip(path._gdipPath, CombineMode.Intersect);
}
finally { Lock.ExitGdiPlus(); }
}
else
{
_gsStack.Current.PushClip(path._pathGeometry);
}
#endif
}
if (_renderer != null)
_renderer.SetClip(path, XCombineMode.Intersect);
}
//public void SetClip(Graphics g);
//public void SetClip(Graphics g, CombineMode combineMode);
//public void SetClip(GraphicsPath path, CombineMode combineMode);
//public void SetClip(Rectangle rect, CombineMode combineMode);
//public void SetClip(GdiRectF rect, CombineMode combineMode);
//public void SetClip(Region region, CombineMode combineMode);
//public void IntersectClip(Region region);
//public void ExcludeClip(Region region);
#endregion
// --------------------------------------------------------------------------------------------
#region Miscellaneous
/// <summary>
/// Writes a comment to the output stream. Comments have no effect on the rendering of the output.
/// They may be useful to mark a position in a content stream of a PDF document.
/// </summary>
public void WriteComment(string comment)
{
if (comment == null)
throw new ArgumentNullException("comment");
if (_drawGraphics)
{
// TODO: Do something if metafile?
}
if (_renderer != null)
_renderer.WriteComment(comment);
}
/// <summary>
/// Permits access to internal data.
/// </summary>
public XGraphicsInternals Internals
{
get { return _internals ?? (_internals = new XGraphicsInternals(this)); }
}
XGraphicsInternals _internals;
/// <summary>
/// (Under construction. May change in future versions.)
/// </summary>
public SpaceTransformer Transformer
{
get { return _transformer ?? (_transformer = new SpaceTransformer(this)); }
}
SpaceTransformer _transformer;
#endregion
// --------------------------------------------------------------------------------------------
#region Internal Helper Functions
#if GDI
/// <summary>
/// Converts a GdiPoint[] into a GdiPointF[].
/// </summary>
internal static GdiPointF[] MakePointFArray(GdiPoint[] points, int offset, int count)
{
if (points == null)
return null;
//int length = points.Length;
GdiPointF[] result = new GdiPointF[count];
for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++)
{
result[idx].X = points[srcIdx].X;
result[idx].Y = points[srcIdx].Y;
}
return result;
}
#endif
#if GDI
/// <summary>
/// Converts a XPoint[] into a GdiPointF[].
/// </summary>
internal static GdiPointF[] MakePointFArray(XPoint[] points)
{
if (points == null)
return null;
int count = points.Length;
GdiPointF[] result = new GdiPointF[count];
for (int idx = 0; idx < count; idx++)
{
result[idx].X = (float)points[idx].X;
result[idx].Y = (float)points[idx].Y;
}
return result;
}
#endif
#if GDI
/// <summary>
/// Converts a Point[] into a XPoint[].
/// </summary>
internal static XPoint[] MakeXPointArray(GdiPoint[] points, int offset, int count)
{
if (points == null)
return null;
//int lengh = points.Length;
XPoint[] result = new XPoint[count];
for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++)
{
result[idx].X = points[srcIdx].X;
result[idx].Y = points[srcIdx].Y;
}
return result;
}
#endif
#if WPF || NETFX_CORE
/// <summary>
/// Converts a Point[] into a XPoint[].
/// </summary>
internal static XPoint[] MakeXPointArray(SysPoint[] points, int offset, int count)
{
if (points == null)
return null;
//int length = points.Length;
XPoint[] result = new XPoint[count];
for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++)
{
result[idx].X = points[srcIdx].X;
result[idx].Y = points[srcIdx].Y;
}
return result;
}
#endif
#if GDI
/// <summary>
/// Converts a GdiPointF[] into a XPoint[].
/// </summary>
internal static XPoint[] MakeXPointArray(GdiPointF[] points, int offset, int count)
{
if (points == null)
return null;
//int length = points.Length;
XPoint[] result = new XPoint[count];
for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++)
{
result[idx].X = points[srcIdx].X;
result[idx].Y = points[srcIdx].Y;
}
return result;
}
#endif
#if GDI
/// <summary>
/// Converts a XRect[] into a GdiRectF[].
/// </summary>
internal static GdiRectF[] MakeRectangleFArray(XRect[] rects, int offset, int count)
{
if (rects == null)
return null;
//int length = rects.Length;
GdiRectF[] result = new GdiRectF[count];
for (int idx = 0, srcIdx = offset; idx < count; idx++, srcIdx++)
{
XRect rect = rects[srcIdx];
result[idx] = new GdiRectF((float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height);
}
return result;
}
#endif
#if WPF || NETFX_CORE
/// <summary>
/// Converts an XPoint[] into a Point[].
/// </summary>
internal static SysPoint[] MakePointArray(XPoint[] points)
{
if (points == null)
return null;
int count = points.Length;
SysPoint[] result = new SysPoint[count];
for (int idx = 0; idx < count; idx++)
{
result[idx].X = points[idx].X;
result[idx].Y = points[idx].Y;
}
return result;
}
#endif
#endregion
///// <summary>
///// Testcode
///// </summary>
//public void TestXObject(PdfDocument thisDoc, PdfPage thisPage, int page,
// PdfDocument externalDoc, ImportedObjectTable impDoc)
//{
// PdfPage impPage = externalDoc.Pages[page];
// // impDoc.ImportPage(impPage);
// PdfFormXObject form = new PdfFormXObject(thisDoc, impDoc, impPage);
// thisDoc.xrefTable.Add(form);
// PdfDictionary xobjects = new PdfDictionary();
// xobjects.Elements["/X42"] = form.XRef;
// thisPage.Resources.Elements[PdfResources.Keys.XObject] = xobjects;
// ((XGraphicsPdfRenderer)renderer).DrawXObject("/X42");
//}
internal void DisassociateImage()
{
if (_associatedImage == null)
throw new InvalidOperationException("No image associated.");
Dispose();
}
internal InternalGraphicsMode InternalGraphicsMode
{
get { return _internalGraphicsMode; }
set { _internalGraphicsMode = value; }
}
InternalGraphicsMode _internalGraphicsMode;
internal XImage AssociatedImage
{
get { return _associatedImage; }
set { _associatedImage = value; }
}
XImage _associatedImage;
#if GDI
/// <summary>
/// Always defined System.Drawing.Graphics object. Used as 'query context' for PDF pages.
/// </summary>
internal Graphics _gfx;
#endif
#if WPF
/// <summary>
/// Always defined System.Drawing.Graphics object. Used as 'query context' for PDF pages.
/// </summary>
#if !SILVERLIGHT
DrawingVisual _dv;
internal DrawingContext _dc;
#else
internal AgDrawingContext _dc;
#endif
#endif
#if UWP
readonly CanvasDrawingSession _cds;
#endif
/// <summary>
/// The transformation matrix from the XGraphics page space to the Graphics world space.
/// (The name 'default view matrix' comes from Microsoft OS/2 Presentation Manager. I choose
/// this name because I have no better one.)
/// </summary>
internal XMatrix DefaultViewMatrix;
/// <summary>
/// Indicates whether to send drawing operations to _gfx or _dc.
/// </summary>
bool _drawGraphics;
readonly XForm _form;
#if GDI
internal Metafile Metafile;
#endif
/// <summary>
/// Interface to an (optional) renderer. Currently it is the XGraphicsPdfRenderer, if defined.
/// </summary>
IXGraphicsRenderer _renderer;
/// <summary>
/// The transformation matrix from XGraphics world space to page unit space.
/// </summary>
XMatrix _transform;
/// <summary>
/// The graphics state stack.
/// </summary>
readonly GraphicsStateStack _gsStack;
/// <summary>
/// Gets the PDF page that serves as drawing surface if PDF is rendered,
/// or null, if no such object exists.
/// </summary>
public PdfPage PdfPage
{
get
{
XGraphicsPdfRenderer renderer = _renderer as PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer;
return renderer != null ? renderer._page : null;
}
}
#if GDI
/// <summary>
/// Gets the System.Drawing.Graphics objects that serves as drawing surface if no PDF is rendered,
/// or null, if no such object exists.
/// </summary>
public Graphics Graphics
{
get { return _gfx; }
}
#endif
//#if CORE || GDI
// /// <summary>
// /// Critical section used to serialize access to GDI+.
// /// This may be necessary to use PDFsharp safely in a Web application.
// /// </summary>
// internal static readonly object GdiPlus = new object();
//#endif
/// <summary>
/// Provides access to internal data structures of the XGraphics class.
/// </summary>
public class XGraphicsInternals
{
internal XGraphicsInternals(XGraphics gfx)
{
_gfx = gfx;
}
readonly XGraphics _gfx;
#if GDI
/// <summary>
/// Gets the underlying Graphics object.
/// </summary>
public Graphics Graphics
{
get { return _gfx._gfx; }
}
#endif
}
/// <summary>
/// (This class is under construction.)
/// Currently used in MigraDoc
/// </summary>
public class SpaceTransformer
{
internal SpaceTransformer(XGraphics gfx)
{
_gfx = gfx;
}
readonly XGraphics _gfx;
/// <summary>
/// Gets the smallest rectangle in default page space units that completely encloses the specified rect
/// in world space units.
/// </summary>
public XRect WorldToDefaultPage(XRect rect)
{
XPoint[] points = new XPoint[4];
points[0] = new XPoint(rect.X, rect.Y);
points[1] = new XPoint(rect.X + rect.Width, rect.Y);
points[2] = new XPoint(rect.X, rect.Y + rect.Height);
points[3] = new XPoint(rect.X + rect.Width, rect.Y + rect.Height);
XMatrix matrix = _gfx.Transform;
matrix.TransformPoints(points);
double height = _gfx.PageSize.Height;
points[0].Y = height - points[0].Y;
points[1].Y = height - points[1].Y;
points[2].Y = height - points[2].Y;
points[3].Y = height - points[3].Y;
double xmin = Math.Min(Math.Min(points[0].X, points[1].X), Math.Min(points[2].X, points[3].X));
double xmax = Math.Max(Math.Max(points[0].X, points[1].X), Math.Max(points[2].X, points[3].X));
double ymin = Math.Min(Math.Min(points[0].Y, points[1].Y), Math.Min(points[2].Y, points[3].Y));
double ymax = Math.Max(Math.Max(points[0].Y, points[1].Y), Math.Max(points[2].Y, points[3].Y));
return new XRect(xmin, ymin, xmax - xmin, ymax - ymin);
}
}
}
}