如何模糊 HTML5 视频标签的特定区域?

雅恩·科林

对于 VueJS 项目,我有一个带有 HTML5<video>标签的视频播放器在此视频中,我想在左下角显示一些模糊点。

我正在使用画布,纯 CSS 方法,但没有任何效果。

在 CSS 中:我在视频前面的 div 上使用了 filter: blur(20px) 但它不起作用,模糊影响了 div 的边框而不是中心。

在 css 中进行模糊测试的图像

使用画布,我们尝试相同的方法,但我从来没有得到任何单一的模糊效果

我只需要对图像的红色部分进行模糊效果:

红色部分需要模糊处理

<template>
<div>  
  <div class="contenant">
    <input  type='range' v-model="width" min="0" max="1281" value="0" >
    <img id='image' class="img" src="image1.jpg" alt="test">
    <div id='filtre' v-bind:style="{ width: width + 'px'}"></div>
  </div>
</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    width: 0,
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.contenant {
  width: fit-content;
}

#filtre {
  height: 96%;
  background-color: red;
  position: absolute;
  bottom: 0;
  opacity: 0.33;
  top: 8px;
  z-index: 2;
  filter: blur(50px);
}

.img{
  position:relative;
}

input[type=range] {
  width: 81%;
  -webkit-appearance: none;
  margin: 10px 0;
  position: absolute;
  z-index: 3;
  height: -webkit-fill-available;
  background-color: transparent;
}

input[type=range]::-webkit-slider-thumb {
  height: 26px;
  width: 26px;
  border-radius: 17px;
  background: #619BFF;
  cursor: pointer;
  -webkit-appearance: none;
}
海道

在支持浏览器时,就像使用具有backdrop-filter: blur()CSS 属性的重叠元素一样简单

// just make the div follow the mouse
const mouse = {
  x: 0,
  y: 0,
  dirty: false
};
const blurme = document.getElementById('soblurme');
document.querySelector('.container')
  .addEventListener('mousemove', (evt) => {
  mouse.x = evt.offsetX;
  mouse.y = evt.offsetY;
  // recently all UI events are already debounced by UAs,
  // but all vendors didn't catch up yet
  if( !mouse.dirty ) {
    requestAnimationFrame( move );
  }
  mouse.dirty = true;
});

function move() {
  blurme.style.left = (mouse.x - 25) + 'px';
  blurme.style.top = (mouse.y - 25) + 'px';
  mouse.dirty = false;
}
.container { position: relative; }
#soblurme {
  position: absolute;
  border: 1px solid white;
  pointer-events: none;
  width: 50px;
  height: 50px;  
  left: 70px;
  top: 20px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
video {
  width: 100%;
  cursor: none;
}
<div class="container">
  <video autoplay muted controls>
    <source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
    <source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
  </video>
  <div id="soblurme"></div>
</div>

对于其他人,您需要在画布上再次绘制视频的那部分:

const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
const ctx = canvas.getContext('2d');

if( ctx.filter !== "none" ) {
  // in case 2DContext.filter is not supported (Safari), some libraries can do the blur for us
  // I'll let the readers choose the one they prefer and implement it
  console.warn( "we should use a falbback like StackBlur.js" );
}

const spread = 10;
ctx.filter = 'blur(' + spread + 'px)';

const border_width = 1; // because we add a css border around the canvas element

let playing = false;

vid.onplaying = startDrawing;
vid.onpause = stopDrawing;

function startDrawing() {
  playing = true;
  loop();
}
function stopDrawing() {
  playing = false;
}

function loop() {
  if( mouse.dirty ) {
    canvas.style.left = mouse.x + 'px';
    canvas.style.top = mouse.y + 'px';
    mouse.dirty = false;
  }
  draw();
  if( playing ) {
    requestAnimationFrame(loop);
  }
}
function draw() {
  const vid_rect = vid.getBoundingClientRect();
  const can_rect = canvas.getBoundingClientRect();
  const s_x = (can_rect.left - vid_rect.left) + border_width;
  const s_y = (can_rect.top - vid_rect.top) + border_width;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  // if we are lazy, we can draw the whole image
  // but the blur effect is quite heavy to calculate
//  ctx.drawImage(vid, -s_x, -s_y, vid_rect.width, vid_rect.height);

  // so for better performances we may prefer to calculate the smallest area to draw
  // because blur spreads we need to draw outside a little bit anyway
  const offset = spread * 2;
  const output_w = canvas.width + (offset * 2);
  const output_h = canvas.height + (offset * 2);
  const ratio_x = vid_rect.width / vid.videoWidth;
  const ratio_y = vid_rect.height / vid.videoHeight;
  
  ctx.drawImage(
    vid,
    (s_x - offset) / ratio_x, (s_y - offset) / ratio_y, output_w  / ratio_x, output_h / ratio_y,
    -offset, -offset, output_w, output_h 
  );
}

