using FastReport.Utils; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; namespace FastReport.Export.Pdf { public partial class PDFExport : ExportBase { private const float KAPPA1 = 1.5522847498f; private const float KAPPA2 = 2 - KAPPA1; private const float GAP_BETWEEN_LINES = 4.5f; private void DrawPDFLine(float x, float y, float width, float thickness, float offsX, Color color, bool transformNeeded, StringBuilder sb) { x = (transformNeeded ? x * PDF_DIVIDER : GetLeft(x)) + offsX; y = transformNeeded ? -y * PDF_DIVIDER : GetTop(y); DrawPDFLine(x, y, x + width * PDF_DIVIDER, y, color, thickness * PDF_DIVIDER, LineStyle.Solid, null, null, sb); } private void DrawPDFRect(float left, float top, float right, float bottom, Color color, float borderWidth, LineStyle lineStyle, StringBuilder sb) { if (lineStyle == LineStyle.Solid) { //old function GetPDFStrokeColor(color, sb); // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images) sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("2 J"); sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); sb.Append(FloatToString(left)).Append(" "). AppendLine(FloatToString(top)). Append(FloatToString(right - left)).Append(" "). Append(FloatToString(bottom - top)).AppendLine(" re").AppendLine("S"); return; } //draw rectangle by lines DrawPDFLine(left, top, right, top, color, borderWidth, lineStyle, null, null, sb); DrawPDFLine(right, top, right, bottom, color, borderWidth, lineStyle, null, null, sb); DrawPDFLine(right, bottom, left, bottom, color, borderWidth, lineStyle, null, null, sb); DrawPDFLine(left, bottom, left, top, color, borderWidth, lineStyle, null, null, sb); } private void DrawPDFFillRect(float Left, float Top, float Width, float Height, FillBase fill, StringBuilder sb) { if (fill is SolidFill && !fill.IsTransparent) { GetPDFFillColor((fill as SolidFill).Color, sb); sb.Append(FloatToString(Left)).Append(" "). Append(FloatToString(Top - Height)).Append(" "). Append(FloatToString(Width)).Append(" "). Append(FloatToString(Height)).AppendLine(" re"); sb.AppendLine("f"); } else if (fill is GlassFill) { GetPDFFillColor((fill as GlassFill).Color, sb); sb.Append(FloatToString(Left)).Append(" "). Append(FloatToString(Top - Height)).Append(" "). Append(FloatToString(Width)).Append(" "). Append(FloatToString(Height / 2)).AppendLine(" re"); sb.AppendLine("f"); Color c = (fill as GlassFill).Color; c = Color.FromArgb(255, (int)Math.Round(c.R + (255 - c.R) * (fill as GlassFill).Blend), (int)Math.Round(c.G + (255 - c.G) * (fill as GlassFill).Blend), (int)Math.Round(c.B + (255 - c.B) * (fill as GlassFill).Blend)); GetPDFFillColor(c, sb); sb.Append(FloatToString(Left)).Append(" "). Append(FloatToString(Top - Height / 2)).Append(" "). Append(FloatToString(Width)).Append(" "). Append(FloatToString(Height / 2)).AppendLine(" re"); sb.AppendLine("f"); } else if (IsFillableGradientGrid(fill)) DrawPDFVectorGradientFill(Left, Top, Width, Height, fill, sb); } private void DrawPDFTriangle(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth, LineStyle lineStyle, StringBuilder sb) { PointF point1 = new PointF(left + width / 2, top); PointF point2 = new PointF(left + width, top - height); PointF point3 = new PointF(left, top - height); if (lineStyle == LineStyle.Solid) { if (fillColor.A != 0) GetPDFFillColor(fillColor, sb); if (borderColor.A != 0) GetPDFStrokeColor(borderColor, sb); // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images) sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m "). Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l "). Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l "). Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l"); if (fillColor.A == 0) sb.AppendLine("S"); else sb.AppendLine("B"); return; } if (fillColor.A != 0) { GetPDFFillColor(fillColor, sb); //sb = GetPDFStrokeColor(fillColor, sb); //sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); //sb.AppendLine(DrawPDFDash(LineStyle.Solid, borderWidth)); sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m "). Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l "). Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l "). Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l"); sb.AppendLine("F"); } DrawPDFLine(point1.X, point1.Y, point2.X, point2.Y, borderColor, borderWidth, lineStyle, null, null, sb); DrawPDFLine(point2.X, point2.Y, point3.X, point3.Y, borderColor, borderWidth, lineStyle, null, null, sb); DrawPDFLine(point3.X, point3.Y, point1.X, point1.Y, borderColor, borderWidth, lineStyle, null, null, sb); } private void DrawPDFDiamond(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth, LineStyle lineStyle, StringBuilder sb) { PointF point1 = new PointF(left + width / 2, top); PointF point2 = new PointF(left + width, top - height / 2); PointF point3 = new PointF(left + width / 2, top - height); PointF point4 = new PointF(left, top - height / 2); if (lineStyle == LineStyle.Solid) { //old function if (fillColor.A != 0) GetPDFFillColor(fillColor, sb); if (borderColor.A != 0) GetPDFStrokeColor(borderColor, sb); // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images) sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m "). Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l "). Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l "). Append(FloatToString(point4.X)).Append(" ").Append(FloatToString(point4.Y)).Append(" l "). Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l"); if (fillColor.A == 0) sb.AppendLine("S"); else sb.AppendLine("B"); return; } //lineStyle != solid if (fillColor.A != 0) { GetPDFFillColor(fillColor, sb); //sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); //sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m "). Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l "). Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l "). Append(FloatToString(point4.X)).Append(" ").Append(FloatToString(point4.Y)).Append(" l "). Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l"); sb.AppendLine("F"); } DrawPDFLine(point1.X, point1.Y, point2.X, point2.Y, borderColor, borderWidth, lineStyle, null, null, sb); DrawPDFLine(point2.X, point2.Y, point3.X, point3.Y, borderColor, borderWidth, lineStyle, null, null, sb); DrawPDFLine(point3.X, point3.Y, point4.X, point4.Y, borderColor, borderWidth, lineStyle, null, null, sb); DrawPDFLine(point4.X, point4.Y, point1.X, point1.Y, borderColor, borderWidth, lineStyle, null, null, sb); } private void DrawPDFEllipse(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth, LineStyle lineStyle, StringBuilder sb) { if (fillColor.A != 0) GetPDFFillColor(fillColor, sb); if (borderColor.A != 0) GetPDFStrokeColor(borderColor, sb); // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images) sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("0 J"); sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); float rx = width / 2; float ry = height / 2; sb.Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" m"); sb.Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry * KAPPA1)).Append(" "). Append(FloatToString(left + rx * KAPPA1)).Append(" ").Append(FloatToString(top - height)).Append(" "). Append(FloatToString(left + rx)).Append(" ").Append(FloatToString(top - height)).AppendLine(" c"); sb.Append(FloatToString(left + rx * KAPPA2)).Append(" ").Append(FloatToString(top - height)).Append(" "). Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry * KAPPA1)).Append(" "). Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" c"); sb.Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry * KAPPA2)).Append(" "). Append(FloatToString(left + rx * KAPPA2)).Append(" ").Append(FloatToString(top)).Append(" "). Append(FloatToString(left + rx)).Append(" ").Append(FloatToString(top)).AppendLine(" c"); sb.Append(FloatToString(left + rx * KAPPA1)).Append(" ").Append(FloatToString(top)).Append(" "). Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry * KAPPA2)).Append(" "). Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" c"); if (fillColor.A == 0) sb.AppendLine("S"); else sb.AppendLine("B"); } private void DrawPDFLine(float left, float top, float right, float bottom, Color color, float width, LineStyle lineStyle, CapSettings startCap, CapSettings endCap, StringBuilder sb, FloatCollection dashPattern = null) { if (!(color.A == 0 || width == 0.0f)) { GetPDFStrokeColor(color, sb); sb.AppendLine(DrawPDFDash(lineStyle, width, dashPattern?.Cast().ToArray())); DrawStyledLine(sb, left, top, right, bottom, lineStyle, width); if (startCap != null && startCap.Style == CapStyle.Arrow) DrawArrow(sb, startCap, width, right, bottom, left, top); if (endCap != null && endCap.Style == CapStyle.Arrow) DrawArrow(sb, endCap, width, left, top, right, bottom); } } // this method is not used private void DrawPDFPolyLine(float left, float top, float right, float bottom, float centerX, float centerY, PointF[] points, bool isClosed, Color borderColor, float borderWidth, LineStyle lineStyle, StringBuilder sb) { if (lineStyle == LineStyle.Solid) { if (borderColor.A != 0) GetPDFStrokeColor(borderColor, sb); sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); bool isFirst = true; foreach (PointF point in points) { if (isFirst) { isFirst = false; sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m "); } else { sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l "); } } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); if (isClosed) sb.AppendLine("s"); else sb.AppendLine("S"); } else { for (int i = 0; i < points.Length - 1; i++) DrawPDFLine( left + (points[i].X + centerX) * PDF_DIVIDER, top - (points[i].Y + centerY) * PDF_DIVIDER, left + (points[i + 1].X + centerX) * PDF_DIVIDER, top - (points[i + 1].Y + centerY) * PDF_DIVIDER, borderColor, borderWidth, lineStyle, null, null, sb); if (isClosed) DrawPDFLine(left + (points[points.Length - 1].X + centerX) * PDF_DIVIDER, top - (points[points.Length - 1].Y + centerY) * PDF_DIVIDER, left + (points[0].X + centerX) * PDF_DIVIDER, top - (points[0].Y + centerY) * PDF_DIVIDER, borderColor, borderWidth, lineStyle, null, null, sb); } } // this method is not used private void DrawPDFPolygon(float left, float top, float right, float bottom, float centerX, float centerY, PointF[] points, Color fillColor, Color borderColor, float borderWidth, LineStyle borderStyle, StringBuilder sb) { if (fillColor.A == 0) { DrawPDFPolyLine(left, top, right, bottom, centerX, centerY, points, true, borderColor, borderWidth, borderStyle, sb); } else { if (borderStyle == LineStyle.Solid) { GetPDFFillColor(fillColor, sb); if (borderColor.A != 0) GetPDFStrokeColor(borderColor, sb); sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); sb.AppendLine(DrawPDFDash(borderStyle, borderWidth)); bool isFirst = true; foreach (PointF point in points) { if (isFirst) { isFirst = false; sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m "); } else { sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l "); } } sb.Append(FloatToString(left + (points[0].X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (points[0].Y + centerY) * PDF_DIVIDER)).Append(" l"); sb.AppendLine(); sb.AppendLine("B"); } else { GetPDFFillColor(fillColor, sb); sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); sb.AppendLine(DrawPDFDash(borderStyle, borderWidth)); bool isFirst = true; foreach (PointF point in points) { if (isFirst) { isFirst = false; sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m "); } else { sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l "); } } sb.Append(FloatToString(left + (points[0].X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (points[0].Y + centerY) * PDF_DIVIDER)).Append(" l"); sb.AppendLine(); sb.AppendLine("f"); DrawPDFPolyLine(left, top, right, bottom, centerX, centerY, points, true, borderColor, borderWidth, borderStyle, sb); } } } private void DrawStyledLine(StringBuilder sb, float left, float top, float right, float bottom, LineStyle lineStyle, float width) { sb.Append(FloatToString(width)).AppendLine(" w").AppendLine("0 J"); switch (lineStyle) { case LineStyle.Dash: DrawDashedLine(sb, left, top, right, bottom, width, "LS"); break; case LineStyle.DashDot: DrawDashedLine(sb, left, top, right, bottom, width, "LSPS"); break; case LineStyle.DashDotDot: DrawDashedLine(sb, left, top, right, bottom, width, "LSPSPS"); break; case LineStyle.Dot: DrawDashedLine(sb, left, top, right, bottom, width, "PS"); break; case LineStyle.Double: DrawLine(sb, left, top, right, bottom); break; case LineStyle.Custom: DrawLine(sb, left, top, right, bottom); break; default: DrawLine(sb, left, top, right, bottom); break; } } // L - line, S - space, P - point private void DrawDashedLine(StringBuilder sb, float left, float top, float right, float bottom, float linewidth, string pattern) { float dash = linewidth * 3.0f; float dot = linewidth; int currentState = 0; bool horizLine = false; bool vertLine = false; float length = 0, alfa = 0; if (left == right) // vertical line { vertLine = true; if (bottom < top) { dash = -dash; dot = -dot; } length = bottom - top; } else if (top == bottom) // horiz line { horizLine = true; if (right < left) { dash = -dash; dot = -dot; } length = right - left; } else { // diag length = (float)Math.Sqrt(Math.Pow(right - left, 2) + Math.Pow(bottom - top, 2)); alfa = (float)Math.Asin((right - left) / length); } float current = 0, currentX = 0, currentY = 0; float delta, deltaX = 0, deltaY = 0; bool penDown; while (Math.Abs(current) < Math.Abs(length)) { char state = pattern[currentState++]; if (currentState >= pattern.Length) currentState = 0; switch (state) { case 'L': // line delta = dash; penDown = true; break; case 'P': // point delta = dot; penDown = true; break; default: // space delta = dot; penDown = false; break; } current += delta; if (alfa != 0) { deltaX = (float)(delta * Math.Sin(alfa)); deltaY = (float)(delta * Math.Cos(alfa)) * Math.Sign(bottom - top); currentX += deltaX; currentY += deltaY; } if (penDown) { if (Math.Abs(current) < Math.Abs(length)) { if (vertLine) DrawLine(sb, left, top + current - delta, right, top + current); else if (horizLine) DrawLine(sb, left + current - delta, top, left + current, bottom); else DrawLine(sb, left + currentX - deltaX, top + currentY - deltaY, left + currentX, top + currentY); } else { if (vertLine) DrawLine(sb, left, top + current - delta, right, bottom); else if (horizLine) DrawLine(sb, left + current - delta, top, right, bottom); else DrawLine(sb, left + currentX - deltaX, top + currentY - deltaY, right, bottom); } } } } private void DrawLine(StringBuilder sb, float left, float top, float right, float bottom) { sb.Append(FloatToString(left)).Append(" "). Append(FloatToString(top)).AppendLine(" m"). Append(FloatToString(right)).Append(" "). Append(FloatToString(bottom)).AppendLine(" l"). AppendLine("S"); } private void DrawArrow(StringBuilder sb, CapSettings Arrow, float lineWidth, float x1, float y1, float x2, float y2) { float k1, a, b, c, d; float xp, yp, x3, y3, x4, y4; float wd = Arrow.Width * lineWidth * PDF_DIVIDER; float ld = Arrow.Height * lineWidth * PDF_DIVIDER; if (Math.Abs(x2 - x1) > 0) { k1 = (y2 - y1) / (x2 - x1); a = (float)Math.Pow(k1, 2) + 1; b = 2 * (k1 * ((x2 * y1 - x1 * y2) / (x2 - x1) - y2) - x2); c = (float)Math.Pow(x2, 2) + (float)Math.Pow(y2, 2) - (float)Math.Pow(ld, 2) + (float)Math.Pow((x2 * y1 - x1 * y2) / (x2 - x1), 2) - 2 * y2 * (x2 * y1 - x1 * y2) / (x2 - x1); d = (float)Math.Pow(b, 2) - 4 * a * c; xp = (-b + (float)Math.Sqrt(d)) / (2 * a); if ((xp > x1) && (xp > x2) || (xp < x1) && (xp < x2)) xp = (-b - (float)Math.Sqrt(d)) / (2 * a); yp = xp * k1 + (x2 * y1 - x1 * y2) / (x2 - x1); if (y2 != y1) { x3 = xp + wd * (float)Math.Sin(Math.Atan(k1)); y3 = yp - wd * (float)Math.Cos(Math.Atan(k1)); x4 = xp - wd * (float)Math.Sin(Math.Atan(k1)); y4 = yp + wd * (float)Math.Cos(Math.Atan(k1)); } else { x3 = xp; y3 = yp - wd; x4 = xp; y4 = yp + wd; } } else { xp = x2; yp = y2 - ld; if ((yp > y1) && (yp > y2) || (yp < y1) && (yp < y2)) yp = y2 + ld; x3 = xp - wd; y3 = yp; x4 = xp + wd; y4 = yp; } sb.AppendLine("2 J").AppendLine("[] 0 d").Append(FloatToString(x3)).Append(" ").Append(FloatToString(y3)).AppendLine(" m"). Append(FloatToString(x2)).Append(" ").Append(FloatToString(y2)).AppendLine(" l"). Append(FloatToString(x4)).Append(" ").Append(FloatToString(y4)).AppendLine(" l").AppendLine("S"); } private string DrawPDFDash(LineStyle lineStyle, float lineWidth, float[] dashesWidth = null) { if (lineStyle == LineStyle.Solid) return "[] 0 d"; else { string dash = FloatToString(lineWidth * 3.0f) + " "; string dot = FloatToString(lineWidth) + " "; StringBuilder result = new StringBuilder(64); switch (lineStyle) { // the first element is a stroke, the second is a space // "space" changed from dash to dot. case LineStyle.Dash: //result.Append(dash); result.Append(dash).Append(dot); break; case LineStyle.DashDot: //result.Append(dash).Append(dash).Append(dot).Append(dash); result.Append(dash).Append(dot).Append(dot).Append(dot); break; case LineStyle.DashDotDot: //result.Append(dash).Append(dash).Append(dot).Append(dash).Append(dot).Append(dash); result.Append(dash).Append(dot).Append(dot).Append(dot).Append(dot).Append(dot); break; case LineStyle.Dot: //result.Append(dot).Append(dash); result.Append(dot).Append(dot); break; case LineStyle.Custom: if (dashesWidth == null) return "[] 0 d"; foreach (var val in dashesWidth) // this value has been commented out because it distorts the appearance of dashes, // as if it is reduced to standard outlines result.Append(FloatToString(val * lineWidth/* * 0.3F*/) + " "); break; } return ExportUtils.StringFormat("[{0}] 0 d", result.ToString()); } } private void DrawPDFBorder(Border Border, float left, float top, float width, float height, StringBuilder sb) { if (Border.Shadow) { DrawPDFFillRect(GetLeft(left + width), GetTop(top + Border.ShadowWidth), Border.ShadowWidth * PDF_DIVIDER, height * PDF_DIVIDER, new SolidFill(Border.ShadowColor), sb); DrawPDFFillRect(GetLeft(left + Border.ShadowWidth), GetTop(top + height), (width - Border.ShadowWidth) * PDF_DIVIDER, Border.ShadowWidth * PDF_DIVIDER, new SolidFill(Border.ShadowColor), sb); } if (Border.Lines != BorderLines.None) { if (Border.Lines == BorderLines.All && Border.LeftLine.Equals(Border.RightLine) && Border.TopLine.Equals(Border.BottomLine) && Border.LeftLine.Equals(Border.TopLine)) { if (Border.Width > 0 && Border.Color.A != 0) { DrawPDFRect(GetLeft(left), GetTop(top), GetLeft(left + width), GetTop(top + height), Border.Color, Border.Width * PDF_DIVIDER, Border.Style, sb); if (Border.LeftLine.Style == LineStyle.Double) DrawPDFRect(GetLeft(left + GAP_BETWEEN_LINES), GetTop(top + GAP_BETWEEN_LINES), GetLeft(left + width - GAP_BETWEEN_LINES), GetTop(top + height - GAP_BETWEEN_LINES), Border.Color, Border.Width * PDF_DIVIDER, Border.Style, sb); } } else { float Left = GetLeft(left); float Top = GetTop(top); float Right = GetLeft(left + width); float Bottom = GetTop(top + height); Top -= 0.1f; Bottom += 0.1f; if ((Border.Lines & BorderLines.Left) > 0) { DrawPDFLine(Left, Top, Left, Bottom, Border.LeftLine.Color, Border.LeftLine.Width * PDF_DIVIDER, Border.LeftLine.Style, null, null, sb); if (Border.LeftLine.Style == LineStyle.Double) DrawPDFLine(Left + GAP_BETWEEN_LINES, Top, Left + GAP_BETWEEN_LINES, Bottom, Border.LeftLine.Color, Border.LeftLine.Width * PDF_DIVIDER, Border.LeftLine.Style, null, null, sb); } if ((Border.Lines & BorderLines.Right) > 0) { DrawPDFLine(Right, Top, Right, Bottom, Border.RightLine.Color, Border.RightLine.Width * PDF_DIVIDER, Border.RightLine.Style, null, null, sb); if (Border.RightLine.Style == LineStyle.Double) DrawPDFLine(Right - GAP_BETWEEN_LINES, Top, Right - GAP_BETWEEN_LINES, Bottom, Border.RightLine.Color, Border.RightLine.Width * PDF_DIVIDER, Border.RightLine.Style, null, null, sb); } Top += 0.1f; Bottom -= 0.1f; Left += 0.1f; Right -= 0.1f; if ((Border.Lines & BorderLines.Top) > 0) { DrawPDFLine(Left, Top, Right, Top, Border.TopLine.Color, Border.TopLine.Width * PDF_DIVIDER, Border.TopLine.Style, null, null, sb); if (Border.TopLine.Style == LineStyle.Double) DrawPDFLine(Left, Top - GAP_BETWEEN_LINES, Right, Top - GAP_BETWEEN_LINES, Border.TopLine.Color, Border.TopLine.Width * PDF_DIVIDER, Border.TopLine.Style, null, null, sb); } if ((Border.Lines & BorderLines.Bottom) > 0) { DrawPDFLine(Left, Bottom, Right, Bottom, Border.BottomLine.Color, Border.BottomLine.Width * PDF_DIVIDER, Border.BottomLine.Style, null, null, sb); if (Border.BottomLine.Style == LineStyle.Double) DrawPDFLine(Left, Bottom + GAP_BETWEEN_LINES, Right, Bottom + GAP_BETWEEN_LINES, Border.BottomLine.Color, Border.BottomLine.Width * PDF_DIVIDER, Border.BottomLine.Style, null, null, sb); } } } } private void DrawPDFPolygonChar(GraphicsPath p, float x, float y, Color c, StringBuilder sb) { GraphicsPath clone = p.Clone() as GraphicsPath; FillPDFGraphicsPath(SizeF.Empty, clone, new SolidBrush(c), sb, curvesInterpolationText, new System.Drawing.Drawing2D.Matrix(PDF_DIVIDER, 0, 0, -PDF_DIVIDER, x, y)); } private void DrawPDFPolygonCharOutline(GraphicsPath p, float x, float y, Color c, float borderWidth, StringBuilder sb) { if (p.PointCount == 0) return; GetPDFStrokeColor(c, sb); sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J"); //sb.AppendLine(DrawPDFDash(lineStyle, borderWidth)); PointF[] ps = p.PathPoints; byte[] pt = p.PathTypes; for (int i = 0; i < p.PointCount;) { switch (pt[i]) { case 0://start sb.AppendLine(); sb.Append(FloatToString(x + ps[i].X * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - ps[i].Y * PDF_DIVIDER)).Append(" m "); i++; break; case 1://line sb.Append(FloatToString(x + ps[i].X * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - ps[i].Y * PDF_DIVIDER)).Append(" l "); i++; break; case 3://interpolate bezier for (float dt = 1; dt < 6; dt++) DrawPDFBezier(x, y, ps[i - 1], ps[i], ps[i + 1], ps[i + 2], dt / 5, sb); i += 3; break; default: i++; break; } //fill } sb.AppendLine(); sb.AppendLine("S"); } private void DrawPDFBezier(float x, float y, PointF p0, PointF p1, PointF p2, PointF p3, float t, StringBuilder sb) { float t1 = 1 - t; float px = t1 * t1 * t1 * p0.X + 3 * t1 * t1 * t * p1.X + 3 * t * t * t1 * p2.X + t * t * t * p3.X; float py = t1 * t1 * t1 * p0.Y + 3 * t1 * t1 * t * p1.Y + 3 * t * t * t1 * p2.Y + t * t * t * p3.Y; sb.Append(FloatToString(x + px * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - py * PDF_DIVIDER)).Append(" l "); } } }