DataEntryList.xaml.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using Syncfusion.Pdf.Graphics;
  5. using Syncfusion.Pdf.Parsing;
  6. using Syncfusion.Pdf;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Drawing.Imaging;
  10. using System.Drawing;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Threading.Tasks;
  15. using System.Windows;
  16. using System.Windows.Media;
  17. using System.Windows.Media.Imaging;
  18. using InABox.DynamicGrid;
  19. using InABox.WPF;
  20. using InABox.Wpf;
  21. using Encoder = System.Drawing.Imaging.Encoder;
  22. using Path = System.IO.Path;
  23. using Image = System.Windows.Controls.Image;
  24. using System.ComponentModel;
  25. using System.Windows.Controls;
  26. using Clipboard = System.Windows.Clipboard;
  27. using DataFormats = System.Windows.DataFormats;
  28. using DragDropEffects = System.Windows.DragDropEffects;
  29. using DragEventArgs = System.Windows.DragEventArgs;
  30. using MessageBox = System.Windows.MessageBox;
  31. using UserControl = System.Windows.Controls.UserControl;
  32. using InABox.Wpf;
  33. using System.Collections.ObjectModel;
  34. using System.Windows.Data;
  35. using PRSDesktop.Panels.DataEntry;
  36. using InABox.Wpf.Editors;
  37. using System.Timers;
  38. using Microsoft.Win32;
  39. using javax.xml.crypto;
  40. namespace PRSDesktop;
  41. public static class PDFExtensions
  42. {
  43. public static IEnumerable<PdfPageBase> GetPages(this PdfDocumentBase doc)
  44. {
  45. if (doc is PdfLoadedDocument lDoc)
  46. return lDoc.Pages.Cast<PdfPageBase>();
  47. if (doc is PdfDocument pdfDoc)
  48. return pdfDoc.Pages.Cast<PdfPageBase>();
  49. throw new Exception($"Unsupported PDF Document type {doc.GetType()}");
  50. }
  51. public static PdfPageBase GetPage(this PdfDocumentBase doc, int index)
  52. {
  53. if (doc is PdfLoadedDocument lDoc)
  54. return lDoc.Pages[index];
  55. if (doc is PdfDocument pdfDoc)
  56. return pdfDoc.Pages[index];
  57. throw new Exception($"Unsupported PDF Document type {doc.GetType()}");
  58. }
  59. public static int PageCount(this PdfDocumentBase doc)
  60. {
  61. if (doc is PdfLoadedDocument lDoc)
  62. return lDoc.Pages.Count;
  63. if (doc is PdfDocument pdfDoc)
  64. return pdfDoc.Pages.Count;
  65. throw new Exception($"Unsupported PDF Document type {doc.GetType()}");
  66. }
  67. public static PdfLoadedDocument AsLoadedDocument(this PdfDocumentBase doc)
  68. {
  69. if (doc is PdfLoadedDocument lDoc)
  70. return lDoc;
  71. if (doc is PdfDocument pdfDoc)
  72. {
  73. using var ms = new MemoryStream();
  74. pdfDoc.Save(ms);
  75. var array = ms.ToArray();
  76. return new PdfLoadedDocument(array);
  77. }
  78. throw new Exception($"Unsupported PDF Document type {doc.GetType()}");
  79. }
  80. public static byte[] SaveToBytes(this PdfDocumentBase doc)
  81. {
  82. using var ms = new MemoryStream();
  83. doc.Save(ms);
  84. return ms.ToArray();
  85. }
  86. }
  87. /// <summary>
  88. /// Interaction logic for ScanPanel.xaml
  89. /// </summary>
  90. public partial class DataEntryList : UserControl, ICorePanel, IDockPanel
  91. {
  92. private List<DataEntryDocument> SelectedScans = new();
  93. public delegate void DateEntrySelectionHandler(String appliesTo, Guid entityID, bool allowprocess);
  94. public event DateEntrySelectionHandler? SelectionChanged;
  95. private readonly object _viewListLock = new object();
  96. private class ViewDocument
  97. {
  98. public ImageSource Image { get; set; }
  99. public DataEntryDocument Document { get; set; }
  100. public int PageNumber { get; set; }
  101. public ViewDocument(ImageSource image, DataEntryDocument document, int page)
  102. {
  103. Image = image;
  104. Document = document;
  105. PageNumber = page;
  106. }
  107. }
  108. private List<ViewDocument> ViewDocuments { get; } = new();
  109. public ObservableCollection<ImageSource> ViewList { get; init; } = new();
  110. private List<DataEntryDocumentWindow> OpenWindows = new();
  111. public DataEntryList()
  112. {
  113. BindingOperations.EnableCollectionSynchronization(ViewList, _viewListLock);
  114. InitializeComponent();
  115. }
  116. #region Panel
  117. public void Setup()
  118. {
  119. _dataEntryGrid.HiddenColumns.Add(x => x.Document.ID);
  120. _dataEntryGrid.Refresh(true, false);
  121. _historyGrid.Refresh(true, false);
  122. }
  123. public void Refresh()
  124. {
  125. if (_pages.SelectedIndex == 0)
  126. _dataEntryGrid.Refresh(false, true);
  127. else if (_pages.SelectedIndex == 1)
  128. _historyGrid.Refresh(false,true);
  129. }
  130. public void Shutdown(CancelEventArgs? cancel)
  131. {
  132. CloseImageWindows();
  133. }
  134. #endregion
  135. #region View List
  136. private static List<byte[]> RenderTextFile(string textData)
  137. {
  138. var pdfDocument = new PdfDocument();
  139. var page = pdfDocument.Pages.Add();
  140. var font = new PdfStandardFont(PdfFontFamily.Courier, 14);
  141. var textElement = new PdfTextElement(textData, font);
  142. var layoutFormat = new PdfLayoutFormat
  143. {
  144. Layout = PdfLayoutType.Paginate,
  145. Break = PdfLayoutBreakType.FitPage
  146. };
  147. textElement.Draw(page, new RectangleF(0, 0, page.GetClientSize().Width, page.GetClientSize().Height), layoutFormat);
  148. using var docStream = new MemoryStream();
  149. pdfDocument.Save(docStream);
  150. var loadeddoc = new PdfLoadedDocument(docStream.ToArray());
  151. Bitmap[] bmpImages = loadeddoc.ExportAsImage(0, loadeddoc.Pages.Count - 1);
  152. var jpgEncoder = ImageUtils.GetEncoder(ImageFormat.Jpeg)!;
  153. var quality = Encoder.Quality;
  154. var encodeParams = new EncoderParameters(1);
  155. encodeParams.Param[0] = new EncoderParameter(quality, 100L);
  156. var images = new List<byte[]>();
  157. if (bmpImages != null)
  158. foreach (var image in bmpImages)
  159. {
  160. using var data = new MemoryStream();
  161. image.Save(data, jpgEncoder, encodeParams);
  162. images.Add(data.ToArray());
  163. }
  164. return images;
  165. }
  166. private void UpdateViewList(bool force = false)
  167. {
  168. var selected = _dataEntryGrid.SelectedRows.Select(x => x.ToObject<DataEntryDocument>()).ToList();
  169. if (!force && selected.Count == SelectedScans.Count && !selected.Any(x => SelectedScans.All(y => x.ID != y.ID)))
  170. return;
  171. SelectedScans = selected;
  172. ViewList.Clear();
  173. ViewDocuments.Clear();
  174. Task.Run(() =>
  175. {
  176. var docs = DataEntryCache.Cache.LoadDocuments(SelectedScans.Select(x => x.Document.ID).Distinct(), checkTimestamp: true);
  177. LoadDocuments(docs);
  178. }).ContinueWith((task) =>
  179. {
  180. if(task.Exception is not null)
  181. {
  182. MessageWindow.ShowError("An error occurred while loading the documents", task.Exception);
  183. }
  184. }, TaskScheduler.FromCurrentSynchronizationContext());
  185. }
  186. private void LoadDocuments(IEnumerable<Document> documents)
  187. {
  188. var bitmaps = new Dictionary<Guid, List<ImageSource>>();
  189. foreach (var document in documents.Where(x=>x.Data?.Any() == true))
  190. {
  191. List<byte[]> images;
  192. var bitmapImages = new List<ImageSource>();
  193. var extension = Path.GetExtension(document.FileName).ToLower();
  194. if (extension == ".pdf")
  195. {
  196. images = new List<byte[]>();
  197. try
  198. {
  199. bitmapImages = ImageUtils.RenderPDFToImageSources(document.Data);
  200. }
  201. catch (Exception e)
  202. {
  203. MessageBox.Show($"Cannot load document '{document.FileName}': {e.Message}");
  204. }
  205. }
  206. else if (extension == ".jpg" || extension == ".jpeg" || extension == ".png" || extension == ".bmp")
  207. {
  208. images = new List<byte[]> { document.Data };
  209. }
  210. else
  211. {
  212. images = ImageUtils.RenderTextFileToImages(Encoding.UTF8.GetString(document.Data));
  213. }
  214. bitmapImages.AddRange(images.Select(x =>
  215. {
  216. try
  217. {
  218. return ImageUtils.LoadImage(x);
  219. }
  220. catch (Exception e)
  221. {
  222. Dispatcher.BeginInvoke(() =>
  223. {
  224. MessageWindow.ShowError($"Cannot load document '{document.FileName}", e);
  225. });
  226. }
  227. return null;
  228. }).Where(x => x != null).Cast<ImageSource>());
  229. foreach (var image in bitmapImages)
  230. {
  231. if (!bitmaps.TryGetValue(document.ID, out var list))
  232. {
  233. list = new List<ImageSource>();
  234. bitmaps[document.ID] = list;
  235. }
  236. list.Add(image);
  237. }
  238. }
  239. ViewDocuments.Clear();
  240. var maxWidth = 0.0;
  241. foreach (var scan in SelectedScans)
  242. {
  243. if (bitmaps.TryGetValue(scan.Document.ID, out var list))
  244. {
  245. int page = 1;
  246. foreach (var bitmap in list)
  247. {
  248. maxWidth = Math.Max(maxWidth, bitmap.Width);
  249. ViewDocuments.Add(new(bitmap, scan, page));
  250. page++;
  251. }
  252. }
  253. }
  254. lock (_viewListLock)
  255. {
  256. ViewList.Clear();
  257. foreach(var doc in ViewDocuments)
  258. {
  259. ViewList.Add(doc.Image);
  260. }
  261. if(maxWidth != 0.0)
  262. {
  263. ZoomPanel.Scale = ZoomPanel.ActualWidth / (maxWidth * 1.1);
  264. ZoomPanel.MinScale = ZoomPanel.Scale / 2;
  265. }
  266. }
  267. }
  268. #endregion
  269. #region Uploading
  270. private static byte[] RenderData(ref string filename, byte[] data)
  271. {
  272. var extension = Path.GetExtension(filename).ToLower();
  273. if ((extension == ".jpg" || extension == ".jpeg" || extension == ".png" || extension == ".bmp") && ImageUtils.TryGetImageType(data, out var format))
  274. {
  275. return data;
  276. }
  277. else if (extension == ".pdf")
  278. {
  279. return data;
  280. }
  281. else
  282. {
  283. using var stream = new MemoryStream(data);
  284. filename = Path.ChangeExtension(filename, "pdf");
  285. return DataEntryReGroupWindow.RenderToPDF(filename, stream).SaveToBytes();
  286. }
  287. throw new Exception("Could not render file to PDF");
  288. }
  289. private void DynamicTabItem_Drop(object sender, DragEventArgs e)
  290. {
  291. Task.Run(() =>
  292. {
  293. Dispatcher.Invoke(() =>
  294. {
  295. Progress.Show("Uploading documents");
  296. try
  297. {
  298. var result = DocumentUtils.HandleFileDrop(e);
  299. if (result is not null)
  300. {
  301. foreach (var (filename, stream) in result)
  302. {
  303. var newFilename = filename;
  304. byte[] data;
  305. if (stream is null)
  306. {
  307. data = File.ReadAllBytes(newFilename);
  308. }
  309. else
  310. {
  311. using var memStream = new MemoryStream();
  312. stream.CopyTo(memStream);
  313. data = memStream.ToArray();
  314. }
  315. data = RenderData(ref newFilename, data);
  316. _dataEntryGrid.UploadDocument(newFilename, data, Guid.Empty);
  317. }
  318. }
  319. Progress.Close();
  320. }
  321. catch (Exception e)
  322. {
  323. Progress.Close();
  324. MessageWindow.ShowError("Could not upload documents.", e);
  325. }
  326. });
  327. });
  328. }
  329. private void DynamicTabItem_DragOver(object sender, DragEventArgs e)
  330. {
  331. if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent("FileGroupDescriptor"))
  332. {
  333. e.Effects = DragDropEffects.Copy;
  334. }
  335. else
  336. {
  337. e.Effects = DragDropEffects.None;
  338. }
  339. e.Handled = true;
  340. }
  341. #endregion
  342. private void _documents_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
  343. {
  344. UpdateViewList(false);
  345. DoSelect(e.Rows);
  346. }
  347. private void DoSelect(CoreRow[]? rows)
  348. {
  349. var appliesTo = rows?.Length == 1
  350. ? rows[0].Get<DataEntryDocument, string>(x => x.Tag.AppliesTo)
  351. : "";
  352. var entityid = rows?.Length == 1
  353. ? rows[0].Get<DataEntryDocument, Guid>(x => x.EntityID)
  354. : Guid.Empty;
  355. var archived = rows?.Length == 1
  356. ? rows[0].Get<DataEntryDocument, DateTime>(x => x.Archived)
  357. : DateTime.MinValue;
  358. SelectionChanged?.Invoke(appliesTo, entityid, archived.IsEmpty());
  359. CloseImageWindows();
  360. }
  361. private void _historyGrid_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
  362. {
  363. DoSelect(e.Rows);
  364. }
  365. private void CloseImageWindows()
  366. {
  367. while (OpenWindows.Count > 0)
  368. {
  369. var win = OpenWindows.Last();
  370. OpenWindows.RemoveAt(OpenWindows.Count - 1);
  371. win.Close();
  372. }
  373. }
  374. private void OpenImageWindow(ImageSource image)
  375. {
  376. var window = OpenWindows.FirstOrDefault(x => x.Images.Contains(image));
  377. if (window is not null)
  378. {
  379. window.Activate();
  380. }
  381. else
  382. {
  383. window = new DataEntryDocumentWindow();
  384. window.Topmost = true;
  385. window.Images.Add(image);
  386. OpenWindows.Add(window);
  387. window.Closed += OpenWindow_Closed;
  388. window.Show();
  389. }
  390. }
  391. private void Image_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
  392. {
  393. if (sender is not Image image) return;
  394. if(e.ClickCount >= 2)
  395. {
  396. OpenImageWindow(image.Source);
  397. e.Handled = true;
  398. }
  399. }
  400. private void OpenWindow_Closed(object? sender, EventArgs e)
  401. {
  402. if (sender is not DataEntryDocumentWindow window) return;
  403. OpenWindows.Remove(window);
  404. }
  405. private void _Explode_OnClick(object sender, RoutedEventArgs e)
  406. {
  407. _dataEntryGrid.DoExplode();
  408. }
  409. private void _ExplodeAll_OnClick(object sender, RoutedEventArgs e)
  410. {
  411. _dataEntryGrid.DoExplodeAll();
  412. }
  413. private List<DataEntryTag>? _tags;
  414. private void _uploadMenu_OnOpened(object sender, RoutedEventArgs e)
  415. {
  416. _uploadMenu.Items.Clear();
  417. _uploadMenu.AddItem("Load from File", null, _addItem_OnClick);
  418. if (Clipboard.ContainsText())
  419. {
  420. _uploadMenu.AddItem("Paste Text from Clipboard", null, _pasteItem_OnClick);
  421. }
  422. else if (Clipboard.ContainsImage())
  423. {
  424. _uploadMenu.AddItem("Paste Image from Clipboard", null, _pasteItem_OnClick);
  425. }
  426. else if (Clipboard.ContainsFileDropList())
  427. {
  428. int count = CheckAllowableFiles();
  429. if (count > 0)
  430. {
  431. _uploadMenu.AddItem($@"Paste {count} File{(count > 1 ? "s" : "")} from Clipboard", null, _pasteItem_OnClick);
  432. }
  433. }
  434. _uploadMenu.AddSeparatorIfNeeded();
  435. if(_dataEntryGrid.SelectedRows.Length > 0)
  436. {
  437. if (Security.CanEdit<DataEntryDocument>())
  438. {
  439. if (Security.IsAllowed<CanSetupDataEntryTags>())
  440. {
  441. _tags ??= DataEntryGrid.GetVisibleTagList();
  442. if(_tags.Count > 0)
  443. {
  444. var changeTag = _uploadMenu.AddItem("Set Tag", null, null);
  445. foreach(var tag in _tags)
  446. {
  447. changeTag.AddItem(tag.Name, null, tag, ChangeTag);
  448. }
  449. changeTag.AddSeparatorIfNeeded();
  450. changeTag.AddItem<DataEntryTag?>("Clear Tags", null, null, ChangeTag);
  451. }
  452. }
  453. _uploadMenu.AddItem("Set Note", null, _dataEntryGrid.SelectedRows, _changeNote_Click);
  454. _uploadMenu.AddSeparator();
  455. _uploadMenu.AddItem("Archive", null, _remove_OnClick);
  456. _uploadMenu.AddItem("Edit", null, _dataEntryGrid.SelectedRows, EditItem_Click);
  457. }
  458. if (Security.CanDelete<DataEntryDocument>())
  459. {
  460. _uploadMenu.AddItem("Delete", null, _dataEntryGrid.SelectedRows, DeleteItem_Click);
  461. }
  462. }
  463. _uploadMenu.RemoveUnnecessarySeparators();
  464. }
  465. private void DeleteItem_Click(CoreRow[] obj)
  466. {
  467. _dataEntryGrid.DeleteItems(obj);
  468. _dataEntryGrid.Refresh(false, true);
  469. }
  470. private void EditItem_Click(CoreRow[] rows)
  471. {
  472. var items = _dataEntryGrid.LoadItems(rows);
  473. if (_dataEntryGrid.EditItems(items))
  474. {
  475. _dataEntryGrid.Refresh(false, true);
  476. }
  477. }
  478. private void ChangeTag(DataEntryTag? obj)
  479. {
  480. _dataEntryGrid.DoChangeTags(obj?.ID ?? Guid.Empty);
  481. }
  482. private void _addItem_OnClick()
  483. {
  484. var ofd = new OpenFileDialog()
  485. {
  486. Filter = @"All Files (*.pdf, *.bmp, *.png, *.jpg, *.jpeg)|*.pdf;*.bmp;*.png;*.jpg;*.jpeg",
  487. Multiselect = true,
  488. Title = @"Select Files to Upload",
  489. InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
  490. };
  491. if (ofd.ShowDialog() == true)
  492. {
  493. foreach (var file in ofd.FileNames)
  494. Upload(
  495. Path.GetFileName(file),
  496. new FileStream(file,FileMode.Open));
  497. }
  498. }
  499. private void _pasteItem_OnClick()
  500. {
  501. if (Clipboard.ContainsText())
  502. {
  503. Upload(
  504. $"Pasted Text {DateTime.Now:yyyy-MM-dd hh-mm-ss-fff}.txt",
  505. new MemoryStream(new UTF8Encoding().GetBytes(Clipboard.GetText()))
  506. );
  507. }
  508. else if (Clipboard.ContainsImage())
  509. {
  510. var img = Clipboard.GetImage();
  511. if (img != null)
  512. {
  513. var bmp = ImageUtils.BitmapSourceToBitmap(img);
  514. using (var ms = new MemoryStream())
  515. {
  516. bmp.Save(ms, ImageFormat.Png);
  517. Upload(
  518. $"Pasted Image {DateTime.Now:yyyy-MM-dd hh-mm-ss-fff}.png",
  519. ms
  520. );
  521. }
  522. }
  523. }
  524. else if (CheckAllowableFiles() > 0)
  525. {
  526. var files = Clipboard.GetFileDropList().OfType<String>().ToArray();
  527. foreach (var file in files)
  528. {
  529. Upload(
  530. Path.GetFileName(file),
  531. new FileStream(file,FileMode.Open)
  532. );
  533. }
  534. }
  535. }
  536. private void Upload(string filename, Stream data)
  537. {
  538. var doc = DataEntryReGroupWindow.RenderToPDF(filename, data);
  539. _dataEntryGrid.UploadDocument(Path.ChangeExtension(filename,"pdf"), doc.SaveToBytes(), Guid.Empty);
  540. }
  541. private static int CheckAllowableFiles()
  542. {
  543. var extensions = Clipboard.GetFileDropList().OfType<String>().Select(x => Path.GetExtension(x.ToUpper())).ToArray();
  544. return extensions.Count(x =>
  545. String.Equals(x, "PDF")
  546. || String.Equals(x, "PNG")
  547. || String.Equals(x, "JPG")
  548. || String.Equals(x, "JPEG")
  549. || String.Equals(x, "BMP")
  550. || String.Equals(x, "TXT")
  551. );
  552. }
  553. private void _pages_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
  554. {
  555. if (_pages.SelectedIndex == 0)
  556. _dataEntryGrid.Refresh(false,true);
  557. else if (_pages.SelectedIndex == 1)
  558. _historyGrid.Refresh(false,true);
  559. }
  560. private void _remove_OnClick()
  561. {
  562. _dataEntryGrid.DoRemove();
  563. }
  564. private void _reopen_OnClick(object sender, RoutedEventArgs e)
  565. {
  566. _historyGrid.DoReopen();
  567. }
  568. private void _changeNote_Click(CoreRow[] rows)
  569. {
  570. var notes = rows.ToObjects<DataEntryDocument>().Select(x => x.Note).Distinct().ToArray();
  571. var note = notes.Length == 1 ? notes[0] : "";
  572. if(TextBoxDialog.Execute("Enter note:", ref note))
  573. {
  574. _dataEntryGrid.DoChangeNote(note);
  575. }
  576. }
  577. private void _dataEntryGrid_OnContextMenuOpening(object sender, ContextMenuEventArgs e)
  578. {
  579. }
  580. private void _ShowImage_Click(object sender, RoutedEventArgs e)
  581. {
  582. if (sender is not MenuItem item || item.Tag is not ImageSource image) return;
  583. OpenImageWindow(image);
  584. }
  585. private void RotateDocument(Document doc, int pageNumber)
  586. {
  587. var extension = Path.GetExtension(doc.FileName).ToLower();
  588. if (extension == ".pdf")
  589. {
  590. var loadeddoc = new PdfLoadedDocument(doc.Data);
  591. bool allPages = loadeddoc.PageCount() > 1;
  592. if (allPages)
  593. {
  594. allPages = MessageWindow.New()
  595. .Message("Do you want to rotate all pages in this PDF?")
  596. .Title("Rotate all?")
  597. .AddYesButton("All pages")
  598. .AddNoButton("Just this page")
  599. .Display().Result == MessageWindowResult.Yes;
  600. }
  601. if(allPages)
  602. {
  603. foreach (var page in loadeddoc.GetPages())
  604. {
  605. var rotation = (int)page.Rotation;
  606. rotation = (rotation + 1) % 4;
  607. page.Rotation = (PdfPageRotateAngle)rotation;
  608. }
  609. }
  610. else if(pageNumber <= loadeddoc.PageCount())
  611. {
  612. var page = loadeddoc.GetPage(pageNumber - 1);
  613. var rotation = (int)page.Rotation;
  614. rotation = (rotation + 1) % 4;
  615. page.Rotation = (PdfPageRotateAngle)rotation;
  616. }
  617. doc.Data = loadeddoc.SaveToBytes();
  618. }
  619. else if (extension == ".jpg" || extension == ".jpeg" || extension == ".png" || extension == ".bmp")
  620. {
  621. using var stream = new MemoryStream(doc.Data);
  622. var bitmap = Bitmap.FromStream(stream);
  623. bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
  624. using var outStream = new MemoryStream();
  625. bitmap.Save(outStream, extension switch
  626. {
  627. ".jpg" or ".jpeg" => ImageFormat.Jpeg,
  628. ".png" => ImageFormat.Png,
  629. _ => ImageFormat.Bmp
  630. });
  631. doc.Data = outStream.ToArray();
  632. }
  633. else
  634. {
  635. using var stream = new MemoryStream(doc.Data);
  636. var loadeddoc = DataEntryReGroupWindow.RenderToPDF(doc.FileName, stream);
  637. foreach (var page in loadeddoc.GetPages())
  638. {
  639. var rotation = (int)page.Rotation;
  640. rotation = (rotation + 1) % 4;
  641. page.Rotation = (PdfPageRotateAngle)rotation;
  642. }
  643. doc.Data = loadeddoc.SaveToBytes();
  644. }
  645. }
  646. private void _RotateImage_Click(object sender, RoutedEventArgs e)
  647. {
  648. if (sender is not MenuItem item || item.Tag is not ImageSource image) return;
  649. var document = ViewDocuments.FirstOrDefault(x => x.Image == image);
  650. if (document is null)
  651. {
  652. MessageWindow.ShowError("An error occurred", "Document does not exist in ViewDocuments list");
  653. return;
  654. }
  655. var doc = DataEntryCache.Cache.LoadDocuments(CoreUtils.One(document.Document.Document.ID), checkTimestamp: true).First();
  656. try
  657. {
  658. RotateDocument(doc, document.PageNumber);
  659. }
  660. catch(Exception err)
  661. {
  662. MessageWindow.ShowError("Something went wrong while trying to rotate this document.", err);
  663. return;
  664. }
  665. Client.Save(doc, "Rotated by user.");
  666. if (Path.GetExtension(doc.FileName) == ".pdf")
  667. {
  668. document.Document.Thumbnail = ImageUtils.GetPDFThumbnail(doc.Data, 256, 256);
  669. }
  670. new Client<DataEntryDocument>().Save(document.Document, "");
  671. DataEntryCache.Cache.Add(new DataEntryCachedDocument(doc));
  672. UpdateViewList(true);
  673. }
  674. }