使用带有透明PNG的画布进行像素化调整

4
我想使用canvas选项imageSmoothingEnabled=false;实现像素化效果,使图像在滚动时“去模糊”。
一切都很好,直到使用透明图像(即PNG)为止。缩放后的图像被投影到背景中。
此外,图像在用户滚动几个像素前不会加载。
我发现canvas.drawImage()函数拥有设置偏移量的参数。然而,我还没有找到解决方法。
演示https://jsfiddle.net/aLjfemru/
var ctx = canvas.getContext('2d'),
  img = new Image(),
  play = false;

/// turn off image smoothing - this will give the pixelated effect
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;


/// wait until image is actually available
img.onload = function(){
                image1.src="nf.png";

                context.drawImage(image1, 50, 50, 10, 10);
                };

img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';

/// MAIN function
function pixelate(v) {
  document.getElementById("v").innerHTML = "(v): " + v;

  /// if in play mode use that value, else use slider value
  var size = v * 0.01;

  var w = canvas.width * size;
  var h = canvas.height * size;

  /// draw original image to the scaled size
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(img, 0, 0, w, h);
  ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}

function onScroll() {
  $(window).on('scroll', function() {
    var y = window.pageYOffset;
    if (y > 10) {
      y = Math.pow(y, 0.8);
      if (y >= 60) {
        y = 100;
      }
      pixelate(y);
    }
  });
}
onScroll();

当你实现requestAnimationFrame时会发生什么?这会解决问题吗? - Sander
说到性能:不是。我的问题是实际(透明)画布图像后面的缩放图像,我想摆脱它。 - form.follows.function
我不知道这是否能帮助您完成您尝试做的最终事情,但是有一个名为“filter”的CSS属性可以获得模糊滤镜。例如:filter: blur(3px); - Omri Luzon
2个回答

2

快速更改以使其生效

使用第二个画布进行像素化

在进行渲染之前等待图像加载完成。

onscroll事件只有在滚动时才会触发,因此当图像已加载时,请调用渲染函数以显示图像。

canvas.width = innerWidth-20;
ctx = canvas.getContext("2d");
var ctxImage;
const img = new Image;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';
/// wait until image is actually available
img.onload = function(){
     // I dont knwo what this is for so removed the following two lines
    //image1.src="nf.png"; 
    //context.drawImage(image1, 50, 50, 10, 10);
    // Create a canvas to match the image
    var c = document.createElement("canvas");
    canvas.width = Math.min(canvas.width,(c.width = this.naturalWidth));
    canvas.height = c.height = this.naturalHeight;
    ctxImage = c.getContext("2d");
    // changing canvas size resets the state so need to set this again.
    ctx.imageSmoothingEnabled = false;
    onScroll();
    pixelate(100); // call first time
};

ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.fillText("Loading please wait.",ctx.canvas.width /2, ctx.canvas.height / 4);
/// MAIN function
function pixelate(v) {
  document.getElementById("v").innerHTML = "(v): " + v;

  /// if in play mode use that value, else use slider value
  var size = Number(v) * 0.01;

  var w = img.width * size;
  var h = img.height * size;

 
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctxImage.clearRect(0, 0, ctxImage.canvas.width, ctxImage.canvas.height);
  ctxImage.drawImage(img, 0, 0, w, h);
  ctx.drawImage(ctxImage.canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}

function onScroll() {
  addEventListener("scroll", function() {

    var y = window.pageYOffset;
    if (y > 10) {
      y = Math.pow(y, 0.65);
      if (y >= 100) {
        y = 100;
      }
      pixelate(y);
    }
  });
      
}
#fix {
      position: fixed;
    }

    html {
      height: 2000px;
    }
<div id="fix">
<p id="v" value="Animate">1</p><br />

<canvas id="canvas"></canvas>
</div>


太棒了,非常感谢!我在考虑将它投影到第二个画布上,但不知道该怎么做。 - form.follows.function

0

这已经被制作成了一个非常极简的库,我的PNG支持PR可以在这里找到。

一旦它被合并,我会回来更新这个答案。

完整的代码,从@Blindman67的答案中概括和简化:

/**
 * 8bit
 *
 * A module that converts an image into a pixelated version (just like
 * 8bit artwork).
 *
 * @author rogeriopvl <https://github.com/rogeriopvl>
 * @license MIT
 */

(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    define([], factory);
  } else if (typeof exports === "object") {
    module.exports = factory();
  } else {
    root.eightBit = factory();
  }
} (this, function () {
  // Necessary to hide the original image with PNG transparency
  const invisibleCanvas = document.createElement("canvas");
  const invisibleCtx = invisibleCanvas.getContext("2d");

  /**
   * Draws a pixelated version of an image in a given canvas.
   * @param {object} canvas - a canvas object
   * @param {object} image - an image HTMLElement object
   * @param {number} quality - the new quality: between 0 and 100
   */
  const eightBit = function (canvas, image, quality) {
    quality /= 100;

    canvas.width = invisibleCanvas.width = image.width;
    canvas.height = invisibleCanvas.height = image.height;

    const scaledW = canvas.width * quality;
    const scaledH = canvas.height * quality;
    const ctx = canvas.getContext("2d");

    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;

    // Draws image scaled to desired quality on the invisible canvas, then
    // draws that scaled image on the visible canvas.
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    invisibleCtx.clearRect(0, 0, invisibleCtx.canvas.width, invisibleCtx.canvas.height);
    invisibleCtx.drawImage(image, 0, 0, scaledW, scaledH);
    ctx.drawImage(invisibleCtx.canvas, 0, 0, scaledW, scaledH, 0, 0, canvas.width, canvas.height);
  };

  return eightBit;
}));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接