Closed rsimbu89 closed 4 years ago
There are some snippet to do this, check issues
@sibelius I tried this ZoomView implementation https://github.com/react-native-community/react-native-camera/issues/1282, But not satisfies with the zoom result. Is there any better solution than this?
Team, Is there any other better solutions?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and i will leave this open.
I implemented this functionality using react-native-gesture-handler module. But is not good enough, the camera does not respond well under continues changes on the zoom prop. Is there any option for this feature? Thanks in advanced
Sorry for the late reply,
Here is the code.
import React, {Component} from "react";
import {PinchGestureHandler, State} from "react-native-gesture-handler";
class PinchGesture extends Component{
constructor(props){
super(props);
}
onPinchGestureEvent({nativeEvent}){
if (nativeEvent.state === State.ACTIVE) {
this.props.onPinchScreen(nativeEvent);
}
}
render(){
return(
<PinchGestureHandler
onGestureEvent={this.onPinchGestureEvent.bind(this)}>
{this.props.children}
</PinchGestureHandler>
);
}
}
export default PinchGesture;
import React, { Component } from "react";
import { View } from "react-native";
import { cameraStyles as styles } from './styles';
import BackButtonCamera from '../buttons/BackButtonCamera';
import { RNCamera } from 'react-native-camera';
/*
* Buttons
*/
import TakeAPicture from '../../components/buttons/camera/TakeAPicture';
import FlashButton from '../../components/buttons/camera/FlashButton';
import ChangeCamera from'../../components/buttons/camera/ChangeCamera';
import GalleryButton from '../../components/buttons/camera/GalleryButton';
import CameraZoomSlider from '../../components/sliders/CameraZoomSlider';
/**
* Gestures
*/
import LongTapGesture from '../../components/gestures/LongTapGesture';
import PinchGesture from '../../components/gestures/PinchGesture';
/**
* Handler
*/
import CameraHandler from '../../modules/helpers/periphericals/CameraHandler';
import RecordBlinkIndicator from "../blinkers/RecordBlinkIndicator";
import VibrationHandler from '../../modules/helpers/periphericals/VibrationHandler';
import SoundHandler from '../../modules/helpers/periphericals/SoundHandler';
class Camera extends Component {
constructor(props) {
super(props);
this.styles = styles;
this.zoomRate = 0.005;
this.helper = new CameraHandler(this);
this.vibrato = new VibrationHandler();
this.sound = null;
this.state = {
// auto - on -off
flashMode: RNCamera.Constants.FlashMode.auto,
// front -> true , back -> false
cameraMode: true,
//Mode counter
// mod -> 0 'auto', mod -> 1, 'off', mod -> 2 'on'
flashModeCounter: 0,
//iconName off -> flash-off, auto -> flash-auto, on -> flash-on
flashButtonName: "flash-auto",
zoom: this.zoomRate,
recordOn: false,
soundLoaded: false
};
}
onPinchGestureEvent(nativeEvent){
this.helper.resolvePinchGesture(nativeEvent);
}
onPressFlashButton(){
this.setState({ flashModeCounter: this.state.flashModeCounter + 1 });
this.helper.resolveOnPressCameraButton();
}
onPressChangeCameraMode(){
this.setState({ cameraMode: ! this.state.cameraMode });
}
takePicture(){
this.sound = new SoundHandler("camera.mp3");
this.vibrato.vibrate();
this.props.onTakePicture(this.camera);
}
onPressBackButton(){
this.props.onPressBackButton();
}
startRecording(){
this.vibrato.vibrate();
this.setState({ recordOn: true });
this.props.onStartRecording(this.camera);
}
stopRecording(){
this.vibrato.vibrate();
this.setState({ recordOn: false });
this.camera.stopRecording();
}
showRecordIndicator(){
if(this.state.recordOn){
return (
<RecordBlinkIndicator />
);
}
}
onChangeZoomValue(newValue){
this.setState({ zoom: newValue })
}
render() {
return(
<View style={ this.styles.container }>
<PinchGesture
onPinchGestureEvent={this.onPinchGestureEvent.bind(this)}
>
<BackButtonCamera
onPress={ this.onPressBackButton.bind(this) }
/>
<CameraZoomSlider
onChangeZoomValue={this.onChangeZoomValue.bind(this)}
/>
{this.showRecordIndicator()}
<View style={{ flex: 1 }}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={styles.preview}
type={ (!this.state.cameraMode) ? RNCamera.Constants.Type.front : RNCamera.Constants.Type.back }
flashMode={this.state.flashMode}
autoFocus={RNCamera.Constants.AutoFocus.on}
androidCameraPermissionOptions={ this.helper.permissionsOptions}
zoom={this.state.zoom}
/>
<View style={this.styles.buttonBarWrapper}>
<ChangeCamera
onPress={this.onPressChangeCameraMode.bind(this)}
/>
<LongTapGesture
onSingleTap={this.takePicture.bind(this)}
onLongTap={this.startRecording.bind(this)}
onLongTapEnd={this.stopRecording.bind(this)}
>
<TakeAPicture />
</LongTapGesture>
{/*
Next release
<GalleryButton
onPress={this.props.onPressGalleryButton}
iconName={this.state.flashButtonName}
/>
*/}
<FlashButton
onPress={this.onPressFlashButton.bind(this)}
iconName={this.state.flashButtonName}
/>
</View>
</View>
</PinchGesture>
</View>
);
}
}
export default Camera;
import { RNCamera } from "react-native-camera";
import FileStorage from '../../helpers/storage/FileStorage';
class CameraHandler{
constructor(cameraComponent){
this.storage = new FileStorage();
// This is the camera component
this.camera = cameraComponent;
this.permissionsOptions = {
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
};
//Camera Options
this.options = {
quality: 0.35,
base64: true,
width: 1280,
mirrorImage:false,
//(can take up to 5 seconds on some devices)
fixOrientation:false,
//"portrait", "portraitUpsideDown", "landscapeLeft" or "landscapeRight"
orientation: "portrait",
doNotSave: false
};
this.optionsRecording = {
/*
*quality. This option specifies the quality of the video to be taken. The possible values are:
RNCamera.Constants.VideoQuality.2160p.
ios Specifies capture settings suitable for 2160p (also called UHD or 4K) quality (3840x2160 pixel) video output.
android Quality level corresponding to the 2160p (3840x2160) resolution. (Android Lollipop and above only!).
RNCamera.Constants.VideoQuality.1080p.
ios Specifies capture settings suitable for 1080p quality (1920x1080 pixel) video output.
android Quality level corresponding to the 1080p (1920 x 1080) resolution.
RNCamera.Constants.VideoQuality.720p.
ios Specifies capture settings suitable for 720p quality (1280x720 pixel) video output.
android Quality level corresponding to the 720p (1280 x 720) resolution.
RNCamera.Constants.VideoQuality.480p.
ios Specifies capture settings suitable for VGA quality (640x480 pixel) video output.
android Quality level corresponding to the 480p (720 x 480) resolution.
RNCamera.Constants.VideoQuality.4:3.
ios Specifies capture settings suitable for VGA quality (640x480 pixel) video output. (Same as RNCamera.Constants.VideoQuality.480p).
android Quality level corresponding to the 480p (720 x 480) resolution but with video frame width set to 640.
* */
quality: RNCamera.Constants.VideoQuality['1080p'],
videoBitrate: 25,
// 100 MB for now
maxFileSize: 100 * 1024 * 1024,
//"portrait", "portraitUpsideDown", "landscapeLeft" or "landscapeRight"
orientation: 'portrait',
/*
RNCamera.Constants.VideoCodec['H264']
RNCamera.Constants.VideoCodec['JPEG']
RNCamera.Constants.VideoCodec['HVEC'] (iOS >= 11)
RNCamera.Constants.VideoCodec['AppleProRes422'] (iOS >= 11)
RNCamera.Constants.VideoCodec['AppleProRes4444'] (iOS >= 11)
* */
//codec: RNCamera.Constants.VideoCodec['JPEG'],
mirrorVideo: false,
//Max video duration
maxDuration: 120,
// x*1024*1024 in bytes
//maxFileSize: 20,
//mute: false,
//path: '',
doNotSave: false
}
}
takeAPicture = async function(camera){
try{
if (camera) {
return await camera.takePictureAsync(this.options);
}
return null;
}catch(error){
return error;
}
};
startRecording = async (camera, successCallBack, failedCallback) => {
try{
if (camera) {
camera.recordAsync(this.optionsRecording).then( (video) => {
successCallBack(video);
} ).catch( (error) => {
failedCallback(error);
} );
}
}catch(error){
failedCallback(error);
}
};
resolveOnPressCameraButton(){
if(this.camera.state.flashModeCounter % 3 === 0){
this.camera.setState({
flashButtonName: 'flash-auto',
flashMode: RNCamera.Constants.FlashMode.auto
});
}else if(this.camera.state.flashModeCounter % 3 === 1){
this.camera.setState({
flashButtonName: 'flash-off',
flashMode: RNCamera.Constants.FlashMode.off
});
}else if(this.camera.state.flashModeCounter % 3 === 2){
this.camera.setState({
flashButtonName: 'flash-on',
flashMode: RNCamera.Constants.FlashMode.torch
});
}
}
resolvePinchGesture(nativeEvent){
if(nativeEvent.scale > 1){
if(this.camera.state.zoom + this.camera.zoomRate > 1){
this.camera.setState({ zoom: 1 });
}else{
this.camera.setState({ zoom: this.camera.state.zoom + this.camera.zoomRate });
}
}else if(nativeEvent.scale < 1){
if(this.camera.state.zoom - this.camera.zoomRate < 0){
this.camera.setState({ zoom: 0 });
}else{
this.camera.setState({ zoom: this.camera.state.zoom - this.camera.zoomRate })
}
}
}
}
export default CameraHandler;
Not sure if this the best channel for this. But how you guys deal with large files/videos on RN. How do you manage to upload those files in the background?. Thanks in advanced
@FaggioniHQ you can give a look at react-native-fetch-blob and react-native-fs.
Yeah, I'm using react-native-fetch-blob already. But seems like this process its a bit slow... moving the videos/images to the filesystem and uploading the file to our backend. I implemented a file queue but seems to take a bit of time. Let me know if you guys have a better approach to this functionality.
Thanks in advanced
It can be related to How react-native works. Btw, i recommend reading about that when working with process that demand a higher process. :smile:
@FaggioniHQ thanks for the code snippet. I managed to make it work better with continuous pitch events by changing if(nativeEvent.scale > 1)
to if (nativeEvent.scale > this.prevZoomScale)
and setting this.prevZoomScale = nativeEvent.scale
at the bottom of the resolvePinchGesture
in your case.
Also, keep in mind that zoom min/max is different on iOS and Android. See this comment for reference: https://github.com/react-native-community/react-native-camera/issues/1772#issuecomment-419068946
This is how I handle it (only for iOS atm):
onPitchGestureEventHandler = ({ nativeEvent }) => {
if (!nativeEvent || nativeEvent.state !== State.ACTIVE) {
return;
}
if (nativeEvent.scale > this.prevZoomScale) {
this.setState({ zoom: Math.min(0.05, this.state.zoom + this.zoomRate) });
} else {
this.setState({ zoom: Math.max(0, this.state.zoom - (this.zoomRate + this.zoomRate / 2)) });
}
this.prevZoomScale = nativeEvent.scale;
}
Thanks for the feedback. I will check this later. 👍
@FaggioniHQ @d-dizhevsky
this is my existing code adapted and cleaned from the following example. Can you help me completing this functionality? Thanks a lot !
import React, { Component } from 'react';
import { View } from 'react-native';
import { PinchGestureHandler, State } from 'react-native-gesture-handler';
export default class ZoomView extends Component {
onGesturePinch = ({ nativeEvent }) => {
this.props.onPinchProgress(nativeEvent.scale)
}
onPinchHandlerStateChange = event => {
const pinch_start = event.nativeEvent.state === State.END
const pinch_begin = event.nativeEvent.oldState === State.BEGAN
const pinch_active = event.nativeEvent.state === State.ACTIVE
if (pinch_start) {
this.props.onPinchEnd()
}
else if (pinch_begin && pinch_active) {
this.props.onPinchStart()
}
}
render() {
const { style } = this.props
return (
<PinchGestureHandler
onGestureEvent={this.onGesturePinch}
onHandlerStateChange={this.onPinchHandlerStateChange}>
{ this.props.children }
</PinchGestureHandler>
)
}
}
and the Camera
Component
import React, { Component } from 'react'
import { RNCamera } from 'react-native-camera';
iimport ZoomView from './ZoomView';
export default class Recorder extends Component {
_render() {
return (
<ZoomView
onPinchStart={() => {}}
onPinchEnd={() => {}}
onPinchProgress={zoom => this.setState({ zoom })}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
zoom={this.state.zoom} />
</ZoomView>
)
}
}
the solution was provided by @cristianoccazinsp with the following answer
Initial testing without using this.camera.setNativeProps({zoom: zoom})
have smooth zoom effect on even old android and iphone 5 devices (as displayed in the below gif)
Thanks a lot for the support!
can someone add this to the docs?
credits go to @cristianoccazinsp with the following answer and the ongoing discussion at #1282
I still need to test the functionality with setNativeProps
and I am not sure that the solution will work for all devices. I currently can only test it on iPhone 5 and Android Oppo A83.
iPhone 5 has relatively small screen so it not a good subject for testing the funcionality.
Thanks a lot
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. You may also mark this issue as a "discussion" and i will leave this open.
Closing this issue after a prolonged period of inactivity. Fell free to reopen this issue, if this still affecting you.
@sibelius I want to contribute writing code. Would you consider having this functionality in this library or as a separate npm package? Thanks a lot
@fabriziobertoglio1987 I think it is better as a new package, so we can reuse in expo camera as well
let me know if you need any help
Considering the extra dependencies (gesture handler?), definitely looks like something that should be added as another library. Not sure if it would be worth it trying to implement it with react native's pan handlers instead.
we can link to the docs to make it easier to find it
Thanks @sibelius and @cristianoccazinsp
This is the result from my research. I exclude OPTION 2 as there is no explicit requirement to implement setNativeZoom()
in react-native-camera
. I would be happy to work on this or other features you approve/open. Thanks a lot.
OPTION 1 - Wrapping CameraViewManager
in a ScaleGestureDetector
instance
The zoom is controlled with CameraViewManager
method setZoom()
.
public class CameraViewManager extends ViewGroupManager<RNCameraView> {
@ReactProp(name = "zoom")
public void setZoom(RNCameraView view, float zoom) {
view.setZoom(zoom);
}
}
The zoom functionality could be built by wrapping a ScaleGestureDetector
instance around the appropriate view and pass the correct value to the method setZoom()
OPTION 2 - Implementing setNativeProps
for CameraViewManager
(avoid re-render)
The RNCamera
component
is the interface layer between Java (CameraViewManager
) and Javascript (React Camera
component).
React Camera
component does not implement setNativeProps
. Most of the ReactNative
components (for example View
) implement the method setNativeProps
with the NativeMethodsMixin
NativeMethodsMixin
provides methods to access the underlying native component directly.
@fabriziobertoglio1987 Hey is this contained in a package anywhere yet for testing (even if its rough)? if not any ETA if its sooonish i can hold off on writing my own implementation and just test what you come up with :)
Thanks!
Thanks @sibelius and @phyzical , but after an extensive research, I don't believe that it makes sense creating a separate package for this functionality. The package would receive negative feedback from the community as it does not solve the main problem explained here.
I agree with @sibelius that this functionality should remain in user land, but I would consider implementing setNativeProps
as discussed here (I may not be able to do this completely alone, but I will help on my evening time).
The feature request is closed and potential pull request will not be merged.
For testing: fork this project and yarn install
the advanced example
One of the demo apps has a pinch to zoom implemented as well. You can always copy paste ;)
El mié., 29 de enero de 2020 06:53, fabriziobertoglio1987 < notifications@github.com> escribió:
Thanks @sibelius https://github.com/sibelius and @phyzical https://github.com/phyzical , but after an extensive research https://github.com/react-native-community/react-native-camera/issues/2178#issuecomment-574228101, I don't believe that it makes sense creating a separate package for this functionality. The package would receive negative feedback from the community as it does not solve the main problem explained here https://github.com/react-native-community/react-native-camera/issues/2178#issuecomment-574228101 .
I agree with @sibelius https://github.com/sibelius that this functionality should remain in user land https://github.com/react-native-community/react-native-camera/issues/1282#issuecomment-392520205, but I would consider implementing setNativeProps as discussed here https://github.com/react-native-community/react-native-camera/issues/2178#issuecomment-574228101 (I may not be able to do this completely alone).
The feature request is closed and potential pull request will not be merged.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/react-native-community/react-native-camera/issues/2178?email_source=notifications&email_token=ALU263G2V2XTUBALMH4W3S3RAFG2NA5CNFSM4HCRBCT2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKGTDOY#issuecomment-579678651, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALU263FM2WDTR5L3VYBPJQTRAFG2NANCNFSM4HCRBCTQ .
Question
Hi Team, Is there any way to integrate Pinch to zoom the camera view for both iOS and Android with RNCamera?