Closed hzburki closed 6 years ago
Any progress ?? I'm kinda on a deadline ?? 😨
I want to play the local video with html element <video src="file:///....."></video>
in WebView, then use canvas to draw the frame data as picture, but the local video from React Native Image Picker can not play.
Maybe because the browser security rules, we can not load local media file in WebView, but I am not so sure.
@hzburki there is no progress to be made, it's a use case needed to be figured out not a bug.
@hzburki
Maybe because the browser security rules, we can not load local media file in WebView, but I am not so sure.
I am sorry I was wrong. I found I can show local image with <img src='file:///...' />
in WebView html.
Maybe we can try to add support for this use case. @iddan
What's needed to be done for it to be supported?
@Riant you can display the local file using the uri key in the response from react-native-image-picker in canvas ??? Can you share the code please ???
Btw I can show the image from image-picker in Image and ImageBackground components easily. Doesn't take long to load either.
Hey, so I just would like to know what this is about: I was planning to convert a web-based application that will let you turn your uploaded photos into memes (put basic shapes and text on it) into a RN app. But if I get this issue right, you are not able to place an image from your local phone gallery on the canvas?
I think you can. Many have reported they were able to pull it off. I think the actual issue is retrieving the image back (I'm accepting PRs). BTW this use case is why I made react-native-canvas initially.
Thanks for component!
Finally could you load image from image picker and show it? Can you add example please
I did that with my own webview component. I want to get the video frame-image with canvas, but I found it is not support on some old Android phone, so we did that with native code on Android, and webview-canvas on iOS.
Some main code below, wish it's useful for you guys:
html.js
const html = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>video-canvas</title>
<style>
html, body { margin: 0; padding: 0;}
body { position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden;}
</style>
</head>
<body>
<video id='video' src='#' muted playsinline></video>
<canvas id='canvas' width='100' height='100'></canvas>
<script>
var canvas = document.getElementById('canvas')
var targets = {
video: document.getElementById('video'),
canvas: canvas,
context2d: canvas.getContext('2d')
}
targets.video.addEventListener('loadeddata', function(){
targets.canvas.width = targets.video.videoWidth
targets.canvas.height = targets.video.videoHeight
postMessage(JSON.stringify({
target: 'video',
type: 'loadeddata',
width: targets.video.videoWidth,
height: targets.video.videoHeight
}))
})
document.addEventListener('message', receiveMessage, false)
function receiveMessage(e) {
var payload = JSON.parse(e.data)
switch (payload.type) {
case 'setVideoPath': {
targets.video.src = payload.value
targets.video.load()
break
}
case 'set': {
Object.keys(payload.params).forEach(key => {
targets[payload.target][key] = payload.params[key]
})
if (payload.target === 'video' && payload.params.src) targets.video.load()
break
}
case 'call': {
targets[payload.target][payload.method]()
break
}
case 'getFrameAsImage': {
targets.context2d.drawImage(targets.video, 0, 0, targets.canvas.width, targets.canvas.height)
postMessage(JSON.stringify({
target: 'canvas',
type: 'gotDataUrl',
width: targets.canvas.width,
height: targets.canvas.height,
localIdentifier: targets.video.localIdentifier,
data: targets.canvas.toDataURL(payload.format || 'image/jpeg', 1)
}))
break
}
}
}
</script>
</body>
</html>
`
export default html
trimmer.ios.js
// 通过 Webview Canvas 截取视频帧图片
import React, { Component } from 'react'
import {
Text,
View,
Image,
WebView,
Alert,
ActivityIndicator,
} from 'react-native'
import RNFS from 'react-native-fs'
import html from './html'
class VideoTrimmer extends React.Component {
constructor(props) {
super(props)
this.state = {
doing: this.props.video && this.props.video.path ? 1 : 0,
}
}
onDone(path) {
this.setState({doing: 0})
this.props.onDone && this.props.onDone({path, from: 'video', second: this.props.second || 0})
}
onMessage(e) {
const data = JSON.parse(e.nativeEvent.data)
if (data.type === 'loadeddata') {
if (global.TEMP[this.props.video.localIdentifier]) return this.onDone(global.TEMP[this.props.video.localIdentifier])
this.postMessage({type: 'getFrameAsImage', format: 'image/jpeg'})
} else if (data.type === 'gotDataUrl') {
const frameImagePath = global.CachePATH + '/frame-0-' + new Date().getTime() + '.jpg'
// Alert.alert('ds', data.data)
RNFS.writeFile(frameImagePath, data.data.replace('data:image/jpeg;base64,', ''), 'base64').then(() => {
// Alert.alert('ss', frameImagePath)
if (data.localIdentifier) global.TEMP[data.localIdentifier] = frameImagePath
this.onDone(frameImagePath)
})
}
}
postMessage(data) {
this.webview.postMessage(JSON.stringify(data))
}
getPreviewImage() {
if (global.TEMP[this.props.video.localIdentifier]) return this.onDone(global.TEMP[this.props.video.localIdentifier])
if (this.state.doing === -1) return
this.setState({doing: -1})
this.postMessage({type: 'set', target: 'video', params: {src: this.props.video.path, localIdentifier: this.props.video.localIdentifier}})
}
onWebviewLoadend() {
if (this.props.video && this.props.video.path) this.getPreviewImage()
}
componentWillReceiveProps(nextProps) {
if (this.state.doing === 1) return
if (nextProps.image.from === 'refresh' || nextProps.second !== this.props.second || (this.props.image.from === 'video' && nextProps.video.path !== this.props.video.path)) {
this.setState({doing: 2})
}
}
componentDidUpdate() {
if (this.state.doing === 2 && this.props.video && this.props.video.path) this.getPreviewImage()
}
render() {
return (
<View style={[{width: this.props.width, height: this.props.height}, this.props.style || {}]}>
<WebView
mediaPlaybackRequiresUserAction={false}
originWhitelist={['*']}
// allowFileAccess={true}
source={{baseUrl: '', html}}
onMessage={e => this.onMessage(e)}
allowsInlineMediaPlayback={true}
ref={ele => this.webview = ele}
onLoadEnd={() => this.onWebviewLoadend()}
style={{width: 5, height: 5, position: 'absolute', top: 0, right: 0, opacity: 0}}
/>
{this.props.image && this.props.image.path &&
<Image source={{uri: this.props.image.path}} resizeMode='contain'
style={{width: this.props.width, height: this.props.height}}
/>
}
{this.state.doing !== 0 &&
<View style={[baseStyles.overlayer, baseStyles.flex0Center]}>
<ActivityIndicator color='#FFF' />
{this.props.doingText && <Text style={{marginTop: 20, color: '#999', fontSize: 12}}>{this.props.doingText}{this.state.doing}</Text>}
</View>
}
</View>
)
}
}
export default VideoTrimmer
Then, use it like below:
// import VideoTrimmer from '../xxx/trimmer'
// render:
<VideoTrimmer video={this.state.video} image={this.state.image} second={0}
onDone={image => this.setState({image})}
width={width - 40} height={mediaHeight}
doingText='Waiting please'
ref={ele => this.VideoTrimmer = ele}
/>
I can only do it with base64 from RNFetchBlob
RNFetchBlob.fs.readFile(this.state.photo,'base64')
.then((data) => {
const image2 = new CanvasImage(canvas);
image2.src ='data:image/png;base64,'+data;
image2.addEventListener('load', () => {
context.drawImage(image2,0,0,width,height)
//be careful of the image ratio!
})
});
Hi, I have this problem too. I can't visualize image in canvas with " file:///data/user/0/host.exp.exponent/cache/ExperienceData/..." uri. Any solutions?
P.S. I can visualise images with web paths and purple boxes, but not with local path.
Hello
I'm making an app which takes a picture from the phone's camera, overlays the timestamp as text and a logo as watermark on the picture. And let's the user store it on their phone.
I'm using react-native-image-picker to access the camera. I get the image and can display it using RN's Image or ImageBackground components, but can't seem to display it on the canvas.
Initial Canvas
Image Picker Response
Note The canvas is rendered after the response from react-native-image-picker is added to the state. I have tried 'uri', 'path' and 'data' attributes but always get a blank canvas. I do get the purple rectangle though.
End Result I want to be able to add the picture on canvas. Then add a logo and text over the picture and save it to my mobiles camera roll.