Related
I'm trying to make a section on a website have two background images that will reveal the bottom one as the pointer moves across the screen.
I'm still new to javascript, and my code is made up of bits and pieces that I've found on google, but I can't seem to get the top image to share the same resolution and image size for whatever reason as the bottom image.
Here is the link to my codepen: https://codepen.io/Awktopus/pen/zYwKOKO
And here is my code:
HTML:
<canvas id="main-canvas" id="canvas-size" class="background-size"></canvas>
<image src="https://i.imgur.com/PbGAAIy.jpg" id="upper-image" class="hidden-bg"></img>
<image src="https://i.imgur.com/Gx14sKW.jpg" id="lower-image" class="hidden-bg"></img>
CSS:
.hidden-bg {
display: none;
}
JS:
var can = document.getElementById('main-canvas');
var ctx = can.getContext('2d');
can.width = window.innerWidth;
can.height = window.innerWidth / 2;
var upperImg = document.getElementById("upper-image");
var lowerImg = document.getElementById("lower-image");
var pat = ctx.createPattern(upperImg, "no-repeat");
var canvas = ctx.canvas ;
var hRatio = canvas.width / lowerImg.width ;
var vRatio = canvas.height / lowerImg.height ;
var ratio = Math.max ( hRatio, vRatio );
var centerShift_x = ( canvas.width - lowerImg.width*ratio ) / 2;
var centerShift_y = ( canvas.height - lowerImg.height*ratio ) / 2;
can.addEventListener('mousemove', function(e) {
var mouse = getMouse(e, can);
redraw(mouse);
}, false);
function redraw(mouse) {
can.width = can.width;
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.drawImage(lowerImg, 0,0, lowerImg.width, lowerImg.height, centerShift_x,centerShift_y,lowerImg.width*ratio, lowerImg.height*ratio);
ctx.beginPath();
ctx.rect(0,0,can.width,can.height);
ctx.arc(mouse.x, mouse.y, 250, 0, Math.PI*2, true)
ctx.clip();
ctx.fillStyle = pat;
ctx.fillRect(0, 0, lowerImg.width, lowerImg.height, centerShift_x, centerShift_y, lowerImg.width*ratio, lowerImg.height*ratio);
}
var img = new Image();
img.onload = function() {
redraw({x: -500, y:-500})
}
function getMouse(e, canvas) {
var element = canvas,
offsetX = 0,
offsetY = 0,
mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {
x: mx,
y: my
};
}
If I understood this right you will want to set the width and height and draw the upper image using drawImage(). Just use the same ratios as the lowerImage. No need to use createPattern for this.
codepen: https://codepen.io/jfirestorm44/pen/BaRLoxX
var can = document.getElementById('main-canvas');
var ctx = can.getContext('2d');
can.width = window.innerWidth;
can.height = window.innerWidth / 2;
var upperImg = document.getElementById("upper-image");
var lowerImg = document.getElementById("lower-image");
//var pat = ctx.createPattern(upperImg, "no-repeat");
var canvas = ctx.canvas ;
var hRatio = canvas.width / lowerImg.width ;
var vRatio = canvas.height / lowerImg.height ;
var ratio = Math.max ( hRatio, vRatio );
var centerShift_x = ( canvas.width - lowerImg.width*ratio ) / 2;
var centerShift_y = ( canvas.height - lowerImg.height*ratio ) / 2;
can.addEventListener('mousemove', function(e) {
var mouse = getMouse(e, can);
redraw(mouse);
}, false);
function redraw(mouse) {
can.width = can.width;
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.drawImage(lowerImg, 0,0, lowerImg.width, lowerImg.height, centerShift_x,centerShift_y,lowerImg.width*ratio, lowerImg.height*ratio);
ctx.beginPath();
ctx.rect(0,0,can.width,can.height);
ctx.arc(mouse.x, mouse.y, 250, 0, Math.PI*2, true)
ctx.clip();
ctx.drawImage(upperImg, 0,0, lowerImg.width, lowerImg.height, centerShift_x,centerShift_y,lowerImg.width*ratio, lowerImg.height*ratio);
}
var img = new Image();
img.onload = function() {
redraw({x: -500, y:-500})
}
function getMouse(e, canvas) {
var element = canvas,
offsetX = 0,
offsetY = 0,
mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {
x: mx,
y: my
};
}
.hidden-bg {
display: none;
}
<canvas id="main-canvas" id="canvas-size" class="background-size"></canvas>
<image src="https://i.imgur.com/PbGAAIy.jpg" id="upper-image" class="hidden-bg"></img>
<image src="https://i.imgur.com/Gx14sKW.jpg" id="lower-image" class="hidden-bg"></img>
So I was playing around the canvas and I tried rotating images loaded from my device hard disk as seen below:
class imageEdits {
constructor(canvas, imageSrc, canvasWidth, canvasHeight) {
this.canvas = canvas;
this.ctx = this.canvas.getContext("2d");
this.image = new Image();
this.image.src = imageSrc;
this.cWidth = canvasWidth;
this.cHeight = canvasHeight;
}
rotateImage = deg => {
this.ctx.save();
function degToRad(deg) {
return (1 / 57.3) * deg;
}
let imageHeight = this.image.naturalHeight,
imageWidth = this.image.naturalWidth;
if (deg !== 0 && deg !== 180) {
imageHeight = this.image.naturalWidth;
imageWidth = this.image.naturalHeight;
} else {
(imageHeight = this.image.naturalHeight),
(imageWidth = this.image.naturalWidth);
}
const {
canvasStyle: { height, width, scale, aspectRatio },
} = this.computeAspectRatio(imageHeight, imageWidth);
console.log({ height, width, scale, aspectRatio });
const halfWidth = width / 2;
const halfHeight = height / 2;
this.ctx.translate(halfWidth, halfHeight);
this.ctx.rotate(degToRad(deg));
this.canvas.style.transform = `scale3d(${scale}, ${scale}, 1)`;
this.canvas.style.backgroundColor = "rgb(0,0,0)";
this.canvas.style.transformOrigin = `top left`;
console.log({ width, height });
this.ctx.drawImage(this.image, -halfWidth, -halfHeight, width, height);
this.ctx.restore();
};
computeAspectRatio = (imageHeight, imageWidth) => {
const height = imageHeight;
const width = imageWidth;
(scale = 1), (canvasStyle = {});
this.canvas.width = width;
this.canvas.height = height;
const scaleX = this.cWidth / width;
const scaleY = this.cHeight / height;
if (scaleX > scaleY) scale = scaleY;
else scale = scaleX;
canvasStyle = { height, width, scale };
return { canvasStyle };
};
}
The problem with the code is that when I rotate the image to the inverse of its aspect ratio which is 90degree of 180degree the image gets centered and doesn't take the full width or height as the case may be of the canvas.
here is a jsfiddle of the working code
And this is what my expected output should look like
But instead this is what I get
Please does anyone see what I am doing wrong? Thanks in advance :)
In general a rotation around the center is done by translating the context to the mid-point of the canvas, rotating the context and finally drawing the image at the negative half of it's width horizontally and negative half of it's height vertically.
What makes things a bit harder in your case is that the image should always fill the entire canvas, while maintaining it's correct aspect ratio. To do this we would need to know the exact width & height of the image - or more precisely it's bounding box - at a given angle. Luckily we just have to deal with four angles, so it's just a matter of swapping the width & height at 90° and 270° - as you already did.
Now that we know the image's dimensions we need to compute the scale along both axes and see which one of those doesn't exceed the canvas width & height after multiplication.
This scale is then used to scale the context - not the css scale you used to size the canvas itself.
Here's an example based on your code (just click on 'Run code snippet'):
const canvas = document.getElementById("edit-canvas");
const ctx = canvas.getContext("2d");
const canvasWidth = 320;
const canvasHeight = 200;
let deg = 0;
let image;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
function degToRad(deg) {
return (1 / 57.3) * deg;
}
function draw() {
let scale, imageHeight, imageWidth, scaleX, scaleY;
if (deg != 0 && deg != 180) {
imageHeight = image.width;
imageWidth = image.height;
} else {
imageHeight = image.height;
imageWidth = image.width;
}
scaleX = canvasWidth / imageWidth;
scaleY = canvasHeight / imageHeight;
if (imageWidth * scaleX <= canvasWidth && imageHeight * scaleX <= canvasHeight) {
scale = scaleX;
} else {
scale = scaleY;
}
ctx.save();
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.translate(canvasWidth / 2, canvasHeight / 2);
ctx.rotate(degToRad(deg));
ctx.scale(scale, scale);
ctx.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height);
ctx.restore();
}
image = new Image();
image.onload = draw;
image.src = "https://picsum.photos/id/1079/300/200";
document.getElementById("rotate").addEventListener("click", () => {
deg += 90;
if (deg == 360) deg = 0;
draw();
});
<div class="canvas-container">
<input type="button" id="rotate" style="padding: 10px; font-size: 16px; position: absolute" value="Rotate" />
<canvas id="edit-canvas" style="border: 1px solid #000; margin-left: 10px;background-color: #c1f0c1;"></canvas>
</div>
I have this function that resizes an image (after that I have some other stuff to rotate and crop to a square.
The problem here is I want the user be able to post images that are at least 640x640. What happens with this function is that if a user posts a 1080X1920 image (iphone picture), it will resize it to 562 X 1000 and then (with not shown code) it will be cropped to 562 X 562 ... The server will so refuse the image because it's smaller then 640X640.
Can anyone help me improve this function so that it will return max width and height 1000 X 1000 but also respect a min width and height 640 X 640 ?
By experimenting I found that if I set the Max Width and Height to 1138 the same 1080X1920 px image will be cropped to 640X640 but that is not acceptable solution. Any clue?
img.onload = function () {
var width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
start_Y,
start_X;
console.log( width, " ", height);
var MAX_WIDTH = 1000;
var MAX_HEIGHT = 1000;
// set proper canvas dimensions before transform & export
if ([5, 6, 7, 8].indexOf(srcOrientation) > -1) {
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = height;
canvas.height = width;
console.log(canvas.width, " ", canvas.height);
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
canvas.width = width;
canvas.height = height;
console.log(canvas.width, " ", canvas.height);
}
}
maybe I found a way, I modified the function like this:
img.onload = function () {
var width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
start_Y,
start_X;
var MAX_WIDTH = 1000;
var MAX_HEIGHT = 1000;
var MIN_WIDTH = 640;
var MIN_HEIGHT = 640;
var ratio;
// set proper canvas dimensions before transform & export
if ([5, 6, 7, 8].indexOf(srcOrientation) > -1) {
if (width > height) {
console.log('w > h');
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
if(height < MIN_HEIGHT){
ratio = MIN_HEIGHT / height;
height = MIN_HEIGHT;
width = MAX_WIDTH * ratio;
}else{
width = MAX_WIDTH;
}
}
} else {
console.log('h > w');
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
if(width < MIN_WIDTH){
ratio = MIN_WIDTH / width;
width = MIN_WIDTH;
height = MIN_HEIGHT * ratio;
}else{
height = MAX_HEIGHT;
}
}
}
canvas.width = height;
canvas.height = width;
console.log(canvas.width, " ", canvas.height);
} else {
console.log('other Orientations');
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
if(width < MIN_WIDTH){
ratio = MIN_WIDTH / width;
width = MIN_WIDTH;
height = MAX_HEIGHT * ratio;
}else{
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
console.log(canvas.width, " ", canvas.height);
}
}
You have to calculate a ratio like this when width is bigger than height
var ratio = 640 / height;
Or
var ratio = 640 / width;
Having this ratio you can calculate the other value
Height = ratio × height;
Width = ratio × width;
After this you have a redized image / element.
I'm drawing images on a canvas like this:
ctx.drawImage(data[i].image, data[i].pos.x, data[i].pos.y, data[i].pos.w, data[i].pos.h);
The picture is getting stretched and I don't want this. How can I simulate the CSS property?
background-size: cover
when drawing images on the canvas?
http://www.w3schools.com/cssref/playit.asp?filename=playcss_background-size&preval=cover
see the difference between 100% 100% (what I currently have) and cover (my goal).
It's a bit more complicated to get a cover functionality, though here is one solution for this:
Updated 2016-04-03 to address special cases. Also see #Yousef's comment below.
/**
* By Ken Fyrstenberg Nilsen
*
* drawImageProp(context, image [, x, y, width, height [,offsetX, offsetY]])
*
* If image and context are only arguments rectangle will equal canvas
*/
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
// default offset is center
offsetX = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? offsetY : 0.5;
// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, // new prop. width
nh = ih * r, // new prop. height
cx, cy, cw, ch, ar = 1;
// decide which gap to fill
if (nw < w) ar = w / nw;
if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated
nw *= ar;
nh *= ar;
// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
Now you can call it like this:
drawImageProp(ctx, image, 0, 0, width, height);
and it will scale the image proportionally to fit inside in that container.
Use the two last parameters to offset the image:
var offsetX = 0.5; // center x
var offsetY = 0.5; // center y
drawImageProp(ctx, image, 0, 0, width, height, offsetX, offsetY);
If you're looking for a simpler solution that will work for most cases, and also includes css contain-like functionality, try this:
function fit(contains) {
return (parentWidth, parentHeight, childWidth, childHeight, scale = 1, offsetX = 0.5, offsetY = 0.5) => {
const childRatio = childWidth / childHeight
const parentRatio = parentWidth / parentHeight
let width = parentWidth * scale
let height = parentHeight * scale
if (contains ? (childRatio > parentRatio) : (childRatio < parentRatio)) {
height = width / childRatio
} else {
width = height * childRatio
}
return {
width,
height,
offsetX: (parentWidth - width) * offsetX,
offsetY: (parentHeight - height) * offsetY
}
}
}
export const contain = fit(true)
export const cover = fit(false)
slightly modified version of intrinsic-scale to include scale and offset
Usage:
import {cover, contain} from './intrinsic-scale'
const {
offsetX,
offsetY,
width,
height
} = cover(parentWidth, parentHeight, imageWidth, imageHeight)
// or...
const {
offsetX,
offsetY,
width,
height
} = contain(parentWidth, parentHeight, imageWidth, imageHeight)
ctx.drawImage(image, offsetX, offsetY, width, height)
Canvas image fitting canvas like background-size cover and contain
const coverImg = (img, type) => {
const imgRatio = img.height / img.width
const winRatio = window.innerHeight / window.innerWidth
if ((imgRatio < winRatio && type === 'contain') || (imgRatio > winRatio && type === 'cover')) {
const h = window.innerWidth * imgRatio
ctx.drawImage(img, 0, (window.innerHeight - h) / 2, window.innerWidth, h)
}
if ((imgRatio > winRatio && type === 'contain') || (imgRatio < winRatio && type === 'cover')) {
const w = window.innerWidth * winRatio / imgRatio
ctx.drawImage(img, (win.w - w) / 2, 0, w, window.innerHeight)
}
}
Codepen demo
Usage:
coverImg(myImage, 'cover');
coverImg(myImage, 'contain');
Try this (based on #daviestar's answer):
getCanvas = function(img, w, h) {
// Create canvas
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// Set width and height
canvas.width = w;
canvas.height = h;
// Draw the image
let containerRatio = h / w;
let width = img.naturalWidth;
let height = img.naturalHeight;
let imgRatio = height / width;
if (imgRatio > containerRatio) { // image's height too big
height = width * containerRatio;
} else { // image's width too big
width = height / containerRatio;
}
let s = {
width: width,
height: height,
offsetX: (img.naturalWidth - width) * .5,
offsetY: (img.naturalHeight - height) * .5
};
ctx.drawImage(img, s.offsetX, s.offsetY, s.width, s.height, 0, 0, w, h);
return canvas;
}
The below script is a reference from #user1693593, and I do some modifications as below
use Destructuring assignment to make the options more flexible
The script provides a runnable example, so you don't worry the link is not found.
<script>
function clamp(num, a, b) {
return num > b ? b
: num < a ? a
: num
}
/**
* #param {CanvasRenderingContext2D} ctx
* #param {HTMLImageElement} img
* #param {Number} dx
* #param {Number} dy
* #param {Number} dw
* #param {Number} dh
* #param {Number} offsetX
* #param {Number} offsetY
* */
function drawImageProp(ctx, img, {dx = 0, dy = 0, dw = undefined, dh = undefined, offsetX = 0.5, offsetY = 0.5}) {
dw = dw ?? ctx.canvas.width
dh = dh ?? ctx.canvas.height
// keep bounds [0.0, 1.0]
offsetX = clamp(offsetX, 0, 1)
offsetY = clamp(offsetY, 0, 1)
let iw = img.width,
ih = img.height,
ratio = Math.min(dw / iw, dh / ih),
nw = iw * ratio,
nh = ih * ratio, // new prop. height
sx, sy, sw, sh, ar = 1;
// decide which gap to fill
if (nw < dw) ar = dw / nw
if (Math.abs(ar - 1) < 1e-14 && nh < dh) ar = dh / nh // updated
nw *= ar
nh *= ar
// source rectangle
sw = iw / (nw / dw)
sh = ih / (nh / dh)
sx = (iw - sw) * offsetX
sy = (ih - sh) * offsetY
// make sure source rectangle is valid
if (sx < 0) sx = 0
if (sy < 0) sy = 0
if (sw > iw) sw = iw
if (sh > ih) sh = ih
img.onload = (event) => {
// fill image in dest. rectangle
ctx.drawImage(event.target, sx, sy, sw, sh, dx, dy, dw, dh)
}
}
// Test Only 👇
window.onload = () => {
const testArray = [
["Default", (ctx, img)=>{drawImageProp(ctx, img, {})}],
["Full", (ctx, img)=>{drawImageProp(ctx, img, {offsetY:0})}], // If you don't want to it cutting from two sides, you can set "offsetY = 0" then it will cut a large part from the bottom
["1/2",(ctx, img)=>{drawImageProp(ctx, img, {dx:window.innerWidth/4, dy:window.innerHeight/4, dw: window.innerWidth/2, dh:window.innerHeight/2})}],
["3/4",(ctx, img)=>{drawImageProp(ctx, img, {dx:window.innerWidth/8, dy:window.innerHeight/8, dw: window.innerWidth*3/4, dh:window.innerHeight*3/4})}]
]
for (const [testName, drawFunc] of testArray) {
const btn = document.createElement("button")
btn.innerText = testName
btn.onclick = () => {
document.querySelectorAll(`canvas`).forEach(e=>e.remove()) // remove old data
const img = new Image(590, 470)
img.src = "https://upload.wikimedia.org/wikipedia/commons/b/bd/Test.svg"
const canvas = document.createElement("canvas")
canvas.width = window.innerWidth
canvas.height = window.innerHeight
const ctx = canvas.getContext("2d")
drawFunc(ctx, img)
document.querySelector(`body`).append(canvas)
}
document.querySelector(`body`).append(btn)
}
}
</script>
For whom it may concern, I was looking for this answer but had to develop my own solution written in typescript, with file type solution:
const resizeBase64Img = (
base64: string, // image base64
type: string, // image mime type
newWidth: number, // new image width
newHeight: number // new image height
) =>
new Promise<string>((resolve, reject) => {
// rejects promise if no document variable
if (!document) {
reject('document is not available');
}
// create a brand new canvas element
const canvasElement = document.createElement('canvas');
// set its width
canvasElement.width = newWidth;
// and height
canvasElement.height = newHeight;
// adjust style for width
canvasElement.style.width = newWidth.toString() + 'px';
// and height
canvasElement.style.height = newHeight.toString() + 'px';
// get canvas context
const context = canvasElement.getContext('2d') as CanvasRenderingContext2D;
// create nem image
const img = new Image();
// set it's source from base64 argument
img.src = base64;
// when it loads
img.onload = () => {
// get the imgRatioType: landscape or portrait
const imgRatioType =
img.width / img.height >= 1 ? 'landscape' : 'portrait'; // 1 > landscape ; 1 < portrait
// if image is a portrait, then what's limiting it's sWidth is the img width. Otherwise it'll be the img height
const sWidth = imgRatioType === 'portrait' ? img.width : img.height;
// if image is a landscape, then what's limiting it's sHeight is the img height. Otherwise it'll be the img width
const sHeight = imgRatioType === 'landscape' ? img.height : img.width;
// if landscape, the image width is equals to 2 equal sx plus the sWidth. Otherwise, it should be 0.
const sx = imgRatioType === 'landscape' ? (img.width - sWidth) / 2 : 0;
// if portrait, the image height is equals to 2 equal sy plus the sHeight. Otherwise, it should be 0.
const sy = imgRatioType === 'portrait' ? (img.height - sHeight) / 2 : 0;
// destination canvas should have no space on dx
const dx = 0;
// neither on dy
const dy = 0;
// it's dWidth should be equal to the canvas width
const dWidth = canvasElement.width;
// and the same applies to dHeight with height
const dHeight = canvasElement.height;
// use clearRect for setting pixels in a clear rectangle with defined width and height
context.clearRect(0, 0, canvasElement.width, canvasElement.height);
// then draws the image
context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
// resolve the promise with canvas toDataUrl method using type argument for mime
resolve(canvasElement.toDataURL(type));
};
img.onerror = (err) => {
// if image fails to load, rejects promise
reject(err);
};
});
I'm trying to scale an image proportionately to the canvas. I'm able to scale it with fixed width and height as so:
context.drawImage(imageObj, 0, 0, 100, 100)
But I only want to resize the width and have the height resize proportionately. Something like the following:
context.drawImage(imageObj, 0, 0, 100, auto)
I've looked everywhere I can think of and haven't seen if this is possible.
context.drawImage(imageObj, 0, 0, 100, 100 * imageObj.height / imageObj.width)
#TechMaze's solution is quite good.
Here is the code after some corrections and the introduction of the image.onload event. image.onload is essential in order to avoid any kind of distortion.
function draw_canvas_image() {
var canvas = document.getElementById("image-holder-canvas");
var context = canvas.getContext("2d");
var imageObj = document.getElementById("myImageToDisplayOnCanvas");
imageObj.onload = function() {
var imgWidth = imageObj.naturalWidth;
var screenWidth = canvas.width;
var scaleX = 1;
if (imgWidth > screenWidth)
scaleX = screenWidth/imgWidth;
var imgHeight = imageObj.naturalHeight;
var screenHeight = canvas.height;
var scaleY = 1;
if (imgHeight > screenHeight)
scaleY = screenHeight/imgHeight;
var scale = scaleY;
if(scaleX < scaleY)
scale = scaleX;
if(scale < 1){
imgHeight = imgHeight*scale;
imgWidth = imgWidth*scale;
}
canvas.height = imgHeight;
canvas.width = imgWidth;
context.drawImage(imageObj, 0, 0, imageObj.naturalWidth, imageObj.naturalHeight, 0,0, imgWidth, imgHeight);
}
}
And if you want to properly scale the picture as per the screen size, here is the code you can use:
var imgWidth = imageObj.naturalWidth;
var screenWidth = $(window).width() - 20;
var scaleX = 1;
if (imageWdith > screenWdith)
scaleX = screenWidth/imgWidth;
var imgHeight = imageObj.naturalHeight;
var screenHeight = $(window).height() - canvas.offsetTop-10;
var scaleY = 1;
if (imgHeight > screenHeight)
scaleY = screenHeight/imgHeight;
var scale = scaleY;
if(scaleX < scaleY)
scale = scaleX;
if(scale < 1){
imgHeight = imgHeight*scale;
imgWidth = imgWidth*scale;
}
canvas.height = imgHeight;
canvas.width = imgWidth;
ctx.drawImage(imageObj, 0, 0, imageObj.naturalWidth, imageObj.naturalHeight, 0,0, imgWidth, imgHeight);
If you are not using jQuery, replace $(window).width with the appropriate equivalent option.