I have the next html template:
-
Those magic coefficients correspond to the ratio between the video
object size and the size of canvas.
Suppose, your video
size is (400 x 300)
and you want to show it on the canvas with size (200 x 150)
. It can be done just by:
context.drawImage(video,0,0,200,150);
It will resize full video
to fit the canvas.
However, you are using clipping version of drawImage()
. The first four coordinate arguments describe clipping parameters. For example in the following case it takes quarter of full video
:
context.drawImage(video,0,0,200,150,0,0,200,150);
Edit according to updated question
The image is clipped, since properties canvas.clientWidth
and canvas.clientHeight
are larger than canvas.width
and canvas.height
. That happens because of CSS display: flex;
. To show full image use:
context.drawImage(video, 0, 0, canvas.width, canvas.height);
讨论(0)
-
Here are working fiddles for my problem. I haven't time yet to investigate why it didn't work on my app. Will update in near future.
To make them both work on JSFiddle I added HTML5-video - autoplay
option, don't know how to do the same on StackOverflow
- JS + JQuery https://jsfiddle.net/ytLgebvg/42/
- React.js https://jsfiddle.net/69z2wepo/18812/
JS + JQuery
function redraw(canvas) {
var context = canvas.getContext("2d");
context.strokeStyle = 'blue';
context.lineWidth = '5';
context.strokeRect(0, 0, window.innerWidth, window.innerHeight);
}
function resizeCanvas(canvas, width, height) {
var canvasClWidthBefore = +window.getComputedStyle(canvas, null).getPropertyValue('width').replace('px', ''),
canvasClHeightBefore = +window.getComputedStyle(canvas, null).getPropertyValue('height').replace('px', '');
alert('canvas cl before: ' + canvasClWidthBefore + 'x' + canvasClHeightBefore);
canvas.width = width;
canvas.height = height;
var canvasClWidthAfter = +window.getComputedStyle(canvas, null).getPropertyValue('width').replace('px', ''),
canvasClHeightAfter = +window.getComputedStyle(canvas, null).getPropertyValue('height').replace('px', '');
alert('canvas cl before: ' + canvasClWidthAfter + 'x' + canvasClHeightAfter);
redraw(canvas);
}
$(document).ready(function() {
// Grab elements, create settings, etc.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = { "video": true };
navigator.webkitGetUserMedia(videoObj, function(stream){
video.src = window.URL.createObjectURL(stream);
video.play();
}, function() {});
$('#snap-photo-btn').click(function() {
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video");
$('#canvas').removeClass('photoMode');
$('#canvas').addClass('editMode');
$('#video').removeClass('photoMode');
$('#video').addClass('editMode');
var videoClWidth = +window.getComputedStyle(video, null).getPropertyValue('width').replace('px', ''),
videoClHeight = +window.getComputedStyle(video, null).getPropertyValue('height').replace('px', '');
resizeCanvas(canvas, videoClWidth, videoClHeight);
var canvasWidth = canvas.width,
canvasHeight = canvas.height;
alert('canvas: ' + canvasWidth + 'x' + canvasHeight);
alert('video cl: ' + videoClWidth + 'x' + videoClHeight);
context.drawImage(video, 0, 0, canvasWidth, canvasHeight);
});
});
.main {
position: relative;
}
video {
position: absolute;
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
height: auto;
width: auto;
}
video.photoMode { z-index: 1000; }
video.editMode { z-index: -1000; }
canvas {
/* position: absolute;
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
height: auto;
width: auto; */
}
canvas.photoMode { z-index: -1000; }
canvas.editMode { z-index: 1000; }
.btn-wrapper {
position: absolute;
width: 100%;
top: 0;
left: 0;
display: flex;
flex-direction: row;
justify-content: center;
z-index: 2000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="main">
<video class="photoMode" id="video" autoPlay></video>
<canvas class="photoMode" id="canvas"></canvas>
<div class="btn-wrapper">
<button id="snap-photo-btn">Snap Photo</button>
</div>
</div>
React
var Hello = React.createClass({
getInitialState() {
return { photoMode: true };
},
render: function() {
const clazz = this.state.photoMode ? 'photoMode' : 'editMode';
return (
<div className="main">
<video className={clazz} id="video" autoPlay></video>
<canvas className={clazz} id="canvas"></canvas>
<div className="btn-wrapper">
<button id="snap-photo-btn" onClick={this._snapPhoto}>Snap Photo</button>
</div>
</div>
);
},
componentDidMount() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
videoObj = { "video": true };
navigator.webkitGetUserMedia(videoObj, function(stream){
video.src = window.URL.createObjectURL(stream);
video.play();
}, function() {});
},
_snapPhoto() {
const canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video");
var videoClWidth = +window.getComputedStyle(video, null).getPropertyValue('width').replace('px', ''),
videoClHeight = +window.getComputedStyle(video, null).getPropertyValue('height').replace('px', '');
this._resizeCanvas(canvas, videoClWidth, videoClHeight);
var canvasWidth = canvas.width,
canvasHeight = canvas.height;
alert('canvas: ' + canvasWidth + 'x' + canvasHeight);
alert('video cl: ' + videoClWidth + 'x' + videoClHeight);
context.drawImage(video, 0, 0, canvasWidth, canvasHeight);
this.setState({photoMode: false});
},
_resizeCanvas(canvas, width, height) {
var canvasClWidthBefore = +window.getComputedStyle(canvas, null).getPropertyValue('width').replace('px', ''),
canvasClHeightBefore = +window.getComputedStyle(canvas, null).getPropertyValue('height').replace('px', '');
alert('canvas cl before: ' + canvasClWidthBefore + 'x' + canvasClHeightBefore);
canvas.width = width;
canvas.height = height;
var canvasClWidthAfter = +window.getComputedStyle(canvas, null).getPropertyValue('width').replace('px', ''),
canvasClHeightAfter = +window.getComputedStyle(canvas, null).getPropertyValue('height').replace('px', '');
alert('canvas cl after: ' + canvasClWidthAfter + 'x' + canvasClHeightAfter);
this._redraw(canvas);
},
_redraw(canvas) {
var context = canvas.getContext("2d");
context.strokeStyle = 'blue';
context.lineWidth = '5';
context.strokeRect(0, 0, window.innerWidth, window.innerHeight);
}
});
ReactDOM.render(
<Hello />,
document.getElementById('container')
);
.main {
position: relative;
}
video {
position: absolute;
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
height: auto;
width: auto;
}
video.photoMode { z-index: 1000; }
video.editMode { z-index: -1000; }
canvas {}
canvas.photoMode { z-index: -1000; }
canvas.editMode { z-index: 1000; }
.btn-wrapper {
position: absolute;
width: 100%;
top: 0;
left: 0;
display: flex;
flex-direction: row;
justify-content: center;
z-index: 2000;
}
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
讨论(0)
-
I did some testing on this, and it seems like the 3rd and 4th parameters, which are the width and height of the area you want to take from the source, are relative to the original size of the media, NOT the size of the element the media is displayed in. So, it's based on the original dimensions of your video, and not the width and height of your video element.
I'm surprised the non-clipping version doesn't work though. It seems like it should if you do:
context.drawImage(video, 0, 0, canvas.clientWidth, canvas.clientHeight);
This should take the full video image and display it at the top left corner of the canvas and over the full width and height of the canvas.
讨论(0)