expo-camera
Version:
A React component that renders a preview for the device's either front or back camera. Camera's parameters like zoom, auto focus, white balance and flash mode are adjustable. With expo-camera, one can also take photos and record videos that are saved to t
217 lines • 8.11 kB
JavaScript
import { UnavailabilityError } from '@unimodules/core';
import mapValues from 'lodash.mapvalues';
import PropTypes from 'prop-types';
import React from 'react';
import { findNodeHandle, Platform, ViewPropTypes } from 'react-native';
import ExponentCamera from './ExponentCamera';
import _CameraManager from './ExponentCameraManager';
// TODO: Bacon: Fix multiplatform
const CameraManager = _CameraManager;
const EventThrottleMs = 500;
const _PICTURE_SAVED_CALLBACKS = {};
let _GLOBAL_PICTURE_ID = 1;
function ensurePictureOptions(options) {
let pictureOptions = options || {};
if (!pictureOptions || typeof pictureOptions !== 'object') {
pictureOptions = {};
}
if (!pictureOptions.quality) {
pictureOptions.quality = 1;
}
if (pictureOptions.onPictureSaved) {
const id = _GLOBAL_PICTURE_ID++;
_PICTURE_SAVED_CALLBACKS[id] = pictureOptions.onPictureSaved;
pictureOptions.id = id;
pictureOptions.fastMode = true;
}
return pictureOptions;
}
function ensureRecordingOptions(options) {
let recordingOptions = options || {};
if (!recordingOptions || typeof recordingOptions !== 'object') {
recordingOptions = {};
}
else if (typeof recordingOptions.quality === 'string') {
recordingOptions.quality = Camera.Constants.VideoQuality[recordingOptions.quality];
}
return recordingOptions;
}
function ensureNativeProps(options) {
let props = options || {};
if (!props || typeof props !== 'object') {
props = {};
}
const newProps = mapValues(props, convertProp);
const propsKeys = Object.keys(newProps);
// barCodeTypes is deprecated
if (!propsKeys.includes('barCodeScannerSettings') && propsKeys.includes('barCodeTypes')) {
newProps.barCodeScannerSettings = {
barCodeTypes: newProps.barCodeTypes,
};
}
if (props.onBarCodeScanned) {
newProps.barCodeScannerEnabled = true;
}
if (props.onFacesDetected) {
newProps.faceDetectorEnabled = true;
}
if (Platform.OS !== 'android') {
delete newProps.ratio;
delete newProps.useCamera2Api;
}
return newProps;
}
function convertProp(value, key) {
if (typeof value === 'string' && Camera.ConversionTables[key]) {
return Camera.ConversionTables[key][value];
}
return value;
}
function _onPictureSaved({ nativeEvent }) {
const { id, data } = nativeEvent;
const callback = _PICTURE_SAVED_CALLBACKS[id];
if (callback) {
callback(data);
delete _PICTURE_SAVED_CALLBACKS[id];
}
}
export default class Camera extends React.Component {
constructor() {
super(...arguments);
this._lastEvents = {};
this._lastEventsTimes = {};
this._onCameraReady = () => {
if (this.props.onCameraReady) {
this.props.onCameraReady();
}
};
this._onMountError = ({ nativeEvent }) => {
if (this.props.onMountError) {
this.props.onMountError(nativeEvent);
}
};
this._onObjectDetected = (callback) => ({ nativeEvent }) => {
const { type } = nativeEvent;
if (this._lastEvents[type] &&
this._lastEventsTimes[type] &&
JSON.stringify(nativeEvent) === this._lastEvents[type] &&
new Date().getTime() - this._lastEventsTimes[type].getTime() < EventThrottleMs) {
return;
}
if (callback) {
callback(nativeEvent);
this._lastEventsTimes[type] = new Date();
this._lastEvents[type] = JSON.stringify(nativeEvent);
}
};
this._setReference = (ref) => {
if (ref) {
this._cameraRef = ref;
// TODO: Bacon: Make this one...
if (Platform.OS === 'web') {
this._cameraHandle = ref;
}
else {
this._cameraHandle = findNodeHandle(ref);
}
}
else {
this._cameraRef = null;
this._cameraHandle = null;
}
};
}
async takePictureAsync(options) {
const pictureOptions = ensurePictureOptions(options);
return await CameraManager.takePicture(pictureOptions, this._cameraHandle);
}
async getSupportedRatiosAsync() {
if (!CameraManager.getSupportedRatios) {
throw new UnavailabilityError('Camera', 'getSupportedRatiosAsync');
}
return await CameraManager.getSupportedRatios(this._cameraHandle);
}
async getAvailablePictureSizesAsync(ratio) {
if (!CameraManager.getAvailablePictureSizes) {
throw new UnavailabilityError('Camera', 'getAvailablePictureSizesAsync');
}
return await CameraManager.getAvailablePictureSizes(ratio, this._cameraHandle);
}
async recordAsync(options) {
if (!CameraManager.record) {
throw new UnavailabilityError('Camera', 'recordAsync');
}
const recordingOptions = ensureRecordingOptions(options);
return await CameraManager.record(recordingOptions, this._cameraHandle);
}
stopRecording() {
if (!CameraManager.stopRecording) {
throw new UnavailabilityError('Camera', 'stopRecording');
}
CameraManager.stopRecording(this._cameraHandle);
}
pausePreview() {
if (!CameraManager.pausePreview) {
throw new UnavailabilityError('Camera', 'pausePreview');
}
CameraManager.pausePreview(this._cameraHandle);
}
resumePreview() {
if (!CameraManager.resumePreview) {
throw new UnavailabilityError('Camera', 'resumePreview');
}
CameraManager.resumePreview(this._cameraHandle);
}
render() {
const nativeProps = ensureNativeProps(this.props);
const onBarCodeScanned = this._onObjectDetected(this.props.onBarCodeScanned);
const onFacesDetected = this._onObjectDetected(this.props.onFacesDetected);
return (<ExponentCamera {...nativeProps} ref={this._setReference} onCameraReady={this._onCameraReady} onMountError={this._onMountError} onBarCodeScanned={onBarCodeScanned} onFacesDetected={onFacesDetected} onPictureSaved={_onPictureSaved}/>);
}
}
Camera.Constants = {
Type: CameraManager.Type,
FlashMode: CameraManager.FlashMode,
AutoFocus: CameraManager.AutoFocus,
WhiteBalance: CameraManager.WhiteBalance,
VideoQuality: CameraManager.VideoQuality,
VideoStabilization: CameraManager.VideoStabilization || {},
};
// Values under keys from this object will be transformed to native options
Camera.ConversionTables = {
type: CameraManager.Type,
flashMode: CameraManager.FlashMode,
autoFocus: CameraManager.AutoFocus,
whiteBalance: CameraManager.WhiteBalance,
};
Camera.propTypes = {
...ViewPropTypes,
zoom: PropTypes.number,
ratio: PropTypes.string,
focusDepth: PropTypes.number,
onMountError: PropTypes.func,
pictureSize: PropTypes.string,
onCameraReady: PropTypes.func,
useCamera2Api: PropTypes.bool,
onBarCodeScanned: PropTypes.func,
barCodeScannerSettings: PropTypes.object,
onFacesDetected: PropTypes.func,
faceDetectorSettings: PropTypes.object,
type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
videoStabilizationMode: PropTypes.number,
whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
autoFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
};
Camera.defaultProps = {
zoom: 0,
ratio: '4:3',
focusDepth: 0,
faceDetectorSettings: {},
type: CameraManager.Type.back,
autoFocus: CameraManager.AutoFocus.on,
flashMode: CameraManager.FlashMode.off,
whiteBalance: CameraManager.WhiteBalance.auto,
};
export const Constants = Camera.Constants;
//# sourceMappingURL=Camera.js.map