// move with mouse
const mouse = {
  x: 0,
  y: 0,
  dirty: false
};
document.querySelector('.container')
  .addEventListener( 'mousemove', ( evt ) => {
  mouse.x = evt.offsetX - canvas.width / 2;
  mouse.y = evt.offsetY - canvas.height / 2;
  if( !mouse.dirty && !playing ) {
    requestAnimationFrame( loop ); 
  }
  mouse.dirty = true;
});
.container { position: relative; }
#soblurme {
  position: absolute;
  border: 1px solid white;
  pointer-events: none;
  left: 70px;
  top: 20px;
}
video {
  width: 100%;
}
<div class="container">
  <video autoplay muted controls>
    <source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
    <source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
  </video>
  <canvas id="soblurme" width="50" height="50"></canvas>
</div>

为了有条件地做到这一点,我们可以进行特征检测:

const supportsBackdropFilter = (function() {
  const style = document.createElement('_').style;
  style.cssText = 'backdrop-filter: blur(2px);webkit-backdrop-filter: blur(2px)';
  return style.length !== 0 &&
    (document.documentMode === undefined || document.documentMode > 9);
})();

所以大家一起:

const supports_backdrop_filter = (function() {
  const style = document.createElement('_').style;
  style.cssText = 'backdrop-filter: blur(2px);-webkit-backdrop-filter: blur(2px);';
  return style.length !== 0 &&
    (document.documentMode === undefined || document.documentMode > 9);
})();

const mouse = {
  x: 0,
  y: 0,
  dirty: false
};
const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
let playing = false;
const ctx = canvas.getContext('2d');
const spread = 10;
const border_width = 1; // because we add a css border around the canvas element
  
document.querySelector('.container')
  .addEventListener('mousemove', (evt) => {
  mouse.x = evt.offsetX;
  mouse.y = evt.offsetY;
  if( !mouse.dirty ) {
    if( supports_backdrop_filter ) {
      requestAnimationFrame( move );
    }
    else if( !playing ) {
      requestAnimationFrame( loop );
    }
  }
  mouse.dirty = true;
});

function move() {
  canvas.style.left = (mouse.x - 25) + 'px';
  canvas.style.top = (mouse.y - 25) + 'px';
  mouse.dirty = false;
}

// unsupporting browsers 
if( !supports_backdrop_filter ) {
  ctx.filter = 'blur(' + spread + 'px)';

  vid.onplaying = startDrawing;
  vid.onpause = stopDrawing;
}

function startDrawing() {
  playing = true;
  loop();
}
function stopDrawing() {
  playing = false;
}

function loop() {
  if( mouse.dirty ) {
    move();
  }
  draw();
  if( playing ) {
    requestAnimationFrame(loop);
  }
}
function draw() {
  const vid_rect = vid.getBoundingClientRect();
  const can_rect = canvas.getBoundingClientRect();
  const s_x = (can_rect.left - vid_rect.left) + border_width;
  const s_y = (can_rect.top - vid_rect.top) + border_width;
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const offset = spread * 2;
  const output_w = canvas.width + (offset * 2);
  const output_h = canvas.height + (offset * 2);
  const ratio_x = vid_rect.width / vid.videoWidth;
  const ratio_y = vid_rect.height / vid.videoHeight;

  ctx.drawImage(
    vid,
    (s_x - offset) / ratio_x, (s_y - offset) / ratio_y, output_w  / ratio_x, output_h / ratio_y,
    -offset, -offset, output_w, output_h 
  );
}
.container { position: relative; }
#soblurme {
  position: absolute;
  border: 1px solid white;
  pointer-events: none;
  left: 70px;
  top: 20px;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
video {
  width: 100%;
  cursor: none;
}
<div class="container">
  <video autoplay muted controls>
    <source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
    <source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
  </video>
  <canvas id="soblurme" width="50" height="50"></canvas>
</div>



OP 在评论中询问,这样模糊实际上会扩散,而不是像前面的例子那样清晰。

要在 CSS 中做到这一点,应该只是添加一个内部元素,我们将在其上设置背景过滤器,其中一半模糊和一些边距,然后blur在元素上添加 a与另一半模糊作为一个简单的filter规则。
但是,当前的 Blink 中似乎存在一个错误,backdrop-filter如果其中一个祖先已经对其blur()应用了该错误,则该错误将被丢弃...

所以这目前只适用于 Safari:

// just make the div follow the mouse
const mouse = {
  x: 0,
  y: 0,
  dirty: false
};
const blurme = document.getElementById('soblurme');
document.querySelector('.container')
  .addEventListener('mousemove', (evt) => {
  mouse.x = evt.offsetX;
  mouse.y = evt.offsetY;
  // recently all UI events are already debounced by UAs,
  // but all vendors didn't catch up yet
  if( !mouse.dirty ) {
    requestAnimationFrame( move );
  }
  mouse.dirty = true;
});

