【问题标题】:Pixelate a whole webpage像素化整个网页
【发布时间】:2021-06-11 22:26:23
【问题描述】:

我了解如何缩放小画布以制作具有厚实而不是模糊像素的大画布。

有没有办法让整个网页显示为 2x2 或 3x3 像素?即用最近邻缩放放大它。我想使用普通的 HTML,但将其像素化以获得虚假的 8 位外观。

【问题讨论】:

  • 有这篇关于像素化图像的 SO 帖子,但不是带有字体的整个页面以及所有可能不可能的内容。见here

标签: html css pixelate


【解决方案1】:

好主意。如果您不关心性能,我想这并不太难。

编辑:我花了一整天的时间进行研究,做了一堆测试并编写了自己的小例子。这些是我的结果:

选项 1:静态 SVG 滤镜

感谢 Amaury Hanser

您可以定义一个 svg 过滤器并在您的 css 中使用它:(参见 https://stackoverflow.com/a/66625778/6292230

这个解决方案在各个方面都很漂亮。

但是,Apple 不喜欢你。 macOS 和 iOS 上的某些过滤器或属性Safari 不支持。例如:当用作 css 过滤器时,Safari 会忽略 x,y,width,height,这会使大多数解决方案无用。如果您可以控制环境(例如 WebView、Electron 等),这是最好的解决方案。

选项 2:动态 SVG 过滤器

计算工作量:每个视口调整大小/页面加载一次

这应该可以跨浏览器工作。在最新的 Safari、Chrome 和 Firefox (macOS) 上测试。 您可以使用选项 1 中描述的类似技术。 但是,您必须将点阵渲染到屏幕外画布并将其注入 svg 过滤器。每次视口大小发生变化时(例如,在调整大小事件之后),您都必须重新计算。

工作代码框示例:https://codesandbox.io/s/pixelate-page-demo-dt6w0?file=/src/index.js (如果没有显示效果,请单击右侧 iframe 中的重新加载按钮)

  1. 在你的体内创建一个空的 svg 过滤器
<body>
    <svg>
      <filter
        id="pixelate"
        x="0"
        y="0"
        width="700"
        height="900"
        filterUnits="userSpaceOnUse"
      ></filter>
    </svg>
</body>
  1. 如下所示动态创建和注入 svg 过滤器
function pixelate(tileSize = 10, sigmaGauss = 2) {
  tileSize = tileSize < 1 ? 1 : tileSize;
  sigmaGauss = sigmaGauss < 1 ? 1 : sigmaGauss;

  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;

  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // only to make the output visible
  // document.body.appendChild(canvas);

  const rows = canvas.height / tileSize;
  const cols = canvas.width / tileSize;
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      ctx.fillStyle = "white";

      ctx.fillRect(
        c * tileSize - 1 + Math.floor(tileSize / 2),
        r * tileSize - 1 + Math.floor(tileSize / 2),
        1,
        1
      );
    }
  }

  const pixelate = document.getElementById("pixelate");
  pixelate.innerHTML = "";

  const blur = document.createElementNS(
    "http://www.w3.org/2000/svg",
    "feGaussianBlur"
  );
  blur.setAttribute("in", "SourceGraphic");
  blur.setAttribute("stdDeviation", sigmaGauss);
  blur.setAttribute("result", "blurred");

  const hmap = document.createElementNS(
    "http://www.w3.org/2000/svg",
    "feImage"
  );
  const hmapUrl = canvas.toDataURL();
  hmap.setAttribute("href", hmapUrl);
  hmap.setAttribute("result", "hmap");

  const blend = document.createElementNS(
    "http://www.w3.org/2000/svg",
    "feBlend"
  );
  // blend.setAttribute("mode", "lighten");
  blend.setAttribute("mode", "multiply");
  blend.setAttribute("in", "blurred");
  blend.setAttribute("in2", "hmap");

  const morph = document.createElementNS(
    "http://www.w3.org/2000/svg",
    "feMorphology"
  );
  morph.setAttribute("operator", "dilate");
  morph.setAttribute("radius", tileSize / 2);

  pixelate.setAttribute("width", canvas.width);
  pixelate.setAttribute("height", canvas.height);
  pixelate.appendChild(blur);
  pixelate.appendChild(hmap);
  pixelate.appendChild(blend);
  pixelate.appendChild(morph);
}
  1. 页面加载/视口调整大小调用后
