• Stars
    star
    2,420
  • Rank 19,011 (Top 0.4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Snapshot a React Native view and save it to an image

react-native-view-shot

Capture a React Native view to an image.

Install

yarn add react-native-view-shot

# In Expo

expo install react-native-view-shot

Make sure react-native-view-shot is correctly linked in Xcode (might require a manual installation, refer to React Native doc).

Before React Native 0.60.x you would have to:

react-native link react-native-view-shot

Since 0.60.x, autolink should just work, on iOS, you'll need to ensure the CocoaPods are installed with:

npx pod-install

High Level API

import ViewShot from "react-native-view-shot";

function ExampleCaptureOnMountManually {
  const ref = useRef();

  useEffect(() => {
    // on mount
    ref.current.capture().then(uri => {
      console.log("do something with ", uri);
    });
  }, []);

  return (
    <ViewShot ref={ref} options={{ fileName: "Your-File-Name", format: "jpg", quality: 0.9 }}>
      <Text>...Something to rasterize...</Text>
    </ViewShot>
  );
}

// alternative
function ExampleCaptureOnMountSimpler {
  const ref = useRef();

  const onCapture = useCallback(uri => {
    console.log("do something with ", uri);
  }, []);

  return (
    <ViewShot onCapture={onCapture} captureMode="mount">
      <Text>...Something to rasterize...</Text>
    </ViewShot>
  );
}

// waiting an image

function ExampleWaitingCapture {
  const ref = useRef();

  const onImageLoad = useCallback(() => {
    ref.current.capture().then(uri => {
      console.log("do something with ", uri);
    })
  }, []);

  return (
    <ViewShot ref={ref}>
      <Text>...Something to rasterize...</Text>
      <Image ... onLoad={onImageLoad} />
    </ViewShot>
  );
}

// capture ScrollView content
// NB: you may need to go the "imperative way" to use snapshotContentContainer with the scrollview ref instead
function ExampleCaptureOnMountSimpler {
  const ref = useRef();

  const onCapture = useCallback(uri => {
    console.log("do something with ", uri);
  }, []);

  return (
    <ScrollView>
      <ViewShot onCapture={onCapture} captureMode="mount">
        <Text>...The Scroll View Content Goes Here...</Text>
      </ViewShot>
    </ScrollView>
  );
}

Props:

  • children: the actual content to rasterize.
  • options: the same options as in captureRef method.
  • captureMode (string):
    • if not defined (default). the capture is not automatic and you need to use the ref and call capture() yourself.
    • "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.)
    • "continuous" EXPERIMENTAL, this will capture A LOT of images continuously. For very specific use-cases.
    • "update" EXPERIMENTAL, this will capture images each time React redraw (on did update). For very specific use-cases.
  • onCapture: when a captureMode is defined, this callback will be called with the capture result.
  • onCaptureFailure: when a captureMode is defined, this callback will be called when a capture fails.

captureRef(view, options) lower level imperative API

import { captureRef } from "react-native-view-shot";

captureRef(viewRef, {
  format: "jpg",
  quality: 0.8,
}).then(
  (uri) => console.log("Image saved to", uri),
  (error) => console.error("Oops, snapshot failed", error)
);

Returns a Promise of the image URI.

  • view is a reference to a React Native component.
  • options may include:
    • fileName (string): (Android only) the file name of the file. Must be at least 3 characters long.
    • 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).
    • format (string): either png or jpg or webm (Android). Defaults to png.
    • quality (number): the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpg)
    • result (string), the method you want to use to save the snapshot, one of:
      • "tmpfile" (default): save to a temporary file (that will only exist for as long as the app is running).
      • "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.
      • "data-uri": same as base64 but also includes the Data URI scheme header.
    • snapshotContentContainer (bool): if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height.
    • [iOS] useRenderInContext (bool): change the iOS snapshot strategy to use method renderInContext instead of drawViewHierarchyInRect which may help for some use cases.

releaseCapture(uri)

This method release a previously captured uri. For tmpfile it will clean them out, for other result types it just won't do anything.

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).

captureScreen() Android and iOS Only

import { captureScreen } from "react-native-view-shot";

