Merge pull request #350 from aarongrider/torch-mode

Add torch mode
This commit is contained in:
Aaron Grider 2021-01-11 11:34:37 -08:00 committed by GitHub
commit ffcf76d0fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 105 additions and 106 deletions

View File

@ -67,6 +67,9 @@ import { CameraScreen } from 'react-native-camera-kit';
}}
cameraFlipImage={require('path/to/image')}
captureButtonImage={require('path/to/image')}
torchOnImage={require('path/to/image')}
torchOffImage={require('path/to/image')}
hideControls={false} // (default false) optional, hides camera controls
showCapturedImageCount={false} // (default false) optional, show count for photos taken during that capture session
/>
```
@ -80,14 +83,10 @@ Additionally, the camera screen can be used for barcode scanning
...
// Barcode props
scanBarcode={true}
laserColor={'blue'}
frameColor={'yellow'}
onReadCode={(event) => Alert.alert('Qr code found')} //optional
hideControls={false} //(default false) optional, hide buttons and additional controls on top and bottom of screen
showFrame={true} //(default false) optional, show frame with transparent layer (qr code or barcode will be read on this area ONLY), start animation for scanner,that stoped when find any code. Frame always at center of the screen
offsetForScannerFrame={10} //(default 30) optional, offset from left and right side of the screen
heightForScannerFrame={300} //(default 200) optional, change height of the scanner frame
colorForScannerFrame={'red'} //(default white) optional, change colot of the scanner frame
laserColor='red' // (default red) optional, color of laser in scanner frame
frameColor='white' // (default white) optional, color of border of scanner frame
/>
```
@ -114,6 +113,7 @@ import { Camera } from 'react-native-camera-kit';
| `flashMode` | `'on'`/`'off'`/`'auto'` | Camera flash mode. Default: `auto` |
| `focusMode` | `'on'`/`'off'` | Camera focus mode. Default: `on` |
| `zoomMode` | `'on'`/`'off'` | Enable pinch to zoom camera. Default: `on` |
| `torchMode` | `'on'`/`'off'` | Toggle flash light when camera is active. Default: `off` |
| `ratioOverlay` | `['int':'int', ...]` | Show a guiding overlay in the camera preview for the selected ratio. Does not crop image as of v9.0. Example: `['16:9', '1:1', '3:4']` |
| `ratioOverlayColor` | Color | Any color with alpha. Default: `'#ffffff77'` |
| `resetFocusTimeout` | Number | iOS only. Dismiss tap to focus after this many milliseconds. Default `0` (disabled). Example: `5000` is 5 seconds. |

View File

@ -192,7 +192,7 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs
orientationListener!!.enable()
// Contain camera feed image within component bounds, centered
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER
viewFinder.scaleType = PreviewView.ScaleType.FILL_CENTER
// Tap to focus
viewFinder.setOnTouchListener { _, event ->
@ -375,7 +375,6 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs
val imageCapture = imageCapture ?: return
val camera = camera ?: return
when (mode) {
"torch" -> camera.cameraControl.enableTorch(true)
"on" -> {
camera.cameraControl.enableTorch(false)
imageCapture.flashMode = ImageCapture.FLASH_MODE_ON
@ -391,6 +390,22 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs
}
}
fun setTorchMode(mode: String?) {
val imageCapture = imageCapture ?: return
val camera = camera ?: return
when (mode) {
"on" -> {
camera.cameraControl.enableTorch(true)
}
"off" -> {
camera.cameraControl.enableTorch(false)
}
else -> { // 'auto' and any wrong values
camera.cameraControl.enableTorch(false)
}
}
}
fun setAutoFocus(mode: String = "on") {
autoFocus = mode
when(mode) {

View File

@ -61,6 +61,11 @@ class CKCameraManager : SimpleViewManager<CKCamera>() {
view.setFlashMode(mode)
}
@ReactProp(name = "torchMode")
fun setTorchMode(view: CKCamera, mode: String?) {
view.setTorchMode(mode)
}
@ReactProp(name = "focusMode")
fun setFocusMode(view: CKCamera, mode: String) {
view.setAutoFocus(mode)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -38,16 +38,12 @@ export default class BarcodeScreenExample extends Component {
}}
scanBarcode
showFrame
laserColor={'yellow'}
frameColor={'yellow'}
surfaceColor={'black'}
laserColor="red"
frameColor="white"
onReadCode={(event) => {
this.setState({ example: CheckingScreen, value: event.nativeEvent.codeStringValue });
}}
hideControls
// offsetForScannerFrame = {10}
// heightForScannerFrame = {300}
colorForScannerFrame={'blue'}
/>
);
}

View File

@ -14,6 +14,7 @@ export default class CameraExample extends Component {
flashMode="auto" // on/off/auto(default)
focusMode="on" // off/on(default)
zoomMode="on" // off/on(default)
torchMode="off" // on/off(default)
ratioOverlay="1:1" // optional
ratioOverlayColor="#00000077" // optional
resetFocusTimeout={0}

View File

@ -25,6 +25,8 @@ export default class CameraScreenExample extends Component {
}}
cameraFlipImage={require('../images/cameraFlipIcon.png')}
captureButtonImage={require('../images/cameraButton.png')}
torchOnImage={require('../images/torchOn.png')}
torchOffImage={require('../images/torchOff.png')}
showCapturedImageCount
/>
);

