Get Pixel Color from Canvas, on Mousemove

Get pixel color from canvas, on mousemove

Here's a complete, self-contained example. First, use the following HTML:

<canvas id="example" width="200" height="60"></canvas>
<div id="status"></div>

Then put some squares on the canvas with random background colors:

var example = document.getElementById('example');
var context = example.getContext('2d');
context.fillStyle = randomColor();
context.fillRect(0, 0, 50, 50);
context.fillStyle = randomColor();
context.fillRect(55, 0, 50, 50);
context.fillStyle = randomColor();
context.fillRect(110, 0, 50, 50);

And print each color on mouseover:

$('#example').mousemove(function(e) {
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
var coord = "x=" + x + ", y=" + 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);
$('#status').html(coord + "<br>" + hex);
});

The code above assumes the presence of jQuery and the following utility functions:

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);
}

function randomInt(max) {
return Math.floor(Math.random() * max);
}

function randomColor() {
return `rgb(${randomInt(256)}, ${randomInt(256)}, ${randomInt(256)})`
}

See it in action here:

  • https://bl.ocks.org/wayneburkett/ca41a5245a9f48766b7bc881448f9203

// set up some sample squares with random colors
var example = document.getElementById('example');
var context = example.getContext('2d');
context.fillStyle = randomColor();
context.fillRect(0, 0, 50, 50);
context.fillStyle = randomColor();
context.fillRect(55, 0, 50, 50);
context.fillStyle = randomColor();
context.fillRect(110, 0, 50, 50);

$('#example').mousemove(function(e) {
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
var coord = "x=" + x + ", y=" + 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);
$('#status').html(coord + "<br>" + hex);
});

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);
}

function randomInt(max) {
return Math.floor(Math.random() * max);
}

function randomColor() {
return `rgb(${randomInt(256)}, ${randomInt(256)}, ${randomInt(256)})`
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="example" width="200" height="60"></canvas>
<div id="status"></div>

Get pixel color from resized canvas, on mouseover

You need to apply a scale factor inside the mouse handler method. The scale factor is the relationship between your canvas's bitmap (actual size) and the element size (CSS size).

For example:

// find scale:
var sx = example.width / parseInt(example.style.width, 10);
var sy = example.height / parseInt(example.style.height, 10);

// apply to x/y
x = (x * sx)|0; // scale and cut any fraction to get integer value
y = (y * sy)|0;

Updated fiddle

In addition the code need to have some boundary check of the coordinates so getImageData() won't fail (not shown here).

get rgb values of pixel of image in fabric.js on mouse move

FabricJS does not have a native method for getting the pixel colors.

The workaround is to use native html5 canvas to fetch the pixel data:

  • Create your Fabric image objects. Be sure to specify crossOrigin as 'anonymous' otherwise the canvas will be tainted with a security violation and then the pixel data will be unavailable.

  • Listen on Fabric's 'mouse:move' event. When it fires, get the current mouse position and use native canvas's context.getImageData to fetch that pixel's color array.

Good luck with your project!

Here's annotatede code and a Demo:

// create a Fabric.Canvas
var canvas = new fabric.Canvas("canvas");

// get a reference to <p id=results></p>
// (used to report pixel color under mouse)
var results = document.getElementById('results');

// get references to the html canvas element & its context
var canvasElement = document.getElementById('canvas');
var ctx = canvasElement.getContext("2d");


// create a test Fabric.Image
addFabricImage('https://cdn.pixabay.com/photo/2019/12/12/05/34/afro-4689826_1280.jpg');

// listen for mouse:move events
canvas.on('mouse:move', function(e) {

// get the current mouse position
var mouse = canvas.getPointer(e.e);
var x = parseInt(mouse.x);
var y = parseInt(mouse.y);

// get the color array for the pixel under the mouse
var px = ctx.getImageData(x, y, 1, 1).data;

// report that pixel data
results.innerHTML = 'At [' + x + ' / ' + y + ']: Red/Green/Blue/Alpha = [' + px[0] + ' / ' + px[1] + ' / ' + px[2] + ' / ' + px[3] + ']';

});



// create a Fabric.Image at x,y using a specified imgSrc
function addFabricImage(imgSrc, x, y) {

// create a new javascript Image object using imgSrc
var img = new Image();

// be sure to set crossOrigin or else
// cross-domain imgSrc's will taint the canvas
// and then we can't get the pixel data
// IMPORTANT!: the source domain must be properly configured
// to allow crossOrigin='anonymous'
img.crossOrigin = 'anonymous';

// when the Image object is fully loaded,
// use it to create a new fabric.Image object
img.onload = function() {

var fabImg = new fabric.Image(this, {
left: 30,
top: 30
});
canvas.add(fabImg);

}

// use imgSrc as the image source
img.src = imgSrc;

}
body {
background-color: ivory;
}
canvas {
border: 1px solid red;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<p id="results">Move mouse over canvas</p>
<canvas id=canvas width=300 height=300></canvas>

How to shift pixel value to the next mousemove position in canvas?

I am very short on time ATM so code only.

Uses an offscreen canvas brush to get a copy of the background canvas background where the mouse was last frame. Then use a radial gradient to feather the brush using ctx.globalCompositeOperation = "destination-in". Then draw the updated brush at the next mouse position.

The main canvas is use just to display, the canvas being smeared is called background You can put whatever content you want on that canvas (eg image) and it can be any size, and you can zoom, pan, rotate the background though you will have to convert the mouse coordinates to match the background coordinates

Click drag mouse to smear colours.

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

// simple mouseconst 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 featherconst 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 canvasfunction 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,yfunction 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 changedfunction 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 functionfunction 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; }
<canvas id="canvas"></canvas>

Get Pixel Color from Canvas

The code seem to read the color from the marker rather than the color "behind" it.

The color needs to be read from the position and then set the marker or you will get the color of the marker instead in that position; and of course as the marker is black that color will be returned each time.



Related Topics



Leave a reply



Submit