captureScreen({
  format: "jpg",
  quality: 0.8,
}).then(
  (uri) => console.log("Image saved to", uri),
  (error) => console.error("Oops, snapshot failed", error)
);

This method will capture the contents of the currently displayed screen as a native hardware screenshot. It does not require a ref input, as it does not work at the view level. This means that ScrollViews will not be captured in their entirety - only the portions currently visible to the user.

Returns a Promise of the image URI.

  • options: the same options as in captureRef method.

Advanced Examples

Checkout react-native-view-shot-example

Interoperability Table

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.

Model tested: iPhone 6 (iOS), Nexus 5 (Android).

System iOS Android Windows
View,Text,Image,.. YES YES YES
WebView YES YES1 YES
gl-react v2 YES NO2 NO3
react-native-video NO NO NO
react-native-maps YES NO4 NO3
react-native-svg YES YES maybe?
react-native-camera Β  NO Β  Β  Β  Β  Β  Β  Β  YES Β  Β  Β  Β  Β  Β  Β  NO 3Β  Β  Β  Β 
  1. Only supported by wrapping a <View collapsable={false}> parent and snapshotting it.
  2. It returns an empty image (not a failure Promise).
  3. Component itself lacks platform support.
  4. But you can just use the react-native-maps snapshot function: https://github.com/airbnb/react-native-maps#take-snapshot-of-map

Performance Optimization

During profiling captured several things that influence on performance:

  1. (de-)allocation of memory for bitmap
  2. (de-)allocation of memory for Base64 output buffer
  3. compression of bitmap to different image formats: PNG, JPG

To solve that in code introduced several new approaches:

  • reusable images, that reduce load on GC;
  • reusable arrays/buffers that also reduce load on GC;
  • RAW image format for avoiding expensive compression;
  • ZIP deflate compression for RAW data, that works faster in compare to Bitmap.compress

more details and code snippet are below.

RAW Images

Introduced a new image format RAW. it correspond a ARGB array of pixels.

Advantages:

  • no compression, so its supper quick. Screenshot taking is less than 16ms;

RAW format supported for zip-base64, base64 and tmpfile result types.

RAW file on disk saved in format: ${width}:${height}|${base64} string.

zip-base64

In compare to BASE64 result string this format fast try to apply zip/deflate compression on screenshot results and only after that convert results to base64 string. In combination zip-base64 + raw we got a super fast approach for capturing screen views and deliver them to the react side.

How to work with zip-base64 and RAW format?

const fs = require("fs");
const zlib = require("zlib");
const PNG = require("pngjs").PNG;
const Buffer = require("buffer").Buffer;

const format = Platform.OS === "android" ? "raw" : "png";
const result = Platform.OS === "android" ? "zip-base64" : "base64";

captureRef(this.ref, { result, format }).then((data) => {
  // expected pattern 'width:height|', example: '1080:1731|'
  const resolution = /^(\d+):(\d+)\|/g.exec(data);
  const width = (resolution || ["", 0, 0])[1];
  const height = (resolution || ["", 0, 0])[2];
  const base64 = data.substr((resolution || [""])[0].length || 0);

  // convert from base64 to Buffer
  const buffer = Buffer.from(base64, "base64");
  // un-compress data
  const inflated = zlib.inflateSync(buffer);
  // compose PNG
  const png = new PNG({ width, height });
  png.data = inflated;
  const pngData = PNG.sync.write(png);
  // save composed PNG
  fs.writeFileSync(output, pngData);
});

Keep in mind that packaging PNG data is a CPU consuming operation as a zlib.inflate.

Hint: use process.fork() approach for converting raw data into PNGs.

Note: code is tested in large commercial project.

Note #2: Don't forget to add packages into your project:

yarn add pngjs
yarn add zlib

Troubleshooting / FAQ

Saving to a file?

The snapshot is rejected with an error?

  • 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).

get a black or blank result or still have an error with simple views?

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.

black background instead of transparency / weird border appear around texts?

  • 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.

on Android, getting "Trying to resolve view with tag '{tagID}' which doesn't exist"

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)

Alternatively, you can use the ViewShot component that will have collapsable={false} set to solve this problem.

Getting "The content size must not be zero or negative."

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.

