HTML 5 Canvas] Image quality when I resize - javascript

thank you for taking a look.
What I am trying to do here is... load image from computer (by using FileReader), put img tag's src to the file. Then draw canvas with that image.
function previewFile(){
var preview = document.querySelector('img'); //selects the query named img
var file = document.querySelector('input[type=file]').files[0]; //sames as here
var reader = new FileReader();
reader.onload = function () {
preview.src = reader.result;
drawCanvas();
}
if (file) {
reader.readAsDataURL(file); //reads the data as a URL
} else {
preview.src = "sample.jpg";
}
}
previewFile(); //calls the function named previewFile
window.onload = function () {drawCanvas(); };
function drawCanvas() {
var img = document.querySelector("img");
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
ctx.filter = window.getComputedStyle(document.querySelector("img")).filter;
ctx.drawImage(img, 0, 0);
}
Problem is when I load another image file. It loads in the canvas, but not fit in the canvas size. It keeps the original image size and "part" of the image is shown in the canvas.
In order to solve it, I tried following:
ctx.drawImage(img, 0, 0, document.getElementById('canvas').width,
document.getElementById('canvas').height);
It works, however the image quality becomes really bad... since it is not original image size. It is adjusted to the certain height and forced to be resized.
All I want to do is... keep the original canvas size (width: some px; height: auto), so when I load the image, it fits to the canvas width and adjusted height.
Would you please help me? Thank you.
Added
I researched myself and found following:
I came up with an idea - change the image size first based on the current width of the canvas.
var img = document.querySelector("img");
var canvas = document.getElementById("image");
var ratio = img.height / img.width;
img.width = canvas.offsetWidth;
img.height = img.width * ratio;
Then draw with the edited image.
var ctx = canvas.getContext('2d');
ctx.filter = window.getComputedStyle(img).filter;
ctx.drawImage(img, 0, 0, img.width, img.height);
Then I found the problem. I checked "img.height" variable is 199px. But canvas's height becomes 150px somehow. I checked and there is no css applied to the canvas at all.
So this time, I set canvas width, before drawImage().
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
ctx.filter = window.getComputedStyle(img).filter;
ctx.drawImage(img, 0, 0);
And again, the original image coming back... and "part" of the image is shown in the canvas. The canvas's size is what I wanted though...

Thank you so much for taking a look the issue. Especially #Kaiido who tried to help. Thank you. I am really new to this stackoverflow... so I didn't know how to create demo.
I found the solution. Well... it was really basic knowledge of the Canvas,,, but I think many people will forget / miss following:
var ctx = canvas.getContext('2d');
ctx.canvas.width = 1000;
ctx.canvas.height = 1000;
ctx.drawImage(img, 0, 0, 800, 800);
ctx.canvas.width is canvas's width. ctx.canvas.height is canvas's height.
In drawImage, those 800s are width and height of the image will be drawn, not the canvas's size!! So if you set... let's say 1000, 1000 in drawImage, the image will be resized to the size and it will be drawn into the canvas. If it is bigger than the canvas size, it will show only "part" of your image.
So what I did was... get the div width size where I want to put my canvas. Then calculate the ratio of the image first ( ratio = image's height / image's width ). Then set canvas size to following ( ctx.canvas.width = div width size, ctx.canvas.height = div width size * ratio ). Then draw canvas with canva's width and height ( ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height) ).
Hope this helps someone new like me :) Thank you.

This is pretty simple!
try this.
getting the ratio, setting the height, drawing the image
var ratio = img.naturalWidth / img.naturalHeight;
var width = canvas.width;
var height = width / ratio;
ctx.drawImage(img, 0, 0, width, height);
this worked for me, try this.
see the line
var width = canvas.width;
you can replace the canvas.width by any other value.

Related

Resizing image with HTML5 canvas

