PDFExportDraw.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. using FastReport.Utils;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Linq;
  7. using System.Text;
  8. namespace FastReport.Export.Pdf
  9. {
  10. public partial class PDFExport : ExportBase
  11. {
  12. private const float KAPPA1 = 1.5522847498f;
  13. private const float KAPPA2 = 2 - KAPPA1;
  14. private const float GAP_BETWEEN_LINES = 4.5f;
  15. private void DrawPDFLine(float x, float y, float width, float thickness, float offsX, Color color, bool transformNeeded, StringBuilder sb)
  16. {
  17. x = (transformNeeded ? x * PDF_DIVIDER : GetLeft(x)) + offsX;
  18. y = transformNeeded ? -y * PDF_DIVIDER : GetTop(y);
  19. DrawPDFLine(x, y, x + width * PDF_DIVIDER, y, color, thickness * PDF_DIVIDER, LineStyle.Solid, null, null, sb);
  20. }
  21. private void DrawPDFRect(float left, float top, float right, float bottom, Color color, float borderWidth,
  22. LineStyle lineStyle, StringBuilder sb)
  23. {
  24. if (lineStyle == LineStyle.Solid)
  25. {
  26. //old function
  27. GetPDFStrokeColor(color, sb);
  28. // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images)
  29. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("2 J");
  30. sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  31. sb.Append(FloatToString(left)).Append(" ").
  32. AppendLine(FloatToString(top)).
  33. Append(FloatToString(right - left)).Append(" ").
  34. Append(FloatToString(bottom - top)).AppendLine(" re").AppendLine("S");
  35. return;
  36. }
  37. //draw rectangle by lines
  38. DrawPDFLine(left, top, right, top, color, borderWidth, lineStyle, null, null, sb);
  39. DrawPDFLine(right, top, right, bottom, color, borderWidth, lineStyle, null, null, sb);
  40. DrawPDFLine(right, bottom, left, bottom, color, borderWidth, lineStyle, null, null, sb);
  41. DrawPDFLine(left, bottom, left, top, color, borderWidth, lineStyle, null, null, sb);
  42. }
  43. private void DrawPDFFillRect(float Left, float Top, float Width, float Height, FillBase fill, StringBuilder sb)
  44. {
  45. if (fill is SolidFill && !fill.IsTransparent)
  46. {
  47. GetPDFFillColor((fill as SolidFill).Color, sb);
  48. sb.Append(FloatToString(Left)).Append(" ").
  49. Append(FloatToString(Top - Height)).Append(" ").
  50. Append(FloatToString(Width)).Append(" ").
  51. Append(FloatToString(Height)).AppendLine(" re");
  52. sb.AppendLine("f");
  53. }
  54. else if (fill is GlassFill)
  55. {
  56. GetPDFFillColor((fill as GlassFill).Color, sb);
  57. sb.Append(FloatToString(Left)).Append(" ").
  58. Append(FloatToString(Top - Height)).Append(" ").
  59. Append(FloatToString(Width)).Append(" ").
  60. Append(FloatToString(Height / 2)).AppendLine(" re");
  61. sb.AppendLine("f");
  62. Color c = (fill as GlassFill).Color;
  63. c = Color.FromArgb(255, (int)Math.Round(c.R + (255 - c.R) * (fill as GlassFill).Blend),
  64. (int)Math.Round(c.G + (255 - c.G) * (fill as GlassFill).Blend),
  65. (int)Math.Round(c.B + (255 - c.B) * (fill as GlassFill).Blend));
  66. GetPDFFillColor(c, sb);
  67. sb.Append(FloatToString(Left)).Append(" ").
  68. Append(FloatToString(Top - Height / 2)).Append(" ").
  69. Append(FloatToString(Width)).Append(" ").
  70. Append(FloatToString(Height / 2)).AppendLine(" re");
  71. sb.AppendLine("f");
  72. }
  73. else if (IsFillableGradientGrid(fill))
  74. DrawPDFVectorGradientFill(Left, Top, Width, Height, fill, sb);
  75. }
  76. private void DrawPDFTriangle(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth,
  77. LineStyle lineStyle, StringBuilder sb)
  78. {
  79. PointF point1 = new PointF(left + width / 2, top);
  80. PointF point2 = new PointF(left + width, top - height);
  81. PointF point3 = new PointF(left, top - height);
  82. if (lineStyle == LineStyle.Solid)
  83. {
  84. if (fillColor.A != 0)
  85. GetPDFFillColor(fillColor, sb);
  86. if (borderColor.A != 0)
  87. GetPDFStrokeColor(borderColor, sb);
  88. // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images)
  89. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  90. sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  91. sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m ").
  92. Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l ").
  93. Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l ").
  94. Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l");
  95. if (fillColor.A == 0)
  96. sb.AppendLine("S");
  97. else
  98. sb.AppendLine("B");
  99. return;
  100. }
  101. if (fillColor.A != 0)
  102. {
  103. GetPDFFillColor(fillColor, sb);
  104. //sb = GetPDFStrokeColor(fillColor, sb);
  105. //sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  106. //sb.AppendLine(DrawPDFDash(LineStyle.Solid, borderWidth));
  107. sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m ").
  108. Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l ").
  109. Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l ").
  110. Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l");
  111. sb.AppendLine("F");
  112. }
  113. DrawPDFLine(point1.X, point1.Y, point2.X, point2.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  114. DrawPDFLine(point2.X, point2.Y, point3.X, point3.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  115. DrawPDFLine(point3.X, point3.Y, point1.X, point1.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  116. }
  117. private void DrawPDFDiamond(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth,
  118. LineStyle lineStyle, StringBuilder sb)
  119. {
  120. PointF point1 = new PointF(left + width / 2, top);
  121. PointF point2 = new PointF(left + width, top - height / 2);
  122. PointF point3 = new PointF(left + width / 2, top - height);
  123. PointF point4 = new PointF(left, top - height / 2);
  124. if (lineStyle == LineStyle.Solid)
  125. {
  126. //old function
  127. if (fillColor.A != 0)
  128. GetPDFFillColor(fillColor, sb);
  129. if (borderColor.A != 0)
  130. GetPDFStrokeColor(borderColor, sb);
  131. // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images)
  132. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  133. sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  134. sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m ").
  135. Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l ").
  136. Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l ").
  137. Append(FloatToString(point4.X)).Append(" ").Append(FloatToString(point4.Y)).Append(" l ").
  138. Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l");
  139. if (fillColor.A == 0)
  140. sb.AppendLine("S");
  141. else
  142. sb.AppendLine("B");
  143. return;
  144. }
  145. //lineStyle != solid
  146. if (fillColor.A != 0)
  147. {
  148. GetPDFFillColor(fillColor, sb);
  149. //sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  150. //sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  151. sb.Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).Append(" m ").
  152. Append(FloatToString(point2.X)).Append(" ").Append(FloatToString(point2.Y)).Append(" l ").
  153. Append(FloatToString(point3.X)).Append(" ").Append(FloatToString(point3.Y)).Append(" l ").
  154. Append(FloatToString(point4.X)).Append(" ").Append(FloatToString(point4.Y)).Append(" l ").
  155. Append(FloatToString(point1.X)).Append(" ").Append(FloatToString(point1.Y)).AppendLine(" l");
  156. sb.AppendLine("F");
  157. }
  158. DrawPDFLine(point1.X, point1.Y, point2.X, point2.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  159. DrawPDFLine(point2.X, point2.Y, point3.X, point3.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  160. DrawPDFLine(point3.X, point3.Y, point4.X, point4.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  161. DrawPDFLine(point4.X, point4.Y, point1.X, point1.Y, borderColor, borderWidth, lineStyle, null, null, sb);
  162. }
  163. private void DrawPDFEllipse(float left, float top, float width, float height, Color fillColor, Color borderColor, float borderWidth,
  164. LineStyle lineStyle, StringBuilder sb)
  165. {
  166. if (fillColor.A != 0)
  167. GetPDFFillColor(fillColor, sb);
  168. if (borderColor.A != 0)
  169. GetPDFStrokeColor(borderColor, sb);
  170. // with repeated multiplication by PDF_DIVIDER, the line thickness in pdf becomes thinner than that of figures with a custom dash pattern (images)
  171. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("0 J");
  172. sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  173. float rx = width / 2;
  174. float ry = height / 2;
  175. sb.Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" m");
  176. sb.Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry * KAPPA1)).Append(" ").
  177. Append(FloatToString(left + rx * KAPPA1)).Append(" ").Append(FloatToString(top - height)).Append(" ").
  178. Append(FloatToString(left + rx)).Append(" ").Append(FloatToString(top - height)).AppendLine(" c");
  179. sb.Append(FloatToString(left + rx * KAPPA2)).Append(" ").Append(FloatToString(top - height)).Append(" ").
  180. Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry * KAPPA1)).Append(" ").
  181. Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" c");
  182. sb.Append(FloatToString(left)).Append(" ").Append(FloatToString(top - ry * KAPPA2)).Append(" ").
  183. Append(FloatToString(left + rx * KAPPA2)).Append(" ").Append(FloatToString(top)).Append(" ").
  184. Append(FloatToString(left + rx)).Append(" ").Append(FloatToString(top)).AppendLine(" c");
  185. sb.Append(FloatToString(left + rx * KAPPA1)).Append(" ").Append(FloatToString(top)).Append(" ").
  186. Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry * KAPPA2)).Append(" ").
  187. Append(FloatToString(left + width)).Append(" ").Append(FloatToString(top - ry)).AppendLine(" c");
  188. if (fillColor.A == 0)
  189. sb.AppendLine("S");
  190. else
  191. sb.AppendLine("B");
  192. }
  193. private void DrawPDFLine(float left, float top, float right, float bottom, Color color, float width,
  194. LineStyle lineStyle, CapSettings startCap, CapSettings endCap, StringBuilder sb, FloatCollection dashPattern = null)
  195. {
  196. if (!(color.A == 0 || width == 0.0f))
  197. {
  198. GetPDFStrokeColor(color, sb);
  199. sb.AppendLine(DrawPDFDash(lineStyle, width, dashPattern?.Cast<float>().ToArray()));
  200. DrawStyledLine(sb, left, top, right, bottom, lineStyle, width);
  201. if (startCap != null && startCap.Style == CapStyle.Arrow)
  202. DrawArrow(sb, startCap, width, right, bottom, left, top);
  203. if (endCap != null && endCap.Style == CapStyle.Arrow)
  204. DrawArrow(sb, endCap, width, left, top, right, bottom);
  205. }
  206. }
  207. // this method is not used
  208. 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)
  209. {
  210. if (lineStyle == LineStyle.Solid)
  211. {
  212. if (borderColor.A != 0)
  213. GetPDFStrokeColor(borderColor, sb);
  214. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  215. sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  216. bool isFirst = true;
  217. foreach (PointF point in points)
  218. {
  219. if (isFirst)
  220. {
  221. isFirst = false;
  222. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m ");
  223. }
  224. else
  225. {
  226. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l ");
  227. }
  228. }
  229. sb.Remove(sb.Length - 1, 1);
  230. sb.AppendLine();
  231. if (isClosed)
  232. sb.AppendLine("s");
  233. else
  234. sb.AppendLine("S");
  235. }
  236. else
  237. {
  238. for (int i = 0; i < points.Length - 1; i++)
  239. DrawPDFLine(
  240. left + (points[i].X + centerX) * PDF_DIVIDER,
  241. top - (points[i].Y + centerY) * PDF_DIVIDER,
  242. left + (points[i + 1].X + centerX) * PDF_DIVIDER,
  243. top - (points[i + 1].Y + centerY) * PDF_DIVIDER,
  244. borderColor, borderWidth, lineStyle, null, null, sb);
  245. if (isClosed)
  246. 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);
  247. }
  248. }
  249. // this method is not used
  250. 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)
  251. {
  252. if (fillColor.A == 0)
  253. {
  254. DrawPDFPolyLine(left, top, right, bottom, centerX, centerY, points, true, borderColor, borderWidth, borderStyle, sb);
  255. }
  256. else
  257. {
  258. if (borderStyle == LineStyle.Solid)
  259. {
  260. GetPDFFillColor(fillColor, sb);
  261. if (borderColor.A != 0)
  262. GetPDFStrokeColor(borderColor, sb);
  263. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  264. sb.AppendLine(DrawPDFDash(borderStyle, borderWidth));
  265. bool isFirst = true;
  266. foreach (PointF point in points)
  267. {
  268. if (isFirst)
  269. {
  270. isFirst = false;
  271. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m ");
  272. }
  273. else
  274. {
  275. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l ");
  276. }
  277. }
  278. sb.Append(FloatToString(left + (points[0].X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (points[0].Y + centerY) * PDF_DIVIDER)).Append(" l");
  279. sb.AppendLine();
  280. sb.AppendLine("B");
  281. }
  282. else
  283. {
  284. GetPDFFillColor(fillColor, sb);
  285. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  286. sb.AppendLine(DrawPDFDash(borderStyle, borderWidth));
  287. bool isFirst = true;
  288. foreach (PointF point in points)
  289. {
  290. if (isFirst)
  291. {
  292. isFirst = false;
  293. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" m ");
  294. }
  295. else
  296. {
  297. sb.Append(FloatToString(left + (point.X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (point.Y + centerY) * PDF_DIVIDER)).Append(" l ");
  298. }
  299. }
  300. sb.Append(FloatToString(left + (points[0].X + centerX) * PDF_DIVIDER)).Append(" ").Append(FloatToString(top - (points[0].Y + centerY) * PDF_DIVIDER)).Append(" l");
  301. sb.AppendLine();
  302. sb.AppendLine("f");
  303. DrawPDFPolyLine(left, top, right, bottom, centerX, centerY, points, true, borderColor, borderWidth, borderStyle, sb);
  304. }
  305. }
  306. }
  307. private void DrawStyledLine(StringBuilder sb, float left, float top, float right, float bottom, LineStyle lineStyle, float width)
  308. {
  309. sb.Append(FloatToString(width)).AppendLine(" w").AppendLine("0 J");
  310. switch (lineStyle)
  311. {
  312. case LineStyle.Dash:
  313. DrawDashedLine(sb, left, top, right, bottom, width, "LS");
  314. break;
  315. case LineStyle.DashDot:
  316. DrawDashedLine(sb, left, top, right, bottom, width, "LSPS");
  317. break;
  318. case LineStyle.DashDotDot:
  319. DrawDashedLine(sb, left, top, right, bottom, width, "LSPSPS");
  320. break;
  321. case LineStyle.Dot:
  322. DrawDashedLine(sb, left, top, right, bottom, width, "PS");
  323. break;
  324. case LineStyle.Double:
  325. DrawLine(sb, left, top, right, bottom);
  326. break;
  327. case LineStyle.Custom:
  328. DrawLine(sb, left, top, right, bottom);
  329. break;
  330. default:
  331. DrawLine(sb, left, top, right, bottom);
  332. break;
  333. }
  334. }
  335. // <param name="pattern">L - line, S - space, P - point</param>
  336. private void DrawDashedLine(StringBuilder sb, float left, float top, float right, float bottom, float linewidth, string pattern)
  337. {
  338. float dash = linewidth * 3.0f;
  339. float dot = linewidth;
  340. int currentState = 0;
  341. bool horizLine = false;
  342. bool vertLine = false;
  343. float length = 0, alfa = 0;
  344. if (left == right) // vertical line
  345. {
  346. vertLine = true;
  347. if (bottom < top)
  348. {
  349. dash = -dash;
  350. dot = -dot;
  351. }
  352. length = bottom - top;
  353. }
  354. else if (top == bottom) // horiz line
  355. {
  356. horizLine = true;
  357. if (right < left)
  358. {
  359. dash = -dash;
  360. dot = -dot;
  361. }
  362. length = right - left;
  363. }
  364. else
  365. {
  366. // diag
  367. length = (float)Math.Sqrt(Math.Pow(right - left, 2) + Math.Pow(bottom - top, 2));
  368. alfa = (float)Math.Asin((right - left) / length);
  369. }
  370. float current = 0, currentX = 0, currentY = 0;
  371. float delta, deltaX = 0, deltaY = 0;
  372. bool penDown;
  373. while (Math.Abs(current) < Math.Abs(length))
  374. {
  375. char state = pattern[currentState++];
  376. if (currentState >= pattern.Length)
  377. currentState = 0;
  378. switch (state)
  379. {
  380. case 'L': // line
  381. delta = dash;
  382. penDown = true;
  383. break;
  384. case 'P': // point
  385. delta = dot;
  386. penDown = true;
  387. break;
  388. default: // space
  389. delta = dot;
  390. penDown = false;
  391. break;
  392. }
  393. current += delta;
  394. if (alfa != 0)
  395. {
  396. deltaX = (float)(delta * Math.Sin(alfa));
  397. deltaY = (float)(delta * Math.Cos(alfa)) * Math.Sign(bottom - top);
  398. currentX += deltaX;
  399. currentY += deltaY;
  400. }
  401. if (penDown)
  402. {
  403. if (Math.Abs(current) < Math.Abs(length))
  404. {
  405. if (vertLine)
  406. DrawLine(sb, left, top + current - delta, right, top + current);
  407. else if (horizLine)
  408. DrawLine(sb, left + current - delta, top, left + current, bottom);
  409. else
  410. DrawLine(sb, left + currentX - deltaX, top + currentY - deltaY, left + currentX, top + currentY);
  411. }
  412. else
  413. {
  414. if (vertLine)
  415. DrawLine(sb, left, top + current - delta, right, bottom);
  416. else if (horizLine)
  417. DrawLine(sb, left + current - delta, top, right, bottom);
  418. else
  419. DrawLine(sb, left + currentX - deltaX, top + currentY - deltaY, right, bottom);
  420. }
  421. }
  422. }
  423. }
  424. private void DrawLine(StringBuilder sb, float left, float top, float right, float bottom)
  425. {
  426. sb.Append(FloatToString(left)).Append(" ").
  427. Append(FloatToString(top)).AppendLine(" m").
  428. Append(FloatToString(right)).Append(" ").
  429. Append(FloatToString(bottom)).AppendLine(" l").
  430. AppendLine("S");
  431. }
  432. private void DrawArrow(StringBuilder sb, CapSettings Arrow, float lineWidth, float x1, float y1, float x2, float y2)
  433. {
  434. float k1, a, b, c, d;
  435. float xp, yp, x3, y3, x4, y4;
  436. float wd = Arrow.Width * lineWidth * PDF_DIVIDER;
  437. float ld = Arrow.Height * lineWidth * PDF_DIVIDER;
  438. if (Math.Abs(x2 - x1) > 0)
  439. {
  440. k1 = (y2 - y1) / (x2 - x1);
  441. a = (float)Math.Pow(k1, 2) + 1;
  442. b = 2 * (k1 * ((x2 * y1 - x1 * y2) / (x2 - x1) - y2) - x2);
  443. c = (float)Math.Pow(x2, 2) + (float)Math.Pow(y2, 2) - (float)Math.Pow(ld, 2) +
  444. (float)Math.Pow((x2 * y1 - x1 * y2) / (x2 - x1), 2) -
  445. 2 * y2 * (x2 * y1 - x1 * y2) / (x2 - x1);
  446. d = (float)Math.Pow(b, 2) - 4 * a * c;
  447. xp = (-b + (float)Math.Sqrt(d)) / (2 * a);
  448. if ((xp > x1) && (xp > x2) || (xp < x1) && (xp < x2))
  449. xp = (-b - (float)Math.Sqrt(d)) / (2 * a);
  450. yp = xp * k1 + (x2 * y1 - x1 * y2) / (x2 - x1);
  451. if (y2 != y1)
  452. {
  453. x3 = xp + wd * (float)Math.Sin(Math.Atan(k1));
  454. y3 = yp - wd * (float)Math.Cos(Math.Atan(k1));
  455. x4 = xp - wd * (float)Math.Sin(Math.Atan(k1));
  456. y4 = yp + wd * (float)Math.Cos(Math.Atan(k1));
  457. }
  458. else
  459. {
  460. x3 = xp; y3 = yp - wd;
  461. x4 = xp; y4 = yp + wd;
  462. }
  463. }
  464. else
  465. {
  466. xp = x2; yp = y2 - ld;
  467. if ((yp > y1) && (yp > y2) || (yp < y1) && (yp < y2))
  468. yp = y2 + ld;
  469. x3 = xp - wd; y3 = yp;
  470. x4 = xp + wd; y4 = yp;
  471. }
  472. sb.AppendLine("2 J").AppendLine("[] 0 d").Append(FloatToString(x3)).Append(" ").Append(FloatToString(y3)).AppendLine(" m").
  473. Append(FloatToString(x2)).Append(" ").Append(FloatToString(y2)).AppendLine(" l").
  474. Append(FloatToString(x4)).Append(" ").Append(FloatToString(y4)).AppendLine(" l").AppendLine("S");
  475. }
  476. private string DrawPDFDash(LineStyle lineStyle, float lineWidth, float[] dashesWidth = null)
  477. {
  478. if (lineStyle == LineStyle.Solid)
  479. return "[] 0 d";
  480. else
  481. {
  482. string dash = FloatToString(lineWidth * 3.0f) + " ";
  483. string dot = FloatToString(lineWidth) + " ";
  484. StringBuilder result = new StringBuilder(64);
  485. switch (lineStyle)
  486. {
  487. // the first element is a stroke, the second is a space
  488. // "space" changed from dash to dot.
  489. case LineStyle.Dash:
  490. //result.Append(dash);
  491. result.Append(dash).Append(dot);
  492. break;
  493. case LineStyle.DashDot:
  494. //result.Append(dash).Append(dash).Append(dot).Append(dash);
  495. result.Append(dash).Append(dot).Append(dot).Append(dot);
  496. break;
  497. case LineStyle.DashDotDot:
  498. //result.Append(dash).Append(dash).Append(dot).Append(dash).Append(dot).Append(dash);
  499. result.Append(dash).Append(dot).Append(dot).Append(dot).Append(dot).Append(dot);
  500. break;
  501. case LineStyle.Dot:
  502. //result.Append(dot).Append(dash);
  503. result.Append(dot).Append(dot);
  504. break;
  505. case LineStyle.Custom:
  506. if (dashesWidth == null)
  507. return "[] 0 d";
  508. foreach (var val in dashesWidth)
  509. // this value has been commented out because it distorts the appearance of dashes,
  510. // as if it is reduced to standard outlines
  511. result.Append(FloatToString(val * lineWidth/* * 0.3F*/) + " ");
  512. break;
  513. }
  514. return ExportUtils.StringFormat("[{0}] 0 d", result.ToString());
  515. }
  516. }
  517. private void DrawPDFBorder(Border Border, float left, float top, float width, float height, StringBuilder sb)
  518. {
  519. if (Border.Shadow)
  520. {
  521. DrawPDFFillRect(GetLeft(left + width),
  522. GetTop(top + Border.ShadowWidth),
  523. Border.ShadowWidth * PDF_DIVIDER,
  524. height * PDF_DIVIDER,
  525. new SolidFill(Border.ShadowColor), sb);
  526. DrawPDFFillRect(GetLeft(left + Border.ShadowWidth),
  527. GetTop(top + height),
  528. (width - Border.ShadowWidth) * PDF_DIVIDER,
  529. Border.ShadowWidth * PDF_DIVIDER,
  530. new SolidFill(Border.ShadowColor), sb);
  531. }
  532. if (Border.Lines != BorderLines.None)
  533. {
  534. if (Border.Lines == BorderLines.All &&
  535. Border.LeftLine.Equals(Border.RightLine) &&
  536. Border.TopLine.Equals(Border.BottomLine) &&
  537. Border.LeftLine.Equals(Border.TopLine))
  538. {
  539. if (Border.Width > 0 && Border.Color.A != 0)
  540. {
  541. DrawPDFRect(GetLeft(left), GetTop(top),
  542. GetLeft(left + width), GetTop(top + height),
  543. Border.Color, Border.Width * PDF_DIVIDER,
  544. Border.Style, sb);
  545. if (Border.LeftLine.Style == LineStyle.Double)
  546. DrawPDFRect(GetLeft(left + GAP_BETWEEN_LINES), GetTop(top + GAP_BETWEEN_LINES),
  547. GetLeft(left + width - GAP_BETWEEN_LINES), GetTop(top + height - GAP_BETWEEN_LINES),
  548. Border.Color, Border.Width * PDF_DIVIDER,
  549. Border.Style, sb);
  550. }
  551. }
  552. else
  553. {
  554. float Left = GetLeft(left);
  555. float Top = GetTop(top);
  556. float Right = GetLeft(left + width);
  557. float Bottom = GetTop(top + height);
  558. Top -= 0.1f;
  559. Bottom += 0.1f;
  560. if ((Border.Lines & BorderLines.Left) > 0)
  561. {
  562. DrawPDFLine(Left, Top, Left, Bottom, Border.LeftLine.Color,
  563. Border.LeftLine.Width * PDF_DIVIDER, Border.LeftLine.Style, null, null, sb);
  564. if (Border.LeftLine.Style == LineStyle.Double)
  565. DrawPDFLine(Left + GAP_BETWEEN_LINES, Top, Left + GAP_BETWEEN_LINES, Bottom, Border.LeftLine.Color,
  566. Border.LeftLine.Width * PDF_DIVIDER, Border.LeftLine.Style, null, null, sb);
  567. }
  568. if ((Border.Lines & BorderLines.Right) > 0)
  569. {
  570. DrawPDFLine(Right, Top, Right, Bottom, Border.RightLine.Color,
  571. Border.RightLine.Width * PDF_DIVIDER, Border.RightLine.Style, null, null, sb);
  572. if (Border.RightLine.Style == LineStyle.Double)
  573. DrawPDFLine(Right - GAP_BETWEEN_LINES, Top, Right - GAP_BETWEEN_LINES, Bottom, Border.RightLine.Color,
  574. Border.RightLine.Width * PDF_DIVIDER, Border.RightLine.Style, null, null, sb);
  575. }
  576. Top += 0.1f;
  577. Bottom -= 0.1f;
  578. Left += 0.1f;
  579. Right -= 0.1f;
  580. if ((Border.Lines & BorderLines.Top) > 0)
  581. {
  582. DrawPDFLine(Left, Top, Right, Top, Border.TopLine.Color,
  583. Border.TopLine.Width * PDF_DIVIDER, Border.TopLine.Style, null, null, sb);
  584. if (Border.TopLine.Style == LineStyle.Double)
  585. DrawPDFLine(Left, Top - GAP_BETWEEN_LINES, Right, Top - GAP_BETWEEN_LINES, Border.TopLine.Color,
  586. Border.TopLine.Width * PDF_DIVIDER, Border.TopLine.Style, null, null, sb);
  587. }
  588. if ((Border.Lines & BorderLines.Bottom) > 0)
  589. {
  590. DrawPDFLine(Left, Bottom, Right, Bottom, Border.BottomLine.Color,
  591. Border.BottomLine.Width * PDF_DIVIDER, Border.BottomLine.Style, null, null, sb);
  592. if (Border.BottomLine.Style == LineStyle.Double)
  593. DrawPDFLine(Left, Bottom + GAP_BETWEEN_LINES, Right, Bottom + GAP_BETWEEN_LINES, Border.BottomLine.Color,
  594. Border.BottomLine.Width * PDF_DIVIDER, Border.BottomLine.Style, null, null, sb);
  595. }
  596. }
  597. }
  598. }
  599. private void DrawPDFPolygonChar(GraphicsPath p, float x, float y, Color c, StringBuilder sb)
  600. {
  601. GraphicsPath clone = p.Clone() as GraphicsPath;
  602. FillPDFGraphicsPath(SizeF.Empty, clone, new SolidBrush(c), sb, curvesInterpolationText,
  603. new System.Drawing.Drawing2D.Matrix(PDF_DIVIDER, 0, 0, -PDF_DIVIDER, x, y));
  604. }
  605. private void DrawPDFPolygonCharOutline(GraphicsPath p, float x, float y, Color c, float borderWidth, StringBuilder sb)
  606. {
  607. if (p.PointCount == 0) return;
  608. GetPDFStrokeColor(c, sb);
  609. sb.Append(FloatToString(borderWidth * PDF_DIVIDER)).AppendLine(" w").AppendLine("1 J");
  610. //sb.AppendLine(DrawPDFDash(lineStyle, borderWidth));
  611. PointF[] ps = p.PathPoints;
  612. byte[] pt = p.PathTypes;
  613. for (int i = 0; i < p.PointCount;)
  614. {
  615. switch (pt[i])
  616. {
  617. case 0://start
  618. sb.AppendLine();
  619. sb.Append(FloatToString(x + ps[i].X * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - ps[i].Y * PDF_DIVIDER)).Append(" m ");
  620. i++;
  621. break;
  622. case 1://line
  623. sb.Append(FloatToString(x + ps[i].X * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - ps[i].Y * PDF_DIVIDER)).Append(" l ");
  624. i++;
  625. break;
  626. case 3://interpolate bezier
  627. for (float dt = 1; dt < 6; dt++)
  628. DrawPDFBezier(x, y, ps[i - 1], ps[i], ps[i + 1], ps[i + 2], dt / 5, sb);
  629. i += 3;
  630. break;
  631. default:
  632. i++;
  633. break;
  634. }
  635. //fill
  636. }
  637. sb.AppendLine();
  638. sb.AppendLine("S");
  639. }
  640. private void DrawPDFBezier(float x, float y, PointF p0, PointF p1, PointF p2, PointF p3, float t, StringBuilder sb)
  641. {
  642. float t1 = 1 - t;
  643. float px = t1 * t1 * t1 * p0.X + 3 * t1 * t1 * t * p1.X + 3 * t * t * t1 * p2.X + t * t * t * p3.X;
  644. float py = t1 * t1 * t1 * p0.Y + 3 * t1 * t1 * t * p1.Y + 3 * t * t * t1 * p2.Y + t * t * t * p3.Y;
  645. sb.Append(FloatToString(x + px * PDF_DIVIDER)).Append(" ").Append(FloatToString(y - py * PDF_DIVIDER)).Append(" l ");
  646. }
  647. }
  648. }