PDFEditorControl.xaml.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Windows;
  10. using System.Windows.Controls;
  11. using Ghostscript.NET;
  12. using Ghostscript.NET.Processor;
  13. using InABox.Clients;
  14. using InABox.Core;
  15. using InABox.WPF;
  16. using Microsoft.Win32;
  17. using Syncfusion.Pdf;
  18. using Syncfusion.Pdf.Graphics;
  19. using Syncfusion.Pdf.Interactive;
  20. using Syncfusion.Pdf.Parsing;
  21. using Syncfusion.Windows.PdfViewer;
  22. using ColorConverter = System.Windows.Media.ColorConverter;
  23. using Image = System.Windows.Controls.Image;
  24. namespace InABox.DynamicGrid
  25. {
  26. public delegate void PDFSettingsChangedEvent(object sender, string linecolor, int fontsize);
  27. public delegate void PDFDocumentLoadedEvent(object sender, IEntityDocument document);
  28. /// <summary>
  29. /// Interaction logic for PDFEditorControl.xaml
  30. /// </summary>
  31. public partial class PDFEditorControl : UserControl, IDocumentEditor
  32. {
  33. private IEntityDocument _document;
  34. //private PdfDocumentView PdfViewer = null;
  35. private readonly List<Guid> currentAnnotations = new();
  36. private byte[] pdfdocument;
  37. public PDFEditorControl()
  38. {
  39. InitializeComponent();
  40. SaveAllowed = false;
  41. ButtonsVisible = true;
  42. PdfViewer.ReferencePath =
  43. AppDomain.CurrentDomain.BaseDirectory; // System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "pdfium");
  44. PdfViewer.PrinterSettings.PageSize = PdfViewerPrintSize.Fit;
  45. }
  46. public string LineColor { get; set; }
  47. public int TextSize { get; set; }
  48. //public bool PrintAllowed { get; set; }
  49. public bool SaveAllowed { get; set; }
  50. public bool EditAllowed { get; set; } = true;
  51. public bool ButtonsVisible { get; set; }
  52. public string Watermark { get; set; }
  53. public PDFSettingsChangedEvent PDFSettingsChanged { get; set; }
  54. public PDFDocumentLoadedEvent PDFDocumentLoaded { get; set; }
  55. public IEntityDocument? Document
  56. {
  57. get => _document;
  58. set
  59. {
  60. UnloadPDF();
  61. _document = value;
  62. LoadPDF();
  63. PDFDocumentLoaded?.Invoke(this, value);
  64. }
  65. }
  66. #region Unload / Save PDF Document
  67. private void UnloadCurrentPDF()
  68. {
  69. UnloadPDFAnnotations();
  70. pdfdocument = null;
  71. }
  72. private string CurrentAnnotations = "";
  73. private string AnnotationsToString()
  74. {
  75. var ms1 = new MemoryStream();
  76. PdfViewer.LoadedDocument.Save(ms1);
  77. ms1.Position = 0;
  78. var doc = new PdfLoadedDocument(ms1);
  79. var sb = new StringBuilder();
  80. for (var i = 0; i < doc.Pages.Count; i++)
  81. {
  82. var page = doc.Pages[i] as PdfLoadedPage;
  83. try
  84. {
  85. foreach (PdfLoadedAnnotation a in page.Annotations)
  86. sb.Append(SaveAnnotation(doc, a));
  87. }
  88. catch (Exception e)
  89. {
  90. Logger.Send(LogType.Error, ClientFactory.UserID, string.Format("*** Unable to retreive Annotations ***\n{0}", e.StackTrace));
  91. }
  92. }
  93. return sb.ToString();
  94. }
  95. private void UnloadPDFAnnotations()
  96. {
  97. try
  98. {
  99. if (Document != null && PdfViewer.IsDocumentEdited)
  100. //if ((PdfViewer != null) && (documentid != Guid.Empty) && (pdfdocument != null) && (PdfViewer.Visibility == Visibility.Visible) && (PdfViewer.IsDocumentEdited))
  101. {
  102. var ms1 = new MemoryStream();
  103. PdfViewer.LoadedDocument.Save(ms1);
  104. ms1.Position = 0;
  105. var doc = new PdfLoadedDocument(ms1);
  106. //SetoutDocument document = documents.FirstOrDefault(x => x.DocumentLink.ID.Equals(documentid));
  107. if (Document != null)
  108. {
  109. var annotations = new Client<EntityDocumentAnnotation>()
  110. .Load(Filter<EntityDocumentAnnotation>.Where(x => x.EntityDocument).IsEqualTo(Document.ID)).ToList();
  111. for (var i = 0; i < doc.Pages.Count; i++)
  112. {
  113. var page = doc.Pages[i] as PdfLoadedPage;
  114. foreach (PdfLoadedAnnotation a in page.Annotations)
  115. {
  116. var atype = GetAnnotationType(a);
  117. if (atype == EntityDocumentAnnotationType.Popup)
  118. continue;
  119. var a_id = Guid.Empty;
  120. if (!string.IsNullOrWhiteSpace(a.Author))
  121. Guid.TryParse(a.Author, out a_id);
  122. if (currentAnnotations.Contains(a_id))
  123. currentAnnotations.Remove(a_id);
  124. var annotation = a_id.Equals(Guid.Empty) ? null : annotations.FirstOrDefault(x => x.ID.Equals(a_id));
  125. if (annotation == null)
  126. {
  127. annotation = new EntityDocumentAnnotation { EntityDocument = Document.ID };
  128. annotations.Add(annotation);
  129. }
  130. annotation.Page = i;
  131. annotation.Type = atype;
  132. annotation.Data = SaveAnnotation(doc, a);
  133. }
  134. }
  135. new Client<EntityDocumentAnnotation>().Save(annotations.Where(x => x.IsChanged()), "");
  136. var _deletes = annotations.Where(x =>
  137. currentAnnotations.Contains(x.ID) || x.Type == EntityDocumentAnnotationType.Popup)
  138. .ToArray();
  139. if (_deletes.Any())
  140. new Client<EntityDocumentAnnotation>().Delete(_deletes, "");
  141. }
  142. }
  143. }
  144. catch (Exception e)
  145. {
  146. MessageBox.Show("Unable to Save Annotations: " + e.Message + "\n" + e.StackTrace);
  147. }
  148. }
  149. public EntityDocumentAnnotationType GetAnnotationType(PdfAnnotation annotation)
  150. {
  151. if (annotation is PdfLoadedLineAnnotation)
  152. return EntityDocumentAnnotationType.Line;
  153. if (annotation is PdfLoadedEllipseAnnotation)
  154. return EntityDocumentAnnotationType.Ellipse;
  155. if (annotation is PdfLoadedRectangleAnnotation)
  156. return EntityDocumentAnnotationType.Rectangle;
  157. if (annotation is PdfLoadedSquareAnnotation)
  158. return EntityDocumentAnnotationType.Rectangle;
  159. if (annotation is PdfLoadedFreeTextAnnotation)
  160. return EntityDocumentAnnotationType.Text;
  161. if (annotation is PdfLoadedInkAnnotation)
  162. return EntityDocumentAnnotationType.Ink;
  163. if (annotation is PdfLoadedPopupAnnotation)
  164. return EntityDocumentAnnotationType.Popup;
  165. if (annotation is PdfLoadedRubberStampAnnotation)
  166. {
  167. if (!string.IsNullOrWhiteSpace(annotation.Subject))
  168. {
  169. if (annotation.Subject.Equals("Warning"))
  170. return EntityDocumentAnnotationType.WarningStamp;
  171. if (annotation.Subject.Equals("Error"))
  172. return EntityDocumentAnnotationType.ErrorStamp;
  173. }
  174. return EntityDocumentAnnotationType.OKStamp;
  175. }
  176. throw new Exception("Unknown Annotation: " + annotation.GetType().Name);
  177. }
  178. public string SaveAnnotation(PdfLoadedDocument doc, PdfLoadedAnnotation annotation)
  179. {
  180. annotation.Author = CoreUtils.FullGuid.ToString();
  181. var ms = new MemoryStream();
  182. var collection = new PdfExportAnnotationCollection();
  183. collection.Add(annotation);
  184. doc.ExportAnnotations(ms, AnnotationDataFormat.XFdf, collection);
  185. var result = Encoding.UTF8.GetString(ms.GetBuffer());
  186. return result;
  187. }
  188. public void LoadAnnotation(PdfLoadedDocument doc, string encoded, Guid id)
  189. {
  190. //PdfLoadedAnnotation annot = new PdfLoadedAnnotation();
  191. var data = encoded.Replace(CoreUtils.FullGuid.ToString(), id.ToString());
  192. var buffer = Encoding.UTF8.GetBytes(data);
  193. var ms = new MemoryStream(buffer);
  194. doc.ImportAnnotations(ms, AnnotationDataFormat.XFdf);
  195. }
  196. private void UnloadPDF()
  197. {
  198. if (Document != null)
  199. try
  200. {
  201. UnloadPDFAnnotations();
  202. PdfViewer.Unload(true);
  203. }
  204. catch (Exception e)
  205. {
  206. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  207. }
  208. }
  209. #endregion
  210. #region Reload / Preprocess PDF Document
  211. private bool DownloadNeeded(Guid id)
  212. {
  213. var cachefile = Path.Combine(CoreUtils.GetPath(), string.Format("{0}.ffd", id.ToString()));
  214. if (!File.Exists(cachefile))
  215. return true;
  216. var indexfile = Path.Combine(CoreUtils.GetPath(), "pdfindex.json");
  217. if (!File.Exists(indexfile))
  218. return true;
  219. var json = File.ReadAllText(indexfile);
  220. var index = Serialization.Deserialize<Dictionary<Guid, string>>(json);
  221. if (!index.ContainsKey(id))
  222. return true;
  223. var entry = new Client<Document>().Query(
  224. Filter<Document>.Where(x => x.ID).IsEqualTo(id),
  225. Columns.None<Document>().Add(x => x.CRC)
  226. ).Rows.FirstOrDefault();
  227. if (entry == null)
  228. return true;
  229. if (!String.Equals(entry.Get<Document, string>(x => x.CRC),index[id]))
  230. {
  231. Dispatcher.BeginInvoke(() =>
  232. {
  233. MessageBox.Show("This PDF has been revised, and will now refresh.\n\nPlease check the drawing for any applicable changes.");
  234. });
  235. return true;
  236. }
  237. return false;
  238. }
  239. private bool AnnotationError;
  240. private void LoadPDF()
  241. {
  242. if (Document == null)
  243. return;
  244. var cachefile = Path.Combine(CoreUtils.GetPath(), string.Format("{0}.ffd", Document.Document.ID.ToString()));
  245. using (new WaitCursor())
  246. {
  247. if (DownloadNeeded(Document.Document.ID))
  248. {
  249. CoreTable table = new Client<Document>().Query(Filter<Document>.Where(x => x.ID).IsEqualTo(Document.Document.ID));
  250. if (!table.Rows.Any())
  251. {
  252. MessageBox.Show("Unable to Load File!");
  253. return;
  254. }
  255. var dbdoc = table.Rows.FirstOrDefault().ToObject<Document>();
  256. var indexfile = Path.Combine(CoreUtils.GetPath(), "pdfindex.json");
  257. var index = new Dictionary<Guid, string>();
  258. if (File.Exists(indexfile))
  259. {
  260. var json = File.ReadAllText(indexfile);
  261. index = Serialization.Deserialize<Dictionary<Guid, string>>(json);
  262. }
  263. index[Document.Document.ID] = dbdoc.CRC;
  264. File.WriteAllText(indexfile, Serialization.Serialize(index));
  265. AnnotationError = false;
  266. pdfdocument = dbdoc.Data;
  267. try
  268. {
  269. pdfdocument = GhostScriptIt(pdfdocument);
  270. }
  271. catch (Exception eGhostscript)
  272. {
  273. Logger.Send(LogType.Information, "", "Ghostscript: " + eGhostscript.Message + "\n" + eGhostscript.StackTrace);
  274. }
  275. try
  276. {
  277. pdfdocument = FlattenPdf(pdfdocument);
  278. }
  279. catch (Exception eFlatten)
  280. {
  281. Logger.Send(LogType.Error, "", "Flatten Error: " + eFlatten.Message + "\n" + eFlatten.StackTrace);
  282. }
  283. try
  284. {
  285. if (AnnotationError)
  286. pdfdocument = RasterizePDF(pdfdocument);
  287. }
  288. catch (Exception eRasterize)
  289. {
  290. Logger.Send(LogType.Error, "", "Rasterize Error: " + eRasterize.Message + "\n" + eRasterize.StackTrace);
  291. }
  292. File.WriteAllBytes(cachefile, pdfdocument);
  293. }
  294. else
  295. {
  296. pdfdocument = File.ReadAllBytes(cachefile);
  297. }
  298. if (pdfdocument.Any())
  299. {
  300. var doc = new PdfLoadedDocument(pdfdocument);
  301. currentAnnotations.Clear();
  302. var watermark = !Document.Superceded.IsEmpty() ? "SUPERCEDED" : Watermark;
  303. if (!string.IsNullOrWhiteSpace(watermark))
  304. foreach (PdfPageBase page in doc.Pages)
  305. {
  306. var rect = new RectangleF(0, 0, page.Size.Width, page.Size.Height);
  307. var graphics = page.Graphics;
  308. PdfFont font = new PdfStandardFont(PdfFontFamily.Helvetica, page.Size.Width / 10,
  309. PdfFontStyle.Bold);
  310. var state = graphics.Save();
  311. graphics.SetTransparency(0.2f);
  312. var format = new PdfStringFormat();
  313. format.Alignment = PdfTextAlignment.Center;
  314. format.LineAlignment = PdfVerticalAlignment.Middle;
  315. var lineheight = (int)Math.Round(font.Height * 2.5);
  316. var lines = new List<string>();
  317. while (lines.Count * lineheight < page.Size.Height)
  318. lines.Add(watermark);
  319. graphics.DrawString(string.Join("\n\n", lines), font, PdfBrushes.Red, rect, format);
  320. }
  321. //foreach (PdfPageBase page in doc.Pages)
  322. //{
  323. // RectangleF rect = new RectangleF(0, 0, page.Size.Width, page.Size.Height);
  324. // PdfGraphics graphics = page.Graphics;
  325. // PdfFont font = new PdfStandardFont(PdfFontFamily.Helvetica, page.Size.Width / 10, PdfFontStyle.Bold);
  326. // PdfGraphicsState state = graphics.Save();
  327. // graphics.SetTransparency(0.2f);
  328. // PdfStringFormat format = new PdfStringFormat();
  329. // format.Alignment = PdfTextAlignment.Center;
  330. // format.LineAlignment = PdfVerticalAlignment.Middle;
  331. // int lineheight = (int)Math.Round(font.Height * 2.5);
  332. // List<String> lines = new List<string>();
  333. // while (lines.Count * lineheight < page.Size.Height)
  334. // lines.Add("SUPERCEDED");
  335. // graphics.DrawString(String.Join("\n\n", lines), font, PdfBrushes.Red, rect, format);
  336. //}
  337. var annotations = new Client<EntityDocumentAnnotation>()
  338. .Load(Filter<EntityDocumentAnnotation>.Where(x => x.EntityDocument).IsEqualTo(Document.ID))
  339. .ToList();
  340. foreach (var annotation in annotations)
  341. try
  342. {
  343. currentAnnotations.Add(annotation.ID);
  344. if (!string.IsNullOrWhiteSpace(annotation.Data))
  345. {
  346. if (annotation.Data.Contains("<freetext") && !annotation.Data.Contains("date=\""))
  347. {
  348. Logger.Send(LogType.Information, ClientFactory.UserID,
  349. string.Format("Annotation #{0} has no date - inserting now..", annotation.ID));
  350. annotation.Data = annotation.Data.Replace("<freetext",
  351. string.Format("<freetext date=\"D:{0:yyyyMMddHHmmss}+08\'00\'\"",
  352. DateTime.Now));
  353. //annotation.Data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n <annots>\r\n <freetext page=\"0\" rect=\"635.782,231.8206,812.7407,282.311\" rotation=\"0\" color=\"#FFFFFF\" title=\"ffffffff-ffff-ffff-ffff-ffffffffffff\" subject=\"Free Text\" date=\"D:20220715001146+08'00'\" name=\"800eae13-14f4-4db9-a60e-6d5d2d2adb55\" fringe=\"0,0,0,0\" border=\"0,0,1\" q=\"0\" IT=\"FreeTextCallout\" head=\"None\">\r\n <defaultappearance>0.2901961 0.5647059 0.8862745 rg </defaultappearance>\r\n <defaultstyle>font:Arial 8pt;style:Regular;color:#FF0000</defaultstyle>\r\n <contents-richtext><body xmlns=\"http://www.w3.org/1999/xhtml\"><p dir=\"ltr\">MC'd by BW\r\nTrolley H18\r\n8 July 2022\r\nNOTE: 3032 Doorleaf is also on Trolley H18</p></body></contents-richtext>\r\n <contents>MC'd by BW\r\nTrolley H18\r\n8 July 2022\r\nNOTE: 3032 Doorleaf is also on Trolley H18</contents>\r\n </freetext>\r\n </annots>\r\n <f href=\"\" />\r\n</xfdf>";
  354. //annotation.Data = "<?xml version =\"1.0\" encoding=\"utf-8\"?>\r\n<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\r\n <annots>\r\n <freetext page=\"0\" rect=\"768.7103,558.5799,898.9603,642.3299\" rotation=\"0\" color=\"#FFFFFF\" title=\"ffffffff-ffff-ffff-ffff-ffffffffffff\" subject=\"Free Text\" date=\"D:20220715001146+08'00'\" flags=\"print\" name=\"690a16b1-647b-45a9-80a5-17f83f63bc93\" fringe=\"18,2,20,16.5\" border=\"0,0,1.5\" justification=\"0\" IT=\"FreeTextCallout\" head=\"OpenArrow\" callout=\"786.7103,625.8299,768.7103,593.2049,786.7103,593.2049\">\r\n <defaultappearance>0.2901961 0.5647059 0.8862745 rg </defaultappearance>\r\n <defaultstyle>font:Arial 12pt;style:Regular;color:#FF0000</defaultstyle>\r\n <contents-richtext><body xmlns=\"http://www.w3.org/1999/xhtml\"><p dir=\"ltr\">Hi Thjere\r\n\r\nawd.flae\r\nsdfgljsdlkfg</p></body></contents-richtext>\r\n <contents>Hi Thjere\r\n\r\nawd.flae\r\nsdfgljsdlkfg</contents>\r\n </freetext>\r\n </annots>\r\n <f href=\"\" />\r\n</xfdf>";
  355. }
  356. LoadAnnotation(doc, annotation.Data.Replace("&", "+"), annotation.ID);
  357. }
  358. }
  359. catch (Exception e)
  360. {
  361. Logger.Send(LogType.Error, "",
  362. string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  363. }
  364. var ms = new MemoryStream();
  365. doc.Save(ms);
  366. PdfViewer.ZoomMode = ZoomMode.FitWidth;
  367. PdfViewer.Load(ms);
  368. CurrentAnnotations = AnnotationsToString();
  369. }
  370. UpdateButtons(PdfNoneImage);
  371. }
  372. }
  373. private byte[] GhostScriptIt(byte[] data)
  374. {
  375. var input = Path.GetTempFileName();
  376. File.WriteAllBytes(input, data);
  377. byte[] result = { };
  378. var gv = new GhostscriptVersionInfo(
  379. new Version(0, 0, 0),
  380. "gsdll64.dll",
  381. "",
  382. GhostscriptLicense.GPL
  383. );
  384. var gsPipedOutput = new GhostscriptPipedOutput();
  385. // pipe handle format: %handle%hexvalue
  386. var outputPipeHandle = "%handle%" + int.Parse(gsPipedOutput.ClientHandle).ToString("X2");
  387. using (var processor = new GhostscriptProcessor(gv, true))
  388. {
  389. var switches = new List<string>();
  390. switches.Add("-empty");
  391. switches.Add("-dQUIET");
  392. switches.Add("-dSAFER");
  393. switches.Add("-dBATCH");
  394. switches.Add("-dNOPAUSE");
  395. switches.Add("-dNOPROMPT");
  396. switches.Add("-dCompatibilityLevel=1.4");
  397. switches.Add("-dPreserveAnnots=false");
  398. switches.Add("-sDEVICE=pdfwrite");
  399. switches.Add("-o" + outputPipeHandle);
  400. switches.Add("-q");
  401. switches.Add("-f");
  402. switches.Add(input);
  403. try
  404. {
  405. processor.StartProcessing(switches.ToArray(), null);
  406. result = gsPipedOutput.Data;
  407. }
  408. catch (Exception ex)
  409. {
  410. Console.WriteLine(ex.Message);
  411. }
  412. finally
  413. {
  414. gsPipedOutput.Dispose();
  415. gsPipedOutput = null;
  416. }
  417. }
  418. File.Delete(input);
  419. return result;
  420. }
  421. private byte[] RasterizePDF(byte[] data)
  422. {
  423. var source = PresentationSource.FromVisual(this);
  424. var dpiX = source != null ? 96.0 * source.CompositionTarget.TransformToDevice.M11 : 0.0F;
  425. var dpiY = source != null ? 96.0 * source.CompositionTarget.TransformToDevice.M22 : 0.0F;
  426. var gsdata = GhostScriptIt(data);
  427. var doc = new PdfLoadedDocument(gsdata);
  428. Bitmap[] bitmaps = doc.ExportAsImage(0, doc.Pages.Count - 1, (float)dpiX, (float)dpiY);
  429. PdfSection section = null;
  430. var pdf = new PdfDocument();
  431. pdf.PageSettings.Margins.All = 0;
  432. for (var i = 0; i < doc.Pages.Count; i++)
  433. {
  434. var oldpage = doc.Pages[i] as PdfLoadedPage;
  435. if (section == null || section.PageSettings.Size.Height != oldpage.Size.Height ||
  436. section.PageSettings.Size.Width != oldpage.Size.Width)
  437. {
  438. section = pdf.Sections.Add();
  439. section.PageSettings.Size = oldpage.Size;
  440. section.PageSettings.Orientation =
  441. oldpage.Size.Height > oldpage.Size.Width ? PdfPageOrientation.Portrait : PdfPageOrientation.Landscape;
  442. }
  443. var newpage = section.Pages.Add();
  444. var graphics = newpage.Graphics;
  445. var bitmap = new PdfBitmap(bitmaps[i]);
  446. graphics.DrawImage(bitmap, new RectangleF(0, 0, section.PageSettings.Size.Width, section.PageSettings.Size.Height));
  447. }
  448. var ms = new MemoryStream();
  449. pdf.Save(ms);
  450. return ms.GetBuffer();
  451. }
  452. private byte[] FlattenPdf(byte[] data)
  453. {
  454. var doc = new PdfLoadedDocument(data);
  455. foreach (PdfLoadedPage page in doc.Pages)
  456. try
  457. {
  458. foreach (PdfLoadedAnnotation annotation in page.Annotations) annotation.Flatten = true;
  459. }
  460. catch (Exception e)
  461. {
  462. AnnotationError = true;
  463. Logger.Send(LogType.Error, ClientFactory.UserID, string.Format("*** Unable to Flatten PDF ***\n{0}", e.Message));
  464. }
  465. var ms = new MemoryStream();
  466. doc.Save(ms);
  467. //doc.Save(filename);
  468. //return File.ReadAllBytes(filename);
  469. return ms.GetBuffer();
  470. }
  471. private void RefreshPDF_Click(object sender, RoutedEventArgs e)
  472. {
  473. UnloadPDF();
  474. var cachefile = Path.Combine(CoreUtils.GetPath(), string.Format("{0}.ffd", Document.Document.ID.ToString()));
  475. if (File.Exists(cachefile))
  476. File.Delete(cachefile);
  477. LoadPDF();
  478. }
  479. #endregion
  480. #region PDF Editing
  481. private Bitmap SizeBitmap()
  482. {
  483. var b = new Bitmap(32, 32);
  484. using (var g = Graphics.FromImage(b))
  485. {
  486. g.SmoothingMode = SmoothingMode.AntiAlias;
  487. g.FillRectangle(new SolidBrush(Color.White), 0, 0, 32, 32);
  488. var text = TextSize.ToString();
  489. var font = new Font("Arial", 12, System.Drawing.FontStyle.Bold);
  490. var size = g.MeasureString(text, font);
  491. var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
  492. g.DrawString(text, font, new SolidBrush(Color.DimGray), new RectangleF(4, 6, 24, 20), sf);
  493. var pen = new Pen(Color.DimGray, 2);
  494. g.DrawRectangle(pen, 4, 4, 24, 24);
  495. }
  496. return b;
  497. }
  498. private Bitmap ColorBitmap()
  499. {
  500. var b = new Bitmap(32, 32);
  501. using (var g = Graphics.FromImage(b))
  502. {
  503. g.SmoothingMode = SmoothingMode.AntiAlias;
  504. g.FillRectangle(new SolidBrush(Color.White), 0, 0, 32, 32);
  505. var color = ColorTranslator.FromHtml(LineColor);
  506. var brush = new SolidBrush(color);
  507. g.FillRectangle(brush, 4, 4, 24, 24);
  508. var pen = new Pen(Color.Black, 1);
  509. g.DrawRectangle(pen, 4, 4, 24, 24);
  510. }
  511. return b;
  512. }
  513. private void UpdateButtons(Image selected)
  514. {
  515. PDFButtonStack.Width = Document != null && Document.Superceded.IsEmpty() && ButtonsVisible
  516. ? new GridLength(44, GridUnitType.Pixel)
  517. : new GridLength(0, GridUnitType.Pixel);
  518. PdfColorImage.Source = ColorBitmap().AsBitmapImage(32, 32, false);
  519. PdfSizeImage.Source = SizeBitmap().AsBitmapImage(32, 32, false);
  520. PdfPrint.Visibility = Visibility.Collapsed; //PrintAllowed ? Visibility.Visible : Visibility.Collapsed;
  521. PdfSave.Visibility = SaveAllowed ? Visibility.Visible : Visibility.Collapsed;
  522. PdfColor.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  523. PdfSize.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  524. PdfNone.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  525. PdfInk.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  526. PdfLine.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  527. PdfRectangle.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  528. PdfCircle.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  529. PdfFreeText.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  530. PDFOKStamp.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  531. PDFWarningStamp.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  532. PDFErrorStamp.Visibility = EditAllowed ? Visibility.Visible : Visibility.Collapsed;
  533. ColorButton(PdfNoneImage, selected,Wpf.Resources.hand);
  534. ColorButton(PdfInkImage, selected,Wpf.Resources.draw);
  535. ColorButton(PdfLineImage, selected,Wpf.Resources.line);
  536. ColorButton(PdfRectangleImage, selected,Wpf.Resources.square);
  537. ColorButton(PdfCircleImage, selected,Wpf.Resources.circle);
  538. ColorButton(PdfFreeTextImage, selected,Wpf.Resources.text);
  539. ColorButton(PdfOKImage, selected,Wpf.Resources.tick);
  540. ColorButton(PdfWarningImage, selected,Wpf.Resources.warning);
  541. ColorButton(PdfErrorImage, selected,Wpf.Resources.delete);
  542. }
  543. private void ColorButton(Image button, Image selected, Bitmap bitmap)
  544. {
  545. button.Source = selected == button
  546. ? bitmap.ChangeColor(Color.White, Color.Yellow).AsBitmapImage(32, 32, false)
  547. : bitmap.AsBitmapImage(32, 32, false);
  548. }
  549. private void PdfPrint_Click(object sender, RoutedEventArgs e)
  550. {
  551. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  552. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  553. UpdateButtons(PdfNoneImage);
  554. PdfViewer.PrinterSettings.ShowPrintStatusDialog = true;
  555. PdfViewer.PrinterSettings.PageSize = PdfViewerPrintSize.Fit;
  556. //String printer = "";
  557. //if (PrinterSelection.Execute(ref printer))
  558. // PdfViewer.Print(printer);
  559. //PdfViewer.PrintCommand.Execute(PdfViewer);
  560. PrintDialog dialog = new PrintDialog();
  561. if (dialog.ShowDialog() == true)
  562. dialog.PrintDocument(PdfViewer.PrintDocument.DocumentPaginator, "PRS Factory Floor Printout");
  563. //var ms = new MemoryStream();
  564. //PdfViewer.LoadedDocument.Save(ms);
  565. //PdfViewer.Print();
  566. //byte[] data = ms.GetBuffer();
  567. //data = FlattenPdf(data);
  568. //String filename = System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), "pdf");
  569. //File.WriteAllBytes(filename, data);
  570. ////PdfViewer.Save(filename);
  571. //PDFPreview preview = new PDFPreview(filename);
  572. //preview.ShowDialog();
  573. }
  574. private void PdfSave_Click(object sender, RoutedEventArgs e)
  575. {
  576. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  577. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  578. UpdateButtons(PdfNoneImage);
  579. var dlg = new SaveFileDialog();
  580. dlg.Filter = "PDF Files (*.pdf)|*.pdf";
  581. dlg.FileName = Path.ChangeExtension(Document.Document.FileName, ".pdf");
  582. if (dlg.ShowDialog() == true)
  583. {
  584. var ms = new MemoryStream();
  585. PdfViewer.LoadedDocument.Save(ms);
  586. var data = ms.GetBuffer();
  587. data = FlattenPdf(data);
  588. var filename = dlg.FileName;
  589. File.WriteAllBytes(filename, data);
  590. var gsProcessInfo = new ProcessStartInfo();
  591. gsProcessInfo.Verb = "open";
  592. gsProcessInfo.WindowStyle = ProcessWindowStyle.Normal;
  593. gsProcessInfo.FileName = filename;
  594. gsProcessInfo.UseShellExecute = true;
  595. Process.Start(gsProcessInfo);
  596. }
  597. }
  598. private void PdfZoomIn_Click(object sender, RoutedEventArgs e)
  599. {
  600. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  601. ;
  602. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  603. UpdateButtons(PdfNoneImage);
  604. PdfViewer.IncreaseZoomCommand.Execute(null);
  605. }
  606. private void PdfZoomWidth_Click(object sender, RoutedEventArgs e)
  607. {
  608. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  609. ;
  610. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  611. UpdateButtons(PdfNoneImage);
  612. PdfViewer.ZoomMode = ZoomMode.FitWidth;
  613. }
  614. private void PdfZoomPage_Click(object sender, RoutedEventArgs e)
  615. {
  616. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  617. ;
  618. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  619. UpdateButtons(PdfNoneImage);
  620. PdfViewer.ZoomMode = ZoomMode.FitPage;
  621. }
  622. private void PdfZoomOut_Click(object sender, RoutedEventArgs e)
  623. {
  624. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  625. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  626. UpdateButtons(PdfNoneImage);
  627. PdfViewer.DecreaseZoomCommand.Execute(null);
  628. }
  629. private void PdfColor_Click(object sender, RoutedEventArgs e)
  630. {
  631. var color = ColorTranslator.FromHtml(LineColor);
  632. if (ColorEdit.Execute("Edit Color", ref color))
  633. {
  634. LineColor = ColorTranslator.ToHtml(color);
  635. PdfColorImage.Source = ColorBitmap().AsBitmapImage(false);
  636. PDFSettingsChanged?.Invoke(this, LineColor, TextSize);
  637. }
  638. }
  639. private void PdfSize_Click(object sender, RoutedEventArgs e)
  640. {
  641. var size = TextSize;
  642. if (NumberEdit.Execute("Edit Font Size", 4, 96, ref size))
  643. {
  644. TextSize = size;
  645. PdfSizeImage.Source = SizeBitmap().AsBitmapImage(false);
  646. }
  647. }
  648. private void PdfNone_Click(object sender, RoutedEventArgs e)
  649. {
  650. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  651. PdfViewer.CursorMode = PdfViewerCursorMode.HandTool;
  652. UpdateButtons(PdfNoneImage);
  653. }
  654. private void PdfInk_Click(object sender, RoutedEventArgs e)
  655. {
  656. PdfViewer.InkAnnotationSettings.InkColor = (System.Windows.Media.Color)ColorConverter.ConvertFromString(LineColor);
  657. PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  658. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.Ink;
  659. UpdateButtons(PdfInkImage);
  660. }
  661. private void PdfLine_Click(object sender, RoutedEventArgs e)
  662. {
  663. if(LineColor is null)
  664. {
  665. return;
  666. }
  667. PdfViewer.LineAnnotationSettings.LineColor = (System.Windows.Media.Color)ColorConverter.ConvertFromString(LineColor);
  668. PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  669. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.Line;
  670. UpdateButtons(PdfLineImage);
  671. }
  672. private void PdfRectangle_Click(object sender, RoutedEventArgs e)
  673. {
  674. PdfViewer.RectangleAnnotationSettings.RectangleColor = (System.Windows.Media.Color)ColorConverter.ConvertFromString(LineColor);
  675. PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  676. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.Rectangle;
  677. UpdateButtons(PdfRectangleImage);
  678. }
  679. private void PdfCircle_Click(object sender, RoutedEventArgs e)
  680. {
  681. PdfViewer.CircleAnnotationSettings.CircleColor = (System.Windows.Media.Color)ColorConverter.ConvertFromString(LineColor);
  682. PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  683. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.Circle;
  684. UpdateButtons(PdfCircleImage);
  685. }
  686. private void PdfFreeText_Click(object sender, RoutedEventArgs e)
  687. {
  688. PdfViewer.FreeTextAnnotationSettings.FontSize = TextSize;
  689. PdfViewer.FreeTextAnnotationSettings.FontColor = (System.Windows.Media.Color)ColorConverter.ConvertFromString(LineColor);
  690. PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  691. PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.FreeText;
  692. UpdateButtons(PdfFreeTextImage);
  693. }
  694. private void PdfOKStamp_Click(object sender, RoutedEventArgs e)
  695. {
  696. //PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  697. //PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  698. //AnnotationType = EntityDocumentAnnotationType.OKStamp;
  699. //UpdateButtons(PdfOKImage);
  700. }
  701. private void PdfWarningStamp_Click(object sender, RoutedEventArgs e)
  702. {
  703. //PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  704. //PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  705. //AnnotationType = EntityDocumentAnnotationType.WarningStamp;
  706. //UpdateButtons(PdfWarningImage);
  707. }
  708. private void PdfErrorStamp_Click(object sender, RoutedEventArgs e)
  709. {
  710. //PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  711. //PdfViewer.AnnotationMode = PdfDocumentView.PdfViewerAnnotationMode.None;
  712. //PdfViewer.CursorMode = PdfViewerCursorMode.SelectTool;
  713. //AnnotationType = EntityDocumentAnnotationType.ErrorStamp;
  714. //UpdateButtons(PdfErrorImage);
  715. }
  716. private EntityDocumentAnnotationType AnnotationType = EntityDocumentAnnotationType.OKStamp;
  717. #endregion
  718. private void PDFBorder_SizeChanged(object sender, SizeChangedEventArgs e)
  719. {
  720. PdfViewer.Width = PDFBorder.ActualWidth;
  721. PdfViewer.Height = PDFBorder.ActualHeight;
  722. }
  723. }
  724. }