I am trying to size an image with canvas. My goal is to have an image of dimensions A x B sized to M x N without changing proportions - like CSS contain. For example, if the source image is 1000x1000 and the destination is 400x300, it should cut off a piece 100 pixels toll at the bottom, and that should correspond to 250 pixels in the source image.
My code is below:
const canvas = document.createElement('canvas');
const img = new Image();
img.src = promotedImage;
const FINAL_WIDTH = 400;
const FINAL_HEIGHT = 250;
const width = img.width;
const height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height, 0, 0, FINAL_WIDTH, FINAL_HEIGHT);
const finalImage = b64toFile(canvas.toDataURL("image/jpg"));
This is not working, like I want to, though. I am obviously using drawImage incorrectly. For me, if copies source to destination without sizing.
Is this because I need to size (change dimensions) for canvas prior to drawing? Please advise.
I have also tried something like Mozilla image upload. It does even scale the image, but it does not crop. Plus, it sizes a source square to the smaller target side, instead of clipping it.
Setting an image source is asynchronous, can be very fast, but often not fast enough to keep up with still-running code. Generally, to make them work reliably, you set an onload handler first and then set src. The canvas element defaults to 300x150 so would also need to be sized. (Canvas obeys CORS. .crossOrigin = '' sets us as anonymous and imgur has a permissive CORS policy. We wouldn't be able to convert the canvas to an image while using a third-party image in this snippet otherwise.)
const MAX_WIDTH = 400;
const MAX_HEIGHT = 300;
const img = new Image();
img.crossOrigin = '';
img.onload = () => {
const wRatio = MAX_WIDTH / img.width;
const hRatio = MAX_HEIGHT / img.height;
var width, height;
if(wRatio > hRatio) {
width = MAX_WIDTH;
height = wRatio * img.height;
}
else {
width = hRatio * img.width;
height = MAX_HEIGHT;
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
//const finalImage = b64toFile(canvas.toDataURL("image/jpg"));
const imgElement = document.createElement('img');
imgElement.src = canvas.toDataURL('image/jpg');
document.body.appendChild(imgElement);
};
img.src = 'https://i.imgur.com/TMeawxt.jpeg';
img { border: 1px solid red; }

How to initialise an image from a canvas?

Assume I have a an image and a canvas. I use the canvas api to modify the displayed image.
I now need to have 2 copies of the image, the original and the modified one.
the pseudo code to convey what I am trying to do would be:
var img = fetchImage();
context.drawLine(0, 0, 100, 100);
var copy = context.getImage();
I have tried searching it up but I don't find an answer to this.
Edit:
By "initialise", I mean creating a deep copy of an image. So, the original image has no line, the modified image in the canvas has a line, I now need 2 independent images, one with the line and one without.
You get an image out of a drawn canvas with the getImageData method.
Or perhaps even toDataURL might be of help.
If you're working with image data URL's, try this snippet
let imageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAFIklEQVR4nO2aT2wUVRzHv7+36+y2NYUCLoYDZrHLVhoVNOpBSWgk6KUxxLSEEJUjakI9STzISaIxRtSEhIPxvxeQYAKJsf6ploNRiyY2DdPZXTbpwdpVhPCnbKez8/XQNTRhp/vnzezWOJ9b+95832++773fe2/eAiEhISH/YyQIUZKRqampzmKx2K6UEsMwrp0/f/5KX1+fE0R7OvhqgGma65RSOwBsJ5kGsKpcdJHkpIh8aRjGcDKZ/MPPdnXwxYB8Ph+3bXsQwAsA7gYQ9ajqkPwNwJuxWOxEMpks+tG+DtoG5HK5FY7jHATwLIC2Wp4hOQvgSCQSeSWVSl3WjUEHLQPKPX8IwBCASJ2POyQPRyKRl1Op1JxOHDoonYdt295Fch/qf3lgYZo8XyqVBnRi0KXhEWCa5joROQ1gi2YMZ0ulUv+mTZumF68eABCPx2fXr19/WURKmm140rABlmXtJfkuGuv9xcwDOEDyT6XU4+XVo6tcdlFEJgF87brucE9Pz++abd1EQwaQjGQymQ9J7vEpjmsADAC3eJQ7AMYBvGUYxjE/V4+GcsDU1FRnuaf8ogPeLw8s5IstAI7atn0ol8ut8Kvhhgwoz9GuqhX9pw3AkOM4B/P5fNwPQa1VoEVESO6zbXuXH2INGRCPx2cBXPQjgEYQkXYAQ6ZprtPVqssAkurcuXMbi8XiXgBrdRvX5J7yuUMLrz37TeTz+dszmcxzSqmnANyBgE6SdRDBwqHrY519Qk0GWJa12bbtNwD0YRnlDZLp8fHxTmhMx6oGWJa1meR70N/xBUFXLBZrh4YBS/ZmOckcxvJ8eV/wHAEkJZPJ7CO5rZkB1YOIXHddd3U2m1WlUsmNRqNXN2zYcEVE3Jo1vApM00yLyBcAkr5EGwxzAAokKSLzJAsiMqaUOmHb9g+9vb12NQFPAyzL2k/ybV/DbR6XROQDpdSr3d3dhaUqVswBIyMjUQCPBBJac1hJcsh13SPZbDaxVMWKBiQSiU7Xde8MJramISSfdF33pbGxMc+DVkUDDMNoF5GVwcXWNATAMx0dHQ97VVg2m5qgINklIju9yisaYNv2LMlLwYXVdB7w+oZQ0YBCoXBZKZULNqbmISIJx3FurVRW0YDyFdaZQKNqLvQq8MwBrusOA8gHEk7zKSilrlQq8DQgnU5bIvIJlnDvv4KI/Ox1A+V5FhARmqZ5VETuA3AvyZr318sFEREAV0me8KxTTWRiYmJVPB6vmED+C8zPzzvT09OF5Xg1H7IcCO67Hin931mrAeDUto0XINJYMvVLx4PAtsL9o9kBAMMCfPXEqDXYah0vAhkB/d9meiHu5wC6F1rhL6A8dqov/VcrdJbC9xEwMDFhQLn78W/QZaIlt66h65dONXw34PpMdCuIxUO1RFc+Pbn9rgut0KmG7waIyBYAi74lyBkRfNQqnWoEYIB7FsBM+c8ZCF9vZM76pVONmq/GaiVWSI/OJSZ3k3iQiPzYVuhu6FTpl041fFkFBo4xcv227FZB6SER/BQrpEePD9Z/X+eXTj34MgKKCWuHEO8DspbEzFxicjeAkVbp1IN2DugfmVwDyou4cV2+llT3t0qnXrQNIPE0wK2L/nWJ5K+t0qkXrSnQPzK5BsI9oNz4qZzgWFvCqSth+aXTCH4vg1m46p3jNdzJNUmnKtqrQP/3mUGwdAAUEuq1032pz1qpUy/6yyApO78xVwHAyUd7/tY59vqiExISEhISEhISUhv/AESDVQMMfbjKAAAAAElFTkSuQmCC';
let image = document.querySelector('img');
image.src = imageDataUrl;
let canvas;
image.addEventListener('load', () => {
canvas = document.querySelector('canvas');
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
let margin = 10;
context.strokeRect(margin, margin, canvas.width - margin * 2, canvas.height - margin * 2);
console.log('new data url:', canvas.toDataURL());
});
<div>
<img src="https://www.google.com/logos/doodles/2019/us-teacher-appreciation-week-2019-begins-4994791740801024-l.png">
</div>
<div>
<canvas></canvas>
</div>

Image on Canvas is drawn larger than original size

On load of my image I:
var img = new Image();
img.src = e.target.result;
var canvas = $('#test-canvas')[0];
$('#test-canvas').width(img.width);
$('#test-canvas').height(img.height);
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
But the image is drawn larger than it's original size? I've tried a few images, same problem.
What's the fix?
jQuery will resize the element through CSS, which won't actually change the canvas internal height and width. This will resize the actual canvas element.
var canvas = document.GetElementById('test-canvas');
canvas.width = img.width;
canvas.height = img.height;
jsFiddle (http://jsfiddle.net/L0drfwgL/) just show it drawing it to scale, and resizing the canvas item itself.
It looks like you are pulling the image from an image element on load. You can use the src from the image element rather than recreating an image object and then get the image width/height from the element to draw the image to canvas.
<script>
$(document).ready(function(){
$('#testImg').on('load',function(){
var image = document.getElementById('testImg');
var canvas = document.getElementById('test-canvas');
canvas.width = image.width;
canvas.height = image.height;
var ctx=canvas.getContext("2d");
ctx.drawImage(image,0,0);
})
});
</script>
/** with vue3 -(to fix drawing canvas image is larger than actual image size **/
const captureImage = () => {
let width = video.value.getBoundingClientRect().width;
let height = video.value.getBoundingClientRect().height;
let context = canvas.value.getContext('2d')
canvas.value.width = width
canvas.value.height = height
context.drawImage(video.value, 0, 0, width, height)
}

Using drawImage() to output fixed size images on a canvas?

How do I use drawImage() to output full size images on a 300px X 380px canvas regardless of the source image size?
Example:
1). If there is a image of 75px X 95px I want to be able to draw it to fit a 300px X 380px canvas.
2). If there is a image of 1500px X 1900px I want to be able to draw it to fit a 300px X 380px canvas.
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("myPic");
ctx.drawImage(img,10,10);
What options are available to prevent any quality loss?
To scale the image to fit is not so hard, just use simple aspect ratio with the sizes:
var ratioX = canvas.width / image.naturalWidth;
var ratioY = canvas.height / image.naturalHeight;
var ratio = Math.min(ratioX, ratioY);
ctx.drawImage(image, 0, 0, image.naturalWidth * ratio, image.naturalHeight * ratio);
To maintain quality; a canvas of 300x380 will either appear very tiny on print, or very blurry.
It's important to keep the data from it in the target resolution. To do this, calculate the size using the target DPI (or rather, PPI). You will also need to know in advance what size the 300x380 area represents (e.g. in either inches, centimeters, millimeters etc.).
For example:
If the target PDF will have a PPI of 300, and the canvas represents 3 x 3.8 cm (just to keep it simple), then the width and height in pixel will be:
var w = (3 / 2.54) * 300; // cm -> inch x PPI
var h = (3.8 / 2.54) * 300;
Use this size on canvas' bitmap, then scale down the element using CSS:
canvas.width = w|0; // actual bitmap size, |0 cuts fractions
canvas.height = h|0;
canvas.style.width = "300px"; // size in pixel for screen use
canvas.style.height = "380px";
You can now use the canvas directly as an image source for the PDF while keeping print quality for the PDF (have in mind though, small images uploaded will not provide high print quality in any case).
And of course, set the canvas size first, then use the code at top to draw in the image.
You'll need to resize your source image. You will need to calculate the destination size of the image, then use a couple extra parameters during your draw.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 188;
var y = 30;
var width = 200;
var height = 137;
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, x, y, width, height);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
body {
margin: 0px;
padding: 0px;
}
<canvas id="myCanvas" width="578" height="200"></canvas>
Source: http://www.html5canvastutorials.com/tutorials/html5-canvas-image-size/

Using canvas to draw image at true size

I'm trying to load an image from a URL into a HTML canvas at a 1:1 scale. I load the image, and set the canvas DOM element to the appropriate dimensions, but for some reason the image in the canvas is significantly upscaled and therefore only the top left hand corner is drawn.
This is demonstrated by the following JSFiddle: http://jsfiddle.net/KdrYr/1/
var img = new Image();
var cv = document.getElementById('thecanvas');
img.src = 'http://www.photographyblogger.net/wp-content/uploads/2009/12/Picture-in-a-picture4.jpg';
img.onload = function() {
var ctx = cv.getContext('2d');
cv.style.width = img.width + 'px';
cv.style.height = img.height + 'px';
ctx.drawImage(img, 0, 0);
};
For example, I'm trying to draw this (sorry about the big images :/)
But end up with this
What could be causing this?
You need to assign the canvas actual width and height, not via its style:
cv.width = img.width;
cv.height = img.height;
Live test case.
As for the why, well, it's explained already here.

Categories

Resources