I want to make a minecraft sort of thing in javascript, and I have a textures image already (an image with all of the textures of the block). Is there a way to get the specific pixel data for said image without drawing it on a canvas?
I don't really know how to upload files to stackoverflow, to make the images work, but I have tried anyways.
I think I have done it using an image and canvas element, it works about three fourths of the time:
//size of individual textures
var textureWidth = 16;
var textureHeight = 16;
//get the image
var image = document.getElementById("texturesImage");
console.log(image);
//get the image canvas
//or textures canvas or tcanvas
var tcanvas = document.getElementById("textures");
var tctx = tcanvas.getContext("2d");
tcanvas.width = image.naturalWidth;
tcanvas.height = image.naturalHeight;
var imgWidth = image.naturalWidth;
var imgHeight = image.naturalHeight;
console.log(tcanvas.width);
console.log(tcanvas.height);
tctx.drawImage(image, 0, 0);
//accepts a full integer between 0 and 15
function getTextureData(blockID) {
if (!Number.isInteger(blockID) || blockID < 0 || blockID > 15) {
console.log(blockID + " is not a valid ID.");
return (false);
}
//get texture x and y
var tx = blockID % (imgWidth / textureWidth) * textureWidth;
var ty = Math.floor(blockID / (imgWidth / textureWidth)) * textureHeight;
//console.log(tx,ty);
//return image data
return (tctx.getImageData(tx, ty, textureWidth, textureHeight));
}
console.log(getTextureData(13));
#textures {
background-color: orange;
}
Hello world
<canvas id="canvas"></canvas>
<canvas id="textures"></canvas>
<image src="/BlockTextures.png" id="texturesImage"></image>
<!--scripts-->
<script src="engine/1setup.js"></script>
<script src="engine/2getTextures.js"></script>
<script src="script.js"></script>
Related
I get an issue with my javascript code... I'd like to display 5 lines of different pictures in my canvas but only one line is displayed and the LIFE function is only called 16 times (canvas.width / imgW).
Why the LIFE function can't be called after the 'while' loop ?
Thank you !
This is the result i get
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var tabImages = ['css3.svg', 'adobe-1.svg', 'html-5.svg', 'jquery.svg'];
var canvasW = canvas.width;
var canvasH = canvas.height;
var imgW = 50;
var imgH = 50;
var x = 0, y = 0, i = 0, posY = 1, increImg = 0, posX = 0;
/* I want to display 5 lines of pictures but only one is displayed */
for(var lignes = 0 ; lignes < 5 ; lignes++) {
i = 0;
while(posX < canvasW) {
/* That function is only called 16 times but i know only that
way to display several differentes images in canvas */
(function(posX, posY) {
var img = new Image();
if(increImg === tabImages.length-1)
increImg = 0;
img.src = 'testanim/img/'+tabImages[increImg];
img.onload = function() {
ctx.drawImage(img, posX, posY, imgW, imgH);
}
})(posX, posY)
i++;
increImg++;
posX = imgW * i;
}
posY = lignes * imgH;
}
</script>
are you looking for something like à kind of gallery :
//our images
let imageArr = ["animage","another","another","another","another","another","another","another","another","another"];
//getting the context (mycanvas is the id of the canvas element)
let context = mycanvas.getContext("2d")
//checking the context
if(context)
// for all images in my array(can't do for in because of the calculation of position later on )
for(let i = 0;i<imageArr.length;i++)
{
//creation of an image html element
let imgel = document.createElement('img');
//addition of src tag
imgel.src=imageArr[i];
//drawing of the image (parameters:(image, xcoordinates,ycoordinates,width,height)
context.drawImage(imgel, (i%5)*100, (Math.floor(i/5))*100,100,100);
//drawing a rectangle around them
context.strokeRect((i%5)*100,(Math.floor(i/5))*100,100,100);
}
canvas{border:1px solid black;}
<canvas id="mycanvas" height="500" width="500"></canvas>
so in order to have several lines of your image in your code you have to use % operator:
for instance if you want 5 lines this gives you :
(i%canvasW)*imgW
what this does it simply stops after 5 images and if you have to go to the line(see below) it will start from 0 again : 0%5 = 0 1%5 = 1 , ... , 5%5 = 0 6%5 = 1
On the other side for the height if you want to go to the line you need to do some kind of oposite calculation which is / this gives you :
Math.floor(i/5)*imgH
This gives you the lines you are hoping for
so if i resume you will have :
ctx.drawImage(img, (i%canvasW)*imgW, Math.floor(i/5)*imgH, imgW, imgH);
and that's also why your while loop is not going through several lines, you have to calculate your posX differently like so :
posX = (i%canvasW)*imgW;
and throw in another variable for the height which will be the condition to stop your while loop
for instance let's say you want to stop once the last image of the last line is hit you would have to calculate this condition like so :
if(canv.getContext("2d"))
{
let max = canv.width*canv.height;
let current = 0;
let imgW=50;
let imgH=50;
let i = 0;
while(current<=max)
{
console.log("stuff");
current = (Math.floor(i/canv.height)*imgH)*((i%canv.width)*imgW);
i++;
}
}
<canvas id="canv" width="500" height="500"></canvas>
i strongly advise using for loops since you almost can calculate the number of steps for every problem :
for(let i = 0; i<(canvas.width*canvas.height);i++)
I'm drawing an image on my canvas and trying to use getImageData() from canvas to get the image data but I got all 0's in return. From my understanding, the image hasn't finished a load so I get the 0's. From this issue: getImageData always returning 0 seems like I need to wait by using onload. Is there another way to get the data by not use onload function? I want to declare an image tag in my html. Here is my code:
<html>
<head>
</head>
<body>
<script>
var bgMap = {
"bg1": "image1.JPG",
"bg2": "image2.JPG"
}
</script>
<center>
<select id="selectBg" onchange="document.getElementById('bgImage').src = bgMap[this.value]">
<option value="bg1">Bg1</option>
<option value="bg2">Bg2</option>
</select>
</center>
<img id='bgImage' src='image1.JPG' width=500 height=500 />
<canvas id='bgCanvas'></canvas>
<script>
var canvas = document.getElementById('bgCanvas')
var bgImage = document.getElementById('bgImage')
canvas.width = 500
canvas.height = 500
var ctx = canvas.getContext("2d")
ctx.drawImage(bgImage, 0, 0, 500, 500)
var imageData = ctx.getImageData(0, 0, 500, 500)
var rgba = imageData.data;
for (var px = 0, ct = 500 * 500 * 4; px < ct; px += 4) {
var r = rgba[px];
var g = rgba[px + 1];
var b = rgba[px + 2];
var a = rgba[px + 3];
console.log(r,g,b,a)
}
console.log(rgba)
</script>
</body>
</html>
Is there any method to replace/remove colors by color range in Javascript, Opencv or anything else that can be operated on website?
As the above image. Is that possible to replace all the white color(It can be white or near white colors) with transparent color? Any suggestion would be appreciated.
With imagemagick this can be done quickly.
convert input.jpg -fuzz 6% -transparent white output.png
The value of -fuzz 6% can be adjusted to match "near white" thresholds.
Note: The format of JPEG has changed to PNG; which, supports transparency.
You could create a canvas and draw that image onto it, that way you're able to get pixel colors and manipulate them. (And also save the result)
This might lead you somewhere to start with. If you require further help, just comment.
EDIT: Little sample of what this should work like:
//Sets up canvas containing the image:
var img = document.getElementById("image");
img.crossOrigin = "Anonymous";
img.src = "https://i.imgur.com/X1fKQsK.jpg";
loadedBefore = false;
img.onload = function(){
if(loadedBefore) return;
else loadedBefore = true;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img,0,0,img.width,img.height);
//Finds pixels matching color black:
for(x=0; x<canvas.width; x++){
for(y=0; y<canvas.height; y++){
imgdata = ctx.getImageData(x,y,1,1);
color = imgdata.data; //Gets color of coordinate (with 1 pixel in size)
if(color[0] > 250 && color[1] > 250 && color[2] > 250){ //Checks if color is pretty white
color[3] = 0; //Sets alpha to 0 -> Makes color transparent
ctx.putImageData(imgdata,x,y);
}
}
}
img.src = canvas.toDataURL(); //Set image to display canvas content / update image
console.log("done!");
}
<img id="image"/>
You can apparently not just load an image from some other website and modifiy it in the canvas, unless you set img.crossOrigin = "Anonymous" and the other website allows it. I got no clue on what exactly happens there, I just know that it works with imgur.com. (That's why everything's in the onload function now)
The loadedBefore stuff is because StackOverflow apparently calls the img.onload function pretty often, you won't have this issue if you use your own image so you don't need the crossOrigin and onload stuff.....
Just a function to do the stuff:
function whiteToTransparent(img){
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img,0,0,img.width,img.height);
//Finds pixels matching color black:
for(x=0; x<canvas.width; x++){
for(y=0; y<canvas.height; y++){
imgdata = ctx.getImageData(x,y,1,1);
color = imgdata.data;
if(color[0] > 250 && color[1] > 250 && color[2] > 250){
color[3] = 0;
ctx.putImageData(imgdata,x,y);
}
}
}
img.src = canvas.toDataURL();
}
I'm trying to get an image to be displayed on an HTML5 Canvas while keeping the aspect ratio and having the image reduced (if larger than the canvas). I've look around at some answers but seem to be missing something and wondered if you guys can help.
I'm using the function "calculateAspectRatioFit" suggested by one of the Stackoverflow answers, but it seems to not resize the image for me, as it did in the answer - so I may be doing something wrong :)
Here's my code:
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
var rtnWidth = srcWidth*ratio;
var rtnHeight = srcHeight*ratio;
return { width: rtnWidth, height: rtnHeight };
}
var canvasImage = new Image();
canvasImage.src = "http://www.greenwallpaper.org/backgrounds/simply-green-502085.jpeg";
var ctx = this.getContext('2d');
var parentWidth = self._widgetSize[0];
var parentHeight = self._widgetSize[1];
canvasImage.onload = function() {
var imgSize = calculateAspectRatioFit(canvasImage.width, canvasImage.height, parentWidth, parentHeight);
ctx.clearRect(0, 0, parentWidth, parentHeight);
ctx.drawImage(canvasImage, 0, 0,imgSize.width, imgSize.height);
};
The image is displayed but is larger than the HTML5 Canvas. What I am after is to have the image the same width as the Canvas, and if the height is larger than the height of the canvas then it overflows and is hidden...I just want to fill the width and keep the aspect ratio.
Can anyone help point out what I am missing?
Appreciate your help :)
---Update 30/11---
I've just added the answer to my code and I get the following: (this is the 2nd answer)
var canvasImage = new Image();
canvasImage.src = "http://www.greenwallpaper.org/backgrounds/simply-green-502085.jpeg";
var ctx = this.getContext('2d');
canvasImage.onload = scaleAndDraw(this, ctx, canvasImage);
function scaleAndDraw(canvas, ctx, srcImage) {
// Image is 2560x1600 - so we need to scale down to canvas size...
// does this code actually 'scale' the image? Image of result suggests it doesn't.
var aspect = getAspect(canvas, srcImage);
var canvasWidth = (srcImage.width * aspect);
var canvasHeight = (srcImage.height * aspect);
ctx.drawImage(srcImage, 0, 0, canvasWidth|0, canvasHeight|0);
}
function getAspect(canvas, image) {
return canvas.size[0] / image.width;
}
So the code for displaying the image works, but the image is keeping it's dimensions and is not resizing to the dimensions of the canvas.
Hopefully the image will help you see the problem I am having. Larger images do not seem to rescale to fit in the canvas while keeping aspect ratio.
Any thoughts? :)
Your code works for me as long as I supply sane parentWidth,parentHeight values:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
var rtnWidth = srcWidth*ratio;
var rtnHeight = srcHeight*ratio;
return { width: rtnWidth, height: rtnHeight };
}
var parentWidth = 100; //self._widgetSize[0];
var parentHeight = 50; //self._widgetSize[1];
var canvasImage = new Image();
canvasImage.onload = function() {
var imgSize = calculateAspectRatioFit(canvasImage.width, canvasImage.height, parentWidth, parentHeight);
ctx.clearRect(0, 0, parentWidth, parentHeight);
ctx.drawImage(canvasImage,30,30,imgSize.width, imgSize.height);
};
canvasImage.src = "http://www.greenwallpaper.org/backgrounds/simply-green-502085.jpeg";
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
I know questions like this have been asked several time, but I have yet to find just what I'm looking for. I am reading an image into a canvas object (in javascript) and trying to manipulate some specific pixels. For example, I am looking for the color RGB: 224 64 102, and trying to change this to a different color.
I can apply greyscale to the image, so I know the manipulation works, but the code is not finding any pixels with this color (that Adobe Illustrator said was the RGB color). I'm hoping I'm just missing a small detail. The code is below, hopefully someone will see it.
Thanks!
var canvas = document.getElementById("testcanvas");
var canvasContext = canvas.getContext('2d');
imgObj = new Image();
imgObj.src = "ss.jpg";
//imgObj.width = 200;
//imgObj.height = 200;
var imgW = imgObj.width;
var imgH = imgObj.height;
canvas.width = imgW;
canvas.height = imgH;
canvasContext.drawImage(imgObj, 0, 0);
var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
//hash_table = {};
for (var x = 0; x < imgPixels.width; x++) {
for (var y = 0; y < imgPixels.height; y++)
{
var i = (y * imgPixels.width + x) * 4;
//Want to go from:
//E04066
//224 64 102 -> to
//134 135 185
if(imgPixels.data[i] == 224 && imgPixels.data[i+1] == 64 && imgPixels.data[i+2] == 102) {
imgPixels.data[i] = 134;
imgPixels.data[i+1] = 135;
imgPixels.data[i+2] = 185;
}
//To greyscale:
/*
var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
imgPixels.data[i] = avg;
imgPixels.data[i + 1] = avg;
imgPixels.data[i + 2] = avg;
imgPixels.data[i + 3] = 255;
*/
}
}
canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
//color_count = 0;
//for(key in hash_table) {
// color_count++;
//}
//console.log(color_count);
//console.log(hash_table);
return canvas.toDataURL();
});
});
</script>
</head>
<body>
<canvas id="testcanvas"></canvas>
<img src="ss.jpg" id="testimage"/>
You are probably unable to get image data from canvas because the canvas has been tainted by cross-origin data.
If that file, ss.jpg is local then it won't work. I imagine that's the case.
Search for canvas cross-origin on SO or Google for more information on that. There's a lot out there. Here's a bit of an explanation:
http://simonsarris.com/blog/480-understanding-the-html5-canvas-image-security-rules
Here's a site about enabling it on your server:
http://enable-cors.org/
Otherwise, your code works. Here is the same code converting a tiny red dot into a tiny green dot:
http://jsfiddle.net/RBaxt/
Canvas really don't work with .JPG format. You have to convert your image into .PNG using any picture editing tool like Photoshop. Your code works well.
I think you are loading an Image that is not ready to be painted. Below I have updated your code above, though I have not test it but I feel it could lead you somewhere
var canvas = document.getElementById("testcanvas");
var canvasContext = canvas.getContext('2d');
imgObj = new Image();
imgObj.src = "ss.jpg";
//imgObj.width = 200;
//imgObj.height = 200;
var imgW = imgObj.width;
var imgH = imgObj.height;
imgObj.onload = function(){
//Put the pixel manipulation code here;
// This ensures the image has been loaded before it is accessed.
}