Browse Source

deprecate "path", replace "file" by "tmpfile"

ctx https://github.com/gre/react-native-view-shot/issues/67
Gaëtan Renaudeau 7 years ago
parent
commit
63d2819585

+ 10
- 24
README.md View File

34
 
34
 
35
 - **`view`** is a reference to a React Native component.
35
 - **`view`** is a reference to a React Native component.
36
 - **`options`** may include:
36
 - **`options`** may include:
37
- - **`width`** / **`height`** *(number)*: the width and height of the final image (resized from the View bound. don't provide it if you want the original pixel size).
38
- - **`format`** *(string)*: either `png` or `jpg`/`jpeg` or `webm` (Android). Defaults to `png`.
39
- - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpeg)
40
- - **`result`** *(string)*, the method you want to use to save the snapshot, one of:
37
+  - **`width`** / **`height`** *(number)*: the width and height of the final image (resized from the View bound. don't provide it if you want the original pixel size).
38
+  - **`format`** *(string)*: either `png` or `jpg`/`jpeg` or `webm` (Android). Defaults to `png`.
39
+  - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpeg)
40
+  - **`result`** *(string)*, the method you want to use to save the snapshot, one of:
41
     - `"file"` (default): save to a temporary file *(that will only exist for as long as the app is running)*.
41
     - `"file"` (default): save to a temporary file *(that will only exist for as long as the app is running)*.
42
     - `"base64"`: encode as base64 and returns the raw string. Use only with small images as this may result of lags (the string is sent over the bridge). *N.B. This is not a data uri, use `data-uri` instead*.
42
     - `"base64"`: encode as base64 and returns the raw string. Use only with small images as this may result of lags (the string is sent over the bridge). *N.B. This is not a data uri, use `data-uri` instead*.
43
     - `"data-uri"`: same as `base64` but also includes the [Data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme) header.
43
     - `"data-uri"`: same as `base64` but also includes the [Data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme) header.
44
- - **`path`** *(string)*: The absolute path where the file get generated. **Read below before using it!** 
45
  - **`snapshotContentContainer`** *(bool)*: if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height.
44
  - **`snapshotContentContainer`** *(bool)*: if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height.
46
 
45
 
47
-### `path` option and `dirs` constants
46
+### DEPRECATED `path` option and `dirs` constants
48
 
47
 
49
-**IMPORTANT: We might actually drop the path feature because of its complexity in the current codebase (and bugs that are not fixed), please consider using react-native-view-shot with https://github.com/itinance/react-native-fs to solve this.**
48
+> A feature used to allow to set an arbitrary file path. This has become tricky to maintain because all the edge cases and use-cases of file management so we have decided to drop it, making this library focusing more on solving snapshotting and not file system.
50
 
49
 
51
-By default, takeSnapshot will export in a temporary folder and the snapshot file will be deleted as soon as the app leaves.
52
-But if you use the `path` option, you make the snapshot file more permanent and at a specific file location. it is up to you to manage the image file lifecycle, the library won't clean it for you (which might result of leaking files on user's phone if you are not careful). There is also no guarantee the file will be successfully saved: you can reach permissions problem, this also is platform specific.
50
+To migrate from this old feature, you have a few solutions:
53
 
51
 
54
-If you still want to do this, we expose a few somewhat universal "constants" to ease the work.
55
-
56
-```js
57
-import { takeSnapshot, dirs } from "react-native-view-shot";
58
-// cross platform dirs:
59
-const { CacheDir, DocumentDir, MainBundleDir, MovieDir, MusicDir, PictureDir } = dirs;
60
-// only available Android:
61
-const { DCIMDir, DownloadDir, RingtoneDir, SDCardDir } = dirs;
62
-
63
-takeSnapshot(viewRef, { path: PictureDir+"/foo.png" })
64
-.then(
65
-  uri => console.log("Image saved to", uri),
66
-  error => console.error("Oops, snapshot failed", error)
67
-);
68
-```
52
+- If you want to save the snapshotted image result to the CameraRoll, just use https://facebook.github.io/react-native/docs/cameraroll.html#savetocameraroll
53
+- If you want to save it to an arbitrary file path, use something like https://github.com/itinance/react-native-fs
54
+- For any more advanced needs, you can write your own (or find another) native module that would solve your use-case.
69
 
55
 
70
 ## Interoperability Table
56
 ## Interoperability Table
71
 
57
 

+ 4
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

71
         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
71
         DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
72
         Integer width = options.hasKey("width") ? (int)(displayMetrics.density * options.getDouble("width")) : null;
72
         Integer width = options.hasKey("width") ? (int)(displayMetrics.density * options.getDouble("width")) : null;
73
         Integer height = options.hasKey("height") ? (int)(displayMetrics.density * options.getDouble("height")) : null;
73
         Integer height = options.hasKey("height") ? (int)(displayMetrics.density * options.getDouble("height")) : null;
