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

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/

Related

HTML 5 Canvas] Image quality when I resize

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.

HTML Canvas fillRect fill 25% of window-height

I'm trying to learn how to use HTML's Canvas and it's properties.
Now I'm trying to draw a ground and a sky, and I want the sky to be 75% of screens height and ground to be 25%.
This was easy using a div, and style it with CSS or JavaScript CSS Query. Now that I'm on a Canvas, I can't figure out how to set the fillRect properties...
My code:
var windowHeight = $(window).height();
var windowWidth = $(window).width();
var skyHeight = windowHeight - (windowHeight * 0.25);
var groundHeight = windowHeight - (windowHeight * 0.75);
ctx = gameCanvas.getContext("2d");
ctx.fillStyle="green";
ctx.fillRect(0,0,windowWidth,windowHeight);
ctx.fillStyle="cyan";
ctx.fillRect(0,0,windowWidth,skyHeight);
Also: if I try using i.e.
ctx.fillStyle="cyan";
ctx.fillRect(0,0,30,30);
This draws a perfect square on top of the green "ground"-background, but if I change to i.e.
ctx.fillRect(0,0,200,200);
it will fill my entire height of the screen, and more than 50% of my screen-width.
According to http://www.w3schools.com/tags/canvas_fillstyle.asp canvas fillrect are using pixels, but 200 x 200 pixels should definitely NOT fill my entire screen height. :/
Where's the part where you tell canvas what its dimensions are? Just like any other HTML media element that you need to be of a specific size (video, image), you need to tell it what its width and height is if you want reliably sized content (if you don't, by convention the canvas will be sized 300 x 150px). And because we're setting the number of pixels we can draw on, this is not "purely cosmetic" like CSS, we have to do it properly:
var cvs = document.querySelector("canvas");
// if you didn't use <canvas width="..." height="...">, we need this:
cvs.width = 800;
cvs.height = 400;
And then you can do your drawing:
var ctx = cvs.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0.75*cvs.height, cvs.width,0.25*cvs.height);
ctx.fillStyle = "lightblue";
ctx.fillRect(0,0, cvs.width, 0.75*cvs.height);
See http://jsbin.com/tejiqixeji/edit?html,js,output

If I resize my canvas, my createJS text becames blurry

I'm using createJS to drawn inside the canvas. I have my canvas set to occupy the browser window maintaining aspect ratio using the resize() function.
This is the code:
mytext = new createjs.Text("Lorem ipsum dolor sit amet 2","19px Calibri","#073949");
mytext.x = 450
mytext.y = 300;
stage.addChild(mytext);
resize = function() {
var canvas = document.getElementById('canvas');
var canvasRatio = canvas.height / canvas.width;
var windowRatio = window.innerHeight / window.innerWidth;
var width;
var height;
if (windowRatio < canvasRatio) {
height = window.innerHeight - 35;
width = height / canvasRatio;
} else {
width = window.innerWidth;
height = width * canvasRatio;
}
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
}()
What happens is that the text gets blurry (decrease of quality) when the canvas resizes.
http://i.imgur.com/RQOSajs.png
vs
http://i.imgur.com/Xwhf5c5.png
How can I solve this issue?
Since you are using CreateJS, you can simply resize the canvas, and scale the entire stage to redraw everything at the new size:
// just showing width to simplify the example:
var newWidth = 800;
var scale = newWidth/myCanvas.width;
myCanvas.width = newWidth;
myStage.scaleX = myStage.scaleY = scale;
myStage.update(); // draw at the new size.
#Adam's answer is correct as far as scaling the canvas goes. You do NOT want to scale with CSS, as it will stretch your canvas instead of changing its pixel dimensions. Set the width and height of the canvas using JavaScript instead.
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
As you stated in your comment, this will only change the canvas size, and not reposition or scale your content. You will have to do this manually. This is fairly simple. Generally, I recommend putting your "resize" listener in the JavaScript in your HTML file, rather than on a frame script.
First, determine the scale, based on the size of the window and the size of your content. You can use the exportRoot.nominalBounds.width and exportRoot.nominalBounds.height which is the bounds of the first frame. If you want to scale something else, use its nominalBounds instead.
Note that nominalBounds is appended to all MovieClips exported from Flash/Animate. If you enable multi-frame bounds, and want to use those, you will have to modify your approach.
The main idea is to use the original, unscaled size of your contents.
var bounds = exportRoot.nominalBounds;
// Uses the larger of the width or height. This will "fill" the viewport.
// Change to Math.min to "fit" instead.
var scale = Math.max(window.innerWidth / bounds.width, window.innerHeight / bounds.height);
exportRoot.scaleX = exportRoot.scaleY = scale;
You can then center it if you want.
exportRoot.x = *window.innerWidth - bounds.width*scale)/2;
exportRoot.y = *window.innerHeight - bounds.height*scale)/2;
Here is a quick sample of a responsive canvas using a simple shape as the scaling contents:
http://jsfiddle.net/lannymcnie/4yy08pax/
Doing this with Flash/Animate CC export has come up a few times, so it is on my list of future EaselJS demos to include on createjs.com, and in the EaselJS GitHub.
I hope this helps.
Take a look at my jsfiddle : https://jsfiddle.net/CanvasCode/ecr7o551/1/
Basically you just store the original canvas size and then use that to work out new positions and sizes
html
<canvas id="canvas" width="400" height="400">
Canvas was unable to start up.
</canvas>
<button onclick="resize()">Click me</button>
javascript
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var originalWidth = canvas.width;
var originalHeight = canvas.height;
render = function()
{
context.fillStyle = "#DDD";
context.fillRect(0,0, originalWidth * (canvas.width / originalWidth), originalHeight * (canvas.height / originalHeight));
context.fillStyle = "#000";
var fontSize = 48 * (canvas.width / originalWidth);
context.font = fontSize+"px serif";
context.fillText("Hello world", 100 * (canvas.width / originalWidth), 200 * (canvas.height / originalHeight));
}
resize = function()
{
canvas.width = 800;
canvas.height = 600;
render();
}
render();
The HTML5 canvas element works with two different sizes
Visual size on screen, controlled via CSS, like you're setting with canvas.style.width/height
Size of pixel buffer for the drawing, controlled via numeric width and height pixel attributes on the canvas element.
The browser will stretch the buffer to fit the size on screen, so if the two values are not 1:1 ratio text will look blurry.
Try adding the following lines to your code
canvas.width = width;
canvas.height = height;
I created a function to resize all the elements on the screen after resizing the canvas. It saves the initial coordinates and scales for the elements with the original width of 900 px and then it changes them according to the current width ratio relative to the original width ratio. The text isn't blurry/bad quality anymore.
resize = function() {
var canvas = document.getElementById('canvas');
var canvasRatio = canvas.height / canvas.width;
var windowRatio = window.innerHeight / window.innerWidth;
var width;
var height;
if (windowRatio < canvasRatio) {
height = window.innerHeight;
width = height / canvasRatio;
} else {
width = window.innerWidth;
height = width * canvasRatio;
}
canvas.width = width;
canvas.height = height;
reziseElements();
};
reziseElements = function()
{
var canvrat = canvas.width / 900;
//Simplified
stage.scaleX = stage.scaleY = canvrat;
//Old Version
/*for (i=0; i<stage.numChildren ;i++)
{
currentChild = stage.getChildAt(i);
if (typeof currentChild.oscaleX == 'undefined')
{
currentChild.oscaleX = currentChild.scaleX;
currentChild.ox = currentChild.x;
currentChild.oy = currentChild.y;
}
}
for (i=0; i<stage.numChildren ;i++)
{
currentChild = stage.getChildAt(i);
currentChild.scaleX = currentChild.scaleY = currentChild.oscaleX * canvrat
currentChild.x = currentChild.ox * canvrat
currentChild.y = currentChild.oy * canvrat
} */
}

