How can I change an image with another keeping aspect ratio? - javascript

I have the following HTML code:
<img id="Card00" src="images/words/back.png" onclick="imageClicked(0,0);">
And the following Javascript code:
function ShowImage(id, row, column)
{
var imagePath = 'images/words/' + id + '.png';
var imgId = '#Card' + row + '' + column;
$(imgId).attr('src', imagePath);
var width = $(imgId).attr('width');
var height = $(imgId).attr('height');
if (width > height)
$(imgId).attr('width', 200);
else
$(imgId).attr('height', 200);
}
imageClicked only calls ShowImage.
Back.png is 200x200. I want to change back.png image with another one. That another one (id + .png), is bigger than 200x200, so I need to resize it on ShowImage function.
But I can't do that, because I can't get its new width and height in this piece of code:
var width = $(imgId).attr('width');
var height = $(imgId).attr('height');
My goal is to change back.png image with another one, keeping aspect radio.
And there is another problem: first I see the bigger image, and then, sometimes, it gets 200x200. I said sometimes because sometimes I get its width or its height.
Any advice?

The best thing to do is just load the image into memory first, then once it loads get its real height and width, use that info -- URL, height and width -- to determine the appropriate dimensions. Note that this isn't foolproof, though, as caching can mess it up.
Note that you can generalize the below to include maximum dimensions in the function itself, but I think it's pretty easily adaptable:
// Example: replaceImage($("img#someID"), "http://example.com/logo.png");
var MAX_HEIGHT = 80;
var MAX_WIDTH = 80;
function keepAspectRatio(temp, $target, url) {
// Get height and width once loaded
var realHeight = temp.height;
var realWidth = temp.width;
// Get how much to divide by (1 if image fits in dimensions)
// Get rid of ", 1" if you just want everything to be either
// MAX_HEIGHT tall or MAX_WIDTH wide
var factor = Math.max(realHeight/MAX_HEIGHT, realWidth/MAX_WIDTH, 1);
realHeight /= factor;
realWidth /= factor;
// Set the target image's source, height and width
$target.attr("src", url).css({height: realHeight, width: realWidth});
}
function replaceImage($target, url) {
$("<img>").load(function() {
keepAspectRatio(this, $target, url);
}).attr("src", url);
}
jsFiddle Example
EDIT
Swapped places of attr and load per the comment below. I'm not going to go too crazy with optimization beyond that, as what we'd really do if we wanted things perfect would be to preload everything, get its real dimensions, and use that information each time we change the original image.

Did you try:
var width = $(imgId).clientWidth;
var height = $(imgId).clientHeight;

Related

How do I get the MIME type of an image/blob in javascript?

