123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. using ReactNative.Bridge;
  2. using ReactNative.UIManager;
  3. using System;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Windows;
  7. using System.Windows.Media;
  8. using System.Windows.Media.Imaging;
  9. namespace RNViewShot
  10. {
  11. public class ViewShot : IUIBlock
  12. {
  13. public const string ErrorUnableToSnapshot = "E_UNABLE_TO_SNAPSHOT";
  14. private int tag;
  15. private string extension;
  16. private double quality;
  17. private int? width;
  18. private int? height;
  19. private string path;
  20. private string result;
  21. private IPromise promise;
  22. public ViewShot(
  23. int tag,
  24. string extension,
  25. double quality,
  26. int? width,
  27. int? height,
  28. string path,
  29. string result,
  30. IPromise promise)
  31. {
  32. this.tag = tag;
  33. this.extension = extension;
  34. this.quality = quality;
  35. this.width = width;
  36. this.height = height;
  37. this.path = path;
  38. this.result = result;
  39. this.promise = promise;
  40. }
  41. public void Execute(NativeViewHierarchyManager nvhm)
  42. {
  43. var view = nvhm.ResolveView(tag) as FrameworkElement;
  44. if (view == null)
  45. {
  46. promise.Reject(ErrorUnableToSnapshot, "No view found with reactTag: " + tag);
  47. return;
  48. }
  49. try
  50. {
  51. BitmapEncoder image = CaptureView(view);
  52. if ("file" == result)
  53. {
  54. string filePath = GetFilePath();
  55. Stream stream = File.Create(filePath);
  56. image.Save(stream);
  57. promise.Resolve(filePath);
  58. stream.Close();
  59. }
  60. else if ("base64" == result)
  61. {
  62. MemoryStream stream = new MemoryStream();
  63. image.Save(stream);
  64. byte[] imageBytes = stream.ToArray();
  65. string data = Convert.ToBase64String(imageBytes);
  66. promise.Resolve(data);
  67. stream.Close();
  68. }
  69. else if ("data-uri" == result)
  70. {
  71. MemoryStream stream = new MemoryStream();
  72. image.Save(stream);
  73. byte[] imageBytes = stream.ToArray();
  74. string data = Convert.ToBase64String(imageBytes);
  75. data = "data:image/" + extension + ";base64," + data;
  76. promise.Resolve(data);
  77. stream.Close();
  78. }
  79. else
  80. {
  81. promise.Reject(ErrorUnableToSnapshot, "Unsupported result: " + result + ". Try one of: file | base64 | data-uri");
  82. }
  83. }
  84. catch (Exception ex)
  85. {
  86. Debug.WriteLine(ex.ToString());
  87. promise.Reject(ErrorUnableToSnapshot, "Failed to capture view snapshot");
  88. }
  89. }
  90. private BitmapEncoder CaptureView(FrameworkElement view)
  91. {
  92. int w = (int)view.ActualWidth;
  93. int h = (int)view.ActualHeight;
  94. if (w <= 0 || h <= 0)
  95. {
  96. throw new InvalidOperationException("Impossible to snapshot the view: view is invalid");
  97. }
  98. RenderTargetBitmap targetBitmap = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Default);
  99. targetBitmap.Render(view);
  100. BitmapSource bitmap;
  101. if (width != null && height != null && (width != w || height != h))
  102. {
  103. double scaleX = (double)width / targetBitmap.PixelWidth;
  104. double scaleY = (double)height / targetBitmap.PixelHeight;
  105. bitmap = new TransformedBitmap(targetBitmap, new ScaleTransform(scaleX, scaleY));
  106. }
  107. else
  108. {
  109. bitmap = targetBitmap;
  110. }
  111. if (bitmap == null)
  112. {
  113. throw new InvalidOperationException("Impossible to snapshot the view");
  114. }
  115. if (extension == "png")
  116. {
  117. PngBitmapEncoder image = new PngBitmapEncoder();
  118. image.Frames.Add(BitmapFrame.Create(bitmap));
  119. return image;
  120. }
  121. else
  122. {
  123. JpegBitmapEncoder image = new JpegBitmapEncoder();
  124. image.QualityLevel = (int)(100.0 * quality);
  125. image.Frames.Add(BitmapFrame.Create(bitmap));
  126. return image;
  127. }
  128. }
  129. private string GetFilePath()
  130. {
  131. if (string.IsNullOrEmpty(path))
  132. {
  133. string tmpFilePath = Path.GetTempPath();
  134. string fileName = Guid.NewGuid().ToString();
  135. fileName = Path.ChangeExtension(fileName, extension);
  136. return Path.Combine(tmpFilePath, fileName);
  137. }
  138. else
  139. {
  140. return path;
  141. }
  142. }
  143. }
  144. }