I want to stretch the image to the size of the canvas. But the image takes its original size instead of taking the canvas size.Any help is appreciated.
var canvas = document.createElement("canvas");
canvas.setAttribute("width", "100px");
canvas.setAttribute("height", "180px");
//alert(canvas.height);
myImg.width = canvas.width;
myImg.height = canvas.height;
var ctx44 = canvas.getContext("2d");
ctx44.drawImage(myImg, 0, 0, canvas.width, canvas.height,0,0,canvas.width,canvas.height);
// image gets displayed in its original size instead of taking the size of the canvas
The 2nd ~ 4th parameters of drawImage represent the source rectangle. That is, a rectangle from where your image will be cropped, before being applied to the destination, resized by the rectangle defined in the following rectangle.
Here is a simple demo:
var img = new Image();
img.onload = e => {
const source = document.getElementById('source');
const destination = document.getElementById('destination');
const imgWIDTH = source.width = destination.width = 300;
const imgHEIGHT = source.height = destination.height = 300;
const src_x = source.getContext('2d');
const dest_x = destination.getContext('2d');
src_x.drawImage(img, 0, 0, imgWIDTH, imgHEIGHT); // simple copy to source canvas
const source_rect = {
x: 20,
y: 20,
w: 150,
h: 150
};
const dest_rect = {
x: 0,
y: 0,
w: 300,
h: 300
};
destination.getContext('2d')
.drawImage(source,
source_rect.x,
source_rect.y,
source_rect.w,
source_rect.h,
dest_rect.x,
dest_rect.y,
dest_rect.w,
dest_rect.h
);
// show the source rectangle on the 'source' canvas
src_x.strokeRect(
source_rect.x,
source_rect.y,
source_rect.w,
source_rect.h,
);
};
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
<canvas id="source"></canvas>
<canvas id="destination"></canvas>
So in your case, if your original image is smaller than the 100x180px of your canvas, you are defining the source rectangle to be outside of the source image, this will then result in no apparent changes from the original image.
What you probably wanted was
ctx44.drawImage(myImg, 0, 0, myImg.naturalWidth, myImg.naturalHeight,0,0,canvas.width,canvas.height);
which is the same as the 5 param version
ctx44.drawImage(myImg,0,0,canvas.width,canvas.height);
var myImg = new Image();
myImg.onload = function(e) {
var canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 180;
var ctx44 = canvas.getContext("2d");
ctx44.drawImage(myImg, 0,0,canvas.width,canvas.height);
document.body.appendChild(myImg);
document.body.appendChild(canvas);
};
myImg.src = "https://i.stack.imgur.com/LbM0l.jpg?s=32&g=1"
Related
I am trying to resize the original photo(corgi.png) to 100 x 100. I am able to to show the original photo by using this code: context.drawImage(image, 0, 0); but the resized photo (100x100) is not showing. What am I doing wr0ng?
let canvas = document.getElementById("demoCanvas");
let context = canvas.getContext("2d");
let image = new Image();
image.src = "corgi.png";
image.onload = () => {
context.drawImage(image, 0, 0);
let smallImageData = new ImageData(100,100);
context.putImageData(smallImageData, 500, 0);
};
I don't understand why you are using drawImage and putImageData both here.
The syntax for drawImage is enough to get the required result:
drawImage(image, dx, dy, dWidth, dHeight)
Using this, your code would look like:
let image = new Image();
image.src = "corgi.png";
image.onload = () => {
context.drawImage(image, 500, 0, 100, 100);
};
Note: Make sure your canvas width is greater than dx + dWidth, i.e. 500 + 100 = 600. Otherwise your image will not be visible.
let canvas = document.getElementById("demoCanvas");
canvas.width = 1000; // >=600
How can I crop an area of an image using JavaScript? As I have read, I must use a canvas to project the image on it.
With the following code I am cutting an area of an image, but the size of the cut area is not the indicated one.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw cropped image
var sourceX = 0;
var sourceY = 0;
var sourceWidth = 500;
var sourceHeight = 150;
var destWidth = sourceWidth;
var destHeight = sourceHeight;
var destX = canvas.width / 2 - destWidth / 2;
var destY = canvas.height / 2 - destHeight / 2;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
<canvas id="myCanvas" style="border:1px solid red"></canvas>
I am trying to represent in this image what I want to do.
my main problem is that the canvas does not adapt to the size of the cropped image and the final height (sourceHeight ) and width (sourceWidth ) They are not the ones I specified
How can i fix it?
The problem
Your source "width" is the same width as the image.
The solution
When using ctx.drawImage with 9 arguments, think of it like a cut and paste.
You want to "cut" the outline in red, and "paste" it to your new - centered - location.
You want to "cut" all the way up to the half way point of the source. So you need to select all the way up to the half way point of the image.
I also suggest maybe changing the variable name from "source" to "crop" (cropX, cropWidth, etc) to better reflect its purpose, as it is not really the width of the "source" anymore.
If you want the image to fill the entire canvas, "paste" it with the canvas' width and height at (0,0)
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, canvas.width, canvas.height);
The code
...
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// crop from 0,0, to 250,150
var cropX = 0;
var cropY = 0;
var cropWidth = 250;
var cropHeight = 150;
//resize our canvas to match the size of the cropped area
canvas.style.width = cropWidth;
canvas.style.height = cropHeight;
//fill canvas with cropped image
context.drawImage(imageObj, cropX, cropY, cropWidth, cropHeight, 0, 0, canvas.width, canvas.height);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
...
You'll need to tell the canvas the size of the image you're trying to display to ensure the canvas has the desiredWith size;
However, the size of your example image is 438 × 300, which makes it hard to crop to 500px.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'https://placehold.it/700x700';
imageObj.onload = function() {
const desiredWidth = 500;
const desiredHeight = 150;
canvas.width = desiredWidth;
canvas.height = desiredHeight;
context.drawImage(imageObj, 0, 0, desiredWidth, desiredHeight, 0, 0, desiredWidth, desiredHeight);
console.log(canvas.width, canvas.height);
};
<canvas id="myCanvas" style="border:1px solid red"></canvas>
I got an image, it could be of every size but I need to take the center area of 86x86. Also I've to do that in javascript when a new image is loaded, replacing the old one.
At the end of the code I need to have my 's src updated with the new image.
function loadedImage(elem,gCount){
var crop = { //just messing with numbers
top : 10,
left : 10,
right : 20,
bottom : 20,
};
var file = elem.files[0]; //I take the loaded image
var img = document.getElementsByName('imag')[gCount]; //I take the interessed <img>
var canvas = document.createElement("canvas"); //create canvas
canvas.width = crop.right - crop.left; //set dimensions
canvas.height = crop.bottom - crop.top;
var ctx = canvas.getContext("2d"); // so we can draw
var image = new Image();
image.setAttribute('crossOrigin', 'anonymous');
image.width = img.width;
image.height = img.height;
image.src = window.URL.createObjectURL(file);
ctx.drawImage(image, -crop.left, -crop.top);
image.src = canvas.toDataURL("image/png");
img.src = image.src;
}
No image is shown
Use a load event listener to wait for your image to load. Once it's ready, you can then start drawing.
To draw the center part of your image, the source x-coordinate should be half the width of your image, minus half the width of the crop. (The source y-coordinate can be calculated in a similar way.)
var input = document.getElementsByName('input')[0];
input.addEventListener('change', function (e) {
var file = e.target.files[0];
drawCroppedImage(file, 86, 86);
});
function drawCroppedImage(file, w, h) {
var canvas = document.getElementById('canvas');
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext('2d');
var image = new Image();
image.addEventListener('load', function (e) {
var sx = (image.width / 2) - (w / 2), // Source X
sy = (image.height / 2) - (h / 2), // Source Y
dx = 0, // Destination X
dy = 0; // Destination Y
ctx.drawImage(image, sx, sy, w, h, dx, dy, w, h);
});
image.src = URL.createObjectURL(file);
}
<input type="file" name="input">
<br><br>
<canvas id="canvas" width="86" height="86"></canvas>
The following code uses GPU.js, a wrapper for WebGL that makes it easy to run matrix operations with WebGL by simply writing JS functions, I render an image on the canvas, but I want to resize it. I've read about nearest neighbor interpolation but I'm confused on how to implement it. I've already set up the resize kernel, all that's left to be done is interpolation logic.
Notes:
the current indexes are available within the kernel function as this.thread.x, this.thread.y, and this.thread.z, depending on the dimensions of the matrix your kernel is computing.
You'll notice the canvas is sized weird. This is a "feature" of GPU.js related to WebGL texture handling (I think they're planning on ironing that out later).
Edit: Made progress but not quite perfected: http://jsfiddle.net/0dusaytk/59/
const canvas1 = document.createElement("canvas");
const context1 = canvas1.getContext("webgl2");
document.body.appendChild(canvas1);
const canvas2 = document.createElement("canvas");
const context2 = canvas2.getContext("2d");
const gpu = new GPU({
canvas: canvas1,
webGl: context1
});
const image = new Image();
image.crossOrigin = "Anonymous";
image.src = "https://i.imgur.com/sl2J6jm.jpg";
image.onload = function() {
const length = 4 * image.height * image.width;
const gpuTexturize = gpu
.createKernel(function(sprite) {
return sprite[this.thread.x];
})
.setOutput([length])
.setOutputToTexture(true);
const gpuResize = gpu
.createKernel(function(sprite, w, h) {
return sprite[this.thread.x];
})
.setOutput([length])
.setOutputToTexture(true);
const gpuRender = gpu
.createKernel(function(sprite, w, h) {
var index = this.thread.x * 4 + (h - this.thread.y) * w * 4;
var r = sprite[index];
var g = sprite[index + 1];
var b = sprite[index + 2];
this.color(r / 255, g / 255, b / 255);
})
.setOutput([image.width, image.height])
.setGraphical(true);
canvas2.width = image.width;
canvas2.height = image.height;
context2.drawImage(image, 0, 0);
const imgData = context2.getImageData(
0,
0,
canvas2.width,
canvas2.height
);
const texture = gpuTexturize(imgData.data);
const resized = gpuResize(texture, 100, 100);
gpuRender(resized, image.width, image.height);
};
body {
background-color: #3a4659;
}
canvas {
background-color: #bcc8db;
}
<script src="https://cdn.jsdelivr.net/npm/gpu.js#latest/dist/gpu-browser.min.js"></script>
I added the second canvas with pixelated render in order to compare this implementation with the browser css default method.
Demo: https://codepen.io/rafaelcastrocouto/pen/pOaaEd
const scale = 4;
// canvas1 will be handled by the gpu
const canvas1 = document.createElement("canvas");
canvas1.className = 'c1';
const context1 = canvas1.getContext("webgl2");
const gpu = new GPU({
canvas: canvas1,
webGl: context1
});
document.body.appendChild(canvas1);
// canvas2 will render the image
const canvas2 = document.createElement("canvas");
canvas2.className = 'c2';
const context2 = canvas2.getContext("2d");
document.body.appendChild(canvas2);
canvas2.style.transform = 'scale('+scale+')';
// load the image
const image = new Image();
image.crossOrigin = "Anonymous";
image.src = "https://placeholdit.imgix.net/~text?txtsize=20&txtpad=1&bg=000&txtclr=fff&txt=64x32&w=64&h=32";
image.onload = function() {
// render image to canvas2
canvas2.width = image.width;
canvas2.height = image.height;
context2.drawImage(image, 0, 0);
// scale imageData
const imgData = context2.getImageData(0,0,image.width,image.height);
const gpuRender = gpu
.createKernel(function(sprite) {
var x = floor(this.thread.x/this.constants.s) * 4;
var y = floor(this.constants.h - this.thread.y/this.constants.s) * 4 * this.constants.w;
var index = x + y;
var r = sprite[ index ]/255;
var g = sprite[index+1]/255;
var b = sprite[index+2]/255;
var a = sprite[index+3]/255;
this.color(r, g, b, a);
},{
constants: {
w: image.width,
h: image.height,
s: scale
}
})
.setOutput([image.width*scale, image.height*scale])
.setGraphical(true);
gpuRender(imgData.data);
};
body {
background-color: #3a4659;
}
canvas {
background-color: #bcc8db;
display: block;
margin: 4em;
}
.c2 {
image-rendering: pixelated;
transform-origin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/gpu.js#latest/dist/gpu-browser.min.js"></script>
I got it working using crop as recommended. Here is how I got it with the plugin. The if statement is only because I have multiple crop sizes, the circular crop is only for square images.
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
if (width==height){
context.globalCompositeOperation='destination-in';
context.beginPath();
context.arc(width/2,height/2,height/2,0,Math.PI*2);
context.closePath();
context.fill();
}
var imageData = canvas.toDataURL('image/png');
return imageData;
},
-- Original Question --
I'm using a jQuery plugin called CropBox which I have set up to export a 300x300 image. I am trying to take the square image and add an overlay that will make the image appear round, adding white corners or subtracting the overlay and have transparent corners.
What I'm going for.
The plugin uses a portion of the canvas to create the image. Once the image is captured I'm looking to add the overlay.
Adding my image and trying to draw the image.
var overlay = new Image();
overlay.src = 'MyOverlay.png';
context.drawImage(overlay, 0, 0);
Then I get lost on how to add this to imageData. It should start at 0, 0 too, any input would be appreciated.
Part of the plugin:
(function ($) {
var cropbox = function(options, el){
var el = el || $(options.imageBox),
obj =
{
state : {},
ratio : 1,
options : options,
imageBox : el,
thumbBox : el.find(options.thumbBox),
spinner : el.find(options.spinner),
image : new Image(),
getDataURL: function ()
{
var width = this.thumbBox.width(),
height = this.thumbBox.height(),
canvas = document.createElement("canvas"),
dim = el.css('background-position').split(' '),
size = el.css('background-size').split(' '),
dx = parseInt(dim[0]) - el.width()/2 + width/2,
dy = parseInt(dim[1]) - el.height()/2 + height/2,
dw = parseInt(size[0]),
dh = parseInt(size[1]),
sh = parseInt(this.image.height),
sw = parseInt(this.image.width);
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
var imageData = canvas.toDataURL('image/png');
return imageData;
},
getBlob: function()
{
var imageData = this.getDataURL();
var b64 = imageData.replace('data:image/png;base64,','');
var binary = atob(b64);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
},