我有一種情況,我需要剪輯圖像或視頻。圖像或視頻需要能夠重疊。我們最初使用SVG嘗試過,但由於各種原因,這樣做效果不佳,所以現在我們在Canvas中進行。什麼是剪輯通過畫布運行的視頻的最有效方法
這對於圖像來說算得很好,但對於視頻來說,瀏覽器在大約2分鐘後幾乎被迫停下來。 (你會不會從示例代碼或鏈接看到的是,我們也暫停視頻,而它不是在視圖,而該標籤還沒有考慮。)
這裏是一個鏈接:http://codepen.io/paceaux/pen/egLOeR
主要關注的是這種方法:
drawFrame() {
if (this.isVideo && this.media.paused) return false;
let x = 0;
let width = this.media.offsetWidth;
let y = 0;
this.imageFrames[this.module.dataset.imageFrame](this.backContext);
this.backContext.drawImage(this.media, x, y, width, this.canvas.height);
this.context.drawImage(this.backCanvas, 0, 0);
if (this.isVideo) {
window.requestAnimationFrame(()=>{
this.drawFrame();
});
}
}
您會發現立即拖慢瀏覽器。我不建議把這個codepen看得太長,因爲任何地方的事情都會變得非常慢。
我使用的是"backCanvas" technique,但這似乎讓事情變得更糟。
我也嘗試過使用Path2D()
來保存剪輯路徑,但這似乎也沒什麼幫助。
wedgeTop: (context, wedgeHeight = defaults.wedgeHeight) => {
var wedge = new Path2D();
wedge.moveTo(this.dimensions.width, 0);
wedge.lineTo(this.dimensions.width, this.dimensions.height);
wedge.lineTo(0, this.dimensions.height);
wedge.lineTo(0, wedgeHeight);
wedge.closePath();
context.clip(wedge);
},
是否還有其他優化我缺少? (除了視頻的大小)。
let imageFrames = function() {
\t let defaults = {
\t \t wedgeHeight: 50
\t };
\t return {
\t \t defaults: defaults,
\t \t //all wedges draw paths clockwise: top right, bottom right, bottom left, top left
\t \t wedgeTop: (context, wedgeHeight = defaults.wedgeHeight) => {
\t \t \t var wedge = new Path2D();
\t \t \t wedge.moveTo(this.dimensions.width, 0);
\t \t \t wedge.lineTo(this.dimensions.width, this.dimensions.height);
\t \t \t wedge.lineTo(0, this.dimensions.height);
\t \t \t wedge.lineTo(0, wedgeHeight);
\t \t \t wedge.closePath();
\t \t \t context.clip(wedge);
\t \t },
\t \t wedgeTopReverse: (context, wedgeHeight = defaults.wedgeHeight) => {
\t \t \t var wedge = new Path2D();
\t \t \t wedge.moveTo(this.dimensions.width, wedgeHeight);
\t \t \t wedge.lineTo(this.dimensions.width, this.dimensions.height);
\t \t \t wedge.lineTo(0, this.dimensions.height);
\t \t \t wedge.lineTo(0, 0);
\t \t \t wedge.closePath();
\t \t \t context.clip(wedge);
\t \t },
\t \t wedgeBottom: (context, wedgeHeight = defaults.wedgeHeight) => {
\t \t \t var wedge = new Path2D();
\t \t \t wedge.moveTo(this.dimensions.width, 0);
\t \t \t wedge.lineTo(this.dimensions.width, this.dimensions.height - wedgeHeight);
\t \t \t wedge.lineTo(0, this.dimensions.height);
\t \t \t wedge.lineTo(0,0);
\t \t \t wedge.closePath();
\t \t \t context.clip(wedge);
\t \t },
\t \t wedgeBottomReverse: (context, wedgeHeight = defaults.wedgeHeight) => {
\t \t \t var wedge = new Path2D();
\t \t \t wedge.moveTo(this.dimensions.width, 0);
\t \t \t wedge.lineTo(this.dimensions.width, this.dimensions.height);
\t \t \t wedge.lineto(0, this.dimensions.height - wedgeHeight);
\t \t \t wedge.lineTo(0, 0);
\t \t \t wedge.closePath();
\t \t \t context.clip(wedge);
\t \t }
\t };
};
class ImageCanvasModule {
\t constructor(module) {
\t \t this.module = module;
\t \t this.imageFrames = imageFrames.call(this);
\t \t if(this.isVideo) {
\t \t \t /*drawFrame has a check where it'll only draw on reqAnimationFrame if video.paused === false,
\t \t \t so we need to fire drawFrame on both events because that boolean will be false when it's paused, thus cancelling the animation frame
\t \t \t */
\t \t \t this.media.addEventListener('play',()=>{
\t \t \t \t this.drawOnCanvas();
\t \t \t });
\t \t \t this.media.addEventListener('pause',()=> {
\t \t \t \t this.drawOnCanvas();
\t \t \t });
\t \t }
\t }
\t get isPicture() {
\t \t return (this.module.nodeName === 'PICTURE');
\t }
\t get isVideo() {
\t \t return (this.module.nodeName === 'VIDEO');
\t }
\t get media() {
\t \t return this.isPicture ? this.module.querySelector('img') : this.module;
\t }
\t get context() {
\t \t return this.canvas.getContext('2d');
\t }
\t get dimensions() {
\t \t return {
\t \t \t width: this.module.offsetWidth,
\t \t \t height: this.module.offsetHeight
\t \t };
\t }
\t createCanvas() {
\t \t let canvas = document.createElement('canvas');
\t \t this.module.parentNode.insertBefore(canvas, this.module.nextSibling);
\t \t canvas.className = this.module.className;
\t \t this.canvas = canvas;
\t \t this.createBackContext();
\t }
\t createBackContext() {
\t \t this.backCanvas = document.createElement('canvas');
\t \t this.backContext = this.backCanvas.getContext('2d');
\t \t this.backCanvas.width = this.dimensions.width;
\t \t this.backCanvas.height = this.backCanvas.height;
\t }
\t sizeCanvas() {
\t \t this.canvas.height = this.dimensions.height;
\t \t this.canvas.width = this.dimensions.width;
\t \t this.backCanvas.height = this.dimensions.height;
\t \t this.backCanvas.width = this.dimensions.width;
\t }
\t drawFrame() {
\t \t if (this.isVideo && this.media.paused) return false;
\t \t let x = 0;
\t \t let width = this.media.offsetWidth;
\t \t let y = 0;
\t \t
\t \t this.imageFrames[this.module.dataset.imageFrame](this.backContext);
\t \t this.backContext.drawImage(this.media, x, y, width, this.canvas.height);
\t \t this.context.drawImage(this.backCanvas, 0, 0);
\t \t if (this.isVideo) {
\t \t \t window.requestAnimationFrame(()=>{
\t \t \t \t this.drawFrame();
\t \t \t });
\t \t }
\t }
\t drawOnCanvas() {
\t \t this.sizeCanvas();
\t \t this.drawFrame();
\t }
\t hideOriginal() {
\t \t //don't use display: none .... you can't get image dimensions when you do that.
\t \t this.module.style.opacity = 0;
\t }
}
console.clear();
window.addEventListener('DOMContentLoaded',()=> {
\t var els = document.querySelectorAll('.canvasify');
\t var canvasified = [];
\t for (el of els) {
\t \t if (el.dataset.imageFrame) {
\t \t \t let imageModule = new ImageCanvasModule(el);
\t \t \t imageModule.createCanvas();
\t \t \t imageModule.drawOnCanvas();
\t \t \t imageModule.hideOriginal();
\t \t \t canvasified.push(imageModule);
\t \t }
\t }
\t console.log(canvasified);
});
body {
\t background-color: #333;
}
.container {
\t height: 600px;
\t width: 100%;
\t position: relative;
\t display: flex;
\t flex-direction: column;
\t justify-content: center;
}
.container + .container {
\t margin-top: -150px;
}
.canvasify {
\t position:absolute;
\t top: 0;
\t left: 0;
\t right: 0;
\t bottom: 0;
\t width: 100%;
\t z-index: -1;
}
video {
\t width: 100%
}
h1 {
\t font-size: 2em;
\t color: #ddd;
}
<div class="container">
\t <img class="canvasify" data-image-frame="wedgeTop" src="http://placekitten.com/1280/500" />
\t <h1>Kitty with a clipped top</h1>
</div>
<div class="container">
<video controls muted class="canvasify" loop autoplay data-image-frame="wedgeTop">
<source src="https://poc5.ssl.cdn.sdlmedia.com/web/635663565028367012PU.mp4">
</video>
\t <h1>video with a clipped top that overlaps the image above</h1>
</div>
的問題是codepen(和運行此代碼的其他頁面)是極其緩慢。我錯過了哪些優化,或者使用不正確?
「重疊」是什麼意思?不確定是什麼問題? – guest271314
問題是頁面運行速度非常慢。 「重疊」意味着應該剪切來自視頻的圖像,並重疊位於其上方的圖像。使它看起來像視頻/圖像不是矩形的,而是以角度切出。 – paceaux
仍然沒有。我正在尋找你在codepen中看到的內容。兩個獨立的容器。一個可能包含一個圖像。另一個可能包含一個視頻。每個容器都有視頻或圖像,並且會以一定角度「裁剪」。來自HTML的文本將位於圖像/視頻之上。因此,一個容器中圖像的底部邊緣將直觀地顯示在可能是視頻的頂部邊緣下方。 我不需要幫助,如何做到這一點(我已經完成了,它的工作原理)我需要幫助讓頁面更好地執行。 – paceaux