浏览代码

Add UWP Support

Ryan Linton 7 年前
父节点
当前提交
ae17afadca
共有 2 个文件被更改,包括 170 次插入45 次删除
  1. 9
    36
      windows/RNViewShot/RNViewShotModule.cs
  2. 161
    9
      windows/RNViewShot/ViewShot.cs

+ 9
- 36
windows/RNViewShot/RNViewShotModule.cs 查看文件

@@ -4,8 +4,6 @@ using ReactNative.UIManager;
4 4
 using System;
5 5
 using System.IO;
6 6
 using System.Collections.Generic;
7
-using Windows.ApplicationModel.Core;
8
-using Windows.UI.Core;
9 7
 
10 8
 namespace RNViewShot
11 9
 {
@@ -20,7 +18,7 @@ namespace RNViewShot
20 18
         /// <summary>
21 19
         /// Instantiates the <see cref="RNViewShotModule"/>.
22 20
         /// </summary>
23
-        public RNViewShotModule(ReactContext reactContext) : base(reactContext) 
21
+        public RNViewShotModule(ReactContext reactContext) : base(reactContext)
24 22
         {
25 23
             this._reactContext = reactContext;
26 24
         }
@@ -40,45 +38,20 @@ namespace RNViewShot
40 38
         public void takeSnapshot(int tag, JObject options, IPromise promise)
41 39
         {
42 40
             string format = options["format"] != null ? options.Value<string>("format") : "png";
43
-            //Bitmap.CompressFormat compressFormat =
44
-            //        format.equals("png")
45
-            //                ? Bitmap.CompressFormat.PNG
46
-            //                : format.equals("jpg") || format.equals("jpeg")
47
-            //                ? Bitmap.CompressFormat.JPEG
48
-            //                : format.equals("webm")
49
-            //                ? Bitmap.CompressFormat.WEBP
50
-            //                : null;
51
-            //if (compressFormat == null)
52
-            //{
53
-            //    promise.reject(ErrorUnableToSnapshot, "Unsupported image format: " + format + ". Try one of: png | jpg | jpeg");
54
-            //    return;
55
-            //}
56 41
             double quality = options["quality"] != null ? options.Value<double>("quality") : 1.0;
57 42
             int? width = options["width"] != null ? options.Value<int?>("width") : null;
58 43
             int? height = options["height"] != null ? options.Value<int?>("height") : null;
59 44
             string result = options["result"] != null ? options.Value<string>("result") : "file";
60
-            bool snapshotContentContainer = options["snapshotContentContainer"] != null ? options.Value<bool>("snapshotContentContainer") : false;
45
+            string path = options["path"] != null ? options.Value<string>("path") : null;
61 46
 
62
-            UIManagerModule uiManager = this._reactContext.GetNativeModule<UIManagerModule>();
63
-            uiManager.AddUIBlock(new ViewShot(tag));
64
-
65
-            //try
66
-            //{
67
-            //    string name = options["filename"] != null ? options.Value<string>("filename") : null;
68
-            //    //File tmpFile = "file" == result ? createTempFile(this._reactContext, format, name) : null;
69
-            //    UIManagerModule uiManager = this._reactContext.GetNativeModule<UIManagerModule>();
70
-            //    //uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, tmpFile, result, snapshotContentContainer, promise));
71
-            //}
72
-            //catch (Exception e)
73
-            //{
74
-            //    promise.reject(ErrorUnableToSnapshot, "Failed to snapshot view tag " + tag);
75
-            //}
47
+            if (format != "png" && format != "jpg" && format != "jpeg")
48
+            {
49
+                promise.Reject(ViewShot.ErrorUnableToSnapshot, "Unsupported image format: " + format + ". Try one of: png | jpg | jpeg");
50
+                return;
51
+            }
76 52
 
77
-            //Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
78
-            //Graphics graphics = Graphics.FromImage(bitmap as Image);
79
-            //graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
80
-            //bitmap.Save("c:\\screenshot.jpeg", ImageFormat.Jpeg);
81
-            promise.Resolve("Format: " + format + " Quality: " + quality);
53
+            UIManagerModule uiManager = this._reactContext.GetNativeModule<UIManagerModule>();
54
+            uiManager.AddUIBlock(new ViewShot(tag, format, quality, width, height, path, result, promise));
82 55
         }
83 56
     }
84 57
 }

+ 161
- 9
windows/RNViewShot/ViewShot.cs 查看文件

@@ -1,26 +1,178 @@
1
-using System;
2
-using System.Collections.Generic;
3
-using System.Linq;
4
-using System.Text;
5
-using System.Threading.Tasks;
1
+using ReactNative.Bridge;
6 2
 using ReactNative.UIManager;
3
+using System;
4
+using System.IO;
5
+using System.Runtime.InteropServices.WindowsRuntime;
6
+using System.Threading.Tasks;
7
+using Windows.Graphics.Display;
8
+using Windows.Graphics.Imaging;
9
+using Windows.Storage;
10
+using Windows.Storage.Streams;
11
+using Windows.UI.Xaml;
12
+using Windows.UI.Xaml.Media;
13
+using Windows.UI.Xaml.Media.Imaging;
7 14
 
8 15
 namespace RNViewShot