Alternatively, you can use the ViewShot component that will wait the first onLayout.

Snapshotted image does not match my width and height but is twice/3-times bigger

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)

on Android, capture GL Views

A prop may be necessary to properly capture GL Surface View in the view tree:

/**
  * if true and when view is a SurfaceView or have it in the view tree, view will be captured.
  * False by default, because it can have signoficant performance impact
  */
handleGLSurfaceViewOnAndroid?: boolean;

Trying to share the capture result with expo-sharing?

tmpfile or the default capture result works best for this. Just be sure to prepend file:// to result before you call shareAsync.

captureRef(viewRef)
  .then((uri) => Sharing.shareAsync(`file://${uri}`, options)

Thanks

More Repositories

1

gl-react

gl-react – React library to write and compose WebGL shaders
JavaScript
2,866
star
2

gl-react-native-v2

DEPRECATED, Please migrate to latest version of gl-react-native that works nicely with expo-gl and unimodules
Java
1,937
star
3

bezier-easing

cubic-bezier implementation for your JavaScript animation easings – MIT License
JavaScript
1,660
star
4

diaporama

image/video/content slideshow engine providing high quality animation effects including Kenburns Effect and GLSL Transitions.
JavaScript
798
star
5

gl-transition-libs

libraries to run GL Transitions and source code of
JavaScript
756
star
6

illuminated.js

Illuminated.js – 2D lights and shadows rendering engine for HTML5 applications
JavaScript
421
star
7

bezier-easing-editor

Cubic Bezier Curve editor made with React & SVG
JavaScript
325
star
8

deprecated-glsl.js

NOT MAINTAINED prefer the use of http://stack.gl or gl-react – a light Javascript & GLSL library for vizualisation and game purposes (2D or 3D).
JavaScript
286
star
9

gl-react-v2

DEPRECATED =>
JavaScript
265
star
10

gl-react-image-effects

[WIP] universal image app that uses different gl-react components
JavaScript
225
star
11

wavegl

Generate Audio in the GPU and pipe to the Audio Card.
JavaScript
190
star
12

deprecated-flexible-nav

NOT MAINTAINED – Improve your navigation experience - this jQuery lib improves a webpage navigation and helps to visualize different sections. of a document, an article,.. any web page.
CoffeeScript
159
star
13

gl-react-dom-v2

WebGL bindings for React to implement complex effects over images and content, in the descriptive VDOM paradigm
JavaScript
138
star
14

behind-asteroids

"Behind Asteroids, The Dark Side" is a JS13K entry for 2015 – winner in Desktop, Mobile and Community categories
JavaScript
128
star
15

diaporama-maker

[BETA] An image slideshow editor – including KenBurns effect and GLSL Transitions. (performed with diaporama)
JavaScript
99
star
16

qrloop

Encode a big binary blob to a loop of QR codes
TypeScript
90
star
17

transitions.glsl.io

WE HAVE MOVED TO
JavaScript
89
star
18

play2vim

Play framework vim plugin
Vim Script
81
star
19

playpainter

A simple Play 2 framework, Canvas and WebSocket experiment where many users can paint their draws simultaneously on a Canvas.
JavaScript
77
star
20

screenshot-webservice

UNMAINTAINED – Screenshot Webservice is an open-source REST web service to perform web page screenshots.
Scala
71
star
21

playCLI

Play Framework Iteratees + UNIX pipe library
Scala
70
star
22

kenburns

Ken Burns effect for DOM, Canvas2D, WebGL
JavaScript
66
star
23

gl-react-image

Universal gl-react Image that implements resizeMode in OpenGL
JavaScript
59
star
24

dta

Drone Tank Arena is a BattleZone-like FPS made in WebGL made during 7dfps contest.
JavaScript
59
star
25

gre

https://greweb.me/
Rust
57
star
26

zound-live

ZOUND live
JavaScript
56
star
27

ipo

easing library allowing to describe complex easings in JSON
JavaScript
55
star
28

zound

Zound, a PlayFramework 2 audio streaming experiment using Iteratees
Scala
53
star
29

multi-slider

React component for multiple values slider (allocate values)
JavaScript
49
star
30

reactjsconf2016

Example used in gl-react's talk at React.js conf 2016
JavaScript
46
star
31

json-beautify

JSON.stringify with fixed maximum character width.
JavaScript
40
star
32

gl-react-blur

Universal gl-react multi-pass gaussian Blur effect with configurable intensity
JavaScript
38
star
33

one-day-one-plot

=> now merged into https://github.com/gre/gre
Rust
37
star
34

beez

100% web real-time audio experiment using smartphones as effect controller. (tech: Android Chrome + WebRTC + Web Audio API)
JavaScript
35
star
35

deprecated-qajax

NOT MAINTAINED – this library was fun but hey, you can just use https://github.com/github/fetch now :) – Minimal Promise ajax library based on Q
JavaScript
35
star
36

glsl-transitions

OUTDATED – please migrate to gl-transitions
JavaScript
30
star
37

same-game-gravity

The Same Game Gravity Desktop version code - licence GPL v3
JavaScript
30
star
38

gl-react-dom-static-container

StaticContainer for gl-react-dom: render the Surface once, snapshot it and release the WebGL context
JavaScript
30
star
39

json2d

Express vectorial content in JSON using canvas2d directives
JavaScript
28
star
40

smoothstep

the smoothstep() function
JavaScript
26
star
41

webaudio-hooks

web audio & midi VS react hooks
JavaScript
26
star
42

glsl-transition

DEPRECATED – new project =>
JavaScript
21
star
43

zpeech

ZPeech, vowel formant analysis experiment with Web Audio API
JavaScript
21
star
44

jscrush

Minimal version of a JSCrusher to be used for js#k golf contest.
JavaScript
20
star
45

diaporama-react

Diaporama component for React
JavaScript
19
star
46

deprecated-gl-react-inspector

DEPRECATED it will be in gre/gl-react monolithic repo
JavaScript
18
star
47

js1k-starter

A convenient JS1K starter with livereload, jscrushing, multifiles support, shader minification, env code splitting
HTML
16
star
48

WebAppBuilder

Important note: I'm working on a more Makefile compliant way for WebAppBuilder (like i've done in some of my recent libs) | using Rakefile and ant are good alternatives | a lightweight Makefile to build a web app project for multiple platforms. This is a mashup of existing cool stuff like : a small template system (Mustache), SASS with Compass, Javascript minimizer, ...
JavaScript
16
star
49

