PDFEditorControl.xaml.cs 34 KB

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