width and height in canvas are not accurate

I'm trying to draw a canvas with width x*100px and height y*100px
var x=6,y=5;
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
canvas.style.width=(100*x)+"px";
canvas.style.height=(100*y)+"px";
for(var i=0;i<x;i++)
for(var j=0;j<y;j++)
{
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (i*100, j*100, 100, 100);
ctx.fillStyle = "rgb(0,0,0)";
ctx.strokeRect(i*100, j*100, 100, 100);
}
jsfiddle
but it looks like the width and height of each tile in the grid are not 100 px, Why is that? and how can I set the width of each tile exactly to 100px?
Use this instead:
canvas.width=(100*x);
canvas.height=(100*y);
It seems a bit strange, but canvas is one element type that does not use CSS styling for its width and height. The number of available physical pixels is very relevant to the way that it draws, so it can't be left as a transient, derived CSS value (ie, width: calc(300vw - 100% - 20px);). That said, it's usually a good idea to have width/height change on a browser resize if you're making the web page responsive.

Getting wrong canvas height

I get a wrong canvas height. Whats wrong here?
I made a fiddle: http://jsfiddle.net/hbcz6/
HTML:
<div id="app">
<div id="percent" class="animated"></div>
<canvas></canvas>
</div>
Javascript:
var canvas = document.getElementsByTagName("canvas")[0];
var context = canvas.getContext('2d');
var x = canvas.width / 2;
console.log("canvas X: ", x);
var y = canvas.height / 2;
console.log("canvas y: ", y);
Please have a look to your console.
As you are not setting the size of the canvas element its bitmap will default to 300 x 150 pixels. If you use CSS rules then the element will be stretched but the bitmap will, stay at the same size just scaled to fit the size of the element (just like an image would).
Here is how to dynamically fit a canvas element inside a parent element settings its size properly:
First, remove the width and height from the CSS rule:
#app canvas {
border:2px solid red;
}
Then use getComputedStyle to get the parent element's dimension in pixels:
var cs = getComputedStyle(app),
width = parseInt(cs.getPropertyValue('width'), 10);
height = parseInt(cs.getPropertyValue('height'), 10);
The parseInt will remove the px at the end - now simply use those for the canvas element:
canvas.width = width;
canvas.height = height;
Working fiddle here
You aren't setting the canvas's dimensions. Using CSS to style it only affects the rendered result, it does not affect the underlying canvas that is being drawn on. In this case, it is using the default sizes, and then stretching it to cover the container.

Categories

Resources