Base64.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using ImageMagick;
  2. using PicView.UILogic;
  3. using System.IO;
  4. using System.Windows;
  5. using System.Windows.Media;
  6. using System.Windows.Media.Imaging;
  7. using System.Windows.Shapes;
  8. using System.Windows.Threading;
  9. namespace PicView.ImageHandling
  10. {
  11. internal static class Base64
  12. {
  13. /// <summary>
  14. /// Converts a Base64 string to a BitmapSource asynchronously.
  15. /// </summary>
  16. /// <param name="base64String">The Base64 string representing the image.</param>
  17. /// <returns>The BitmapSource created from the Base64 string, or null if conversion fails.</returns>
  18. internal static async Task<BitmapSource?> Base64StringToBitmapAsync(string base64String)
  19. {
  20. return await GetBitmapSourceFromBase64Async(base64String).ConfigureAwait(false);
  21. }
  22. /// <summary>
  23. /// Converts the contents of a file to a BitmapSource asynchronously.
  24. /// </summary>
  25. /// <param name="fileInfo">The file to read the Base64 string from.</param>
  26. /// <returns>The BitmapSource created from the Base64 string in the file, or null if conversion fails.</returns>
  27. internal static async Task<BitmapSource?> Base64StringToBitmapAsync(FileInfo fileInfo)
  28. {
  29. var base64String = await File.ReadAllTextAsync(fileInfo.FullName).ConfigureAwait(false);
  30. return await GetBitmapSourceFromBase64Async(base64String).ConfigureAwait(false);
  31. }
  32. /// <summary>
  33. /// Converts a Base64 string to a BitmapSource asynchronously.
  34. /// </summary>
  35. /// <param name="base64String">The Base64 string representing the image.</param>
  36. /// <returns>The BitmapSource created from the Base64 string, or null if conversion fails.</returns>
  37. private static async Task<BitmapSource?> GetBitmapSourceFromBase64Async(string base64String)
  38. {
  39. try
  40. {
  41. var base64Data = Convert.FromBase64String(base64String);
  42. using var magickImage = new MagickImage
  43. {
  44. Quality = 100,
  45. ColorSpace = ColorSpace.Transparent
  46. };
  47. var readSettings = new MagickReadSettings
  48. {
  49. Density = new Density(300, 300),
  50. BackgroundColor = MagickColors.Transparent
  51. };
  52. await magickImage.ReadAsync(new MemoryStream(base64Data), readSettings).ConfigureAwait(false);
  53. var bitmapSource = magickImage.ToBitmapSource();
  54. bitmapSource.Freeze();
  55. return bitmapSource;
  56. }
  57. catch (MagickException)
  58. {
  59. return null;
  60. }
  61. }
  62. /// <summary>
  63. /// Determines whether a string is a valid Base64 string.
  64. /// </summary>
  65. /// <param name="base64">The string to check.</param>
  66. /// <returns>True if the string is a valid Base64 string; otherwise, false.</returns>
  67. internal static bool IsBase64String(string base64)
  68. {
  69. if (string.IsNullOrEmpty(base64))
  70. {
  71. return false;
  72. }
  73. var buffer = new Span<byte>(new byte[base64.Length]);
  74. return Convert.TryFromBase64String(base64, buffer, out _);
  75. }
  76. /// <summary>
  77. /// Converts the current rendered bitmap frame to a Base64 string.
  78. /// </summary>
  79. /// <returns>A Task representing the asynchronous operation.</returns>
  80. private static async Task<string> ConvertToBase64(string? path = null)
  81. {
  82. BitmapFrame frame;
  83. if (path is null)
  84. {
  85. frame = await ConfigureWindows.GetMainWindow.Dispatcher.InvokeAsync(Image2BitmapSource
  86. .GetRenderedBitmapFrame);
  87. }
  88. else
  89. {
  90. var bitmapSource = await Image2BitmapSource.ReturnBitmapSourceAsync(new FileInfo(path)).ConfigureAwait(false);
  91. var sourceSize = new Size(bitmapSource.PixelWidth, bitmapSource.PixelHeight);
  92. var rectangle = new Rectangle
  93. {
  94. Fill = new ImageBrush(bitmapSource),
  95. };
  96. rectangle.Measure(sourceSize);
  97. rectangle.Arrange(new Rect(sourceSize));
  98. var renderedBitmap = new RenderTargetBitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight,
  99. bitmapSource.DpiX, bitmapSource.DpiY, PixelFormats.Default);
  100. renderedBitmap.Render(rectangle);
  101. frame = BitmapFrame.Create(renderedBitmap);
  102. frame.Freeze();
  103. }
  104. byte[]? bytes;
  105. var b64 = "";
  106. await Task.Run(() =>
  107. {
  108. try
  109. {
  110. using var ms = new MemoryStream();
  111. var pngBitmapEncoder = new PngBitmapEncoder();
  112. pngBitmapEncoder.Frames.Add(frame);
  113. pngBitmapEncoder.Save(ms);
  114. bytes = ms.ToArray();
  115. b64 = Convert.ToBase64String(bytes);
  116. }
  117. catch (Exception e)
  118. {
  119. Tooltip.ShowTooltipMessage(e.Message, true, TimeSpan.FromSeconds(5));
  120. }
  121. }).ConfigureAwait(false);
  122. return b64;
  123. }
  124. /// <summary>
  125. /// Converts the current rendered bitmap frame to a Base64 string and sets it to the clipboard.
  126. /// </summary>
  127. /// <returns>A Task representing the asynchronous operation.</returns>
  128. internal static async Task SendToClipboard(string? path = null)
  129. {
  130. var base64String = await ConvertToBase64(path).ConfigureAwait(false);
  131. if (string.IsNullOrWhiteSpace(base64String))
  132. {
  133. Tooltip.ShowTooltipMessage(Application.Current.Resources["UnexpectedError"]);
  134. return;
  135. }
  136. await UC.GetPicGallery.Dispatcher.InvokeAsync(() => { Clipboard.SetText(base64String); },
  137. DispatcherPriority.Background);
  138. Tooltip.ShowTooltipMessage(Application.Current.Resources["ConvertedToBase64"]);
  139. }
  140. }
  141. }