react-native-webgl-view-shot

React Native WebGL extension to rasterize a view as a GL Texture.
Java
15
star
50

memocart

MEMO CART – lowrezjam 2017 – game
JavaScript
13
star
51

deprecated-qretry

UNMAINTAINED– Promise retry system for Q
JavaScript
13
star
52

timelapse

js13kgames submission - Timelapse, a psychedelic rhythm game - Web Audio API + WebGL (GLSL)
JavaScript
12
star
53

audio-notes

Note frequencies for equal-tempered scale
JavaScript
12
star
54

jardin

[STATUS: project paused. no time to maintain] gre's personal gardening data & tools
JavaScript
11
star
55

webgltexture-loader

load & cache various kind of WebGLTexture with an extensible and loosely coupled system
JavaScript
11
star
56

DEPRECATED_react-native-view-shot-example

DEPRECATED – see updated example in https://github.com/gre/react-native-view-shot (example folder)
JavaScript
11
star
57

deprecated-qimage

UNMAINTAINED no need for a lib, see https://twitter.com/greweb/status/675620261232836608 – Simple Promise Image Loader based on Q
JavaScript
10
star
58

diaporama-recorder

Client side library to record a diaporama and obtain a stream of frames
JavaScript
10
star
59

kenburns-editor

React component to edit a Kenburns effect
JavaScript
10
star
60

ibex

the entry hosted on js13k is broken, please go on ->
JavaScript
10
star
61

glsl-uniforms-editor

UNMAINTAINED – React component with inputs to edit uniforms of a GLSL shader
JavaScript
9
star
62

sliding-window

sliding-window is an unidimensional chunk allocation / free system.
JavaScript
8
star
63

glsl-transition-vignette-grid

OUTDATED – renders a grid of glsl-transition-vignette efficiently (cached + pull of WebGL canvas)
JavaScript
8
star
64