9 16
 {
10 17
     public class ViewShot : IUIBlock
11 18
     {
19
+        public const string ErrorUnableToSnapshot = "E_UNABLE_TO_SNAPSHOT";
12 20
         private int tag;
21
+        private string extension;
22
+        private double quality;
23
+        private int? width;
24
+        private int? height;
25
+        private string path;
26
+        private string result;
27
+        private IPromise promise;
13 28
 
14
-        public ViewShot(int tag)
29
+        public ViewShot(
30
+            int tag,
31
+            string extension,
32
+            double quality,
33
+            int? width,
34
+            int? height,
35
+            string path,
36
+            string result,
37
+            IPromise promise)
15 38
         {
16 39
             this.tag = tag;
40
+            this.extension = extension;
41
+            this.quality = quality;
42
+            this.width = width;
43
+            this.height = height;
44
+            this.path = path;
45
+            this.result = result;
46
+            this.promise = promise;
17 47
         }
18 48
 
19
-        public void Execute(NativeViewHierarchyManager nvhm)
49
+        public async void Execute(NativeViewHierarchyManager nvhm)
20 50
         {
21
-            var view = nvhm.ResolveView(this.tag);
51
+            var view = nvhm.ResolveView(tag) as FrameworkElement;
52
+            if (view == null)
53
+            {
54
+                promise.Reject(ErrorUnableToSnapshot, "No view found with reactTag: " + tag);
55
+                return;
56
+            }
57
+
58
+            try
59
+            {
60
+                if ("file" == result)
61
+                {
62
+                    using (InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream())
63
+                    {
64
+                        await CaptureView(view, ras);
65
+                        StorageFile file = await GetStorageFile();
66
+                        using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
67
+                        {
68
+                            await RandomAccessStream.CopyAndCloseAsync(ras.GetInputStreamAt(0), fileStream.GetOutputStreamAt(0));
69
+                            promise.Resolve(file.Path);
70
+                        }
71
+                    }
72
+                }
73
+                else if ("base64" == result)
74
+                {
75
+                    using (InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream())
76
+                    {
77
+                        await CaptureView(view, ras);
78
+                        byte[] imageBytes = new byte[ras.Size];
79
+                        await ras.AsStream().ReadAsync(imageBytes, 0, imageBytes.Length);
80
+                        string data = Convert.ToBase64String(imageBytes);
81
+                        promise.Resolve(data);
82
+                    }
83
+                }
84
+                else if ("data-uri" == result)
85
+                {
86
+                    using (InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream())
87
+                    {
88
+                        await CaptureView(view, ras);
89
+                        byte[] imageBytes = new byte[ras.Size];
90
+                        await ras.AsStream().ReadAsync(imageBytes, 0, imageBytes.Length);
91
+                        string data = Convert.ToBase64String(imageBytes);
92
+                        data = "data:image/" + extension + ";base64," + data;
93
+                        promise.Resolve(data);
94
+                    }
95
+                }
96
+                else
97
+                {
98
+                    promise.Reject(ErrorUnableToSnapshot, "Unsupported result: " + result + ". Try one of: file | base64 | data-uri");
99
+                }
100
+            }
101
+            catch (Exception ex)
102
+            {
103
+                Console.WriteLine(ex.ToString());
104
+                promise.Reject(ErrorUnableToSnapshot, "Failed to capture view snapshot");
105
+            }
106
+        }
107
+
108
+        private async Task<BitmapEncoder> CaptureView(FrameworkElement view, IRandomAccessStream stream)
109
+        {
110
+            int w = (int)view.ActualWidth;
111
+            int h = (int)view.ActualHeight;
112
+
113
+            if (w <= 0 || h <= 0)
114
+            {
115
+                throw new InvalidOperationException("Impossible to snapshot the view: view is invalid");
116
+            }
117
+
118
+            RenderTargetBitmap targetBitmap = new RenderTargetBitmap();
119
+            await targetBitmap.RenderAsync(view, w, h);
120
+
121
+            BitmapEncoder encoder;
122
+            if (extension != "png")
123
+            {
124
+                var propertySet = new BitmapPropertySet();
125
+                var qualityValue = new BitmapTypedValue(quality, Windows.Foundation.PropertyType.Single);
126
+                propertySet.Add("ImageQuality", qualityValue);
127
+                encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream, propertySet);
128
+            }
129
+            else
130
+            {
131
+                encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
132
+            }
22 133
 
23
-            string depObj = view.ToString();
134
+            var displayInformation = DisplayInformation.GetForCurrentView();
135
+            var pixelBuffer = await targetBitmap.GetPixelsAsync();
136
+
137
+            encoder.SetPixelData(
138
+                BitmapPixelFormat.Bgra8,
139
+                BitmapAlphaMode.Ignore,
140
+                (uint)targetBitmap.PixelWidth,
141
+                (uint)targetBitmap.PixelHeight,
142
+                displayInformation.LogicalDpi,
143
+                displayInformation.LogicalDpi,
144
+                pixelBuffer.ToArray());                
145
+
146
+
147
+            if (width != null && height != null && (width != w || height != h))
148
+            {
149
+                encoder.BitmapTransform.ScaledWidth = (uint)width;
150
+                encoder.BitmapTransform.ScaledWidth = (uint)height;
151
+            }
152
+
153
+            if (encoder == null)
154
+            {
155
+                throw new InvalidOperationException("Impossible to snapshot the view");
156
+            }
157
+
158
+            await encoder.FlushAsync();
159
+
160
+            return encoder;            
161
+        }
162
+
163
+        private async Task<StorageFile> GetStorageFile()
164
+        {
165
+            StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
166
+            if (string.IsNullOrEmpty(path))
167
+            {
168
+                string fileName = Guid.NewGuid().ToString();
169
+                fileName = Path.ChangeExtension(fileName, extension);
170
+                return await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
171
+            }
172
+            else
173
+            {
174
+                return await storageFolder.CreateFileAsync(path, CreationCollisionOption.ReplaceExisting);
175
+            }
24 176
         }
25 177
     }
26 178
 }