I'm new to image processing. I found the "gpu.js" package and it seems to be very powerful for any kind of image operations in the browser, but there is not much information on google about it and I don't understand how to use it properly.
What I'm trying to do now: I've drawn a canvas with a black (0,0,0) background. I also overlaid a few pixels of different colors on it. I want to get the coordinates (x, y) of all exact RGB pixels on the canvas but I am stuck on this and I don't even see is it possible.
The code for canvas:
const draw = async () => {
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.backgroundColor = 'rgb(0,0,0)'
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(234,0,255)";
ctx.fillRect(100,100,1,1);
ctx.fillStyle = "rgb(0,0,255)";
ctx.fillRect(600,600,1,1);
ctx.fillStyle = "rgb(0,255,0)";
ctx.fillRect(600,450,1,1);
ctx.fillStyle = "rgb(0,254,253)";
ctx.fillRect(230,230,1,1);
ctx.fillStyle = "rgb(140,8,9)";
ctx.fillRect(230,118,1,1);
}
draw();
const gpu = new GPU({mode: "gpu"});
* {
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>GPU</title>
<script src="https://cdn.jsdelivr.net/npm/gpu.js#latest/dist/gpu-browser.min.js"></script>
<style>
</style>
</head>
<body>
</body>
</html>
For example I'd like to find coordinates of pixels with colors rgb(234,0,255) and rgb(140,8,9)
What should I do to achieve it?
Related
Introduction
I'm trying to deal with blurry visuals on my canvas animation. The blurriness is especially prevalent on mobile-devices, retina and high-dpi (dots-per-inch) screens.
I'm looking for a way to ensure the pixels that are drawn using the canvas look their best on low-dpi screens and high-dpi screens. As a solution to this problem I red multiple articles about canvas-down-scaling and followed this tutorial:
https://www.kirupa.com/canvas/canvas_high_dpi_retina.htm
Integrating down-scaling in the project
The project in which I want to implement down-scaling can be found below and consists of a few important features:
There is a (big) main canvas. (Performance optimization)
There are multiple (pre-rendered) smaller canvasses that are used to draw and load a image into. (Performance optimization)
The canvas is animated. (In the code snippet, there is no visible animation but the animation function is intergrated.)
Question
What im trying to achieve: The problem I'm facing seems quite simple. When the website (with the canvas) is opened on a mobile device (eg. an Iphone, with more pixels per inch then a regular desktop). The images appear more blurry. What I'm actually trying to achieve is to remove this blurriness from the images. I red this and it stated that blurriness can be removed by downsampling. I tried to incorporate this technique in the code provided, but it did not work completely. The images just became larger and I was unable to scale the images back to the original size. snippet it is not implemented correctly, the output is still blurry. What did I do wrong and how am I able to fix this issue?
Explanation of the code snippet
The variable devicePixelRatio is set to 2 to simulate a high-dpi phone screen, low-dpi screens have a devicePixelRatio of 1.
Multiple pre-rendered canvasses generated is the function spawn is the snippet there are 5 different canvasses, but on the production environment there are 10's.
If there are any pieces of information missing or questions about this post, please let me know. Thanks a lot!
Code Snippet
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d' );
var circles = [];
//Simulate Retina screen = 2, Normal screen = 1
let devicePixelRatio = 2
function mainCanvasPixelRatio() {
// get current size of the canvas
let rect = canvas.getBoundingClientRect();
// increase the actual size of our canvas
canvas.width = rect.width * devicePixelRatio;
canvas.height = rect.height * devicePixelRatio;
// ensure all drawing operations are scaled
c.scale(devicePixelRatio, devicePixelRatio);
// scale everything down using CSS
canvas.style.width = rect.width + 'px';
canvas.style.height = rect.height + 'px';
}
// Initial Spawn
function spawn() {
for (let i = 0; i < 2; i++) {
//Set Radius
let radius = parseInt(i*30);
//Give position
let x = Math.round((canvas.width/devicePixelRatio) / 2);
let y = Math.round((canvas.height /devicePixelRatio) / 2);
//Begin Prerender canvas
let PreRenderCanvas = document.createElement('canvas');
const tmp = PreRenderCanvas.getContext("2d");
//Set PreRenderCanvas width and height
let PreRenderCanvasWidth = ((radius*2)*1.5)+1;
let PreRenderCanvasHeight = ((radius*2)*1.5)+1;
//Increase the actual size of PreRenderCanvas
PreRenderCanvas.width = PreRenderCanvasWidth * devicePixelRatio;
PreRenderCanvas.height = PreRenderCanvasHeight * devicePixelRatio;
//Scale PreRenderCanvas down using CSS
PreRenderCanvas.style.width = PreRenderCanvasWidth + 'px';
PreRenderCanvas.style.height = PreRenderCanvasHeight + 'px';
//Ensure PreRenderCanvas drawing operations are scaled
tmp.scale(devicePixelRatio, devicePixelRatio);
//Init image
const image= new Image();
//Get center of PreRenderCanvas
let m_canvasCenterX = (PreRenderCanvas.width/devicePixelRatio) * .5;
let m_canvasCenterY = (PreRenderCanvas.height/devicePixelRatio) * .5;
//Draw red circle on PreRenderCanvas
tmp.strokeStyle = "red";
tmp.beginPath();
tmp.arc((m_canvasCenterX), (m_canvasCenterY), ((PreRenderCanvas.width/devicePixelRatio)/3) , 0, 2 * Math.PI);
tmp.lineWidth = 2;
tmp.stroke();
tmp.restore();
tmp.closePath()
//Set Image
image .src= "https://play-lh.googleusercontent.com/IeNJWoKYx1waOhfWF6TiuSiWBLfqLb18lmZYXSgsH1fvb8v1IYiZr5aYWe0Gxu-pVZX3"
//Get padding
let paddingX = (PreRenderCanvas.width/devicePixelRatio)/5;
let paddingY = (PreRenderCanvas.height/devicePixelRatio)/5;
//Load image
image.onload = function () {
tmp.beginPath()
tmp.drawImage(image, paddingX,paddingY, (PreRenderCanvas.width/devicePixelRatio)-(paddingX*2),(PreRenderCanvas.height/devicePixelRatio)-(paddingY*2));
tmp.closePath()
}
let circle = new Circle(x, y, c ,PreRenderCanvas);
circles.push(circle)
}
}
// Circle parameters
function Circle(x, y, c ,m_canvas) {
this.x = x;
this.y = y;
this.c = c;
this.m_canvas = m_canvas;
}
//Draw circle on canvas
Circle.prototype = {
//Draw circle on canvas
draw: function () {
this.c.drawImage( this.m_canvas, (this.x - (this.m_canvas.width)/2), (this.y - this.m_canvas.height/2));
}
};
// Animate
function animate() {
//Clear canvas each time
c.clearRect(0, 0, (canvas.width /devicePixelRatio), (canvas.height /devicePixelRatio));
//Draw in reverse for info overlap
circles.slice().reverse().forEach(function( circle ) {
circle.draw();
});
requestAnimationFrame(animate);
}
mainCanvasPixelRatio()
spawn()
animate()
#mainCanvas {
background:blue;
}
<canvas id="mainCanvas"></canvas>
<br>
<!DOCTYPE html>
<html>
<body>
<p>Image to use:</p>
<img id="scream" width="220" height="277"
src="pic_the_scream.jpg" alt="The Scream">
<p>Canvas:</p>
<canvas id="myCanvas" width="240" height="297"
style="border:1px solid #d3d3d3;">
</canvas>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("scream");
ctx.drawImage(img, 10, 10);
};
</script>
</body>
This question already has answers here:
Size of HTML5 Canvas via CSS versus element attributes
(3 answers)
Closed 2 years ago.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Archade!</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div style="text-align: center;">
<canvas id="gameCanvas"></canvas>
</div>
<script>
var canvas;
var canvasContext;
window.onload = function () {
console.log("Game working!");
canvas = document.getElementById("gameCanvas");
canvasContext = canvas.getContext("2d");
canvasContext.fillStyle = "black";
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
console.log("Loading red box");
canvasContext.fillStyle = "red";
canvasContext.fillRect(500, 500, 50, 25);
console.log("Red box should be loaded!");
};
</script>
</body>
</html>
This is my html code, [ in style.css i've just set width and height of the canvas ].
The black canvas is being displayed on the screen but the red box isn't displayed anywhere.
The console log above and below the red rectangle is also working fine.
Please help me fix this! I want the red rectangle to be displayed as well.
Thanks for your time :)
From this reference - https://www.w3schools.com/tags/canvas_fill.asp
You can do the following:
First draw the rectangle.
Then, set the fillStyle.
Then fill the rectangle.
Check the code below:
var canvas;
var canvasContext;
window.onload = function() {
console.log("Game working!");
canvas = document.getElementById("gameCanvas");
canvasContext = canvas.getContext("2d");
canvasContext.rect(0, 0, canvas.width, canvas.height);
canvasContext.fillStyle = "black";
canvasContext.fill();
console.log("Loading red box");
canvasContext.rect(500, 500, 50, 25);
canvasContext.fillStyle = "red";
canvasContext.fill();
console.log("Red box should be loaded!");
};
<div style="text-align: center;">
<canvas id="gameCanvas"></canvas>
</div>
Setting the canvas size in css might not be enough.
Try also setting the width/height attributes of the canvas element.
For example:
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
I think the red rectangle isn't displayed because it's position exceeds the default size of a canvas.
How to fill the whole HTML5 <canvas> with one color.
I saw some solutions such as this to change the background color using CSS but this is not a good solution since the canvas remains transparent, the only thing that changes is the color of the space it occupies.
Another one is by creating something with the color inside the canvas, for example, a rectangle(see here) but it still does not fill the whole canvas with the color (in case the canvas is bigger than the shape we created).
Is there a solution to fill the whole canvas with a specific color?
Yes, fill in a Rectangle with a solid color across the canvas, use the height and width of the canvas itself:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
canvas{ border: 1px solid black; }
<canvas width=300 height=150 id="canvas">
If you want to do the background explicitly, you must be certain that you draw behind the current elements on the canvas.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Add behind elements.
ctx.globalCompositeOperation = 'destination-over'
// Now draw!
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
You can change the background of the canvas by doing this:
<head>
<style>
canvas {
background-color: blue;
}
</style>
</head>
let canvas = document.getElementById('canvas');
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
let ctx = canvas.getContext('2d');
//Draw Canvas Fill mode
ctx.fillStyle = 'blue';
ctx.fillRect(0,0,canvas.width, canvas.height);
* { margin: 0; padding: 0; box-sizing: border-box; }
body { overflow: hidden; }
<canvas id='canvas'></canvas>
We don't need to access the canvas context.
Implementing hednek in pure JS you would get canvas.setAttribute('style', 'background-color:#00F8'). But my preferred method requires converting the kabab-case to camelCase.
canvas.style.backgroundColor = '#00F8'
You know what, there is an entire library for canvas graphics. It is called p5.js
You can add it with just a single line in your head element and an additional sketch.js file.
Do this to your html and body tags first:
<html style="margin:0 ; padding:0">
<body style="margin:0 ; padding:0">
Add this to your head:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"></script>
<script type="text/javascript" src="sketch.js"></script>
The sketch.js file
function setup() {
createCanvas(windowWidth, windowHeight);
background(r, g, b);
}
I'm having an issue with drawImage() re-sizing a loaded image below a certain width and height. The image I'm trying to re-size is 1080x1920 and I want it to be re-sized to 540x960. If I apply drawImage() to reduce it to 764x1358, it works. But any resolution smaller than that (on either parameter) results in the image not being displayed on the canvas.
There is definitely some correlation between the lower bounds on the resolution, because both are approximately 70.7% of the original resolution. I'm wondering if there's an inherit limit on drawImage but I couldn't find any specification that said so.
Here's the relevant code:
var image = new Image();
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.canvas.width = this.width * 2;
ctx.canvas.height = this.height;
$(image).on("load", function() {
ctx.drawImage(image, 0, 0, 764, 1358);
});
image.src = "test2.jpg";
I edited the code to show where image came from.
Full Code:
<!DOCTYPE html>
<html>
<head>
<title>Canvas from scratch</title>
<meta charset="utf-8">
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jcanvas.min.js"></script>
</head>
<body>
<canvas id="myCanvas" width="1920" height="1920">
</canvas>
<script>
$(document).ready(
function() {
$("<img>").attr("src", "test2.jpg").on('load', function() {
var imgWidth, imgHeight;
var imageData;
var image = new Image();
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.canvas.width = this.width * 2;
ctx.canvas.height = this.height;
$(image).on("load", function() {
/* This is where the image is loaded and
inserted into the canvas */
ctx.drawImage(image, 0, 0, 763, 1358);
});
image.src = "test2.jpg";
imageData = ctx.getImageData(0, 0,
this.width,
this.height);
/* This is just part of the image manipulation,
bland right now */
var newImgData = ctx.createImageData(imageData.width,
imageData.height);
for ( var i = 0; i < newImgData.data.length; i += 4) {
newImgData.data[i + 0] = 255;
newImgData.data[i + 1] = 0;
newImgData.data[i + 2] = 0;
newImgData.data[i + 3] = 255;
}
// ctx.putImageData(newImgData, imageData.width, 0);
});
});
</script>
</body>
</html>
Last Edit: I found out the solution.
As it turns out, my issue was the version of JQuery I was using. I was originally just version 1, but 1.8.3 fixed everything. So, the solution is to simply change
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
to
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
I found this helpful tutorial
http://www.rgraph.net/blog/2013/february/an-example-of-the-html5-canvas-ispointinpath-function.html
i copied it into my own text editor and nothing happens when I open it. I changed it by adding a declaration
<!DOCTYPE html>
<html lang="en">
<head>
<title>exampleMouseOver</title>
</head>
<script>
window.onload = function (e)
{
var canvas = document.getElementById('cvs');
var context = canvas.getContext('2d');
// Draw the rectangle
context.beginPath();
context.rect(50,50,100,100);
context.fill();
context.fillStyle = 'red';
// Draw the circle
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
context.fill();
context.fillStyle = 'green';
// Draw the shape
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
context.fill();
canvas.onmousemove = function (e)
{
var canvas = e.target;
var context = canvas.getContext('2d');
// This gets the mouse coordinates (relative to the canvas)
var mouseXY = RGraph.getMouseXY(e);
var mouseX = mouseXY[0];
var mouseY = mouseXY[1];
// Replay the rectangle path (no need to fill() it) and test it
context.beginPath();
context.rect(50,50,100,100);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the circle path (no need to fill() it) and test it
context.beginPath();
context.arc(450,175, 50, 0,2 * Math.PI, false);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Replay the irregular shape path (no need to fill() it) and test it
context.beginPath();
context.moveTo(250,100);
context.lineTo(350,175);
context.lineTo(325,215);
context.lineTo(185,195);
if (context.isPointInPath(mouseX, mouseY)) {
canvas.style.cursor = 'pointer';
return;
}
///////////////////////////////////////////////////////////////
// Return the cursor to the default style
canvas.style.cursor = 'default';
}
}
</script>
</html>
You'll need a body element and a canvas element. Also your script element needs to be inside either your head element or your body element.
The following is what the sample was using, but did not include in their sample code:
<body>
<canvas id="cvs" width="600" height="250" style="border: 1px solid gray; cursor: pointer;">[No canvas support]</canvas>
</body>
Edit: Additionally the code is calling "RGraph.getMouseXY(e)", which is in a library file that you are not referencing. You can either add a reference to that library or get the mouse position yourself.
If you want to use other parts of the RGraph library, for drawing charts, you should add the library. To add the library you should follow the instructions on the RGraph site related to downloading and starting with RGraph (http://www.rgraph.net/docs/starting-with-rgraph.html).
If this was just a sample that happened to do what you wanted to do, you should get the mouse position yourself. You can do this by changing these lines:
var mouseXY = RGraph.getMouseXY(e);
var mouseX = mouseXY[0];
var mouseY = mouseXY[1];
to these:
var mouseX = e.clientX - canvas.getBoundingClientRect().left;
var mouseY = e.clientY - canvas.getBoundingClientRect().top;
This may not be the most robust solution, but it should suffice for your purposes. Essentially you are getting the mouse position in the window, then subtracting the top-left of the canvas in the window, so that you are left with the mouse position in the canvas.