react-native-view-capture
v1.0.0
Published
Zero-dependency utilities for React Native view capture — options builders, format helpers, URI/base64 converters, dimension tools, filename generators, share payloads
Maintainers
Readme
react-native-view-capture
Zero-dependency utilities for React Native view capture.
Options builders, format/MIME helpers, URI & base64 converters, dimension scaling, crop helpers, filename generators, share payloads, watermark configs, native module bridge, batch capture, retry logic, and React hook factories — the full JavaScript layer for capturing views in React Native.
npm install react-native-view-captureNative module required for
captureRefandcaptureScreen. Wire up your native module withregisterNativeModule(). All other utilities are pure JS and work anywhere.
Setup
import { NativeModules } from 'react-native';
import { registerNativeModule } from 'react-native-view-capture';
// Register once at app startup (e.g. index.js)
registerNativeModule(NativeModules.RNViewCapture);Capturing a view
import { useRef } from 'react';
import { View, Button } from 'react-native';
import { captureRef } from 'react-native-view-capture';
function MyScreen() {
const ref = useRef(null);
async function onCapture() {
const uri = await captureRef(ref, { format: 'jpg', quality: 0.9 });
console.log(uri); // file:///tmp/capture_20240615_143022.jpg
}
return (
<>
<View ref={ref}>
{/* … */}
</View>
<Button title="Capture" onPress={onCapture} />
</>
);
}captureRef(ref, opts?)
| Option | Type | Default | Description |
|---|---|---|---|
| format | 'png' \| 'jpg' \| 'webp' | 'png' | Output format |
| quality | number 0–1 | 1.0 | JPEG/WebP quality |
| result | 'tmpfile' \| 'file' \| 'base64' \| 'data-uri' | 'tmpfile' | Where to return the result |
| width | number | — | Override output width |
| height | number | — | Override output height |
| path | string | — | Output path when result: 'file' |
| snapshotContentContainer | boolean | false | Capture full scroll content |
| useRenderInContext | boolean | false | iOS: avoid GPU surfaces |
| handleGLSurfaceViewOnAndroid | boolean | false | Android GL surfaces |
captureScreen(opts?)
Same options as captureRef, captures the entire screen.
releaseCapture(uri)
Release a temp file once you're done with it.
Hook factory
import { useRef, useCallback } from 'react';
import { createUseViewCapture } from 'react-native-view-capture';
const useViewCapture = createUseViewCapture({ useRef, useCallback });
function MyComponent() {
const { ref, capture } = useViewCapture({ format: 'png' });
return (
<View ref={ref}>
<Button title="Save" onPress={() => capture()} />
</View>
);
}Capture history hook
import { useState, useCallback } from 'react';
import { createUseCaptureHistory } from 'react-native-view-capture';
const useCaptureHistory = createUseCaptureHistory({ useState, useCallback });
function GalleryScreen() {
const { history, push, clear, last } = useCaptureHistory(10);
async function onCapture() {
const uri = await captureRef(ref);
push(uri);
}
}Batch capture
import { captureRefs, captureRefWithRetry } from 'react-native-view-capture';
// Capture multiple refs in sequence
const uris = await captureRefs([refA, refB, refC], { format: 'jpg' }, { delayMs: 100 });
// Retry on failure
const uri = await captureRefWithRetry(ref, { format: 'png' }, { retries: 3, retryDelayMs: 200 });Options builder
import { buildCaptureOptions, defaultCaptureOptions } from 'react-native-view-capture';
const opts = buildCaptureOptions({ format: 'jpg', quality: 0.85 });
// Validates quality range, unknown format, dimension signs
// Throws RangeError / TypeError on invalid inputFormat helpers
import { mimeTypeForFormat, extensionForMime, formatFromExtension, formatFromMime } from 'react-native-view-capture';
mimeTypeForFormat('jpg') // 'image/jpeg'
mimeTypeForFormat('png') // 'image/png'
extensionForMime('image/jpeg') // 'jpg'
formatFromExtension('photo.webp') // 'webp'
formatFromMime('image/png') // 'png'URI / base64 utilities
import {
isDataUri, isFileUri, isBase64,
base64ToDataUri, dataUriToBase64, mimeFromDataUri,
parseDataUri, normaliseCaptureResult,
} from 'react-native-view-capture';
isFileUri('file:///tmp/cap.png') // true
isDataUri('data:image/png;base64,...') // true
isBase64('iVBORw0KGgoAAAANSUhEUgAA...') // true
base64ToDataUri(b64, 'png') // 'data:image/png;base64,...'
dataUriToBase64(dataUri) // raw base64 string
mimeFromDataUri(dataUri) // 'image/png'
parseDataUri(dataUri) // { mime: 'image/png', base64: '...' }
// Normalise any result into a unified object
normaliseCaptureResult(uri, 'jpg')
// { type: 'file', uri: 'file:///...', mime: 'image/jpeg' }
// { type: 'base64', base64: '...', uri: 'data:...', mime: 'image/jpeg' }
// { type: 'dataUri', uri: 'data:...', base64: '...', mime: 'image/png' }Dimension helpers
import { scaleDimensions, coverDimensions, normaliseCropRect, absoluteCropRect, aspectRatioString, estimateFileSize } from 'react-native-view-capture';
// Fit within a 800×600 box
scaleDimensions(1920, 1080, 800, 600)
// { width: 800, height: 450, scale: 0.416 }
// Cover a 400×400 thumbnail
coverDimensions(1920, 1080, 400, 400)
// { width: 711, height: 400, scale: 0.37 }
// Normalised crop rect
normaliseCropRect(100, 50, 300, 200, 1200, 800)
// { x: 0.083, y: 0.0625, width: 0.25, height: 0.25 }
aspectRatioString(1920, 1080) // '16:9'
aspectRatioString(1, 1) // '1:1'
estimateFileSize(1080, 1920, 'jpg', 0.85) // ~45000 bytes
estimateFileSize(1080, 1920, 'png') // ~3110400 bytesFilename and path helpers
import { generateFilename, buildFileUri, filenameFromUri, replaceExtension } from 'react-native-view-capture';
generateFilename() // 'capture_20240615_143022.png'
generateFilename({ prefix: 'shot', format: 'jpg', suffix: 'home' })
// 'shot_20240615_143022_home.jpg'
buildFileUri('/tmp/captures', 'shot.png') // 'file:///tmp/captures/shot.png'
filenameFromUri('file:///tmp/cap_123.jpg') // 'cap_123.jpg'
replaceExtension('capture.png', 'webp') // 'capture.webp'Share & export
import { buildSharePayload, buildCameraRollOptions } from 'react-native-view-capture';
import { Share } from 'react-native';
const payload = buildSharePayload(uri, { message: 'Check this out!', title: 'My capture' });
await Share.share(payload);
// CameraRoll
import CameraRoll from '@react-native-camera-roll/camera-roll';
const opts = buildCameraRollOptions(uri, { album: 'My App' });
await CameraRoll.save(uri, opts);Watermark config
import { buildWatermarkConfig, watermarkPosition } from 'react-native-view-capture';
const wm = buildWatermarkConfig('© MyApp 2024', {
position: 'bottom-right',
fontSize: 12,
color: '#ffffff',
opacity: 0.6,
padding: 12,
});
const anchor = watermarkPosition('bottom-right', 1080, 1920, 12);
// { x: 1068, y: 1908, anchor: 'right' }CommonJS
const { captureRef, buildCaptureOptions, normaliseCaptureResult } = require('react-native-view-capture');License
MIT