chess-game

NOT MAINTAINED – A sample Chess Game made with HTML5 and CSS3 and targeting multi plateform. (made for "HTML5 Game Most Wanted") - the game is not fully finished but illustrates some concepts explained in the book
JavaScript
8
star
65

twitbot

a Clojure twitter bot engine that uses Google Spreadsheet as a sentence database, made for educational purpose
Clojure
7
star
66

livedraw

livedraw is a real-time collaborative pen plotter stream experience (e.g. twitch)
HTML
7
star
67

gl-react-contrast-saturation-brightness

Universal gl-react which combines Contrast, Saturation and Brightness effects
JavaScript
7
star
68

HTML5-File-Uploader

Asynchronous file upload, using html5 drag and drop if supported. Example with play! framework
JavaScript
6
star
69

gl-react-hue-rotate

Universal gl-react Hue Rotate effect
JavaScript
6
star
70

zampling

a simple audio editor built with Web Audio API
JavaScript
6
star
71

playCLI-examples

Presentation slides and Examples for playCLI
Scala
6
star
72

gl-react-color-matrix

Universal gl-react effect to apply 4x4 rgba color matrix on a content
JavaScript
6
star
73

glsl-transition-examples

OUTDATED – GLSL Transition Examples
CSS
6
star
74

glsl-transition-vignette

OUTDATED – A React component which display a GLSL Transition as a vignette (with hover and click controls)
JavaScript
6
star
75

deprecated-qanimationframe

DEPRECATED just use requestAnimationFrame– Promisified requestAnimationFrame with Q
JavaScript
6
star
76

workshop-gl-react-expo

JavaScript
5
star
77

Battle-Brushes

HTML5 Canvas game - brushes try to paint the best surface on screen
JavaScript
5
star
78

same-game

a same game in HTML canvas
JavaScript
5
star
79

ld29

Anthill, a game made for LudumDare 29
JavaScript
5
star
80

glsldoc

a JSON-structured documentation of all WebGL GLSL predefined functions, constants, types, qualifiers,...
5
star
81

blazing-race

Blazing Race is a HTML5 against-the-clock platform game where you control a fireball with your mouse and you try to light candles.
JavaScript
5
star
82

ld25

Ludum Dare 25 "You are the Villain" submission - HTML5 game
JavaScript
5
star
83

deprecated-kenburns-webgl

DEPRECATED use [email protected] – Ken Burns effect – webgl implementation
JavaScript
5
star
84

backbone-extend-standalone

Standalone version of Backbone's extend
JavaScript
4
star
85

Play-completion

a bash completion for Play! Framework
4
star
86

react-json2d

JavaScript
4
star
87

morpion-solitaire

A morpion solitaire game implementation in C using ncurses.
C
4
star
88

audio-chunks

slice/append/insert/subset/copy operations on AudioBuffer linked-list chunks
JavaScript
4
star
89

shape-editor

A graphic editor in Java made for an university project.
Java
3
star
90

rect-crop

Crop a dimension in a viewport: Compute a rectangle from a zoom ratio and a center point while preserving the dimension ratio.
JavaScript
3
star
91

rect-clamp

Constraint a Rectangle into another by preserving the ratio.
JavaScript
3
star
92

bezier-easing-picker

React component which allows to pick predefined bezier curve
JavaScript
3
star
93

deprecated-kenburns-dom

DEPRECATED use [email protected] – Ken Burns effect – DOM implementation
JavaScript
3
star
94

gl-react-negative

Universal gl-react negative effect
JavaScript
3
star
95

Bee--Hornets-and-flowers

A WebWorkers and Canvas demo. You control the bee and have to consume flowers pollen and avoid hornets collision.
JavaScript
3
star
96

deprecated-kenburns-core

DEPRECATED use [email protected] – Ken Burns effect – core
JavaScript
3
star
97

rust-generative-web-setup-example

JavaScript
3
star
98

js13k-2017

AMAZ3D is a game, made in a few days for js13k 2017 gamejam.
JavaScript
3
star
99

ld41

Tetrikaruga – entry for LD41 gamejam
JavaScript
3
star
100

ld28

LudumDare 28 - You Only Get One
JavaScript
3
star