|
@@ -5,15 +5,84 @@ Capture a React Native view to an image.
|
5
|
5
|
|
6
|
6
|
<img src="https://github.com/gre/react-native-view-shot-example/raw/master/docs/recursive.gif" width=300 />
|
7
|
7
|
|
8
|
|
-> iOS: For React Native version between `0.30.x` and `0.39.x`, you should use `react-native-view-shot@1.5.1`.
|
|
8
|
+## Install
|
9
|
9
|
|
10
|
|
-## Usage
|
|
10
|
+```bash
|
|
11
|
+yarn add react-native-view-shot
|
|
12
|
+react-native link react-native-view-shot
|
|
13
|
+```
|
|
14
|
+
|
|
15
|
+## Recommended High Level API
|
|
16
|
+
|
|
17
|
+```js
|
|
18
|
+import { ViewShot } from "react-native-view-shot";
|
|
19
|
+
|
|
20
|
+class ExampleCaptureOnMountManually extends Component {
|
|
21
|
+ componentDidMount () {
|
|
22
|
+ this.refs.viewShot.capture().then(uri => {
|
|
23
|
+ console.log("do something with ", uri);
|
|
24
|
+ });
|
|
25
|
+ }
|
|
26
|
+ render() {
|
|
27
|
+ return (
|
|
28
|
+ <ViewShot ref="viewShot" options={{ format: "jpg", quality: 0.9 }}>
|
|
29
|
+ <Text>...Something to rasterize...</Text>
|
|
30
|
+ </ViewShot>
|
|
31
|
+ );
|
|
32
|
+ }
|
|
33
|
+}
|
|
34
|
+
|
|
35
|
+// alternative
|
|
36
|
+class ExampleCaptureOnMountSimpler extends Component {
|
|
37
|
+ onCapture = uri => {
|
|
38
|
+ console.log("do something with ", uri);
|
|
39
|
+ }
|
|
40
|
+ render() {
|
|
41
|
+ return (
|
|
42
|
+ <ViewShot onCapture={this.onCapture} captureMode="mount">
|
|
43
|
+ <Text>...Something to rasterize...</Text>
|
|
44
|
+ </ViewShot>
|
|
45
|
+ );
|
|
46
|
+ }
|
|
47
|
+}
|
|
48
|
+
|
|
49
|
+// waiting an image
|
|
50
|
+class ExampleWaitingCapture extends Component {
|
|
51
|
+ onImageLoad = () => {
|
|
52
|
+ this.refs.viewShot.capture().then(uri => {
|
|
53
|
+ console.log("do something with ", uri);
|
|
54
|
+ })
|
|
55
|
+ };
|
|
56
|
+ render() {
|
|
57
|
+ return (
|
|
58
|
+ <ViewShot ref="viewShot">
|
|
59
|
+ <Text>...Something to rasterize...</Text>
|
|
60
|
+ <Image ... onLoad={this.onImageLoad} />
|
|
61
|
+ </ViewShot>
|
|
62
|
+ );
|
|
63
|
+ }
|
|
64
|
+}
|
|
65
|
+```
|
|
66
|
+
|
|
67
|
+**Props:**
|
|
68
|
+
|
|
69
|
+- **`children`**: the actual content to rasterize.
|
|
70
|
+- **`options`**: the same options as in `captureRef` method.
|
|
71
|
+- **`captureMode`** (string):
|
|
72
|
+ - if not defined (default). the capture is not automatic and you need to use the ref and call `capture()` yourself.
|
|
73
|
+ - `"mount"`. Capture the view once at mount. (It is important to understand image loading won't be waited, in such case you want to use `"none"` with `viewShotRef.capture()` after `Image#onLoad`.)
|
|
74
|
+ - `"continuous"` EXPERIMENTAL, this will capture A LOT of images continuously. For very specific use-cases.
|
|
75
|
+ - `"update"` EXPERIMENTAL, this will capture images each time React redraw (on did update). For very specific use-cases.
|
|
76
|
+- **`onCapture`**: when a `captureMode` is defined, this callback will be called with the capture result.
|
|
77
|
+- **`onCaptureFailure`**: when a `captureMode` is defined, this callback will be called when a capture fails.
|
|
78
|
+
|
|
79
|
+## `captureRef(view, options)` lower level imperative API
|
11
|
80
|
|
12
|
81
|
```js
|
13
|
|
-import { takeSnapshot } from "react-native-view-shot";
|
|
82
|
+import { captureRef } from "react-native-view-shot";
|
14
|
83
|
|
15
|
|
-takeSnapshot(viewRef, {
|
16
|
|
- format: "jpeg",
|
|
84
|
+captureRef(viewRef, {
|
|
85
|
+ format: "jpg",
|
17
|
86
|
quality: 0.8
|
18
|
87
|
})
|
19
|
88
|
.then(
|
|
@@ -22,39 +91,33 @@ takeSnapshot(viewRef, {
|
22
|
91
|
);
|
23
|
92
|
```
|
24
|
93
|
|
25
|
|
-### Example
|
26
|
|
-
|
27
|
|
-[Checkout react-native-view-shot-example](https://github.com/gre/react-native-view-shot-example)
|
28
|
|
-
|
29
|
|
-## Full API
|
30
|
|
-
|
31
|
|
-### `takeSnapshot(view, options)`
|
32
|
|
-
|
33
|
94
|
Returns a Promise of the image URI.
|
34
|
95
|
|
35
|
96
|
- **`view`** is a reference to a React Native component.
|
36
|
97
|
- **`options`** may include:
|
37
|
98
|
- **`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)
|
|
99
|
+ - **`format`** *(string)*: either `png` or `jpg` or `webm` (Android). Defaults to `png`.
|
|
100
|
+ - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpg)
|
40
|
101
|
- **`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)*.
|
|
102
|
+ - `"tmpfile"` (default): save to a temporary file *(that will only exist for as long as the app is running)*.
|
42
|
103
|
- `"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
|
104
|
- `"data-uri"`: same as `base64` but also includes the [Data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme) header.
|
44
|
105
|
- **`snapshotContentContainer`** *(bool)*: if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height.
|
45
|
106
|
|
46
|
|
-### DEPRECATED `path` option and `dirs` constants
|
|
107
|
+## `releaseCapture(uri)`
|
47
|
108
|
|
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.
|
|
109
|
+This method release a previously captured `uri`. For tmpfile it will clean them out, for other result types it just won't do anything.
|
49
|
110
|
|
50
|
|
-To migrate from this old feature, you have a few solutions:
|
|
111
|
+NB: the tmpfile captures are automatically cleaned out after the app closes, so you might not have to worry about this unless advanced usecases. The `ViewShot` component will use it each time you capture more than once (useful for continuous capture to not leak files).
|
51
|
112
|
|
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.
|
|
113
|
+### Advanced Examples
|
|
114
|
+
|
|
115
|
+[Checkout react-native-view-shot-example](https://github.com/gre/react-native-view-shot-example)
|
55
|
116
|
|
56
|
117
|
## Interoperability Table
|
57
|
118
|
|
|
119
|
+> Snapshots are not guaranteed to be pixel perfect. It also depends on the platform. Here is some difference we have noticed and how to workaround.
|
|
120
|
+
|
58
|
121
|
Model tested: iPhone 6 (iOS), Nexus 5 (Android).
|
59
|
122
|
|
60
|
123
|
| System | iOS | Android | Windows |
|
|
@@ -71,60 +134,44 @@ Model tested: iPhone 6 (iOS), Nexus 5 (Android).
|
71
|
134
|
3. Component itself lacks platform support.
|
72
|
135
|
4. But you can just use the react-native-maps snapshot function: https://github.com/airbnb/react-native-maps#take-snapshot-of-map
|
73
|
136
|
|
74
|
|
-## Caveats
|
|
137
|
+## Troubleshooting / FAQ
|
75
|
138
|
|
76
|
|
-Snapshots are not guaranteed to be pixel perfect. It also depends on the platform. Here is some difference we have noticed and how to workaround.
|
|
139
|
+### Saving to a file?
|
77
|
140
|
|
78
|
|
-- Support of special components like Video / GL views is not guaranteed to work. In case of failure, the `takeSnapshot` promise gets rejected (the library won't crash).
|
79
|
|
-- It's preferable to **use a background color on the view you rasterize** to avoid transparent pixels and potential weirdness that some border appear around texts.
|
|
141
|
+- If you want to save the snapshotted image result to the CameraRoll, just use https://facebook.github.io/react-native/docs/cameraroll.html#savetocameraroll
|
|
142
|
+- If you want to save it to an arbitrary file path, use something like https://github.com/itinance/react-native-fs
|
|
143
|
+- For any more advanced needs, you can write your own (or find another) native module that would solve your use-case.
|
80
|
144
|
|
81
|
|
-### specific to Android implementation
|
|
145
|
+### The snapshot is rejected with an error?
|
82
|
146
|
|
83
|
|
-- you need to make sure `collapsable` is set to `false` if you want to snapshot a **View**. Some content might even need to be wrapped into such `<View collapsable={false}>` to actually make them snapshotable! Otherwise that view won't reflect any UI View. ([found by @gaguirre](https://github.com/gre/react-native-view-shot/issues/7#issuecomment-245302844))
|
84
|
|
-- if you implement a third party library and want to get back a File, you must first resolve the `Uri`. (the `file` result returns an `Uri` so it's consistent with iOS and can be given to APIs like `Image.getSize`)
|
|
147
|
+- Support of special components like Video / GL views is not guaranteed to work. In case of failure, the `captureRef` promise gets rejected (the library won't crash).
|
85
|
148
|
|
86
|
|
-## Getting started
|
|
149
|
+### get a black or blank result or still have an error with simple views?
|
87
|
150
|
|
88
|
|
-```
|
89
|
|
-npm install --save react-native-view-shot
|
90
|
|
-```
|
|
151
|
+Check the **Interoperability Table** above. Some special components are unfortunately not supported. If you have a View that contains one of an unsupported component, the whole snapshot might be compromised as well.
|
91
|
152
|
|
92
|
|
-### Mostly automatic installation
|
|
153
|
+### black background instead of transparency / weird border appear around texts?
|
93
|
154
|
|
94
|
|
-```
|
95
|
|
-react-native link react-native-view-shot
|
96
|
|
-```
|
|
155
|
+- It's preferable to **use a background color on the view you rasterize** to avoid transparent pixels and potential weirdness that some border appear around texts.
|
|
156
|
+
|
|
157
|
+### on Android, getting "Trying to resolve view with tag '{tagID}' which doesn't exist"
|
|
158
|
+
|
|
159
|
+> you need to make sure `collapsable` is set to `false` if you want to snapshot a **View**. Some content might even need to be wrapped into such `<View collapsable={false}>` to actually make them snapshotable! Otherwise that view won't reflect any UI View. ([found by @gaguirre](https://github.com/gre/react-native-view-shot/issues/7#issuecomment-245302844))
|
|
160
|
+
|
|
161
|
+Alternatively, you can use the `ViewShot` component that will have `collapsable={false}` set to solve this problem.
|
97
|
162
|
|
98
|
|
-### Manual installation
|
|
163
|
+### Getting "The content size must not be zero or negative."
|
99
|
164
|
|
100
|
|
-#### iOS
|
|
165
|
+> Make sure you don't snapshot instantly, you need to wait at least there is a first `onLayout` event, or after a timeout, otherwise the View might not be ready yet. (It should also be safe to just wait Image `onLoad` if you have one). If you still have the problem, make sure your view actually have a width and height > 0.
|
101
|
166
|
|
102
|
|
-1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
|
103
|
|
-2. Go to `node_modules` ➜ `react-native-view-shot` and add `RNViewShot.xcodeproj`
|
104
|
|
-3. In XCode, in the project navigator, select your project. Add `libRNViewShot.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
|
105
|
|
-4. Run your project (`Cmd+R`)<
|
|
167
|
+Alternatively, you can use the `ViewShot` component that will wait the first `onLayout`.
|
106
|
168
|
|
107
|
|
-#### Android
|
|
169
|
+### Snapshotted image does not match my width and height but is twice/3-times bigger
|
108
|
170
|
|
109
|
|
-1. Open up `android/app/src/main/java/[...]/MainActivity.java`
|
110
|
|
- - Add `import fr.greweb.reactnativeviewshot.RNViewShotPackage;` to the imports at the top of the file
|
111
|
|
- - Add `new RNViewShotPackage()` to the list returned by the `getPackages()` method
|
112
|
|
-2. Append the following lines to `android/settings.gradle`:
|
113
|
|
- ```
|
114
|
|
- include ':react-native-view-shot'
|
115
|
|
- project(':react-native-view-shot').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-view-shot/android')
|
116
|
|
- ```
|
117
|
|
-3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
|
118
|
|
- ```
|
119
|
|
- compile project(':react-native-view-shot')
|
120
|
|
- ```
|
|
171
|
+This is because the snapshot image result is in real pixel size where the width/height defined in a React Native style are defined in "point" unit. You might want to set width and height option to force a resize. (might affect image quality)
|
121
|
172
|
|
122
|
|
-#### Windows
|
123
|
173
|
|
124
|
|
-1. In Visual Studio, in the solution explorer, right click on your solution then select `Add` ➜ `ExisitingProject`
|
125
|
|
-2. Go to `node_modules` ➜ `react-native-view-shot` and add `RNViewShot.csproj` (UWP) or optionally `RNViewShot.Net46.csproj` (WPF)
|
126
|
|
-3. In Visual Studio, in the solution explorer, right click on your Application project then select `Add` ➜ `Reference`
|
127
|
|
-4. Under the projects tab select `RNViewShot` (UWP) or `RNViewShot.Net46` (WPF)
|
|
174
|
+---
|
128
|
175
|
|
129
|
176
|
## Thanks
|
130
|
177
|
|