/// <summary> /// Create PDF pages from given HTML and appends them to the provided PDF document.<br/> /// </summary> /// <param name="document">PDF document to append pages to</param> /// <param name="html">HTML source to create PDF from</param> /// <param name="config">the configuration to use for the PDF generation (page size/page orientation/margins/etc.)</param> /// <param name="cssData">optional: the style to use for html rendering (default - use W3 default style)</param> /// <param name="stylesheetLoad">optional: can be used to overwrite stylesheet resolution logic</param> /// <param name="imageLoad">optional: can be used to overwrite image resolution logic</param> /// <returns>the generated image of the html</returns> public static void AddPdfPages(PdfDocument document, string html, PdfGenerateConfig config, CssData cssData = null, EventHandler<HtmlStylesheetLoadEventArgs> stylesheetLoad = null, EventHandler<HtmlImageLoadEventArgs> imageLoad = null) { XSize orgPageSize; // get the size of each page to layout the HTML in if (config.PageSize != PageSize.Undefined) orgPageSize = PageSizeConverter.ToSize(config.PageSize); else orgPageSize = config.ManualPageSize; if (config.PageOrientation == PageOrientation.Landscape) { // invert pagesize for landscape orgPageSize = new XSize(orgPageSize.Height, orgPageSize.Width); } var pageSize = new XSize(orgPageSize.Width - config.MarginLeft - config.MarginRight, orgPageSize.Height - config.MarginTop - config.MarginBottom); if (!string.IsNullOrEmpty(html)) { using (var container = new HtmlContainer()) { if (stylesheetLoad != null) container.StylesheetLoad += stylesheetLoad; if (imageLoad != null) container.ImageLoad += imageLoad; container.Location = new XPoint(config.MarginLeft, config.MarginTop); container.MaxSize = new XSize(pageSize.Width, 0); container.SetHtml(html, cssData); container.PageSize = pageSize; container.MarginBottom = config.MarginBottom; container.MarginLeft = config.MarginLeft; container.MarginRight = config.MarginRight; container.MarginTop = config.MarginTop; // layout the HTML with the page width restriction to know how many pages are required using (var measure = XGraphics.CreateMeasureContext(pageSize, XGraphicsUnit.Point, XPageDirection.Downwards)) { container.PerformLayout(measure); } // while there is un-rendered HTML, create another PDF page and render with proper offset for the next page double scrollOffset = 0; while (scrollOffset > -container.ActualSize.Height) { var page = document.AddPage(); page.Height = orgPageSize.Height; page.Width = orgPageSize.Width; using (var g = XGraphics.FromPdfPage(page)) { //g.IntersectClip(new XRect(config.MarginLeft, config.MarginTop, pageSize.Width, pageSize.Height)); g.IntersectClip(new XRect(0, 0, page.Width, page.Height)); container.ScrollOffset = new XPoint(0, scrollOffset); container.PerformPaint(g); } scrollOffset -= pageSize.Height; } // add web links and anchors HandleLinks(document, container, orgPageSize, pageSize); } } }
public override void RenderPage(XGraphics gfx) { base.RenderPage(gfx); DrawGridlines(gfx); // Create a new graphical path XGraphicsPath path = new XGraphicsPath(); XSize size = new XSize(90, 140); double rotationAngle = 130; path.AddArc(new XPoint(100, 100), new XPoint(200, 200), size, rotationAngle, false, System.Windows.Media.SweepDirection.Clockwise); path.StartFigure(); path.AddArc(new XPoint(400, 100), new XPoint(500, 200), size, rotationAngle, false, System.Windows.Media.SweepDirection.Counterclockwise); path.StartFigure(); path.AddArc(new XPoint(100, 300), new XPoint(200, 400), size, rotationAngle, true, System.Windows.Media.SweepDirection.Clockwise); path.StartFigure(); path.AddArc(new XPoint(400, 300), new XPoint(500, 400), size, rotationAngle, true, System.Windows.Media.SweepDirection.Counterclockwise); path.StartFigure(); #if DEBUG_ gfx.WriteComment("PathArcSegment"); #endif gfx.DrawPath(XPens.Red, path); }
// ...took a look at the source code of WPF. About 50 classes and several 10,000 lines of code // deal with that what colloquial is called 'fonts'. // So let's start simple. /// <summary> /// Simple measure string function. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorStock.Global.CreateDescriptor(font) as OpenTypeDescriptor; if (descriptor != null) { size.Height = (descriptor.Ascender + Math.Abs(descriptor.Descender)) * font.Size / font.unitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.fontData.cmap.symbol; int length = text.Length; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; int glyphIndex = 0; if (symbol) { glyphIndex = ch + (descriptor.fontData.os2.usFirstCharIndex & 0xFF00); // @@@ glyphIndex = descriptor.CharCodeToGlyphIndex((char)glyphIndex); } else glyphIndex = descriptor.CharCodeToGlyphIndex(ch); //double width = descriptor.GlyphIndexToEmfWidth(glyphIndex, font.Size); //size.Width += width; width += descriptor.GlyphIndexToWidth(glyphIndex); } size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return size; }
/// <summary> /// Initializes a new instance of the <see cref="BarCode"/> class. /// </summary> /// <param name="text"></param> /// <param name="size"></param> /// <param name="direction"></param> public BarCode(string text, XSize size, CodeDirection direction) : base(text, size, direction) { this.text = text; this.size = size; this.direction = direction; }
/// <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) throw new ArgumentNullException("gfx"); this.gfx = gfx; this.drawGraphics = true; this.pageSize = new XSize(size.width, size.height); this.pageUnit = pageUnit; switch (pageUnit) { case XGraphicsUnit.Point: this.pageSizePoints = new XSize(size.width, size.height); break; case XGraphicsUnit.Inch: this.pageSizePoints = new XSize(XUnit.FromInch(size.width), XUnit.FromInch(size.height)); break; case XGraphicsUnit.Millimeter: this.pageSizePoints = new XSize(XUnit.FromMillimeter(size.width), XUnit.FromMillimeter(size.height)); break; case XGraphicsUnit.Centimeter: this.pageSizePoints = new XSize(XUnit.FromCentimeter(size.width), XUnit.FromCentimeter(size.height)); break; default: throw new NotImplementedException("unit"); } this.pageDirection = pageDirection; Initialize(); }
/// <summary> /// Calculates the space used for the X axis. /// </summary> internal override void Format() { AxisRendererInfo xari = ((ChartRendererInfo)this.rendererParms.RendererInfo).xAxisRendererInfo; if (xari.axis != null) { AxisTitleRendererInfo atri = xari.axisTitleRendererInfo; // Calculate space used for axis title. XSize titleSize = new XSize(0, 0); if (atri != null && atri.AxisTitleText != null && atri.AxisTitleText.Length > 0) titleSize = this.rendererParms.Graphics.MeasureString(atri.AxisTitleText, atri.AxisTitleFont); // Calculate space used for tick labels. XSize size = new XSize(0, 0); foreach (XSeries xs in xari.XValues) { foreach (XValue xv in xs) { XSize valueSize = this.rendererParms.Graphics.MeasureString(xv.Value, xari.TickLabelsFont); size.Height += valueSize.Height; size.Width = Math.Max(valueSize.Width, size.Width); } } // Remember space for later drawing. if (atri != null) atri.AxisTitleSize = titleSize; xari.TickLabelsHeight = size.Height; xari.Height = size.Height; xari.Width = titleSize.Width + size.Width + xari.MajorTickMarkWidth; } }
/// <summary> /// Initializes a new instance of the XRect class. /// </summary> public XRect(XPoint location, XSize size) { this.x = location.X; this.y = location.Y; this.width = size.Width; this.height = size.Height; }
private void plpage_Paint(object sender, PaintEventArgs e) { if (m_source != null) { float zoom = zoomControl1.Zoom * m_zoomFactor; GraphicsState state = e.Graphics.Save(); e.Graphics.ScaleTransform(zoom, zoom); XSize size = new XSize(plpage.Width * zoom, plpage.Height * zoom); m_source.DrawPage(XGraphics.FromGraphics(e.Graphics, size), tbpage.Value); e.Graphics.Restore(state); } }
/// <summary> /// Initializes a new instance of the XRect class. /// </summary> public XRect(XPoint location, XSize size) { if (size.IsEmpty) { this = s_empty; } else { _x = location.X; _y = location.Y; _width = size.Width; _height = size.Height; } }
/// <summary> /// Initializes a new instance of the XRect class. /// </summary> public XRect(XPoint location, XSize size) { if (size.IsEmpty) { this = s_empty; } else { this.x = location.x; this.y = location.y; this.width = size.width; this.height = size.height; } }
/// <summary> /// Creates a bar code from the specified code type. /// </summary> public static BarCode FromType(CodeType type, string text, XSize size, CodeDirection direction) { switch (type) { case CodeType.Code2of5Interleaved: return new Code2of5Interleaved(text, size, direction); case CodeType.Code3of9Standard: return new Code3of9Standard(text, size, direction); default: throw new InvalidEnumArgumentException("type", (int)type, typeof(CodeType)); } }
public void AddArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArg, XSweepDirection sweepDirection) { List <XPoint> points = GeometryHelper.BezierCurveFromArc(point1, point2, size, rotationAngle, isLargeArg, sweepDirection == XSweepDirection.Clockwise, PathStart.MoveTo1st); int count = points.Count; Debug.Assert((count + 2) % 3 == 0); MoveOrLineTo(points[0].X, points[0].Y); for (int idx = 1; idx < count; idx += 3) { BezierTo(points[idx].X, points[idx].Y, points[idx + 1].X, points[idx + 1].Y, points[idx + 2].X, points[idx + 2].Y, false); } }
/// <summary> /// Calculates the space used for the Y axis. /// </summary> internal override void Format() { AxisRendererInfo yari = ((ChartRendererInfo)this.rendererParms.RendererInfo).yAxisRendererInfo; if (yari.axis != null) { XGraphics gfx = this.rendererParms.Graphics; XSize size = new XSize(0, 0); // height of all ticklabels double yMin = yari.MinimumScale; double yMax = yari.MaximumScale; double yMajorTick = yari.MajorTick; double lineHeight = Double.MinValue; XSize labelSize = new XSize(0, 0); for (double y = yMin; y <= yMax; y += yMajorTick) { string str = y.ToString(yari.TickLabelsFormat); labelSize = gfx.MeasureString(str, yari.TickLabelsFont); size.Height += labelSize.Height; size.Width = Math.Max(size.Width, labelSize.Width); lineHeight = Math.Max(lineHeight, labelSize.Height); } // add space for tickmarks size.Width += yari.MajorTickMarkWidth * 1.5; // Measure axis title XSize titleSize = new XSize(0, 0); if (yari.axisTitleRendererInfo != null) { RendererParameters parms = new RendererParameters(); parms.Graphics = gfx; parms.RendererInfo = yari; AxisTitleRenderer atr = new AxisTitleRenderer(parms); atr.Format(); titleSize.Height = yari.axisTitleRendererInfo.Height; titleSize.Width = yari.axisTitleRendererInfo.Width; } yari.Height = Math.Max(size.Height, titleSize.Height); yari.Width = size.Width + titleSize.Width; yari.InnerRect = yari.Rect; yari.InnerRect.Y += yari.TickLabelsFont.Height / 2; yari.LabelSize = labelSize; } }
/// <summary> /// Measure string directly from font data. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat_notyetused) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as OpenTypeDescriptor; if (descriptor != null) { // Height is the sum of ascender and descender. size.Height = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.FontFace.cmap.symbol; int length = text.Length; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; // HACK: Unclear what to do here. if (ch < 32) { continue; } if (symbol) { // Remap ch for symbol fonts. ch = (char)(ch | (descriptor.FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor // Used | instead of + because of: http://PdfSharp.codeplex.com/workitem/15954 } int glyphIndex = descriptor.CharCodeToGlyphIndex(ch); width += descriptor.GlyphIndexToWidth(glyphIndex); } // What? size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; size.Width = width * font.Size / descriptor.UnitsPerEm; // Adjust bold simulation. if ((font.GlyphTypeface.StyleSimulations & XStyleSimulations.BoldSimulation) == XStyleSimulations.BoldSimulation || DoApplyBoldHack(font.FamilyName)) //BOLD hacks for helvetica { // Add 2% of the em-size for each character. // Unsure how to deal with white space. Currently count as regular character. size.Width += length * font.Size * Const.BoldEmphasis; } } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return(size); }
/// <summary> /// Layouts and calculates the space used by the legend. /// </summary> internal override void Format() { ChartRendererInfo cri = (ChartRendererInfo)this.rendererParms.RendererInfo; LegendRendererInfo lri = cri.legendRendererInfo; if (lri == null) return; RendererParameters parms = new RendererParameters(); parms.Graphics = this.rendererParms.Graphics; bool verticalLegend = (lri.legend.docking == DockingType.Left || lri.legend.docking == DockingType.Right); XSize maxMarkerArea = new XSize(); LegendEntryRenderer ler = new LegendEntryRenderer(parms); foreach (LegendEntryRendererInfo leri in lri.Entries) { parms.RendererInfo = leri; ler.Format(); maxMarkerArea.Width = Math.Max(leri.MarkerArea.Width, maxMarkerArea.Width); maxMarkerArea.Height = Math.Max(leri.MarkerArea.Height, maxMarkerArea.Height); if (verticalLegend) { lri.Width = Math.Max(lri.Width, leri.Width); lri.Height += leri.Height; } else { lri.Width += leri.Width; lri.Height = Math.Max(lri.Height, leri.Height); } } // Add padding to left, right, top and bottom int paddingFactor = 1; if (lri.BorderPen != null) paddingFactor = 2; lri.Width += (LegendRenderer.LeftPadding + LegendRenderer.RightPadding) * paddingFactor; lri.Height += (LegendRenderer.TopPadding + LegendRenderer.BottomPadding) * paddingFactor; if (verticalLegend) lri.Height += LegendRenderer.EntrySpacing * (lri.Entries.Length - 1); else lri.Width += LegendRenderer.EntrySpacing * (lri.Entries.Length - 1); foreach (LegendEntryRendererInfo leri in lri.Entries) leri.MarkerArea = maxMarkerArea; }
/// <summary> /// Initializes a new instance of the <see cref="XForm"/> class that represents a page of a PDF document. /// </summary> /// <param name="document">The PDF document.</param> /// <param name="size">The size of the page.</param> public XForm(PdfDocument document, XSize size) : this(document, new XRect(0, 0, size.Width, size.Height)) { ////if (size.width < 1 || size.height < 1) //// throw new ArgumentNullException("size", "The size of the XPdfForm is to small."); ////// I must tie the XPdfForm to a document immediately, because otherwise I would have no place where ////// to store the resources. ////if (document == null) //// throw new ArgumentNullException("document", "An XPdfForm template must be associated with a document."); ////_formState = FormState.Created; ////_document = document; ////pdfForm = new PdfFormXObject(document, this); ////templateSize = size; ////PdfRectangle rect = new PdfRectangle(new XPoint(), size); ////pdfForm.Elements.SetRectangle(PdfFormXObject.Keys.BBox, rect); }
/// <summary> /// Parses the size from a string. /// </summary> public static XSize Parse(string source) { XSize empty; CultureInfo cultureInfo = CultureInfo.InvariantCulture; TokenizerHelper helper = new TokenizerHelper(source, cultureInfo); string str = helper.NextTokenRequired(); if (str == "Empty") { empty = Empty; } else { empty = new XSize(Convert.ToDouble(str, cultureInfo), Convert.ToDouble(helper.NextTokenRequired(), cultureInfo)); } helper.LastTokenRequired(); return(empty); }
/// <summary> /// Measure string directly from font data. /// </summary> public static XSize MeasureString(string text, XFont font, XStringFormat stringFormat) { XSize size = new XSize(); OpenTypeDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as OpenTypeDescriptor; if (descriptor != null) { // Height is the sum of ascender and descender. size.Height = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.FontFace.cmap.symbol; int length = text.Length; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; // HACK: Unclear what to do here. if (ch < 32) continue; if (symbol) { // Remap ch for symbol fonts. ch = (char)(ch | (descriptor.FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor // Used | instead of + because of: http://pdfsharp.codeplex.com/workitem/15954 } int glyphIndex = descriptor.CharCodeToGlyphIndex(ch); width += descriptor.GlyphIndexToWidth(glyphIndex); } // What? size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; size.Width = width * font.Size / descriptor.UnitsPerEm; // Adjust bold simulation. if ((font.GlyphTypeface.StyleSimulations & XStyleSimulations.BoldSimulation) == XStyleSimulations.BoldSimulation) { // Add 2% of the em-size for each character. // Unsure how to deal with white space. Currently count as regular character. size.Width += length * font.Size * Const.BoldEmphasis; } } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); return size; }
/// <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) { //throw new ArgumentNullException("gfx"); gfx = Graphics.FromHwnd(IntPtr.Zero); } this.gsStack = new GraphicsStateStack(this); this.targetContext = XGraphicTargetContext.GDI; this.gfx = gfx; this.drawGraphics = true; this.pageSize = new XSize(size.width, size.height); this.pageUnit = pageUnit; switch (pageUnit) { case XGraphicsUnit.Point: this.pageSizePoints = new XSize(size.width, size.height); break; case XGraphicsUnit.Inch: this.pageSizePoints = new XSize(XUnit.FromInch(size.width), XUnit.FromInch(size.height)); break; case XGraphicsUnit.Millimeter: this.pageSizePoints = new XSize(XUnit.FromMillimeter(size.width), XUnit.FromMillimeter(size.height)); break; case XGraphicsUnit.Centimeter: this.pageSizePoints = new XSize(XUnit.FromCentimeter(size.width), XUnit.FromCentimeter(size.height)); break; case XGraphicsUnit.Presentation: this.pageSizePoints = new XSize(XUnit.FromPresentation(size.width), XUnit.FromPresentation(size.height)); break; default: throw new NotImplementedException("unit"); } this.pageDirection = pageDirection; Initialize(); }
/// <summary> /// Initializes a new instance of the <see cref="MatrixCode"/> class. /// </summary> public MatrixCode(string text, string encoding, int rows, int columns, XSize size) : base(text, size, CodeDirection.LeftToRight) { this.encoding = encoding; if (this.encoding == "" || this.encoding == null) this.encoding = new String('a', this.text.Length); if (columns < rows) { this.rows = columns; this.columns = rows; } else { this.columns = columns; this.rows = rows; } this.Text = text; }
/// <summary> /// Calculates the space used for the X axis. /// </summary> internal override void Format() { AxisRendererInfo xari = ((ChartRendererInfo)_rendererParms.RendererInfo).xAxisRendererInfo; if (xari._axis != null) { AxisTitleRendererInfo atri = xari._axisTitleRendererInfo; // Calculate space used for axis title. XSize titleSize = new XSize(0, 0); if (atri != null && atri.AxisTitleText != null && atri.AxisTitleText.Length > 0) { titleSize = _rendererParms.Graphics.MeasureString(atri.AxisTitleText, atri.AxisTitleFont); atri.AxisTitleSize = titleSize; } // Calculate space used for tick labels. XSize size = new XSize(0, 0); if (xari.XValues.Count > 0) { XSeries xs = xari.XValues[0]; foreach (XValue xv in xs) { if (xv != null) { string tickLabel = xv._value; XSize valueSize = _rendererParms.Graphics.MeasureString(tickLabel, xari.TickLabelsFont); size.Height = Math.Max(valueSize.Height, size.Height); size.Width += valueSize.Width; } } } // Remember space for later drawing. xari.TickLabelsHeight = size.Height; xari.Height = titleSize.Height + size.Height + xari.MajorTickMarkWidth; xari.Width = Math.Max(titleSize.Width, size.Width); } }
/// <summary> /// Adds an elliptical arc to the current figure. The arc is specified WPF like. /// </summary> public void AddArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArg, XSweepDirection sweepDirection) { _corePath.AddArc(point1, point2, size, rotationAngle, isLargeArg, sweepDirection); }
/// <summary> /// Expands the rectangle by using the specified Size, in all directions. /// </summary> public void Inflate(XSize size) { Inflate(size.width, size.height); }
/// <summary> /// Indicates whether this tow instance are equal. /// </summary> public static bool Equals(XSize size1, XSize size2) { if (size1.IsEmpty) return size2.IsEmpty; return size1.Width.Equals(size2.Width) && size1.Height.Equals(size2.Height); }
private static XSize CreateEmptySize() { XSize size = new XSize(); size.width = double.NegativeInfinity; size.height = double.NegativeInfinity; return size; }
static XSize() { s_empty = CreateEmptySize(); }
/// <summary> /// Indicates whether this instance and a specified size are equal. /// </summary> public bool Equals(XSize value) { return(Equals(this, value)); }
/// <summary> /// Indicates whether the values are so close that they can be considered as equal. /// </summary> public static bool AreClose(XSize size1, XSize size2) { return AreClose(size1.Width, size2.Width) && AreClose(size1.Height, size2.Height); }
/// <summary> /// Expands the rectangle by using the specified Size, in all directions. /// </summary> public void Inflate(XSize size) { Inflate(size.Width, size.Height); }
public static PDF.XGraphicsPath ToXGraphicsPath(this IPathGeometry pg, Func <double, double> scale) { var gp = new PDF.XGraphicsPath() { FillMode = pg.FillRule == FillRule.EvenOdd ? PDF.XFillMode.Alternate : PDF.XFillMode.Winding }; foreach (var pf in pg.Figures) { var startPoint = pf.StartPoint; foreach (var segment in pf.Segments) { if (segment is IArcSegment arcSegment) { #if WPF var point1 = new PDF.XPoint( scale(startPoint.X), scale(startPoint.Y)); var point2 = new PDF.XPoint( scale(arcSegment.Point.X), scale(arcSegment.Point.Y)); var size = new PDF.XSize( scale(arcSegment.Size.Width), scale(arcSegment.Size.Height)); gp.AddArc( point1, point2, size, arcSegment.RotationAngle, arcSegment.IsLargeArc, arcSegment.SweepDirection == SweepDirection.Clockwise ? PDF.XSweepDirection.Clockwise : PDF.XSweepDirection.Counterclockwise); startPoint = arcSegment.Point; #else // TODO: Convert WPF/SVG elliptical arc segment format to GDI+ bezier curves. startPoint = arcSegment.Point; #endif } else if (segment is ICubicBezierSegment cubicBezierSegment) { gp.AddBezier( scale(startPoint.X), scale(startPoint.Y), scale(cubicBezierSegment.Point1.X), scale(cubicBezierSegment.Point1.Y), scale(cubicBezierSegment.Point2.X), scale(cubicBezierSegment.Point2.Y), scale(cubicBezierSegment.Point3.X), scale(cubicBezierSegment.Point3.Y)); startPoint = cubicBezierSegment.Point3; } else if (segment is ILineSegment) { var lineSegment = segment as ILineSegment; gp.AddLine( scale(startPoint.X), scale(startPoint.Y), scale(lineSegment.Point.X), scale(lineSegment.Point.Y)); startPoint = lineSegment.Point; } else if (segment is IQuadraticBezierSegment quadraticBezierSegment) { var p1 = startPoint; var p2 = quadraticBezierSegment.Point1; var p3 = quadraticBezierSegment.Point2; double x1 = p1.X; double y1 = p1.Y; double x2 = p1.X + (2.0 * (p2.X - p1.X)) / 3.0; double y2 = p1.Y + (2.0 * (p2.Y - p1.Y)) / 3.0; double x3 = x2 + (p3.X - p1.X) / 3.0; double y3 = y2 + (p3.Y - p1.Y) / 3.0; double x4 = p3.X; double y4 = p3.Y; gp.AddBezier( scale(x1), scale(y1), scale(x2), scale(y2), scale(x3), scale(y3), scale(x4), scale(y4)); startPoint = quadraticBezierSegment.Point2; } else { throw new NotSupportedException("Not supported segment type: " + segment.GetType()); } } if (pf.IsClosed) { gp.CloseFigure(); } else { gp.StartFigure(); } } return(gp); }
/// <summary> /// Initializes a new instance of the <see cref="ThickThinBarCode"/> class. /// </summary> public ThickThinBarCode(string code, XSize size, CodeDirection direction) : base(code, size, direction) { }
/// <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) { XGraphics gfx = null; #if GDI gfx = new XGraphics((System.Drawing.Graphics)null, size, pageUnit, pageDirection); #endif #if WPF && !SILVERLIGHT gfx = new XGraphics((System.Windows.Media.DrawingContext)null, size, pageUnit, pageDirection); #endif #if SILVERLIGHT gfx = new XGraphics(new Canvas(), size, pageUnit, pageDirection); #endif return gfx; }
/// <summary> /// Draws the vertical Y axis. /// </summary> internal override void Draw() { AxisRendererInfo yari = ((ChartRendererInfo)this.rendererParms.RendererInfo).yAxisRendererInfo; double yMin = yari.MinimumScale; double yMax = yari.MaximumScale; double yMajorTick = yari.MajorTick; double yMinorTick = yari.MinorTick; XMatrix matrix = XMatrix.Identity; matrix.TranslatePrepend(-yari.InnerRect.X, yMax); matrix.Scale(1, yari.InnerRect.Height / (yMax - yMin), XMatrixOrder.Append); matrix.ScalePrepend(1, -1); // mirror horizontal matrix.Translate(yari.InnerRect.X, yari.InnerRect.Y, XMatrixOrder.Append); // Draw axis. // First draw tick marks, second draw axis. double majorTickMarkStart = 0, majorTickMarkEnd = 0, minorTickMarkStart = 0, minorTickMarkEnd = 0; GetTickMarkPos(yari, ref majorTickMarkStart, ref majorTickMarkEnd, ref minorTickMarkStart, ref minorTickMarkEnd); XGraphics gfx = this.rendererParms.Graphics; LineFormatRenderer lineFormatRenderer = new LineFormatRenderer(gfx, yari.LineFormat); LineFormatRenderer minorTickMarkLineFormat = new LineFormatRenderer(gfx, yari.MinorTickMarkLineFormat); LineFormatRenderer majorTickMarkLineFormat = new LineFormatRenderer(gfx, yari.MajorTickMarkLineFormat); XPoint[] points = new XPoint[2]; // Draw minor tick marks. if (yari.MinorTickMark != TickMarkType.None) { for (double y = yMin + yMinorTick; y < yMax; y += yMinorTick) { points[0].X = minorTickMarkStart; points[0].Y = y; points[1].X = minorTickMarkEnd; points[1].Y = y; matrix.TransformPoints(points); minorTickMarkLineFormat.DrawLine(points[0], points[1]); } } double lineSpace = yari.TickLabelsFont.GetHeight(gfx); int cellSpace = yari.TickLabelsFont.FontFamily.GetLineSpacing(yari.TickLabelsFont.Style); double xHeight = yari.TickLabelsFont.Metrics.XHeight; XSize labelSize = new XSize(0, 0); labelSize.Height = lineSpace * xHeight / cellSpace; int countTickLabels = (int)((yMax - yMin) / yMajorTick) + 1; for (int i = 0; i < countTickLabels; ++i) { double y = yMin + yMajorTick * i; string str = y.ToString(yari.TickLabelsFormat); labelSize.Width = gfx.MeasureString(str, yari.TickLabelsFont).Width; // Draw major tick marks. if (yari.MajorTickMark != TickMarkType.None) { labelSize.Width += yari.MajorTickMarkWidth * 1.5; points[0].X = majorTickMarkStart; points[0].Y = y; points[1].X = majorTickMarkEnd; points[1].Y = y; matrix.TransformPoints(points); majorTickMarkLineFormat.DrawLine(points[0], points[1]); } else labelSize.Width += SpaceBetweenLabelAndTickmark; // Draw label text. XPoint[] layoutText = new XPoint[1]; layoutText[0].X = yari.InnerRect.X + yari.InnerRect.Width - labelSize.Width; layoutText[0].Y = y; matrix.TransformPoints(layoutText); layoutText[0].Y += labelSize.Height / 2; // Center text vertically. gfx.DrawString(str, yari.TickLabelsFont, yari.TickLabelsBrush, layoutText[0]); } // Draw axis. if (yari.LineFormat != null && yari.LineFormat.Width > 0) { points[0].X = yari.InnerRect.X + yari.InnerRect.Width; points[0].Y = yMin; points[1].X = yari.InnerRect.X + yari.InnerRect.Width; points[1].Y = yMax; matrix.TransformPoints(points); if (yari.MajorTickMark != TickMarkType.None) { // yMax is at the upper side of the axis points[1].Y -= yari.LineFormat.Width / 2; points[0].Y += yari.LineFormat.Width / 2; } lineFormatRenderer.DrawLine(points[0], points[1]); } // Draw axis title if (yari.axisTitleRendererInfo != null && yari.axisTitleRendererInfo.AxisTitleText != "") { RendererParameters parms = new RendererParameters(); parms.Graphics = gfx; parms.RendererInfo = yari; double width = yari.axisTitleRendererInfo.Width; yari.axisTitleRendererInfo.Rect = yari.InnerRect; yari.axisTitleRendererInfo.Width = width; AxisTitleRenderer atr = new AxisTitleRenderer(parms); atr.Draw(); } }
/// <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) { // TODO: Get object from cache... 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) //{ // // TODO: Get object from cache... // 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) //{ // // TODO: Get object from cache... // 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); }
/// <summary> /// Creates a bar code from the specified code type. /// </summary> public static BarCode FromType(CodeType type, string text, XSize size) { return FromType(type, text, size, CodeDirection.LeftToRight); }
/// <summary> /// Returns the rectangle that results from expanding the specified rectangle by the specified Size, in all directions. /// </summary> public static XRect Inflate(XRect rect, XSize size) { rect.Inflate(size.Width, size.Height); return(rect); }
/// <summary> /// Creates between 1 and 5 Béziers curves from parameters specified like in WPF. /// </summary> public static List <XPoint> BezierCurveFromArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArc, bool clockwise, PathStart pathStart) { // See also http://www.charlespetzold.com/blog/blog.xml from January 2, 2008: // http://www.charlespetzold.com/blog/2008/01/Mathematics-of-ArcSegment.html double δx = size.Width; double δy = size.Height; Debug.Assert(δx * δy > 0); double factor = δy / δx; bool isCounterclockwise = !clockwise; // Adjust for different radii and rotation angle. XMatrix matrix = new XMatrix(); matrix.RotateAppend(-rotationAngle); matrix.ScaleAppend(δy / δx, 1); XPoint pt1 = matrix.Transform(point1); XPoint pt2 = matrix.Transform(point2); // Get info about chord that connects both points. XPoint midPoint = new XPoint((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2); XVector vect = pt2 - pt1; double halfChord = vect.Length / 2; // Get vector from chord to center. XVector vectRotated; // (comparing two Booleans here!) if (isLargeArc == isCounterclockwise) { vectRotated = new XVector(-vect.Y, vect.X); } else { vectRotated = new XVector(vect.Y, -vect.X); } vectRotated.Normalize(); // Distance from chord to center. double centerDistance = Math.Sqrt(δy * δy - halfChord * halfChord); if (double.IsNaN(centerDistance)) { centerDistance = 0; } // Calculate center point. XPoint center = midPoint + centerDistance * vectRotated; // Get angles from center to the two points. double α = Math.Atan2(pt1.Y - center.Y, pt1.X - center.X); double β = Math.Atan2(pt2.Y - center.Y, pt2.X - center.X); // (another comparison of two Booleans!) if (isLargeArc == (Math.Abs(β - α) < Math.PI)) { if (α < β) { α += 2 * Math.PI; } else { β += 2 * Math.PI; } } // Invert matrix for final point calculation. matrix.Invert(); double sweepAngle = β - α; // Let the algorithm of GDI+ DrawArc to Bézier curves do the rest of the job return(BezierCurveFromArc(center.X - δx * factor, center.Y - δy, 2 * δx * factor, 2 * δy, α / Calc.Deg2Rad, sweepAngle / Calc.Deg2Rad, pathStart, ref matrix)); }
/// <summary> /// Indicates whether this instance and a specified size are equal. /// </summary> public bool Equals(XSize value) { return Equals(this, value); }
/// <summary> /// Parses the size from a string. /// </summary> public static XSize Parse(string source) { XSize empty; CultureInfo cultureInfo = CultureInfo.InvariantCulture; TokenizerHelper helper = new TokenizerHelper(source, cultureInfo); string str = helper.NextTokenRequired(); if (str == "Empty") empty = Empty; else empty = new XSize(Convert.ToDouble(str, cultureInfo), Convert.ToDouble(helper.NextTokenRequired(), cultureInfo)); helper.LastTokenRequired(); return empty; }
/// <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); }
/// <summary> /// /// </summary> /// <param name="pg"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="scale"></param> /// <returns></returns> public static PDF.XGraphicsPath ToXGraphicsPath(this IPathGeometry pg, double dx, double dy, Func <double, double> scale) { var gp = new PDF.XGraphicsPath() { FillMode = pg.FillRule == FillRule.EvenOdd ? PDF.XFillMode.Alternate : PDF.XFillMode.Winding }; foreach (var pf in pg.Figures) { var startPoint = pf.StartPoint; foreach (var segment in pf.Segments) { if (segment is IArcSegment arcSegment) { #if WPF var point1 = new PDF.XPoint( scale(startPoint.X + dx), scale(startPoint.Y + dy)); var point2 = new PDF.XPoint( scale(arcSegment.Point.X + dx), scale(arcSegment.Point.Y + dy)); var size = new PDF.XSize( scale(arcSegment.Size.Width), scale(arcSegment.Size.Height)); gp.AddArc( point1, point2, size, arcSegment.RotationAngle, arcSegment.IsLargeArc, arcSegment.SweepDirection == SweepDirection.Clockwise ? PDF.XSweepDirection.Clockwise : PDF.XSweepDirection.Counterclockwise); startPoint = arcSegment.Point; #else throw new NotSupportedException("Not supported segment type: " + segment.GetType()); // TODO: Convert WPF/SVG elliptical arc segment format to GDI+ bezier curves. //startPoint = arcSegment.Point; #endif } else if (segment is ICubicBezierSegment cubicBezierSegment) { gp.AddBezier( scale(startPoint.X + dx), scale(startPoint.Y + dy), scale(cubicBezierSegment.Point1.X + dx), scale(cubicBezierSegment.Point1.Y + dy), scale(cubicBezierSegment.Point2.X + dx), scale(cubicBezierSegment.Point2.Y + dy), scale(cubicBezierSegment.Point3.X + dx), scale(cubicBezierSegment.Point3.Y + dy)); startPoint = cubicBezierSegment.Point3; } else if (segment is ILineSegment) { var lineSegment = segment as ILineSegment; gp.AddLine( scale(startPoint.X + dx), scale(startPoint.Y + dy), scale(lineSegment.Point.X + dx), scale(lineSegment.Point.Y + dy)); startPoint = lineSegment.Point; } else if (segment is IPolyCubicBezierSegment polyCubicBezierSegment) { if (polyCubicBezierSegment.Points.Length >= 3) { gp.AddBezier( scale(startPoint.X + dx), scale(startPoint.Y + dy), scale(polyCubicBezierSegment.Points[0].X + dx), scale(polyCubicBezierSegment.Points[0].Y + dy), scale(polyCubicBezierSegment.Points[1].X + dx), scale(polyCubicBezierSegment.Points[1].Y + dy), scale(polyCubicBezierSegment.Points[2].X + dx), scale(polyCubicBezierSegment.Points[2].Y + dy)); } if (polyCubicBezierSegment.Points.Length > 3 && polyCubicBezierSegment.Points.Length % 3 == 0) { for (int i = 3; i < polyCubicBezierSegment.Points.Length; i += 3) { gp.AddBezier( scale(polyCubicBezierSegment.Points[i - 1].X + dx), scale(polyCubicBezierSegment.Points[i - 1].Y + dy), scale(polyCubicBezierSegment.Points[i].X + dx), scale(polyCubicBezierSegment.Points[i].Y + dy), scale(polyCubicBezierSegment.Points[i + 1].X + dx), scale(polyCubicBezierSegment.Points[i + 1].Y + dy), scale(polyCubicBezierSegment.Points[i + 2].X + dx), scale(polyCubicBezierSegment.Points[i + 2].Y + dy)); } } startPoint = polyCubicBezierSegment.Points.Last(); } else if (segment is IPolyLineSegment polyLineSegment) { if (polyLineSegment.Points.Length >= 1) { gp.AddLine( scale(startPoint.X + dx), scale(startPoint.Y + dy), scale(polyLineSegment.Points[0].X + dx), scale(polyLineSegment.Points[0].Y + dy)); } if (polyLineSegment.Points.Length > 1) { for (int i = 1; i < polyLineSegment.Points.Length; i++) { gp.AddLine( scale(polyLineSegment.Points[i - 1].X + dx), scale(polyLineSegment.Points[i - 1].Y + dy), scale(polyLineSegment.Points[i].X + dx), scale(polyLineSegment.Points[i].Y + dy)); } } startPoint = polyLineSegment.Points.Last(); } else if (segment is IPolyQuadraticBezierSegment polyQuadraticSegment) { if (polyQuadraticSegment.Points.Length >= 2) { var p1 = startPoint; var p2 = polyQuadraticSegment.Points[0]; var p3 = polyQuadraticSegment.Points[1]; double x1 = p1.X; double y1 = p1.Y; double x2 = p1.X + (2.0 * (p2.X - p1.X)) / 3.0; double y2 = p1.Y + (2.0 * (p2.Y - p1.Y)) / 3.0; double x3 = x2 + (p3.X - p1.X) / 3.0; double y3 = y2 + (p3.Y - p1.Y) / 3.0; double x4 = p3.X; double y4 = p3.Y; gp.AddBezier( scale(x1 + dx), scale(y1 + dy), scale(x2 + dx), scale(y2 + dy), scale(x3 + dx), scale(y3 + dy), scale(x4 + dx), scale(y4 + dy)); } if (polyQuadraticSegment.Points.Length > 2 && polyQuadraticSegment.Points.Length % 2 == 0) { for (int i = 3; i < polyQuadraticSegment.Points.Length; i += 3) { var p1 = polyQuadraticSegment.Points[i - 1]; var p2 = polyQuadraticSegment.Points[i]; var p3 = polyQuadraticSegment.Points[i + 1]; double x1 = p1.X; double y1 = p1.Y; double x2 = p1.X + (2.0 * (p2.X - p1.X)) / 3.0; double y2 = p1.Y + (2.0 * (p2.Y - p1.Y)) / 3.0; double x3 = x2 + (p3.X - p1.X) / 3.0; double y3 = y2 + (p3.Y - p1.Y) / 3.0; double x4 = p3.X; double y4 = p3.Y; gp.AddBezier( scale(x1 + dx), scale(y1 + dy), scale(x2 + dx), scale(y2 + dy), scale(x3 + dx), scale(y3 + dy), scale(x4 + dx), scale(y4 + dy)); } } startPoint = polyQuadraticSegment.Points.Last(); } else if (segment is IQuadraticBezierSegment quadraticBezierSegment) { var p1 = startPoint; var p2 = quadraticBezierSegment.Point1; var p3 = quadraticBezierSegment.Point2; double x1 = p1.X; double y1 = p1.Y; double x2 = p1.X + (2.0 * (p2.X - p1.X)) / 3.0; double y2 = p1.Y + (2.0 * (p2.Y - p1.Y)) / 3.0; double x3 = x2 + (p3.X - p1.X) / 3.0; double y3 = y2 + (p3.Y - p1.Y) / 3.0; double x4 = p3.X; double y4 = p3.Y; gp.AddBezier( scale(x1 + dx), scale(y1 + dy), scale(x2 + dx), scale(y2 + dy), scale(x3 + dx), scale(y3 + dy), scale(x4 + dx), scale(y4 + dy)); startPoint = quadraticBezierSegment.Point2; } else { throw new NotSupportedException("Not supported segment type: " + segment.GetType()); } } if (pf.IsClosed) { gp.CloseFigure(); } else { gp.StartFigure(); } } return(gp); }
/// <summary> /// Raises the <see cref="E:System.Drawing.Printing.PrintDocument.PrintPage"/> event. It is called before a page prints. /// </summary> /// <param name="e">A <see cref="T:System.Drawing.Printing.PrintPageEventArgs"/> that contains the event data.</param> protected override void OnPrintPage(PrintPageEventArgs e) { base.OnPrintPage(e); if (!e.Cancel) { PageSettings settings = e.PageSettings; try { Graphics graphics = e.Graphics; IntPtr hdc = graphics.GetHdc(); int xOffset = GetDeviceCaps(hdc, PHYSICALOFFSETX); int yOffset = GetDeviceCaps(hdc, PHYSICALOFFSETY); graphics.ReleaseHdc(hdc); graphics.TranslateTransform(-xOffset * 100 / graphics.DpiX, -yOffset * 100 / graphics.DpiY); // Recall: Width and Height are exchanged when settings.Landscape is true. XSize size = new XSize(e.PageSettings.Bounds.Width / 100.0 * 72, e.PageSettings.Bounds.Height / 100.0 * 72); float scale = 100f / 72f; graphics.ScaleTransform(scale, scale); // draw line A4 portrait //graphics.DrawLine(Pens.Red, 0, 0, 21f / 2.54f * 72, 29.7f / 2.54f * 72); #if WPF //#warning TODO WPFPDF // TODO WPFPDF #else XGraphics gfx = XGraphics.FromGraphics(graphics, size); this.renderer.RenderPage(gfx, this.pageNumber); #endif } catch { e.Cancel = true; } this.pageNumber++; this.pageCount--; e.HasMorePages = this.pageCount > 0; } }
/// <summary> /// Handle HTML links by create PDF Documents link either to external URL or to another page in the document. /// </summary> private static void HandleLinks(PdfDocument document, HtmlContainer container, XSize orgPageSize, XSize pageSize) { foreach (var link in container.GetLinks()) { int i = (int)(link.Rectangle.Top / pageSize.Height); for (; i < document.Pages.Count && pageSize.Height * i < link.Rectangle.Bottom; i++) { var offset = pageSize.Height * i; // f*****g position is from the bottom of the page var xRect = new XRect(link.Rectangle.Left, orgPageSize.Height - (link.Rectangle.Height + link.Rectangle.Top - offset), link.Rectangle.Width, link.Rectangle.Height); if (link.IsAnchor) { // create link to another page in the document var anchorRect = container.GetElementRectangle(link.AnchorId); if (anchorRect.HasValue) { // document links to the same page as the link is not allowed int anchorPageIdx = (int)(anchorRect.Value.Top / pageSize.Height); if (i != anchorPageIdx) document.Pages[i].AddDocumentLink(new PdfRectangle(xRect), anchorPageIdx); } } else { // create link to URL document.Pages[i].AddWebLink(new PdfRectangle(xRect), link.Href); } } } }
public void AddArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArg, XSweepDirection sweepDirection) { List<XPoint> points = GeometryHelper.BezierCurveFromArc(point1, point2, size, rotationAngle, isLargeArg, sweepDirection == XSweepDirection.Clockwise, PathStart.MoveTo1st); int count = points.Count; Debug.Assert((count + 2) % 3 == 0); MoveOrLineTo(points[0].X, points[0].Y); for (int idx = 1; idx < count; idx += 3) BezierTo(points[idx].X, points[idx].Y, points[idx + 1].X, points[idx + 1].Y, points[idx + 2].X, points[idx + 2].Y, false); }