View File

@ -22,18 +22,6 @@ typedef NS_ENUM(NSInteger, CKCameraType) {
@end
typedef NS_ENUM(NSInteger, CKCameraTorchMode) {
CKCameraTorchModeAuto,
CKCameraTorchModeOn,
CKCameraTorchModeOff
};
@interface RCTConvert(CKCameraTorchMode)
+ (CKCameraTorchMode)CKCameraTorchMode:(id)json;
@end
typedef NS_ENUM(NSInteger, CKCameraFlashMode) {
CKCameraFlashModeAuto,
CKCameraFlashModeOn,
@ -46,6 +34,16 @@ typedef NS_ENUM(NSInteger, CKCameraFlashMode) {
@end
typedef NS_ENUM(NSInteger, CKCameraTorchMode) {
CKCameraTorchModeOn,
CKCameraTorchModeOff
};
@interface RCTConvert(CKCameraTorchMode)
+ (CKCameraTorchMode)CKCameraTorchMode:(id)json;
@end
typedef NS_ENUM(NSInteger, CKCameraFocusMode) {
CKCameraFocusModeOn,

View File

@ -33,12 +33,9 @@ RCT_ENUM_CONVERTER(CKCameraType, (@{
@implementation RCTConvert(CKCameraTorchMode)
RCT_ENUM_CONVERTER(CKCameraTorchMode, (@{
@"auto": @(AVCaptureTorchModeAuto),
@"on": @(AVCaptureTorchModeOn),
@"off": @(AVCaptureTorchModeOff)
}), AVCaptureTorchModeAuto, integerValue)
@end
@implementation RCTConvert(CKCameraFlashMode)
@ -102,13 +99,12 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
@property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
// scanner options
@property (nonatomic, strong) NSDictionary *scannerOptions;
@property (nonatomic) BOOL showFrame;
@property (nonatomic) UIView *greenScanner;
@property (nonatomic) UIView *scannerView;
@property (nonatomic, strong) RCTDirectEventBlock onReadCode;
@property (nonatomic) CGFloat frameOffset;
@property (nonatomic) CGFloat heightFrame;
@property (nonatomic) CGFloat frameHeight;
@property (nonatomic, strong) UIColor *laserColor;
@property (nonatomic, strong) UIColor *frameColor;
@property (nonatomic) UIView * dataReadingFrame;
@ -208,6 +204,11 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
self.zoomMode = CKCameraZoomModeOn;
self.flashMode = CKCameraFlashModeAuto;
self.focusMode = CKCameraFocusModeOn;
self.frameColor = [UIColor whiteColor];
self.laserColor = [UIColor redColor];
self.frameOffset = 30;
self.frameHeight = 200;
}
return self;
@ -288,6 +289,18 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
}
}
- (void)setLaserColor:(UIColor *)color {
if (color != nil) {
_laserColor = color;
}
}
- (void)setFrameColor:(UIColor *)color {
if (color != nil) {
_frameColor = color;
}
}
-(void)setupCaptureSession {
// Setup the capture session.
// In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
@ -884,29 +897,15 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
}
}
- (void)setScannerOptions:(NSDictionary *)scannerOptions {
if (scannerOptions[offsetForScannerFrame]) {
self.frameOffset = [scannerOptions[offsetForScannerFrame] floatValue];
}
if (scannerOptions[heightForScannerFrame]) {
self.heightFrame = [scannerOptions[heightForScannerFrame] floatValue];
}
if (scannerOptions[colorForFrame]) {
UIColor *acolor = [RCTConvert UIColor:scannerOptions[colorForFrame]];
self.frameColor = (acolor) ? acolor : [UIColor whiteColor];
}
}
- (void)addFrameForScanner {
CGFloat frameWidth = self.bounds.size.width - 2 * self.frameOffset;
if (!self.dataReadingFrame) {
self.dataReadingFrame = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frameWidth, self.heightFrame)]; //
self.dataReadingFrame = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frameWidth, self.frameHeight)]; //
self.dataReadingFrame.center = self.center;
self.dataReadingFrame.backgroundColor = [UIColor clearColor];
[self createCustomFramesForView:self.dataReadingFrame];
[self addSubview:self.dataReadingFrame];
[self startAnimatingScanner:self.dataReadingFrame];
[self addVisualEffects:self.dataReadingFrame.frame];
@ -955,7 +954,6 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
UIView * cornerView = [[UIView alloc] initWithFrame:CGRectMake(x, y, width, height)];
cornerView.backgroundColor = self.frameColor;
[frameView addSubview:cornerView];
}
}
@ -964,38 +962,37 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{
topView.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.4];
[self addSubview:topView];
UIView *leftSideView = [[UIView alloc] initWithFrame:CGRectMake(0, inputRect.origin.y, self.frameOffset, self.heightFrame)]; //paddingForScanner scannerHeight
UIView *leftSideView = [[UIView alloc] initWithFrame:CGRectMake(0, inputRect.origin.y, self.frameOffset, self.frameHeight)]; //paddingForScanner scannerHeight
leftSideView.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.4];
[self addSubview:leftSideView];
UIView *rightSideView = [[UIView alloc] initWithFrame:CGRectMake(inputRect.size.width + self.frameOffset, inputRect.origin.y, self.frameOffset, self.heightFrame)];
UIView *rightSideView = [[UIView alloc] initWithFrame:CGRectMake(inputRect.size.width + self.frameOffset, inputRect.origin.y, self.frameOffset, self.frameHeight)];
rightSideView.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.4];
[self addSubview:rightSideView];
UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, inputRect.origin.y + self.heightFrame, self.frame.size.width,
self.frame.size.height - inputRect.origin.y - self.heightFrame)];
UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, inputRect.origin.y + self.frameHeight, self.frame.size.width,
self.frame.size.height - inputRect.origin.y - self.frameHeight)];
bottomView.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.4];
[self addSubview:bottomView];
}
- (void)startAnimatingScanner:(UIView *)inputView {
if (!self.greenScanner) {
self.greenScanner = [[UIView alloc] initWithFrame:CGRectMake(2, 0, inputView.frame.size.width - 4, 2)];
self.greenScanner.backgroundColor = [UIColor whiteColor];
if (!self.scannerView) {
self.scannerView = [[UIView alloc] initWithFrame:CGRectMake(2, 0, inputView.frame.size.width - 4, 2)];
self.scannerView.backgroundColor = self.laserColor;
}
if (self.greenScanner.frame.origin.y != 0) {
[self.greenScanner setFrame:CGRectMake(2, 0, inputView.frame.size.width - 4, 2)];
if (self.scannerView.frame.origin.y != 0) {
[self.scannerView setFrame:CGRectMake(2, 0, inputView.frame.size.width - 4, 2)];
}
[inputView addSubview:self.greenScanner];
[inputView addSubview:self.scannerView];
[UIView animateWithDuration:3 delay:0 options:(UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat) animations:^{
CGFloat middleX = inputView.frame.size.width / 2;
self.greenScanner.center = CGPointMake(middleX, inputView.frame.size.height - 1);
self.scannerView.center = CGPointMake(middleX, inputView.frame.size.height - 1);
} completion:^(BOOL finished) {}];
}
- (void)stopAnimatingScanner {
[self.greenScanner removeFromSuperview];
[self.scannerView removeFromSuperview];
}
//Observer actions

View File

@ -19,15 +19,16 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(cameraType, CKCameraType)
RCT_EXPORT_VIEW_PROPERTY(flashMode, CKCameraFlashMode)
RCT_EXPORT_VIEW_PROPERTY(torchMode, CKCameraTorchMode)
RCT_EXPORT_VIEW_PROPERTY(focusMode, CKCameraFocusMode)
RCT_EXPORT_VIEW_PROPERTY(zoomMode, CKCameraZoomMode)
RCT_EXPORT_VIEW_PROPERTY(ratioOverlay, NSString)
RCT_EXPORT_VIEW_PROPERTY(ratioOverlayColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(onReadCode, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(scannerOptions, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(showFrame, BOOL)
RCT_EXPORT_VIEW_PROPERTY(laserColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(frameColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(resetFocusTimeout, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(resetFocusWhenMotionDetected, BOOL)
RCT_EXPORT_VIEW_PROPERTY(saveToCameraRoll, BOOL)

View File

@ -9,7 +9,6 @@ import {
Dimensions,
Platform,
SafeAreaView,
processColor,
} from 'react-native';
import _ from 'lodash';
import Camera from './Camera';
@ -17,10 +16,6 @@ import Camera from './Camera';
const FLASH_MODE_AUTO = 'auto';
const FLASH_MODE_ON = 'on';
const FLASH_MODE_OFF = 'off';
const TORCH_MODE_ON = 'on';
const TORCH_MODE_OFF = 'off';
const OFFSET_FRAME = 30;
const FRAME_HEIGHT = 200;
const { width, height } = Dimensions.get('window');
@ -35,18 +30,15 @@ export type Props = {
allowCaptureRetake: boolean,
cameraRatioOverlay: any,
showCapturedImageCount?: boolean,
scannerOptions: any,
offsetForScannerFrame: any,
heightForScannerFrame: any,
colorForScannerFrame: any,
captureButtonImage: any,
cameraFlipImage: any,
hideControls: any,
showFrame: any,
captureButtonImage: any,
scanBarcode: any,
laserColor: any,
frameColor: any,
surfaceColor: any,
torchOnImage: any,
torchOffImage: any,
onReadCode: (any) => void;
onBottomButtonPressed: (any) => void;
}
@ -54,12 +46,11 @@ export type Props = {
type State = {
captureImages: any[],
flashData: any,
torchData: boolean,
torchMode: boolean,
ratios: any[],
ratioArrayPosition: number,
imageCaptured: any,
captured: boolean,
scannerOptions: any,
cameraType: CameraType,
}
@ -97,28 +88,21 @@ export default class CameraScreen extends Component<Props, State> {
this.state = {
captureImages: [],
flashData: this.flashArray[this.currentFlashArrayPosition],
torchData: false,
torchMode: false,
ratios: [],
ratioArrayPosition: -1,
imageCaptured: false,
captured: false,
scannerOptions: {},
cameraType: CameraType.Back,
};
this.onSetFlash = this.onSetFlash.bind(this);
this.onSetTorch = this.onSetTorch.bind(this);
this.onSwitchCameraPressed = this.onSwitchCameraPressed.bind(this);
}
componentDidMount() {
const scannerOptions = this.getScannerOptions();
let ratios = [];
if (this.props.cameraRatioOverlay) {
ratios = this.props.cameraRatioOverlay.ratios || [];
}
this.setState({
scannerOptions,
ratios: ratios || [],
ratioArrayPosition: ratios.length > 0 ? 0 : -1,
});
@ -128,18 +112,6 @@ export default class CameraScreen extends Component<Props, State> {
return !!(this.props.allowCaptureRetake && !_.isUndefined(this.state.imageCaptured));
}
getScannerOptions() {
const scannerOptions = this.props.scannerOptions || {};
scannerOptions.offsetFrame = this.props.offsetForScannerFrame || OFFSET_FRAME;
scannerOptions.frameHeight = this.props.heightForScannerFrame || FRAME_HEIGHT;
if (this.props.colorForScannerFrame) {
scannerOptions.colorForFrame = processColor(this.props.colorForScannerFrame);
} else {
scannerOptions.colorForFrame = processColor('white');
}
return scannerOptions;
}
renderFlashButton() {
return (
!this.isCaptureRetakeMode() && (
@ -154,11 +126,25 @@ export default class CameraScreen extends Component<Props, State> {
);
}
renderTorchButton() {
return (
!this.isCaptureRetakeMode() && (
<TouchableOpacity style={{ paddingHorizontal: 15 }} onPress={() => this.onSetTorch()}>
<Image
style={{ flex: 1, justifyContent: 'center' }}
source={this.state.torchMode ? this.props.torchOnImage : this.props.torchOffImage}
resizeMode="contain"
/>
</TouchableOpacity>
)
);
}
renderSwitchCameraButton() {
return (
this.props.cameraFlipImage &&
!this.isCaptureRetakeMode() && (
<TouchableOpacity style={{ paddingHorizontal: 15 }} onPress={this.onSwitchCameraPressed}>
<TouchableOpacity style={{ paddingHorizontal: 15 }} onPress={() => this.onSwitchCameraPressed()}>
<Image
style={{ flex: 1, justifyContent: 'center' }}
source={this.props.cameraFlipImage}
@ -175,6 +161,7 @@ export default class CameraScreen extends Component<Props, State> {
<SafeAreaView style={styles.topButtons}>
{this.renderFlashButton()}
{this.renderSwitchCameraButton()}
{this.renderTorchButton()}
</SafeAreaView>
)
);
@ -191,6 +178,7 @@ export default class CameraScreen extends Component<Props, State> {
style={{ flex: 1, justifyContent: 'flex-end' }}
cameraType={this.state.cameraType}
flashMode={this.state.flashData.mode}
torchMode={this.state.torchMode ? 'on' : 'off'}
focusMode={this.props.focusMode}
zoomMode={this.props.zoomMode}
ratioOverlay={this.state.ratios[this.state.ratioArrayPosition]}
@ -199,9 +187,7 @@ export default class CameraScreen extends Component<Props, State> {
scanBarcode={this.props.scanBarcode}
laserColor={this.props.laserColor}
frameColor={this.props.frameColor}
surfaceColor={this.props.surfaceColor}
onReadCode={this.props.onReadCode}
scannerOptions={this.state.scannerOptions}
/>
)}
</View>
@ -303,20 +289,18 @@ export default class CameraScreen extends Component<Props, State> {
}
onSwitchCameraPressed() {
const direction = this.state.type === CameraType.Back ? CameraType.Front : CameraType.Back;
this.setState({ type: direction });
const direction = this.state.cameraType === CameraType.Back ? CameraType.Front : CameraType.Back;
this.setState({ cameraType: direction });
}
async onSetFlash() {
onSetFlash() {
this.currentFlashArrayPosition = (this.currentFlashArrayPosition + 1) % 3;
const newFlashData = this.flashArray[this.currentFlashArrayPosition];
this.setState({ flashData: newFlashData });
}
onSetTorch() {
const newTorchData = !this.state.torchData;
this.setState({ torchData: newTorchData });
newTorchData ? this.camera.setTorchMode(TORCH_MODE_ON) : this.camera.setTorchMode(TORCH_MODE_OFF);
this.setState({ torchMode: !this.state.torchMode });
}
async onCaptureImagePressed() {