I'm working on a Chrome Extension in which I resize images (actually resize; not changing the browser display) that users right click on. When they right click on the image, I get access to the image's 'src'.
I can resize the images that aren't gifs fine; I'm using canvases to do this. You can see me do this here https://jsfiddle.net/cyqvacc6/6/.
img_url = 'https://i.imgur.com/SHo6Fub.jpg';
function get_image(image_url, emoji_name) {
var img_el = document.createElement('img');
img_el.onload = function () {
canvas = img_to_canvas(img_el);
emoji_sized_canvas = emoji_sized(canvas);
document.body.appendChild(emoji_sized_canvas);
};
img_el.src = image_url;
}
function img_to_canvas(img) {
canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas_ctx = canvas.getContext('2d');
canvas_ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
return canvas;
}
function emoji_sized(canvas) {
var target_dim = emoji_dimensions(canvas.width, canvas.height);
var factor = 2;
var canvas_long_side = Math.max(canvas.width, canvas.height);
var target_long_side = Math.max(target_dim.width, target_dim.height);
new_canvas = document.createElement('canvas');
new_canvas_ctx = new_canvas.getContext('2d');
if ((target_long_side === canvas_long_side)) {
// Return the image.
return canvas;
} else if (target_long_side > canvas_long_side * factor) {
// Increase the size of the image and then resize the result.
new_canvas.width = canvas.width * factor;
new_canvas.height = canvas.height * factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else if (canvas_long_side > target_long_side * factor) {
// Half the size of the image and then resize the result.
var width = new_canvas.width = canvas.width / factor;
var height = new_canvas.height = canvas.height / factor;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return emoji_sized(new_canvas);
} else {
// Resize the image in one shot
new_canvas.width = target_dim.width;
new_canvas.height = target_dim.height;
new_canvas_ctx.drawImage(canvas, 0, 0, new_canvas.width, new_canvas.height);
return new_canvas;
}
}
function emoji_dimensions(width, height) {
const MAX_SIDE_LENGTH = 128;
// Get the larger side
long_side = Math.max(height, width);
// Determine the scale ratio
// If the image is between 95% to 100% of the target
// emoji size, don't adjust it's size.
var scale;
if ((long_side >= 0.95 * MAX_SIDE_LENGTH) && (long_side <= MAX_SIDE_LENGTH))
{
scale = 1;
} else {
scale = MAX_SIDE_LENGTH / long_side;
}
return {
'height': height * scale,
'width': width * scale
};
}
Unfortunately, I'm not seeing an easy way to resize gifs using canvases. When I try the same approach on gifs, the 'resized' image is no longer a gif; it's just the first frame of the gif resized.
I think I'm going to end up sending gifs to a server to resize them, but still, in order to do this, I need to know whether the image I'm working on is animated or not, which I don't know how to do.
So, how do I determine if an image is a gif? Also, is it possible to resize these gifs from the client, i.e. javascript?
For reference, I need to reduce the gifs in terms of byte size and pixel, i.e. the gif needs to be both below 128px in both height and width and less than 64k in total byte size.
Since your question actually contains multiple questions, it's quite hard to answer it, so I'll currently don't include code in here.
First, Canvas API can only draw the first frame of any animated image passed through an <img> element. According to specs.
Specifically, when a CanvasImageSource object represents an animated image in an HTMLOrSVGImageElement, the user agent must use the default image of the animation (the one that the format defines is to be used when animation is not supported or is disabled), or, if there is no such image, the first frame of the animation, when rendering the image for CanvasRenderingContext2D APIs.
So you won't natively be able to render all your gif's frames on the canvas.
For this, you'll have to parse the file and extract every frames of your file.
Here are is an untested library that do propose this functionality :
libgif-js.
If you don't like libraries, you could also write a script yourself.
edit: I tried this lib and it's awfull... don't use it, maybe you could fork it, but it's really not meant to do image processing
Once you've got the frames, you can resize these with canvas, and then reencode them all in a final gif file. Untested either gif.js seems to be able to do that.
Tested too, little bit less awfull but it doesn't like transparency and it needs to have the js files hosted, so no online demo... Would also probably need a fork...
And finally, to answer the title question, "How to check the MIME type of a file", check this Q/A.
Basically, the steps are to extract the 4 first bits of your file and checking it against magic-numbers. 'image/gif' magic-numbers are 47 49 46 38.

correct canvas height and width not being passed to a function

Canvas element not being passed with correct height and width to a function, for now I fixed the problem by again assigning the height and width of the canvas after it has been passed to the accepting function. As I am new to this so I want to know if this is a problem with canvas or not?.
$(document).ready(function(){
calling_function = function(eventObj){
//some code
ajaxOptsFtn = {
url: '/xyz_data/',
dataType: 'json',
data: form_vals,
success: function(resp){
//initialisation for function.
if(resp.var_ready === true){
//dynamically adding canvas element.
var canvas_obj = $('<canvas/>').css({width:160, height:240});
$(clicked_element).children('canvas').remove();
$(clicked_element).append(canvas_obj);
//intilise other arguments with some values
var x = 30;
var y= http://abcs.com/dds.jpg;
var z = resp.apparel_img_url;
var nl = gamma_value;
var wD = 23;
var wU = 26;
acceptingFunction(canvas_obj[0],y,z,x,n,wU,wD);
}
else{
console.log('some other message');
}
},
};
if (data.var_ready) {
$.ajax(ajaxOptsFtn);
}
else{
console.log('some message');
};
};
acceptingFunction = function(canvas_obj,y,z,x,n,wU,wD){
canvas = canvas_obj;
console.log("canvas passed height and width:"+ canvas.height +","+canvas.width);
console.log("re assigning expected values");
canvas.width = 160;
canvas.height = 240;
var context = canvas.getContext('2d');
//some code
AimageObj.onload = function () {
//some code
};
BimageObj.onload = function () {
//some code
};
};
You must set the size of the canvas using its attributes, not CSS - for example:
var canvas_obj = $('<canvas/>').attr({'width': 160, 'height': 240});
If you don't do this the canvas element will default to size 300 x 150 pixels which is only stretched by CSS (like an image).
And likewise you also read the same attributes/properties when you want to get the canvas' size.
I have written a blog post that explains this in details - it's too long for SO but here is the essential part:
If we don’t set any actual size for the canvas’ source bitmap it will
default to 300 x 150 pixels as per specification. If you now set the
CSS size of the element to lets say 900 x 450 pixels what happens is
that those 300 x 150 pixels are simply scaled to the new size as the
CSS applies to the element while the default 300 x 150 applies to the
source bitmap (ie. the image). The applied CSS rule doesn’t do
anything with the actual bitmap size.
It would be exactly the same if the canvas was an image, which works
in a similar fashion: it has the image element and then the source
bitmap – the image itself. If you choose to use a different size for
the element than what the image is, the image is simply stretched but
its original data stays the same. There are no more or less pixels in
the original image.
It's also very easy to do it from an HTML5 standpoint. As Simple as:
<canvas id="canvasName" width="160" height="240">
<p>Sorry, The Canvas element is not supported in this browser :(</p>
</canvas>
Adding the paragraph makes it so that a browser that doesn't support the Canvas (IE6 for example) makes this line pop up instead of the Canvas. But putting this into the HTML5 file makes it simple for drawing the Canvas which can be worked with with Javascript. Just make sure you load the Canvas before you load the Javascript, otherwise it will crash
You would then have to declare it in Javascript with
var canvas = document.getElementById("mCanvas");
var context = canvas.getContext("2d");
And you can Console.log it to make sure it is connected properly

Get full size of image in javascript/jquery

I have an image on page that has been resized to fit in a div, say, 400x300. How can I get the full size of the image (~4000x3000) in jQuery? .width() and .height() only seem to return the current size of the image.
Images have naturalWidth and naturalHeight properties that contain the actual, non-modified width and height of the image, i.e. the real dimensions of the image, not what CSS sets it to.
One would still have to wait for the image to load though
$('#idOfMyimg').on('load', function() {
var height = this.naturalHeight,
width = this.naturalWidth;
});
Another option would be to create a new image with the same file as the source, and get the dimensions from that, as long as it's never added to the DOM, not external styles will affect it
var img = new Image();
img.onload = function() {
var height = this.height,
width = this.width;
}
img.src = $('#idOfMyimg').attr('src');
FIDDLE
You can clone the image, remove the height and width attributes, append it to the body and get the width and size before removing it.
jsFiddle demo is here: http://jsfiddle.net/58dA2/
Code is:
$(function() {
var img = $('#kitteh'); // image selector
var hiddenImg = img.clone().css('visibility', 'hidden').removeAttr('height').removeAttr('width').appendTo('body');
$('#height').text(hiddenImg.height());
$('#width').text(hiddenImg.width());
hiddenImg.remove();
});​
You can do this with an Image object that holds the same source file like:
var preloader = new Image();
preloader.src = 'path/to/my/file.jpg';
preloader.onload = function(){
var height = preloader.height;
var width = preloader.width;
}
Try this:
var pic = $("img")
// need to remove these in of case img-element has set width and height
pic.removeAttr("width");
pic.removeAttr("height");
var pic_real_width = pic.width();
var pic_real_height = pic.height();

Getting original image for cropping, ignoring the width attribute?

My user can upload really big images, and for cropping and display purposes i'm adding width attribute so it will fit well in the browser window. Real image size can be - say 1920 x 1080 px.
<!-- width added for display purpose -->
<img class="croppable" src="images/fhd.jpg" width="640" />
In order to calculate real selection box dimension (if the x coordinate is 20px then would be 60px in the original full hd picture) i need to get the full image size before apply the width attribute.
The problem is that this will return 640 as value, taking into account the width attribute:
// Important: Use load event to avoid problems with webkit browser like safari
// when using cached images
$(window).load(function(){
$('img.croppable').each(function(){
alert(this.width);
});
});
Please don't flag this as duplicate since what i'm asking is completly different from simple image width/height retrival (which works, actually).
EDIT: Chris G. solution seems not working:
$(window).load(function(){
$('img.croppable').each(function(){
console.log(this.src);
var original = new Image(this.src);
console.log(original);
$("#original_w").text(original.width); // Temp, more images to be added
$("#original_h").text(original.height); // Temp, more images to be added
});
});
Console output:
http://localhost/DigitLifeAdminExtension/images/pillars-of-creation.jpg
<img width="0">
Get the width/height of the image itself, not the div it is contained within.
$(window).load(function(){
$('img.croppable').each(function(){
var img = new Image();
img.src = $(this).src;
alert(img.width);
});
});
You can remove the attributes, get the width and put the attributes in place again:
var $img = $(img);
var oldWidth = $img.attr("width");
var imgWidth = $img.removeAttr("width").width();
$img.width(oldWidth);
But I think Chris G.'s answer works well too, just making sure it will be loaded when you try to get the width:
img.onload = function() {
if (!img.complete) return; // IMG not loaded
width = img.width;
imgManipulationGoesHere();
}
Works in most up-to-date browsers and IE9.
$(window).load(function(){
$('img.croppable').each(function(){
alert(this.naturalHeight);
});
});
The working solution would be:
$(function(){
$('img.croppable').each(function () {
var original = new Image(this.src);
original.onload = function () {
alert(original.src + ': ' + original.width + 'x' +original.height);
};
});
});

How to get the downloaded image's width&height?

I want to set the width and height of the container <div> of <img> after the image is downloaded, how to do it?
function fn (div, url_path) {
var img = new Image();
img.onload = function () {
div.style.width = img.width;
div.style.height = img.height;
};
img.src = "url_path";
}
fn(document.getElementsByTagName('div')[0], 'http://some-url-to-image.com/1.jpg');
Put it on the page hidden, then measure its width. See here for a good explanation of how to measure the width of a hidden object (just calling width() returns 0).
It is best to wait for the image to be loaded unless you want false results.
jQuery('#image').load(function() {
var jThis = jQuery(this);
var width = jThis.width();
var height = jThis.height();
yourFunction(width, height); //whatever you want to do with these values
jThis.unbind('load'); //might be necessary if you only want this to happen once. Remove this if #image is a container for multiple uses.
})
EDIT 1
Instead of yourFunction(), you could use this since it fits your description better:
jThis.parents('#container').css({
width: width,
height: height
});

Categories