我知道如何缩放一个小画布,使其成为一个像素较粗而非模糊的大画布。
有没有什么方法可以让整个网页显示出2×2或3×3的像素?即用最近邻缩放来放大它。我想使用普通的HTML,但将其像素化为faux-8位外观。
好主意。如果你不在乎表现,我想这并不难。
编辑:我花了一整天的时间进行研究,做了一堆测试,并写了自己的小例子。这些是我的结果:
选项1:静态SVG过滤器
感谢Amaury Hanser
您可以定义svg过滤器并在css中使用它:(请参阅https://stackoverflow.com/a/66625778/6292230)
这个解决方案在各个方面都很漂亮。
然而,苹果不喜欢你。macOS和iOS上的Safari不支持某些筛选器或属性。例如:当用作css过滤器时,Safari会忽略x、y、宽度和高度,这会使大多数解决方案变得无用。如果您可以控制环境(例如WebView、Electron…(,这是最好的解决方案。
选项2:动态SVG过滤器
计算工作量:每个视口一次调整大小/页面加载
这应该可以跨浏览器工作。在最新的Safari、Chrome和Firefox(macOS(上进行了测试。您可以使用选项1中描述的类似技术。但是,必须将点阵渲染到屏幕外画布,并将其注入svg过滤器。每次视口大小更改时(例如,在调整大小事件之后(,都必须重新进行计算。
工作代码沙盒示例:https://codesandbox.io/s/pixelate-page-demo-dt6w0?file=/src/index.js(如果效果未显示,请单击右侧iframe中的重新加载按钮(
- 在体内创建一个空的svg过滤器
<body>
<svg>
<filter
id="pixelate"
x="0"
y="0"
width="700"
height="900"
filterUnits="userSpaceOnUse"
></filter>
</svg>
</body>
- 动态创建并注入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);
}
页面加载/视口调整大小调用后
pixelate(5, 1); // 5 = tileSize, 1 = std deviation gaussian blur
- 添加css提示:不要使用
display: none;
来隐藏svg,因为它会在Firefox中崩溃
html {
filter: url(#pixelate);
}
svg {
position: absolute;
height: 0;
}
选项3:叠加画布
计算工作量:每次DOM更改
如果没有一个有效的例子,我会这样做:
将页面渲染到DOM
将页面渲染到画布上(请参见html2canvas:http://html2canvas.hertzen.com或更好的光栅化HTML:https://github.com/cburgmer/rasterizeHTML.js)
覆盖画布
position: absolute; left: 0; top: 0; width: 100%; z-index: 100;
不要在画布上点击,这样下面渲染的DOM上的按钮/链接就可以工作
pointer-events: none;
无需图像平滑即可缩放画布(请参阅此处:如何使用画布和javascript对图像进行像素化(
为了获得最佳性能,请尝试阻止动态转发器。
选项4:WebGL着色器
计算工作量:每帧
到目前为止,最酷的方法是通过WebGL渲染您的网站,并使用着色器来创建所需的效果。
- 您可以扩展选项3,渲染全尺寸画布(请记住,为retina设备渲染双倍尺寸(,获取WebGl上下文并附加着色器
- 或者,您可以使用HTML GL(http://htmlgl.com/)。我不推荐它,因为它似乎未经维护,也不支持视网膜设备(=>因此一切都会很模糊(
您可以使用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文档上了解有关svf过滤器的更多信息。