pixelate(5, 1); // 5 = tileSize, 1 = std deviation gaussian blur
  1. 添加 CSS。 提示:不要使用display: none; 隐藏 svg,因为它会在 Firefox 中中断
html {
  filter: url(#pixelate);
}

svg {
  position: absolute;
  height: 0;
}

选项 3:覆盖画布

计算工作量:每次 DOM 更改

如果没有工作示例,我会这样做:

  1. 将页面渲染到 DOM

  2. 将您的页面呈现到画布上(请参阅 html2canvas:http://html2canvas.hertzen.com 或更好的 rasterizeHTML:https://github.com/cburgmer/rasterizeHTML.js

  3. 覆盖画布position: absolute; left: 0; top: 0; width: 100%; z-index: 100;

  4. 不要捕捉画布上的点击,因此下面呈现的 DOM 上的按钮/链接将起作用pointer-events: none;

  5. 在不进行图像平滑的情况下缩放画布(参见此处:How to pixelate an image with canvas and javascript

尽量防止动态重新渲染以获得最佳性能。

选项 4:WebGL 着色器

计算工作量:每一帧

目前为止最酷的方法是通过 WebGL 渲染您的网站并使用着色器来创建所需的效果。

  • 您可以扩展选项 3,渲染全尺寸画布(请记住为视网膜设备渲染双倍尺寸),获取 WebGl 上下文并附加着色器
  • 您也可以使用 HTML GL (http://htmlgl.com/)。我不推荐它,因为它似乎没有维护,也不支持视网膜设备(=> 因此一切都会模糊)

【讨论】:

  • 信息量很大,谢谢。方法 2 在计算机上看起来很重,但调整两个参数就这么简单,真是太酷了!你给了我很多读物!
  • @AmauryHanser 事实上,选项 2 比选项 3 和 4 的性能更高。它相当高效的原因是,“holemap”只需要计算一次(+视口调整大小)而不是对于每个 dom 更改(选项 3)或每一帧(选项 4)。
  • 哦,对了,我误读了视口大小的变化。再次恭喜您的研究!
【解决方案2】:

您可以为此使用 svg 过滤器

请注意,此解决方案不能跨浏览器。
正如@adroste 所说,它不适用于 Safari (Mac/iOS) 或旧版浏览器

您需要对其进行调整以使其看起来符合您的要求,但这里有一个简单的示例:

html { filter: url("#pixelate") }
svg { display: block }
h1 { color: red }
h2 { color: blue}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
  <defs>
    <filter id="pixelate" x="0" y="0">
      <feFlood x="2" y="2" height="1" width="1"/> 
      <feComposite width="5" height="5"/>
      <feTile result="a"/>
      <feComposite in="SourceGraphic" in2="a" 
                   operator="in"/>
      <feMorphology operator="dilate"
                    radius="2.5"/>
    </filter>
  </defs>
</svg>    
<h1>
  Lorem ipsum, dolor sit amet consectetur adipisicing elit.
</h1>
<h2>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit, fuga.
</h2>
<p>
  Lorem ipsum, dolor sit amet consectetur adipisicing elit. Doloribus dolorem, maxime recusandae modi adipisci, praesentium qui aliquam consequatur tempore fugiat quasi minus necessitatibus excepturi enim sapiente quibusdam deleniti perferendis quisquam?
</p>

您可能可以使用不同的过滤器来实现此效果。
您可以在MDN docs了解更多关于 svf 过滤器的信息。

【讨论】:

  • 很好的解决方案,但不适用于 Safari (Mac/iOS) 或更旧的浏览器
  • 你是对的@adroste,我会把它添加到答案中。你知道什么是不支持的吗?从caniuse 开始,支持 svg 过滤器,所以猜猜是别的什么?
  • 我不知道。我会试着找出什么中断。我可以尝试用卷积+位移矩阵替换您的解决方案。
  • 在 safari 中使用 url 语法时,似乎洪水和复合过滤器有问题。也许它会内联工作,但它在 svg 之外表现得很奇怪。 Safari 真的很烦人。
  • 我不得不承认我不是 svg 过滤器方面的专家。如果您找到更好的解决方案,我会很乐意为它投票以增加吸引力。
猜你喜欢
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多