74
-        String result = options.hasKey("result") ? options.getString("result") : "file";
74
+        String result = options.hasKey("result") ? options.getString("result") : "tmpfile";
75
         Boolean snapshotContentContainer = options.hasKey("snapshotContentContainer") ? options.getBoolean("snapshotContentContainer") : false;
75
         Boolean snapshotContentContainer = options.hasKey("snapshotContentContainer") ? options.getBoolean("snapshotContentContainer") : false;
76
         try {
76
         try {
77
             File file = null;
77
             File file = null;
85
                     file = createTempFile(getReactApplicationContext(), format);
85
                     file = createTempFile(getReactApplicationContext(), format);
86
                 }
86
                 }
87
             }
87
             }
88
+            else if ("tmpfile".equals(result)) {
89
+                file = createTempFile(getReactApplicationContext(), format);
90
+            }
88
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
91
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
89
             uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer,reactContext, promise));
92
             uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer,reactContext, promise));
90
         }
93
         }

+ 1
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java View File

79
             return;
79
             return;
80
         }
80
         }
81
         try {
81
         try {
82
-            if ("file".equals(result)) {
82
+            if ("file".equals(result) || "tmpfile".equals(result)) {
83
                 os = new FileOutputStream(output);
83
                 os = new FileOutputStream(output);
84
                 captureView(view, os);
84
                 captureView(view, os);
85
                 String uri = Uri.fromFile(output).toString();
85
                 String uri = Uri.fromFile(output).toString();

+ 16
- 4
index.js View File

14
   DCIMDir: RNViewShot.DCIMDir,
14
   DCIMDir: RNViewShot.DCIMDir,
15
   DownloadDir: RNViewShot.DownloadDir,
15
   DownloadDir: RNViewShot.DownloadDir,
16
   RingtoneDir: RNViewShot.RingtoneDir,
16
   RingtoneDir: RNViewShot.RingtoneDir,
17
-  SDCardDir: RNViewShot.SDCardDir,
17
+  SDCardDir: RNViewShot.SDCardDir
18
 };
18
 };
19
 
19
 
20
 export function takeSnapshot(
20
 export function takeSnapshot(
25
     path?: string,
25
     path?: string,
26
     format?: "png" | "jpg" | "jpeg" | "webm",
26
     format?: "png" | "jpg" | "jpeg" | "webm",
27
     quality?: number,
27
     quality?: number,
28
-    result?: "file" | "base64" | "data-uri",
29
-    snapshotContentContainer?: bool
28
+    result?: "tmpfile" | "file" | "base64" | "data-uri",
29
+    snapshotContentContainer?: boolean
30
   } = {}
30
   } = {}
31
 ): Promise<string> {
31
 ): Promise<string> {
32
+  if (options.result === "file") {
33
+    console.warn(
34
+      "react-native-view-shot: result='file' is deprecated, has been renamed to 'tmpfile' and no longer support any 'path' option. See README for more information"
35
+    );
36
+  } else if ("path" in options) {
37
+    console.warn(
38
+      "react-native-view-shot: path option is deprecated. See README for more information"
39
+    );
40
+  }
32
   if (typeof view !== "number") {
41
   if (typeof view !== "number") {
33
     const node = findNodeHandle(view);
42
     const node = findNodeHandle(view);
34
-    if (!node) return Promise.reject(new Error("findNodeHandle failed to resolve view="+String(view)));
43
+    if (!node)
44
+      return Promise.reject(
45
+        new Error("findNodeHandle failed to resolve view=" + String(view))
46
+      );
35
     view = node;
47
     view = node;
36
   }
48
   }
37
   return RNViewShot.takeSnapshot(view, options);
49
   return RNViewShot.takeSnapshot(view, options);

+ 14
- 14
ios/RNViewShot.m View File

42
                   reject:(RCTPromiseRejectBlock)reject)
42
                   reject:(RCTPromiseRejectBlock)reject)