function move() {
  blurme.style.left = (mouse.x - 25) + 'px';
  blurme.style.top = (mouse.y - 25) + 'px';
  mouse.dirty = false;
}
.container { position: relative; }
#soblurme {
  position: absolute;
  pointer-events: none;
  width: 50px;
  height: 50px;  
  left: 70px;
  top: 20px;
  --spread: 10px;
  filter: blur(calc(var(--spread) ));
}
#soblurme > div {
  width: calc(100% - var(--spread));
  height: calc(100% - var(--spread));
  backdrop-filter: blur(calc(var(--spread) / 2));
  -webkit-backdrop-filter: blur(calc(var(--spread) / 2));
  padding: 10px;
}
video {
  width: 100%;
  cursor: none;
}
<div class="container">
  <video autoplay muted controls>
    <source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
    <source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
  </video>
 <div id="soblurme"> <!-- we apply a simple blur() here -->
  <div></div> <!-- this one will get the backdrop-filter -->
 </div>
</div>

然而,好消息是画布版本变得更简单了。
我们要做的是简单地在画布上绘制视频,然后filter:blur()直接从 CSS将 CSS 应用到画布元素上。
由于我们不需要考虑点差,因此 drawImage 的计算更容易,但由于我们没有应用任何过滤器,我们甚至可以使用第二个代码段注释中的惰性版本:

const vid = document.querySelector('video');
const canvas = document.getElementById('soblurme');
const ctx = canvas.getContext('2d');

let playing = false;

vid.onplaying = startDrawing;
vid.onpause = stopDrawing;

function startDrawing() {
  playing = true;
  loop();
}
function stopDrawing() {
  playing = false;
}

function loop() {
  if( mouse.dirty ) {
    canvas.style.left = mouse.x + 'px';
    canvas.style.top = mouse.y + 'px';
    mouse.dirty = false;
  }
  draw();
  if( playing ) {
    requestAnimationFrame(loop);
  }
}
function draw() {
  const vid_rect = vid.getBoundingClientRect();
  const can_rect = canvas.getBoundingClientRect();
  const s_x = (can_rect.left - vid_rect.left);
  const s_y = (can_rect.top - vid_rect.top);
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(vid, -s_x, -s_y, vid_rect.width, vid_rect.height);
}

// move with mouse
const mouse = {
  x: 0,
  y: 0,
  dirty: false
};
document.querySelector('.container')
  .addEventListener( 'mousemove', ( evt ) => {
  mouse.x = evt.offsetX - canvas.width / 2;
  mouse.y = evt.offsetY - canvas.height / 2;
  if( !mouse.dirty && !playing ) {
    requestAnimationFrame( loop ); 
  }
  mouse.dirty = true;
});
.container { position: relative; }
#soblurme {
  position: absolute;
  pointer-events: none;
  left: 70px;
  top: 20px;
  filter: blur(10px);
}
video {
  width: 100%;
}
<div class="container">
  <video autoplay muted controls>
    <source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm">
    <source src="https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4">
  </video>
  <canvas id="soblurme" width="50" height="50"></canvas>
</div>

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何以圆形显示HTML5视频标签?

来自分类Dev

如何以圆形显示HTML5视频标签?

来自分类Dev

如何检测HTML5视频标签中的“无用”点击?

来自分类Dev

如何使用HTML5 canvas标签显示视频

来自分类Dev

如何同步HTML5视频?

来自分类Dev

如何使用HTML5播放视频?

来自分类Dev

html5视频如何静音?

来自分类Dev

如何在HTML5视频的顶部和底部切出黑色区域?

来自分类Dev

浏览器如何确定HTML5视频标签是否显示全屏按钮?

来自分类Dev

如何禁用全屏播放与iPhone中的html5视频标签?

来自分类Dev

如何通过Chrome扩展程序访问Netflix的HTML5视频标签元数据

来自分类Dev

浏览器如何确定HTML5视频标签是否显示全屏按钮?

来自分类Dev

播放和暂停多个html5视频,并在暂停时对其进行模糊处理

来自分类Dev

如何使2个HTML5视频重叠?

来自分类Dev

如何包装HTML5视频元素的currentTime属性?

来自分类Dev

如何制作通用的HTML5视频播放器

来自分类Dev

HTML5视频,如何检测何时没有音轨?

来自分类Dev

如何检测HTML5视频是否已暂停缓冲?

来自分类Dev

如何动态添加HTML5视频控件

来自分类Dev

如何使用HTML5重置视频

来自分类Dev

如何让系统在非全屏html5视频上休眠?

来自分类Dev

完成加载后如何使HTML5视频淡入?

来自分类Dev

如何访问HTML5视频解码状态?

来自分类Dev

如何使用Firefox在YouTube上禁用HTML5视频?

来自分类Dev

在视口外时如何停止播放html5视频?

来自分类Dev

如何设置固定的html5视频高度?

来自分类Dev

如何使用jQuery引用HTML5视频元素?

来自分类Dev

如何使用html5重置视频

来自分类Dev

如何使togglefullscreen与HTML5视频配合使用?

Related 相关文章

热门标签

归档