I have a canvas like this
<canvas id="canvas" width="600px" height="300px"></canvas>
Now I am trying to show image inside the canvas of some 260px width and height. But its showing the image full screened in canvas. What I am doing wrong?
img.onload = function(){
var im = this;
var imgWidth = im.width;
var imgHeight = im.height;
var imgScaledWidth = 0;
var imgScaledHeight = 0;
imgScaledHeight = self.conHeight - 40;
imgScaledWidth = imgScaledHeight * (imgWidth/imgHeight);
self.context.drawImage(this, 0,0,imgScaledWidth,imgScaledHeight);
}
Its showing like this
There's no reason why your code shouldn't be working based on what you've shown in the question. Here is an example based on the code you've given with some minor changes to account for not having a self variable.
<script>
var img = document.getElementById("image");
var c = document.getElementById("canvas");
var con = c.getContext("2d");
img.onload = function(){
var im = this;
var imgWidth = im.width;
var imgHeight = im.height;
var imgScaledWidth = 0;
var imgScaledHeight = 0;
var off=20;
imgScaledHeight = c.height - off;
imgScaledWidth = imgScaledHeight * (imgWidth/imgHeight);
con.drawImage(this, 0,0+(off/2),imgScaledWidth,imgScaledHeight);
}
</script>
You are stretching it. If you don't want to show the image stretched, just don't pass any size to drawImage:
self.context.drawImage(this, 0, 0);
Related
PS: Is it not a research kind of question! I have been trying to do this from very long time.
I am trying to make web based an image editor where user can select multiple cropping area and after selection save/download all the image area. like below.
As of now I discovered two libraries
1.Cropper.JS where is only single selection feature is available.
2.Jcrop where only single selection area restrictions.
I am currently using cropper.Js but it seems impossible for me to make multiple selection cropping.
Any help is much appreciated.if any other method/library available in JavaScript, Angular or PHP or reactJS for multiple image area selection and crop and download in one go as in the image below.
As per #Keyhan Answer I am Updating my Jcrop library Code
<div style="padding:0 5%;">
<img id="target" src="https://d3o1694hluedf9.cloudfront.net/market-750.jpg">
</div>
<button id="save">Crop it!</button>
<link rel="stylesheet" href="https://unpkg.com/jcrop/dist/jcrop.css">
<script src="https://unpkg.com/jcrop"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
JavaScript
<script>
setImage();
var jcp;
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img, { multi: true });
});
// to fix security issue when trying to convert to Data URI
function setImage() {
document.getElementById('target').setAttribute('crossOrigin', 'anonymous');
document.getElementById('target').src = 'https://d3o1694hluedf9.cloudfront.net/market-750.jpg';
}
var link = document.getElementById('save');
link.onclick = function () {
//we check if at least one crop is available
if (jcp.active) {
var i = 0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for (area of jcp.crops) {
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width', area.pos.w);
canvas.setAttribute('height', area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area' + i + '.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
</script>
I tried to explain the code with comments:
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img,{multi:true});
});
//assuming you have a button with id="save" for exporting cropped areas
var link=document.getElementById('save');
link.onclick = function(){
//we check if at least one crop is available
if(jcp.active){
var i=0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for(area of jcp.crops){
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
EDIT: As you commented it would be nicer if we have local image loader, we can add a file input to our html
<img id="target" />
<br/>
<input type="file" id="imageLoader" name="imageLoader"/><!-- add this for file picker -->
<button id="save">save</button>
and a function to our js to handle it
var jcp;
var save=document.getElementById('save');
var imageLoader = document.getElementById('imageLoader');
var img = document.getElementById("target");
imageLoader.onchange=function handleImage(e){//handling our image picker <input>:
var reader = new FileReader();
reader.onload = function(event){
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
save.onclick = function(){
if(jcp&&jcp.active){
var i=0;
for(area of jcp.crops){
i++;
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(img, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
Jcrop.load('target').then(img => {
jcp = Jcrop.attach(img,{multi:true});
});
Yes, #keyhan was right <input type="file"> is another question, but still, I am giving you an idea of how to implement Kayhan's code above.
<div>
<input type="file" id="image-input" accept="image/*">
<!-- img id name should be "target" as it is also using by Jcrop -->
<img id="target"></img>
</div>
and Now you can put below JavaScript Code just above setImage()
<script>
let imgInput = document.getElementById('image-input');
imgInput.addEventListener('change', function (e) {
if (e.target.files) {
let imageFile = e.target.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("img");
img.onload = function (event) {
var MAX_WIDTH = 1600;
var MAX_HEIGHT = 800;
var width = img.width;
var height = img.height;
// Change the resizing logic
if (width > height) {
if (width > MAX_WIDTH) {
height = height * (MAX_WIDTH / width);
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width = width * (MAX_HEIGHT / height);
height = MAX_HEIGHT;
}
}
// Dynamically create a canvas element
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
// var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Actual resizing
ctx.drawImage(img, 0, 0, width, height);
// Show resized image in preview element
var dataurl = canvas.toDataURL(imageFile.type);
document.getElementById("target").src = dataurl;
}
img.src = e.target.result;
}
reader.readAsDataURL(imageFile);
}
});
</script>
In a NR dashboard I'm trying to determine the width and heigth of a widget group:
var groupWidth = document.getElementById('Home_Test2_cards').offsetWidth;
var groupHeight = document.getElementById('Home_Test2_cards').offsetHeight;
It works for groupWidth but not for groupHeight. I found some references that a div will not return its height when set to invisible but this is not the case here. Is there any way to determine the height?
Using jQuery:
Calling var groupHeight = $('#Home_Test2_cards').height(); works but still only returns 0.
Edit:
Browser Screenshot
Dashboard Template content:
<script>
(function(scope) {
scope.$watch('msg.payload', function(data) {
if (data !== undefined) {
imageObj.src=data;
}
});
}(scope));
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var groupWidth = document.getElementById('Home_Test2_cards').offsetWidth;
//var groupHeight = document.getElementById('Home_Test2_cards').offsetHeigth;
var groupHeight = $('#Home_Test2_cards').height();
console.log('Width:' + groupWidth);
console.log('Height:' + groupHeight);
var imageObj = new Image();
imageObj.onload= function() {
var wRatio = groupWidth / imageObj.width;
var hRatio = groupHeight / imageObj.height;
var ratio = Math.min(wRatio, hRatio);
context.drawImage(imageObj, 0, 0, canvas.width, canvas.height, 0, 0, imageObj.width*ratio, imageObj.height*ratio);
};
</script>
<canvas id="myCanvas"></canvas>
Based on the screenshot above I would expect the height to be 351.
The node-red Dashboard includes the JQuery library, so you should be able to use:
var groupWidth = $('#Home_Test2_cards').width;
var groupHeight = $('#Home_Test2_cards').height;
Importing a picture to EaselJS with Bitmap:
var stage;
$(document).ready(function(){
var gameCanvas = document.getElementById("game");
stage = new createjs.Stage(gameCanvas);
loadPics();
function loadPics() {
let image = new Image();
image.src = "assets/img/island1.png";
image.onload = loadPic;
}
function loadPic(event) {
let bitmap = new createjs.Bitmap(event.target);
bitmap.scaleX = 1;
bitmap.scaleY = 1;
bitmap.image.width = gameCanvas.width;
stage.addChild(bitmap);
stage.update();
}
});
It doesn't matter if I export the picture from photoshop with 400x400 or 200x200
The picture is still all over the canvas.
If i scale it down
bitmap.scaleX = 0.2;
bitmap.scaleY = 0.2;
It becomes extremely blurred
Anyone knows a fix?
Canvas output can get pixelated if scaled with CSS
Make sure you're not adjusting canvas size in CSS but directly on the canvas element via either HTML or JS, otherwise canvas output can get distorted.
var stage;
$(document).ready(function(){
var gameCanvas = document.getElementById("game"),
windowWidth = $(window).width(),
windowHeight = $(window).height();
$(gameCanvas).width(windowWidth+'px');
$(gameCanvas).height(windowHeight+'px');
stage = new createjs.Stage(gameCanvas);
loadPics();
function loadPics() {
let image = new Image();
image.src = "assets/img/island1.png";
image.onload = loadPic;
}
function loadPic(event) {
let bitmap = new createjs.Bitmap(event.target);
bitmap.scaleX = 1;
bitmap.scaleY = 1;
bitmap.image.width = gameCanvas.width;
stage.addChild(bitmap);
stage.update();
}
});
I want to resize a background image 30% to its original size then use it as background to an element. I am sure my mistake is somewhere in the last line.
Here is my code :
var img = new Image();
img.src = "wallpaper.jpg";
var a = img.height;
var newWidth = (img.width*0.3));
var newHeight = (img.height*0.3));
t.getBody().style.backgroundImage = "url("+img.src+")";
t.getBody().style.backgroundSize = "(newWidth)px (newHeight)px";
Values of background-size property should be like Xpx Ypx. Try change Your last line to this:
t.getBody().style.backgroundSize = newWidth+"px "+newHeight+"px";
substitute the newWidth and newHeight values with a space in between.
var img = new Image();
img.src = "wallpaper.jpg";
var a = img.height;
var newWidth = (parseInt(img.width)*0.3);
var newHeight = (parseInt(img.height)*0.3);
t.getBody().style.backgroundImage = "url("+img.src+")";
t.getBody().style.backgroundSize = newWidth+"px "+newHeight+"px";
So I am sure I am missing something small here. I wrote this awhile ago but I came back to it the other day to try and remember why I stopped working on it. Then I realized it's because when you load the page for the first time it doesn't resize the images in the image gallery container.
Then on page refresh the images resize themselves the way they are supposed to. Here is the code.
var ImageGallery = (function(){
/*
Load Images expects an array of URLS for your images, then
it returns an array of new images.
*/
function loadImages(urls){
var images = [];
for(i = 0; i < urls.length; i++){
var tempImage = new Image();
tempImage.src = urls[i];
tempImage.className = "slider-images";
var image = scaleImage(tempImage, 100,100);
//adds even listener to each image
image.addEventListener('click', function(){
addMainPicture(this);
}, false);
images.push(image);
}
var imageContainer = document.getElementById("image-container");
for(i = 0; i < images.length; i++){
imageContainer.appendChild(images[i]);
}
//add main picture
var temp = new Image();
temp.src = urls[0];
temp.className = "slider-images";
var tempMainImage = scaleImage(temp,350,350);
console.log(tempMainImage);
addMainPicture(tempMainImage);
}
/*
Adds the Main Picture. In here you can set the size you want the image
to be, and other styling for the image. Takes in the url for the image.
*/
function addMainPicture(image){
var mainPicture = document.getElementById("main-picture");
mainPicture.src = image.src;
//add styles
mainPicture.style.display = "block";
mainPicture.style.margin = "0px auto";
}
/*
Scales the image taken in to the maxWidth, and maxHeight
stated.Only scales down. Not up.
*/
function scaleImage(img, maxW, maxH){
var maxWidth = maxW,
maxHeight = maxH,
ratio = 0,
imgWidth = img.width,
imgHeight = img.height;
//check width
if(imgWidth > maxWidth){
ratio = maxWidth / imgWidth;
img.width = maxWidth;
img.height = imgHeight * ratio;
imgHeight = imgHeight * ratio;
imgWidth = imgWidth * ratio;
}
//check height
if(imgHeight > maxHeight){
ratio = maxHeight / imgHeight;
img.height = maxHeight;
img.width = maxWidth;
imgWidth = imgWidth * ratio;
}
return img;
}
/*
This runs it all.
*/
function init(){
var urls = ["http://placehold.it/400x400","http://placehold.it/400x400/FFF000","http://placehold.it/400x400/FF0000","http://placehold.it/400x400/0000FF"];
//load in urls for images
loadImages(urls);
var leftButton = document.getElementById("scroll-left"),
rightButton = document.getElementById("scroll-right");
leftButton.addEventListener('click', function(){
var imageContainer = document.getElementById("image-container");
var currentLeft = "";
//checks for NaN
if(imageContainer.style.left == ""){
currentLeft = 0;
}else{
currentLeft = parseInt(imageContainer.style.left);
}
var end = currentLeft + 300;
function frame(){
currentLeft+=5;
imageContainer.style.left = currentLeft+"px";
if(currentLeft == end)
clearInterval(id);
}
var id = setInterval(frame, 10);
}, false);
rightButton.addEventListener('click', function(){
var imageContainer = document.getElementById("image-container");
var currentLeft = "";
if(imageContainer.style.left == ""){
currentLeft = 0;
}else{
currentLeft = parseInt(imageContainer.style.left);
}
var end = currentLeft - 300;
function frame(){
currentLeft-=5;
imageContainer.style.left = currentLeft+"px";
if(currentLeft == end)
clearInterval(id);
}
var id = setInterval(frame, 10);
}, false);
}
return {
init: function(){
init();
}
}
}());
ImageGallery.init();
Sure I am missing something small here but would really like another set of eyes on it.
Here is the fiddle.
Use onLoad event for images. Because your images are not loaded and you need to load images first to scale them:-
tempImage.onload = function(){
scaleImage(this, 100,100);//here your scale code goes
}
You need to run ImageGallery.init(); once the document has loaded, with jQuery you would use:
$(function() {
ImageGallery.init();
});
Without jQuery, you can use
<body onload="ImageGallery.init();">