43
 {
43
 {
44
   [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
44
   [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
45
-    
45
+
46
     // Get view
46
     // Get view
47
     UIView *view;
47
     UIView *view;
48
     view = viewRegistry[target];
48
     view = viewRegistry[target];
50
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
50
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
51
       return;
51
       return;
52
     }
52
     }
53
-    
53
+
54
     // Get options
54
     // Get options
55
     CGSize size = [RCTConvert CGSize:options];
55
     CGSize size = [RCTConvert CGSize:options];
56
     NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
56
     NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
57
-    NSString *result = [RCTConvert NSString:options[@"result"] ?: @"file"];
57
+    NSString *result = [RCTConvert NSString:options[@"result"] ?: @"tmpfile"];
58
     BOOL snapshotContentContainer = [RCTConvert BOOL:options[@"snapshotContentContainer"] ?: @"false"];
58
     BOOL snapshotContentContainer = [RCTConvert BOOL:options[@"snapshotContentContainer"] ?: @"false"];
59
 
59
 
60
     // Capture image
60
     // Capture image
61
     BOOL success;
61
     BOOL success;
62
-    
62
+
63
     UIView* rendered;
63
     UIView* rendered;
64
     UIScrollView* scrollView;
64
     UIScrollView* scrollView;
65
     if (snapshotContentContainer) {
65
     if (snapshotContentContainer) {
74
     else {
74
     else {
75
       rendered = view;
75
       rendered = view;
76
     }
76
     }
77
-    
77
+
78
     if (size.width < 0.1 || size.height < 0.1) {
78
     if (size.width < 0.1 || size.height < 0.1) {
79
       size = snapshotContentContainer ? scrollView.contentSize : view.bounds.size;
79
       size = snapshotContentContainer ? scrollView.contentSize : view.bounds.size;
80
     }
80
     }
82
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"The content size must not be zero or negative. Got: (%g, %g)", size.width, size.height], nil);
82
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"The content size must not be zero or negative. Got: (%g, %g)", size.width, size.height], nil);
83
       return;
83
       return;
84
     }
84
     }
85
-    
85
+
86
     CGPoint savedContentOffset;
86
     CGPoint savedContentOffset;
87
     CGRect savedFrame;
87
     CGRect savedFrame;
88
     if (snapshotContentContainer) {
88
     if (snapshotContentContainer) {
96
     success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
96
     success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
97
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
97
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
98
     UIGraphicsEndImageContext();
98
     UIGraphicsEndImageContext();
99
-    
99
+
100
     if (snapshotContentContainer) {
100
     if (snapshotContentContainer) {
101
       // Restore scroll & frame
101
       // Restore scroll & frame
102
       scrollView.contentOffset = savedContentOffset;
102
       scrollView.contentOffset = savedContentOffset;
103
       scrollView.frame = savedFrame;
103
       scrollView.frame = savedFrame;
104
     }
104
     }
105
-    
105
+
106
     if (!success) {
106
     if (!success) {
107
       reject(RCTErrorUnspecified, @"The view cannot be captured. drawViewHierarchyInRect was not successful. This is a potential technical or security limitation.", nil);
107
       reject(RCTErrorUnspecified, @"The view cannot be captured. drawViewHierarchyInRect was not successful. This is a potential technical or security limitation.", nil);
108
       return;
108
       return;
112
       reject(RCTErrorUnspecified, @"Failed to capture view snapshot. UIGraphicsGetImageFromCurrentImageContext() returned nil!", nil);
112
       reject(RCTErrorUnspecified, @"Failed to capture view snapshot. UIGraphicsGetImageFromCurrentImageContext() returned nil!", nil);
113
       return;
113
       return;
114
     }
114
     }
115
-    
115
+
116
     // Convert image to data (on a background thread)
116
     // Convert image to data (on a background thread)
117
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
117
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
118
-      
118
+
119
       NSData *data;
119
       NSData *data;
120
       if ([format isEqualToString:@"png"]) {
120
       if ([format isEqualToString:@"png"]) {
121
         data = UIImagePNGRepresentation(image);
121
         data = UIImagePNGRepresentation(image);
126
         reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported image format: %@. Try one of: png | jpg | jpeg", format], nil);
126
         reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported image format: %@. Try one of: png | jpg | jpeg", format], nil);
127
         return;
127
         return;
128
       }
128
       }
129
-      
129
+
130
       NSError *error = nil;
130
       NSError *error = nil;
131
       NSString *res = nil;
131
       NSString *res = nil;
132
-      if ([result isEqualToString:@"file"]) {
132
+      if ([result isEqualToString:@"file"] || [result isEqualToString:@"tmpfile"] ) {
133
         // Save to a temp file
133
         // Save to a temp file
134
         NSString *path;
134
         NSString *path;
135
-        if (options[@"path"]) {
135
+        if (options[@"path"] && [result isEqualToString:@"file"]) {
136
           path = options[@"path"];
136
           path = options[@"path"];
137
           NSString * folder = [path stringByDeletingLastPathComponent];
137
           NSString * folder = [path stringByDeletingLastPathComponent];
138
           NSFileManager * fm = [NSFileManager defaultManager];
138
           NSFileManager * fm = [NSFileManager defaultManager];
167
         resolve(res);
167
         resolve(res);
168
         return;
168
         return;
169
       }
169
       }
170
-      
170
+
171
       // If we reached here, something went wrong
171
       // If we reached here, something went wrong
172
       if (error) reject(RCTErrorUnspecified, error.localizedDescription, error);
172
       if (error) reject(RCTErrorUnspecified, error.localizedDescription, error);
173
       else reject(RCTErrorUnspecified, @"viewshot unknown error", nil);
173
       else reject(RCTErrorUnspecified, @"viewshot unknown error", nil);