// ===========================================================================
// ©2013-2026 WebSupergoo. All rights reserved.
//
// This source code is for use exclusively with the ABCpdf product with
// which it is distributed, under the terms of the license for that
// product. Details can be found at
//
// http://www.websupergoo.com/
//
// This copyright notice must not be deleted and must be reproduced alongside
// any sections of code extracted from this module.
// ===========================================================================
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using WebSupergoo.ABCpdf14;
using WebSupergoo.ABCpdf14.Atoms;
using WebSupergoo.ABCpdf14.Objects;
using TextState = WebSupergoo.ABCpdf14.Drawing.TextState;
using FontStyle = WebSupergoo.ABCpdf14.Drawing.FontStyle;
using FontInfoConvert = WebSupergoo.ABCpdf14.Drawing.FontInfoConvert;
using Font = WebSupergoo.ABCpdf14.Drawing.Font;
using BuiltInFont = WebSupergoo.ABCpdf14.Drawing.BuiltInFont;
namespace WebSupergoo.ABCpdf14.Drawing {
public enum ColorSpace { GrayScale, RGB, CMYK }
#region Drawing2D
namespace Drawing2D {
/// <summary>The line join style specifies the shape to be used at
/// the corners of paths that are stroked.</summary>
public enum LineJoin {
/// <summary>Miter join. The outer edges of the strokes for the two
/// segments are extended until they meet at an angle. If the segments
/// meet at too sharp an angle, a bevel join is used instead.</summary>
Miter,
/// <summary>Round join. An arc of a circle with a diameter equal to
/// the line width is drawn around the point where the two segments
/// meet, connecting the outer edges of the strokes for the two segments.
/// This pieslice-shaped figure is filled in, producing a rounded corner.</summary>
Round,
/// <summary>Bevel join. The two segments are finished with butt caps
/// and the resulting notch beyond the ends of the segments is filled
/// with a triangle.</summary>
Bevel
}
/// <summary>The line cap style specifies the shape to be used at the
/// ends of open subpaths (and dashes, if any) when they are stroked.</summary>
public enum LineCap {
/// <summary>Flat cap. The stroke is squared off at the endpoint of
/// the path. There is no projection beyond the end of the path.</summary>
Flat,
/// <summary>Round cap. A semicircular arc with a diameter equal to
/// the line width is drawn around the endpoint and filled in.</summary>
Round,
/// <summary>Projecting square cap. The stroke continues beyond the
/// endpoint of the path for a distance equal to half the line width
/// and is squared off.</summary>
Square
}
/// <summary>Specifies the style of dashed lines drawn with a Pen object.</summary>
public enum DashStyle {
/// <summary>Specifies a user-defined custom dash style.</summary>
Custom,
/// <summary>Specifies a line consisting of dashes.</summary>
Dash,
/// <summary>Specifies a line consisting of a repeating pattern of dash-dot.</summary>
DashDot,
/// <summary>Specifies a line consisting of a repeating pattern of dash-dot-dot.</summary>
DashDotDot,
/// <summary>Specifies a line consisting of dots.</summary>
Dot,
/// <summary>Specifies a solid line.</summary>
Solid
}
/// <summary>Specifies how the interior of a closed path is filled.</summary>
public enum FillMode {
/// <summary>The even-odd rule rule determines whether a point is
/// inside a path by drawing a ray from that point in any direction
/// and simply counting the number of path segments that cross the
/// ray, regardless of direction.</summary>
Alternate,
/// <summary>The nonzero winding number rule determines whether a
/// given point is inside a path by conceptually drawing a ray from
/// that point to infinity in any direction and then examining the
/// places where a segment of the path crosses the ray.</summary>
Winding
}
public enum PathPointType {
Start = 1,
Line = 2,
CloseSubPath = 4
}
public enum MatrixOrder { Prepend, Append }
/// <summary>Specifies a PDF transformation matrix.</summary>
public sealed class Matrix {
private double _a = 1;
private double _b = 0;
private double _c = 0;
private double _d = 1;
private double _e = 0;
private double _f = 0;
public double A {
get { return _a; }
set { _a = value; }
}
public double B {
get { return _b; }
set { _b = value; }
}
public double C {
get { return _c; }
set { _c = value; }
}
public double D {
get { return _d; }
set { _d = value; }
}
public double E {
get { return _e; }
set { _e = value; }
}
public double F {
get { return _f; }
set { _f = value; }
}
public Matrix() { }
public Matrix(double a, double b, double c, double d, double e, double f) {
_a = a;
_b = b;
_c = c;
_d = d;
_e = e;
_f = f;
}
public void Multiply(double a, double b, double c, double d, double e, double f) {
Multiply(a, b, c, d, e, f, MatrixOrder.Prepend);
}
public void Multiply(double a, double b, double c, double d, double e, double f, MatrixOrder order) {
double ra, rb, rc, rd, re, rf;
if (order == MatrixOrder.Prepend) {
ra = a * _a + b * _c;
rb = a * _b + b * _d;
rc = c * _a + d * _c;
rd = c * _b + d * _d;
re = e * _a + f * _c + _e ;
rf = e * _b + f * _d + _f ;
}
else {
ra = _a * a + _b * c;
rb = _a * b + _b * d;
rc = _c * a + _d * c;
rd = _c * b + _d * d;
re = _e * a + _f * c + e ;
rf = _e * b + _f * d + f ;
}
_a = ra;
_b = rb;
_c = rc;
_d = rd;
_e = re;
_f = rf;
}
public void Multiply(Matrix m, MatrixOrder order) {
Multiply(m.A, m.B, m.C, m.D, m.E, m.F, order);
}
public void Multiply(Matrix m) {
Multiply(m, MatrixOrder.Prepend);
}
public void Rotate(double angle) {
double cos = Math.Cos(angle / 180 * Math.PI);
double sin = Math.Sin(angle / 180 * Math.PI);
Multiply(cos, sin, -sin, cos, 0, 0, MatrixOrder.Prepend);
}
public void Scale(double width, double height) {
Multiply(width, 0, 0, height, 0, 0, MatrixOrder.Prepend);
}
internal double TransformX(System.Drawing.SizeF size) {
return size.Width * _a + size.Height * _c + _e;
}
internal double TransformY(System.Drawing.SizeF size) {
return size.Width * _b + size.Height * _d + _f;
}
public override bool Equals(object obj) {
Matrix m = obj as Matrix;
if (m == null)
return false;
return (A == m.A && B == m.B && C == m.C && D == m.D && E == m.E && F == m.F);
}
public override int GetHashCode() {
return base.GetHashCode ();
}
public override string ToString() {
return string.Format(NumberFormatInfo.InvariantInfo,
"{0:0.#####} {1:0.#####} {2:0.#####} {3:0.#####} {4:0.#####} {5:0.#####}",
A, B, C, D, E, F);
}
internal Matrix Clone() {
return new Matrix(A, B, C, D, E, F);
}
}
}
#endregion
#region Graphics
/// <summary>Encapsulates a PDF drawing surface. This class cannot be inherited.</summary>
public sealed class Graphics {
#region Declare variables
internal readonly PDFContent Content;
private System.Drawing.Rectangle _clip;
private Drawing2D.Matrix _curMatrix = new Drawing2D.Matrix();
private ColorSpace _colorSpace;
private float _resolution = 96;
#endregion
#region Properties
/// <summary>Defining the bounds of the visible content.</summary>
public System.Drawing.Rectangle Rect {
get { return Content.Doc.Rect.Rectangle; }
set { Content.Doc.Rect.Rectangle = value; }
}
/// <summary>Determines the current world space transform.</summary>
public Drawing2D.Matrix Transform {
get { return _curMatrix; }
set { _curMatrix = value; }
}
/// <summary>Gets or sets a Rectangle that limits the drawing region of this Graphics.</summary>
public System.Drawing.Rectangle Clip {
get { return _clip; }
set { _clip = value; }
}
/// <summary>Gets a RectangleF structure that bounds the clipping region of this Graphics.</summary>
/// <value>A RectangleF structure that represents a bounding rectangle for the clipping region of this Graphics.</value>
public System.Drawing.RectangleF ClipBounds{ get{ return _clip; } }
#endregion
#region Constructors
/// <summary>Initializes a new instance of the Graphics class with
/// the specified Page parent.</summary>
internal Graphics(Page page) {
Content = page.Document.NewContent();
_clip = Content.Doc.Rect.Rectangle;
_colorSpace = page.Document.ColorSpace;
_resolution = page.Document.Resolution;
}
#endregion
/// <summary>Write content to the doc.</summary>
public bool Realize() {
return Content.AddToDoc(); // idempotent
}
#region Line methods
/// <summary>Draws a line connecting two Point structures.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="pt1">The point at the start of the line.</param>
/// <param name="pt2">The point at the end of the line.</param>
public void DrawLine(Pen pen, System.Drawing.Point pt1, System.Drawing.Point pt2) {
DrawLines(pen, new System.Drawing.PointF[] { new System.Drawing.PointF(pt1.X, pt1.Y), new System.Drawing.PointF(pt2.X, pt2.Y) });
}
/// <summary>Draws a line connecting two System.Drawing.PointF structures.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="pt1">The point at the start of the line.</param>
/// <param name="pt2">The point at the end of the line.</param>
public void DrawLine(Pen pen, System.Drawing.PointF pt1, System.Drawing.PointF pt2) {
DrawLines(pen, new System.Drawing.PointF[] { pt1, pt2 });
}
/// <summary>Draws a line connecting the two points specified by coordinate pairs.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="x1">x-coordinate of the first point.</param>
/// <param name="y1">y-coordinate of the first point.</param>
/// <param name="x2">x-coordinate of the second point.</param>
/// <param name="y2">y-coordinate of the second point.</param>
public void DrawLine(Pen pen, double x1, double y1, double x2, double y2) {
DrawLines(pen, new System.Drawing.PointF[] { new System.Drawing.PointF((float)x1, (float)y1), new System.Drawing.PointF((float)x2, (float)y2) });
}
/// <summary>Draws a series of line segments that connect an array of points.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="points">The points to be connected.</param>
public void DrawLines(Pen pen, System.Drawing.Point[] points) {
DrawLines(pen, ToPointFArray(points));
}
/// <summary>Draws a series of line segments that connect an array of System.Drawing.PointF structures.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="points">The points to be connected.</param>
public void DrawLines(Pen pen, System.Drawing.PointF[] points) {
DrawLines(pen, points, false);
}
/// <summary>Draws a series of line segments that connect an array of System.Drawing.PointF structures.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="points">The points to be connected.</param>
/// <param name="closePath">Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath.</param>
private void DrawLines(Pen pen, System.Drawing.PointF[] points, bool closePath) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Move(points[0].X, Rect.Height - points[0].Y);
for (int i = 1; i < points.Length; i++) {
Content.Line(points[i].X, Rect.Height - points[i].Y);
}
if (closePath)
Content.Close();
Content.Stroke();
RestoreState();
}
#endregion
#region Polygon methods
/// <summary>Draws a polygon defined by an array of points.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="points">Array of points that represent the vertices of the polygon.</param>
public void DrawPolygon(Pen pen, System.Drawing.Point[] points) {
DrawLines(pen, ToPointFArray(points), true);
}
/// <summary>Draws a polygon defined by an array of System.Drawing.PointF structures.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the line.</param>
/// <param name="points">Array of points that represent the vertices of the polygon.</param>
public void DrawPolygon(Pen pen, System.Drawing.PointF[] points) {
DrawLines(pen, points, true);
}
/// <summary>Fills the interior of a polygon defined by an array of points specified by points using the specified fill mode.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="points">Array of points that represent the vertices of the polygon to be filled.</param>
/// <param name="fillMode">The style of the fill.</param>
public void FillPolygon(Brush brush, System.Drawing.Point[] points, Drawing2D.FillMode fillMode) {
FillPolygon(brush, ToPointFArray(points), fillMode);
}
/// <summary>Fills the interior of a polygon defined by an array of points specified by points using the specified fill mode.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="points">Array of points that represent the vertices of the polygon to fill.</param>
public void FillPolygon(Brush brush, System.Drawing.Point[] points) {
FillPolygon(brush, points, Drawing2D.FillMode.Alternate);
}
/// <summary>Fills the interior of a polygon defined by an array of points specified by System.Drawing.PointF structures using the specified fill mode.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="points">Array of points that represent the vertices of the polygon to be filled.</param>
/// <param name="fillMode">The style of the fill.</param>
public void FillPolygon(Brush brush, System.Drawing.PointF[] points, Drawing2D.FillMode fillMode) {
SaveState();
SetCoordinateSystems();
SetBrushStyle(brush);
Content.Move(points[0].X, Rect.Height - points[0].Y);
for (int i = 1; i < points.Length; i++) {
Content.Line(points[i].X, Rect.Height - points[i].Y);
}
if (fillMode == Drawing2D.FillMode.Winding) {
Content.Fill();
}
else if (fillMode == Drawing2D.FillMode.Alternate) {
Content.FillEvenOddRule();
}
RestoreState();
}
/// <summary>Fills the interior of a polygon defined by an array of points specified by System.Drawing.PointF structures using the specified fill mode.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="points">Array of points that represent the vertices of the polygon to be filled.</param>
public void FillPolygon(Brush brush, System.Drawing.PointF[] points) {
FillPolygon(brush, points, Drawing2D.FillMode.Alternate);
}
#endregion
#region Rectangle methods
/// <summary>Draws a rectangle specified by a coordinate pair, a width, and a height.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the rectangle.</param>
/// <param name="x">x-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="y">y-coordinate of the upper-left corner of the rectangle to draw.</param>
/// <param name="width">Width of the rectangle to draw.</param>
/// <param name="height">Height of the rectangle to draw.</param>
public void DrawRectangle(Pen pen, double x, double y, double width, double height) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Rect(x, Rect.Height - y - height, width, height);
Content.Stroke();
RestoreState();
}
/// <summary>Draws a rectangle.</summary>
/// <param name="pen">Pen object that determines the color, width, and style of the rectangle.</param>
/// <param name="rect">The rectangle to be drawn.</param>
public void DrawRectangle(Pen pen, System.Drawing.Rectangle rect) {
DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>Draws a series of rectangles.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the rectangles.</param>
/// <param name="rects">Array of rectangles to be drawn.</param>
public void DrawRectangles(Pen pen, System.Drawing.Rectangle[] rects) {
DrawRectangles(pen, ToRectangleFArray(rects));
}
/// <summary>Draws a series of rectangles.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the rectangles.</param>
/// <param name="rects">Array of rectangles to be drawn.</param>
public void DrawRectangles(Pen pen, System.Drawing.RectangleF[] rects) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
foreach (System.Drawing.RectangleF rect in rects) {
Content.Rect(rect.X, Rect.Height - rect.Y - rect.Height, rect.Width, rect.Height);
Content.Stroke();
}
RestoreState();
}
/// <summary>Fills the interior of a rectangle.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="rect">The rectangle to be filled.</param>
public void FillRectangle(Brush brush, System.Drawing.Rectangle rect) {
FillRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>Fills the interior of a rectangle.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="rect">The rectangle to be filled.</param>
public void FillRectangle(Brush brush, System.Drawing.RectangleF rect) {
FillRectangle(brush, rect.X, rect.Y, rect.Width, rect.Height);
}
/// <summary>Fills the interior of a rectangle.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="x">x-coordinate of the upper-left corner of the rectangle.</param>
/// <param name="y">y-coordinate of the upper-left corner of the rectangle.</param>
/// <param name="width">Width of the rectangle.</param>
/// <param name="height">Height of the rectangle.</param>
public void FillRectangle(Brush brush, double x, double y, double width, double height) {
SaveState();
SetCoordinateSystems();
SetBrushStyle(brush);
Content.Rect(x, Rect.Height - y - height, width, height);
Content.Fill();
RestoreState();
}
/// <summary>Fills the interiors of a series of rectangles.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="rects">The rectangles to be filled.</param>
public void FillRectangles(Brush brush, System.Drawing.Rectangle[] rects) {
FillRectangles(brush, ToRectangleFArray(rects));
}
/// <summary>Fills the interiors of a series of rectangles.</summary>
/// <param name="brush">Brush object that determines the characteristics of the fill.</param>
/// <param name="rects">The rectangles to be filled.</param>
public void FillRectangles(Brush brush, System.Drawing.RectangleF[] rects) {
SaveState();
SetCoordinateSystems();
SetBrushStyle(brush);
foreach (System.Drawing.RectangleF rect in rects) {
Content.Rect(rect.X, rect.Y, rect.Width, rect.Height);
Content.Fill();
}
RestoreState();
}
#endregion
#region Arc methods
private void ContentArc(double x, double y, double width, double height,
double startAngle, double sweepAngle, bool inMove) {
Content.Arc(-startAngle, -(startAngle + sweepAngle),
x + (width / 2), Rect.Height - y - (height / 2),
width / 2, height / 2, 0, inMove);
}
/// <summary>Draws an arc representing a portion of an ellipse.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the arc.</param>
/// <param name="rect">The rectangle that defines the boundaries of the ellipse.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the starting point of the arc.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to ending point of the arc.</param>
public void DrawArc(Pen pen, System.Drawing.Rectangle rect, double startAngle, double sweepAngle) {
DrawArc(pen, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Draws an arc representing a portion of an ellipse.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the arc.</param>
/// <param name="rect">The rectangle that defines the boundaries of the ellipse.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the starting point of the arc.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to ending point of the arc.</param>
public void DrawArc(Pen pen, System.Drawing.RectangleF rect, double startAngle, double sweepAngle) {
DrawArc(pen, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Draws an arc representing a portion of an ellipse.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the arc.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the rectangle that defines the ellipse.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the rectangle that defines the ellipse.</param>
/// <param name="width">Width of the rectangle that defines the ellipse.</param>
/// <param name="height">Height of the rectangle that defines the ellipse.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the starting point of the arc.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to ending point of the arc.</param>
public void DrawArc(Pen pen, double x, double y, double width, double height,
double startAngle, double sweepAngle) {
DrawArc(pen, x, y, width, height, startAngle, sweepAngle, false);
}
private void DrawArc(Pen pen, double x, double y, double width, double height,
double startAngle, double sweepAngle, bool closePath) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
ContentArc(x, y, width, height, startAngle, sweepAngle, true);
if (closePath)
Content.Close();
Content.Stroke();
RestoreState();
}
/// <summary>Draws a pie shape defined by an ellipse and two radial lines.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the pie shape.</param>
/// <param name="rect">The rectangle that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie shape.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie shape.</param>
public void DrawPie(Pen pen, System.Drawing.Rectangle rect, double startAngle, double sweepAngle) {
DrawPie(pen, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Draws a pie shape defined by an ellipse and two radial lines.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the pie shape.</param>
/// <param name="rect">The rectangle that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie shape.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie shape.</param>
public void DrawPie(Pen pen, System.Drawing.RectangleF rect, double startAngle, double sweepAngle) {
DrawPie(pen, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Draws a pie shape defined by an ellipse specified by a coordinate pair, a width, a height, and two radial lines.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the pie shape.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="width">Width of the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="height">Height of the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie shape.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie shape.</param>
public void DrawPie(Pen pen, double x, double y, double width, double height,
double startAngle, double sweepAngle) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Move(x + (width / 2), Rect.Height - y - (height / 2));
ContentArc(x, y, width, height, startAngle, sweepAngle, true);
Content.Line(x + (width / 2), Rect.Height - y - (height / 2));
Content.Close();
Content.Stroke();
RestoreState();
}
/// <summary>Fills the interior of a pie section defined by an ellipse specified by a rectangle and two radial lines.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="rect">The rectangle that represents the bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie section.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie section.</param>
public void FillPie(Brush brush, System.Drawing.Rectangle rect, double startAngle, double sweepAngle) {
FillPie(brush, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Fills the interior of a pie section defined by an ellipse specified by a rectangle and two radial lines.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="rect">The bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie section.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie section.</param>
public void FillPie(Brush brush, System.Drawing.RectangleF rect, double startAngle, double sweepAngle) {
FillPie(brush, rect.Left, rect.Top, rect.Width, rect.Height, startAngle, sweepAngle);
}
/// <summary>Fills the interior of a pie section defined by an ellipse specified by a pair of coordinates, a width, a height, and two radial lines.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="width">Width of the bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="height">Height of the bounding rectangle that defines the ellipse from which the pie section comes.</param>
/// <param name="startAngle">Angle in degrees measured clockwise from the x-axis to the first side of the pie section.</param>
/// <param name="sweepAngle">Angle in degrees measured clockwise from the <paramref name="startAngle"/> parameter to the second side of the pie section.</param>
public void FillPie(Brush brush, double x, double y, double width, double height,
double startAngle, double sweepAngle) {
SaveState();
SetCoordinateSystems();
SetBrushStyle(brush);
Content.Move(x + (width / 2), Rect.Height - y - (height / 2));
ContentArc(x, y, width, height, startAngle, sweepAngle, true);
Content.Line(x + (width / 2), Rect.Height - y - (height / 2));
Content.Close();
Drawing2D.FillMode fillMode = Drawing2D.FillMode.Alternate;
if (fillMode == Drawing2D.FillMode.Winding)
Content.Fill();
else if (fillMode == Drawing2D.FillMode.Alternate)
Content.FillEvenOddRule();
RestoreState();
}
/// <summary>Draws an ellipse defined by a bounding rectangle.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the ellipse.</param>
/// <param name="rect">The rectangle that defines the boundaries of the ellipse.</param>
public void DrawEllipse(Pen pen, System.Drawing.Rectangle rect){
DrawArc(pen, rect, 0, 360);
}
/// <summary>Draws an ellipse defined by a bounding rectangle.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the ellipse.</param>
/// <param name="rect">The rectangle that defines the boundaries of the ellipse.</param>
public void DrawEllipse(Pen pen, System.Drawing.RectangleF rect){
DrawArc(pen, rect, 0, 360);
}
/// <summary>Draws an ellipse defined by a bounding rectangle specified by a pair of coordinates, a width, and a height.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the ellipse.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse.</param>
/// <param name="width">Width of the bounding rectangle that defines the ellipse.</param>
/// <param name="height">Height of the bounding rectangle that defines the ellipse.</param>
public void DrawEllipse(Pen pen, double x, double y, double width, double height){
DrawArc(pen, x, y, width, height, 0, 360);
}
/// <summary>Fills the interior of an ellipse defined by a bounding rectangle.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="rect">The bounding rectangle that defines the ellipse.</param>
public void FillEllipse(Brush brush, System.Drawing.Rectangle rect){
FillPie(brush, rect, 0, 360);
}
/// <summary>Fills the interior of an ellipse defined by a bounding rectangle.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="rect">The bounding rectangle that defines the ellipse.</param>
public void FillEllipse(Brush brush, System.Drawing.RectangleF rect){
FillPie(brush, rect, 0, 360);
}
/// <summary>Fills the interior of an ellipse defined by a bounding rectangle specified by a pair of coordinates, a width, and a height.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the bounding rectangle that defines the ellipse.</param>
/// <param name="width">Width of the bounding rectangle that defines the ellipse.</param>
/// <param name="height">Height of the bounding rectangle that defines the ellipse.</param>
public void FillEllipse(Brush brush, double x, double y, double width, double height){
FillPie(brush, x, y, width, height, 0, 360);
}
#endregion
#region Bezier methods
/// <summary>Draws a Bezier spline defined by four points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="pt1">The starting point of the curve.</param>
/// <param name="pt2">The first control point for the curve.</param>
/// <param name="pt3">The second control point for the curve.</param>
/// <param name="pt4">The ending point of the curve.</param>
public void DrawBezier(Pen pen, System.Drawing.Point pt1, System.Drawing.Point pt2, System.Drawing.Point pt3, System.Drawing.Point pt4) {
DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
}
/// <summary>Draws a Bezier spline defined by four points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="pt1">The starting point of the curve.</param>
/// <param name="pt2">The first control point for the curve.</param>
/// <param name="pt3">The second control point for the curve.</param>
/// <param name="pt4">The ending point of the curve.</param>
public void DrawBezier(Pen pen, System.Drawing.PointF pt1, System.Drawing.PointF pt2, System.Drawing.PointF pt3, System.Drawing.PointF pt4) {
DrawBezier(pen, pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y);
}
/// <summary>Draws a Bezier spline defined by four ordered pairs of coordinates that represent points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="x1">x-coordinate of the starting point of the curve.</param>
/// <param name="y1">y-coordinate of the starting point of the curve.</param>
/// <param name="x2">x-coordinate of the first control point of the curve.</param>
/// <param name="y2">y-coordinate of the first control point of the curve.</param>
/// <param name="x3">x-coordinate of the second control point of the curve.</param>
/// <param name="y3">y-coordinate of the second control point of the curve.</param>
/// <param name="x4">x-coordinate of the ending point of the curve.</param>
/// <param name="y4">y-coordinate of the ending point of the curve.</param>
public void DrawBezier(Pen pen, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
DrawBezier(pen, x1, y1, x2, y2, x3, y3, x4, y4, false);
}
/// <summary>Draws a Bezier spline defined by four ordered pairs of coordinates that represent points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="x1">x-coordinate of the starting point of the curve.</param>
/// <param name="y1">y-coordinate of the starting point of the curve.</param>
/// <param name="x2">x-coordinate of the first control point of the curve.</param>
/// <param name="y2">y-coordinate of the first control point of the curve.</param>
/// <param name="x3">x-coordinate of the second control point of the curve.</param>
/// <param name="y3">y-coordinate of the second control point of the curve.</param>
/// <param name="x4">x-coordinate of the ending point of the curve.</param>
/// <param name="y4">y-coordinate of the ending point of the curve.</param>
/// <param name="closePath">Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath.</param>
private void DrawBezier(Pen pen, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, bool closePath) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Move(x1, Rect.Height - y1);
Content.Bezier(x2, Rect.Height - y2, x3, Rect.Height - y3, x4, Rect.Height - y4);
if (closePath) {
Content.Close();
}
Content.Stroke();
RestoreState();
}
/// <summary>Draws a series of Bezier splines from an array of points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="points">Array of points that represent the points that determine the curve.</param>
public void DrawBeziers(Pen pen, System.Drawing.Point[] points) {
DrawBeziers(pen , ToPointFArray(points));
}
/// <summary>Draws a series of Bezier splines from an array of points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="points">Array of System.Drawing.PointF structures that represent the points that determine the curve.</param>
public void DrawBeziers(Pen pen, System.Drawing.PointF[] points) {
DrawBeziers(pen, points, false);
}
/// <summary>Draws a series of Bezier splines from an array of points.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the curve.</param>
/// <param name="points">Array of System.Drawing.PointF structures that represent the points that determine the curve.</param>
/// <param name="closePath">Close the current subpath by appending a straight line segment from the current point to the starting point of the subpath.</param>
private void DrawBeziers(Pen pen, System.Drawing.PointF[] points, bool closePath) {
if(points.Length <= 0)
return;
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Move(points[0].X, Rect.Height - points[0].Y);
for(int i = 0; i < points.Length - 3; i += 3){
Content.Bezier(points[i + 1].X, Rect.Height - points[i + 1].Y,
points[i + 2].X, Rect.Height - points[i + 2].Y,
points[i + 3].X, Rect.Height - points[i + 3].Y);
}
if (closePath) {
Content.Close();
}
Content.Stroke();
RestoreState();
}
#endregion
#region Path methods
/// <summary>Draws a Drawing2D.GraphicsPath.</summary>
/// <param name="pen">Pen that determines the color, width, and style of the path.</param>
/// <param name="path">The path to draw.</param>
public void DrawPath(Pen pen, Drawing2D.GraphicsPath path) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
Content.Contents.Append(path.Content.Contents.ToString());
Content.Stroke();
RestoreState();
}
/// <summary>Fills the interior of a Drawing2D.GraphicsPath.</summary>
/// <param name="brush">Brush that determines the characteristics of the fill.</param>
/// <param name="path">The path to fill.</param>
public void FillPath(Brush brush, Drawing2D.GraphicsPath path) {
SaveState();
SetCoordinateSystems();
SetBrushStyle(brush);
Content.Contents.Append(path.Content.Contents.ToString());
//Content.Close();
if (path.FillMode == Drawing2D.FillMode.Winding) {
Content.Fill();
}
else if (path.FillMode == Drawing2D.FillMode.Alternate) {
Content.FillEvenOddRule();
}
RestoreState();
}
#endregion
#region Text methods
/// <summary>Draws the specified text string at the specified location with the specified Brush and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the drawn text.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the drawn text.</param>
public void DrawString(string s, Font font, Brush brush, double x, double y) {
DrawString(s, font, new Pen(brush.Color), brush, x, y, new TextState());
}
/// <summary>Draws the specified text string at the specified location with the specified Brush and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="point">System.Drawing.PointF structure that specifies the upper-left corner of the drawn text.</param>
public void DrawString(string s, Font font, Brush brush, System.Drawing.PointF point) {
DrawString(s, font, new Pen(brush.Color), brush, point, new TextState());
}
/// <summary>Draws the specified text string in the specified rectangle with the specified Brush and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="layoutRectangle">The rectangle that specifies the location of the drawn text.</param>
public void DrawString(string s, Font font, Brush brush,
System.Drawing.RectangleF layoutRectangle) {
DrawString(s, font, new Pen(brush.Color), brush, layoutRectangle, new TextState());
}
/// <summary>Draws the specified text string at the specified location with the specified Pen, Brush, and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the drawn text.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush, double x, double y) {
DrawString(s, font, pen, brush, x, y, new TextState());
}
/// <summary>Draws the specified text string at the specified location with the specified Pen, Brush, and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="point">The upper-left corner of the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush,
System.Drawing.PointF point) {
DrawString(s, font, pen, brush, point, new TextState());
}
/// <summary>Draws the specified text string in the specified rectangle with the specified Pen, Brush, and Font objects.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="layoutRectangle">The rectangle that specifies the location of the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush,
System.Drawing.RectangleF layoutRectangle) {
DrawString(s, font, pen, brush, layoutRectangle, new TextState());
}
/// <summary>Draws the specified text string at the specified location with the specified Pen, Brush, and Font objects using the styling attributes of the specified TextState.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the drawn text.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the drawn text.</param>
/// <param name="state">TextState that specifies styling attributes that are applied to the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush,
double x, double y, TextState state) {
DrawString(s, font, pen, brush, x, y, 1000000, 1000000, state);
}
/// <summary>Draws the specified text string at the specified location with the specified Pen, Brush, and Font objects using the styling attributes of the specified TextState.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="point">The upper-left corner of the drawn text.</param>
/// <param name="state">TextState that specifies styling attributes that are applied to the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush,
System.Drawing.PointF point, TextState state) {
DrawString(s, font, pen, brush, point.X, point.Y, state);
}
/// <summary>Draws the specified text string in the specified rectangle with the specified Pen, Brush, and Font objects using the styling attributes of the specified TextState.</summary>
/// <param name="s">String to draw</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="pen">Pen that determines the color, width, and style of the outlines of the drawn text.</param>
/// <param name="brush">Brush that determines the color and texture of the drawn text.</param>
/// <param name="layoutRectangle">The rectangle that specifies the location of the drawn text.</param>
/// <param name="state">TextState that specifies styling attributes that are applied to the drawn text.</param>
public void DrawString(string s, Font font, Pen pen, Brush brush,
System.Drawing.RectangleF layoutRectangle, TextState state) {
DrawString(s, font, pen, brush,
layoutRectangle.Left, layoutRectangle.Top,
layoutRectangle.Width, layoutRectangle.Height, state);
}
private void DrawString(string s, Font font, Pen pen, Brush brush,
double x, double y, double width, double height, TextState state) {
SaveState();
SetCoordinateSystems();
SetPenStyle(pen);
SetBrushStyle(brush);
SetFontAndTextStyle(font, state);
string oldRect = Content.Doc.Rect.String;
string oldTransform = Content.Doc.Transform.String;
double hscale = state.HorizontalScaling / 100;
Content.Doc.Rect.Left = x;
Content.Doc.Rect.Width = width / hscale;
Content.Doc.Rect.Top = Content.Doc.MediaBox.Top - y; // - Content.mDoc.TextStyle.LineSpacing;
Content.Doc.Rect.Bottom = Content.Doc.Rect.Top - height;
Content.Doc.Transform.Magnify(hscale, 1,
Content.Doc.Rect.Left, Content.Doc.Rect.Top);
string renderingModeStr;
switch (state.RenderingMode) {
case TextRenderingMode.FillThenStrokeText :
case TextRenderingMode.FillThenStrokeTextAndAddForClipping :
case TextRenderingMode.StrokeText :
case TextRenderingMode.StrokeTextAndAddForClipping :
renderingModeStr = string.Format("rendering-mode=\"{0}\" outline=\"1\"",
(int)state.RenderingMode);
break;
default :
renderingModeStr = string.Format("rendering-mode=\"{0}\"",
(int)state.RenderingMode);
break;
}
string colorFillStr = string.Format(
"color-fill=\"#{0:x2}{1:x2}{2:x2}\"",
(int)(brush.Color.R * 255),
(int)(brush.Color.G * 255),
(int)(brush.Color.B * 255));
string colorStrokeStr = string.Format(
"color-stroke=\"#{0:x2}{1:x2}{2:x2}\"",
(int)(pen.Color.R * 255),
(int)(pen.Color.G * 255),
(int)(pen.Color.B * 255));
int id = Content.Doc.AddTextStyled(string.Format("<Font {1} {2} {3}><Pre>{0}</Pre></Font>",
System.Web.HttpUtility.HtmlEncode(s),
renderingModeStr, colorFillStr, colorStrokeStr));
string stream = Content.Doc.GetInfo(id, "stream");
Objects.Page page = (Objects.Page)Content.Doc.ObjectSoup[Content.Doc.Page];
page.Detach(Content.Doc.ObjectSoup[id] as StreamObject);
Content.Contents.Append(" ").Append(stream).Append(" ");
Content.Doc.Transform.String = oldTransform;
Content.Doc.Rect.String = oldRect;
RestoreState();
}
/// <summary>Measures the specified string when drawn with the specified Font.</summary>
/// <param name="s">String to measure</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <returns>The size, in points, of the string specified by the <paramref name="s"/> parameter as drawn with the <paramref name="font"/> parameter.</returns>
public System.Drawing.SizeF MeasureString(string s, Font font) {
return MeasureString(s, font, new TextState());
}
/// <summary>Measures the specified string when drawn with the specified Font using the styling attributes of the specified TextState.</summary>
/// <param name="s">String to measure</param>
/// <param name="font">Font that defines the text format of the string.</param>
/// <param name="state">The styling attributes that are applied to the drawn text.</param>
/// <returns>The size, in points, of the string specified by the <paramref name="s"/> parameter as drawn with the <paramref name="font"/> parameter.</returns>
public System.Drawing.SizeF MeasureString(string s, Font font, TextState state) {
FontStyle leftoutFontStyle;
int fontId = SetFontAndTextStyle(font, state, out leftoutFontStyle);
string widths = Content.Doc.GetInfo(fontId, "widths " + s);
float width = 0;
foreach(string widthStr in widths.Split(',')) {
if(widthStr != string.Empty) {
try {
width += float.Parse(widthStr, NumberFormatInfo.InvariantInfo);
}
catch{}
}
}
double adjustItalic = 0;
double adjustBold = 0;
if(s.Length > 0){
if(font.Italic)
adjustItalic = 0.25 - 0.1;
if(FontInfoConvert.TestFlag(leftoutFontStyle, FontStyle.Bold))
adjustBold = 0.03;
}
int ascent = font.FontFamily.GetCellAscent(font.Style);
int descent = font.FontFamily.GetCellDescent(font.Style);
int emHeight = font.FontFamily.GetEmHeight(font.Style);
float sizeInPixels = (font.SizeInPoints * _resolution) / 72;
return new System.Drawing.SizeF(
(float)(sizeInPixels
* (width / 1000d + adjustBold + adjustItalic * ascent / emHeight)),
(float)(sizeInPixels * (ascent + descent) / emHeight));
}
#endregion
#region Image methods
/// <summary>Draws the specified Image, using its original physical size, at the specified location.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="point">The location of the upper-left corner of the drawn image.</param>
public void DrawImage(Image image, System.Drawing.Point point) {
DrawImage(image, point.X, point.Y, double.NaN, double.NaN);
}
/// <summary>Draws the specified Image, using its original physical size, at the specified location.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="point">The location of the upper-left corner of the drawn image.</param>
public void DrawImage(Image image, System.Drawing.PointF point) {
DrawImage(image, point.X, point.Y, double.NaN, double.NaN);
}
/// <summary>Draws the specified Image at the specified location and with the specified size.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="rect">The rectangle into which the image should be drawn.</param>
public void DrawImage(Image image, System.Drawing.Rectangle rect) {
DrawImage(image, rect.Left, rect.Top, rect.Width, rect.Height);
}
/// <summary>Draws the specified Image at the specified location and with the specified size.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="rect">The rectangle into which the image should be drawn.</param>
public void DrawImage(Image image, System.Drawing.RectangleF rect) {
DrawImage(image, rect.Left, rect.Top, rect.Width, rect.Height);
}
/// <summary>Draws the specified Image, using its original physical size, at the specified location.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the drawn image.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the drawn image.</param>
public void DrawImage(Image image, double x, double y) {
DrawImage(image, x, y, double.NaN, double.NaN);
}
/// <summary>Draws the specified Image at the specified location and with the specified size.</summary>
/// <param name="image">Image to draw.</param>
/// <param name="x">The x-coordinate of the upper-left corner of the drawn image.</param>
/// <param name="y">The y-coordinate of the upper-left corner of the drawn image.</param>
/// <param name="width">Width of the drawn image.</param>
/// <param name="height">Height of the drawn image.</param>
public void DrawImage(Image image, double x, double y, double width, double height) {
if (double.IsNaN(width)) {
if (double.IsNaN(height)) {
width = image.Width / image.xImage.HRes * 72;
height = image.Height / image.xImage.VRes * 72;
}
else {
width = image.Width * height / image.Height;
}
}
else if (double.IsNaN(height)) {
height = image.Height * width / image.Width;
}
Drawing2D.Matrix m = GetTransformMatrix();
m.Multiply(width, 0, 0, height, x, Rect.Height - y - height);
int imageID = Content.GetReferencedImageID(image);
if (imageID != 0) {
Content.SaveState();
Content.Transform(m.A, m.B, m.C, m.D, m.E, m.F);
Content.DoImage(imageID);
Content.RestoreState();
}
else {
string oldTransform = Content.Doc.Transform.String;
string oldRect = Content.Doc.Rect.String;
Content.Doc.Transform.SetTransform(m.A, m.B, m.C, m.D, m.E, m.F);
Content.Doc.Rect.SetRect(0, 0, 1, 1);
imageID = Content.Doc.AddImageObject(image.xImage, false);
Content.AddReferencedImage(image, imageID);
string stream = Content.Doc.GetInfo(imageID, "stream");
Objects.Page page = (Objects.Page)Content.Doc.ObjectSoup[Content.Doc.Page];
page.Detach(Content.Doc.ObjectSoup[imageID] as StreamObject);
Content.Contents.Append(" ").Append(stream).Append(" ");
Content.Doc.Rect.String = oldRect;
Content.Doc.Transform.String = oldTransform;
}
}
#endregion
#region Private methods
private System.Drawing.PointF[] ToPointFArray(System.Drawing.Point[] points){
System.Drawing.PointF[] arr = new System.Drawing.PointF[points.Length];
for(int i = 0; i < points.Length; ++i)
arr[i] = points[i];
return arr;
}
private System.Drawing.RectangleF[] ToRectangleFArray(System.Drawing.Rectangle[] rects){
System.Drawing.RectangleF[] arr = new System.Drawing.RectangleF[rects.Length];
for(int i = 0; i < rects.Length; ++i)
arr[i] = rects[i];
return arr;
}
private int SetFontAndTextStyle(Font font, TextState state){
FontStyle leftoutFontStyle;
return SetFontAndTextStyle(font, state, out leftoutFontStyle);
}
private int SetFontAndTextStyle(Font font, TextState state, out FontStyle leftoutFontStyle) {
XTextStyle textStyle = Content.Doc.TextStyle;
textStyle.Size = (font.SizeInPoints * _resolution) / 72;
textStyle.CharSpacing = state.CharacterSpacing;
textStyle.WordSpacing = state.WordSpacing;
textStyle.LineSpacing = state.Leading + (font.GetHeight(_resolution) - textStyle.Size);
string embeddedFontName = font.GetEmbeddedFontName(out leftoutFontStyle);
textStyle.Bold = FontInfoConvert.TestFlag(leftoutFontStyle, FontStyle.Bold);
textStyle.Italic = FontInfoConvert.TestFlag(leftoutFontStyle, FontStyle.Italic);
textStyle.Underline = FontInfoConvert.TestFlag(leftoutFontStyle, FontStyle.Underline);
textStyle.Strike = FontInfoConvert.TestFlag(leftoutFontStyle, FontStyle.Strikeout);
int fontId = 0;
if (font is BuiltInFont)
fontId = Content.Doc.AddFont(embeddedFontName);
if (fontId == 0)
fontId = Content.Doc.EmbedFont(embeddedFontName, LanguageType.Unicode, false, true);
if (fontId == 0)
fontId = Content.Doc.AddFont(embeddedFontName);
#if DEBUG
if (fontId == 0)
throw new ApplicationException("Unable to find font \"" + embeddedFontName + "\".");
#endif
Content.Doc.Font = fontId;
return fontId;
}
private Drawing2D.Matrix GetTransformMatrix() {
Drawing2D.Matrix transform = Transform;
double rectHeight = Rect.Height;
return new Drawing2D.Matrix(transform.A, -transform.B, -transform.C, transform.D,
transform.E + transform.C * rectHeight,
rectHeight - transform.F - transform.D * rectHeight);
}
private void SetCoordinateSystems() {
if (!_curMatrix.Equals(new Drawing2D.Matrix())) {
Drawing2D.Matrix m = GetTransformMatrix();
Content.Transform(m.A, m.B, m.C, m.D, m.E, m.F);
}
if (!Content.Doc.Rect.Rectangle.Equals(_clip)) {
Content.SetNonStrokeAlpha(0);
Content.Clip();
Content.Rect(_clip.X, Rect.Height - _clip.Y - _clip.Height, _clip.Width, _clip.Height);
Content.Fill();
}
}
private void SetPenStyle(Pen pen) {
Content.SetLineWidth(pen.Width);
Content.SetLineJoin((int)pen.LineJoin);
Content.SetLineCap((int)pen.LineCap);
Content.SetStrokeAlpha(pen.Color.A);
if (_colorSpace == ColorSpace.RGB) {
Content.SetRGBStrokeColor(pen.Color.R, pen.Color.G, pen.Color.B);
}
else if (_colorSpace == ColorSpace.CMYK) {
Content.SetCMYKStrokeColor(pen.Color.C, pen.Color.M, pen.Color.Y, pen.Color.K);
}
else if (_colorSpace == ColorSpace.GrayScale) {
Content.SetGrayStrokeColor(pen.Color.GrayScale);
}
Content.SetMiterLimit(pen.MiterLimit);
StringBuilder sb = new StringBuilder();
switch (pen.DashStyle) {
case Drawing2D.DashStyle.Custom:
sb.Append("[ ");
foreach (double p in pen.DashPattern)
sb.Append(p).Append(" ");
sb.Append("] ");
break;
case Drawing2D.DashStyle.Dash:
sb.Append("[ 10 5 ] ");
break;
case Drawing2D.DashStyle.DashDot:
sb.Append("[ 10 5 3 5 ] ");
break;
case Drawing2D.DashStyle.DashDotDot:
sb.Append("[ 10 5 3 5 3 5 ] ");
break;
case Drawing2D.DashStyle.Dot:
sb.Append("[ 3 10 ] ");
break;
case Drawing2D.DashStyle.Solid:
default:
sb.Append("[ ] ");
break;
}
Content.LineDash(sb.Append(pen.DashOffset).ToString());
}
private void SaveState() {
if (!_curMatrix.Equals(new Drawing2D.Matrix()) || !Content.Doc.Rect.Rectangle.Equals(_clip))
Content.SaveState();
}
private void RestoreState() {
if (!_curMatrix.Equals(new Drawing2D.Matrix()) || !Content.Doc.Rect.Rectangle.Equals(_clip))
Content.RestoreState();
}
private void SetBrushStyle(Brush brush) {
Content.SetNonStrokeAlpha(brush.Color.A);
if (_colorSpace == ColorSpace.RGB) {
Content.SetRGBNonStrokeColor(brush.Color.R, brush.Color.G, brush.Color.B);
}
else if (_colorSpace == ColorSpace.CMYK) {
Content.SetCMYKNonStrokeColor(brush.Color.C, brush.Color.M, brush.Color.Y, brush.Color.K);
}
else if (_colorSpace == ColorSpace.GrayScale) {
Content.SetGrayNonStrokeColor(brush.Color.GrayScale);
}
}
#endregion
}
#endregion
}