【问题标题】:How to shift pixel value to the next mousemove position in canvas?如何将像素值移动到画布中的下一个鼠标移动位置?
【发布时间】:2018-01-26 21:36:52
【问题描述】:

我正在使用 HTML5 画布创建一个涂抹工具。现在我必须将鼠标指针处的像素颜色移动到鼠标指针移动的下一个位置。可以用javascript做吗?

<canvas id="canvas"><canvas>
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var url = 'download.jpg';
var imgObj = new Image();
imgObj.src = url;
imgObj.onload = function(e) {
  context.drawImage(imgObj, 0, 0);
}

function findPos(obj) {
  var curleft = 0,
    curtop = 0;
  if (obj.offsetParent) {
    do {
      curleft += obj.offsetLeft;
      curtop += obj.offsetTop;
    } while (obj = obj.offsetParent);
    return {
      x: curleft,
      y: curtop
    };
  }
  return undefined;
}

function rgbToHex(r, g, b) {
  if (r > 255 || g > 255 || b > 255)
    throw "Invalid color component";
  return ((r << 16) | (g << 8) | b).toString(16);
}

$('#canvas').mousemove(function(e) {
  var pos = findPos(this);
  var x = e.pageX - pos.x;
  var y = e.pageY - pos.y;
  console.log(x, y);
  var c = this.getContext('2d');
  var p = c.getImageData(x, y, 1, 1).data;
  var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
  console.log(hex)
});

【问题讨论】:

  • 最好的方法是创建一个比画笔大小稍大的离屏画布。将要移动的画布部分渲染到该画布上。使用渐变和目标输入来羽化复制的画笔,然后将屏幕外画布渲染回下一个鼠标位置,然后重复。这将比逐个像素地进行更快并提供更好的结果。
  • @Blindman67 那是一个更好的主意。有任何参考代码可用吗?

标签: javascript jquery canvas html5-canvas


【解决方案1】:

我的 ATM 时间很短,所以只能打码。

使用屏幕外画布brush 获取背景画布background 的副本,其中鼠标位于最后一帧。然后使用ctx.globalCompositeOperation = "destination-in" 使用径向渐变来羽化画笔。然后在下一个鼠标位置绘制更新后的画笔。

主画布仅用于显示,被涂抹的画布称为background您可以在该画布上放置您想要的任何内容(例如图像),它可以是任何大小,您可以缩放,平移,旋转背景虽然你必须转换鼠标坐标以匹配背景坐标

点击拖动鼠标涂抹颜色。

const ctx = canvas.getContext("2d");
const background = createCanvas(canvas.width,canvas.height);
const brushSize = 64;
const bs = brushSize;
const bsh = bs / 2;
const smudgeAmount = 0.25; // values from 0 none to 1 full

 // helpers
const doFor = (count, cb) => { var i = 0; while (i < count && cb(i++) !== true); }; // the ; after while loop is important don't remove
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;


// simple mouse
const mouse  = {x : 0, y : 0, button : false}
function mouseEvents(e){
	mouse.x = e.pageX;
	mouse.y = e.pageY;
	mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
}
["down","up","move"].forEach(name => document.addEventListener("mouse"+name,mouseEvents));


// brush gradient for feather
const grad = ctx.createRadialGradient(bsh,bsh,0,bsh,bsh,bsh);
grad.addColorStop(0,"black");
grad.addColorStop(1,"rgba(0,0,0,0)");
const brush = createCanvas(brushSize)

// creates an offscreen canvas
function createCanvas(w,h = w){
  var c = document.createElement("canvas");
  c.width = w;
  c.height = h;
  c.ctx = c.getContext("2d");
  return c;
}

// get the brush from source ctx at x,y
function brushFrom(ctx,x,y){
  brush.ctx.globalCompositeOperation = "source-over";
  brush.ctx.globalAlpha = 1;
  brush.ctx.drawImage(ctx.canvas,-(x - bsh),-(y - bsh));
  brush.ctx.globalCompositeOperation = "destination-in";
  brush.ctx.globalAlpha = 1;
  brush.ctx.fillStyle = grad;
  brush.ctx.fillRect(0,0,bs,bs);
}
  
  



				
// short cut vars 
var w = canvas.width;
var h = canvas.height;
var cw = w / 2;  // center 
var ch = h / 2;
var globalTime;
var lastX;
var lastY;

// update background is size changed
function createBackground(){
  background.width = w;
  background.height = h;
  background.ctx.fillStyle = "white";
  background.ctx.fillRect(0,0,w,h);
  doFor(64,()=>{
    background.ctx.fillStyle = `rgb(${randI(255)},${randI(255)},${randI(255)}`;
    background.ctx.fillRect(randI(w),randI(h),randI(10,100),randI(10,100));
  });
}



// main update function
function update(timer){
    globalTime = timer;
    ctx.setTransform(1,0,0,1,0,0); // reset transform
    ctx.globalAlpha = 1;           // reset alpha
	if(w !== innerWidth || h !== innerHeight){
		cw = (w = canvas.width = innerWidth) / 2;
		ch = (h = canvas.height = innerHeight) / 2;
    createBackground();
	}else{
		ctx.clearRect(0,0,w,h);
	}
  ctx.drawImage(background,0,0);


  // if mouse down then do the smudge for all pixels between last mouse and mouse now
  if(mouse.button){
    brush.ctx.globalAlpha = smudgeAmount;
    var dx = mouse.x - lastX;
    var dy = mouse.y - lastY;
    var dist = Math.sqrt(dx*dx+dy*dy);
    for(var i = 0;i < dist; i += 1){
      var ni = i / dist;
      brushFrom(background.ctx,lastX + dx * ni,lastY + dy * ni);
      ni = (i+1) / dist;
      background.ctx.drawImage(brush,lastX + dx * ni - bsh,lastY + dy * ni - bsh);
    }
    
  }else{
     brush.ctx.clearRect(0,0,bs,bs); /// clear brush if not used
  }
	
	lastX = mouse.x;
	lastY = mouse.y;
	
    requestAnimationFrame(update);
}
requestAnimationFrame(update);
canvas { position : absolute; top : 0px; left : 0px; }
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

【讨论】:

  • 先生,如何将图片设置为jpg或png图片
  • @AjithVManali 使用const image = new Image; image.src = "url"; image.onload = background.width = image.width; background.height = image.height; background.ctx.drawImage(image,0,0) 并删除函数createBackground 并调用该函数。现在设置背景来保存图像。
  • 我们可以用纯像素颜色代替涂抹效果吗?
  • @AjithVManali 你明白这个答案是如何工作的吗?只需将函数brushFrom中的brush.ctx.drawImage(ctx.canvas,-(x - bsh),-(y - bsh));行更改为以下两行brush.ctx.fillStyle = theColorYouWant;brush.ctx.fillRect(0,0,bs,bs);
  • 效果很好。是否可以只绘制画布的选定部分?
猜你喜欢
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-02
相关资源
最近更新 更多