Creating thumbnail squares of images in javascript (without losing aspect ratio)
I am making a client side Drag and Drop file upload script as a bookm开发者_开发技巧arklet. Before uploading I am using the File API to read the images into base64 format and display them as thumbnails.
This is how my thumbnails look like. I want them to look more square but without loosing their aspect ratio. (please ignore progress bar)
This is how I want the thumbnails to be like, they are centered and being cropped based on min(height,width).
Can I do this using javascript only (changing styles via script will do)? Please try to make sure that your solution will fit with base64 images (after the images are read via file API as DATA URL).
I have uploaded these exact set of images here.
Thanks for the help.
Just wanted to share how I resolved my issue. Since I wanted a purely javascript only solution, I used throwaway canvas elements to do the dirty work.
Here is my code for the same:
function resizeImage(url, width, height, callback, file) {
console.log("In_resizeImage");
var sourceImage = new Image();
sourceImage.onload = (function (f) {
return function (evt) {
console.log("In_sourceImage_onload");
console.log("sourceImage.width:" + sourceImage.width);
console.log("sourceImage.height:" + sourceImage.height);
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
if (sourceImage.width == sourceImage.height) {
canvas.getContext("2d").drawImage(sourceImage, 0, 0, width, height);
} else {
minVal = Math.min(sourceImage.width, sourceImage.height);
if (sourceImage.width > sourceImage.height) {
canvas.getContext("2d").drawImage(sourceImage, (sourceImage.width - minVal) / 2, 0, minVal, minVal, 0, 0, width, height);
} else {
canvas.getContext("2d").drawImage(sourceImage, 0, (sourceImage.height - minVal) / 2, minVal, minVal, 0, 0, width, height);
}
}
callback(canvas.toDataURL(), f);
}
})(file);
sourceImage.src = url;
}
I was directly dealing with image files so I was able to use Image object. For others to use, little bit tweaking might be required.
Instanciate another html-element (I would chose a table, but I'm old and outdated) and align the picture as a background picture with CSS, something like
thetable { background: url('planets.jpg') 0px -150px no-repeat; width: 60 px; height 60 px}
I stole it all from here: How to create CSS-sprites
This should support both image and video. It will create a thumbnail for the media but will also keep the media aspect ratio.
This should also clean up after itself so no event leaks should persist. It will also smooth the thumbnail image.
/* example to resize an image to 300px width
and keep the aspect */
resizeMedia('/images/logo.jpg', 300, function(data)
{
console.log(data); // the new thumbnail data uri
});
/* this will create a thumbnail of an image or video
and keep the aspect.
@param (string | object) media = the image string or video object
@param (int) width = the new width to contain the media
@param (function) callBack = the callBack to handle the
image data uri */
function resizeMedia(media, width, callBack)
{
var self = this;
/* this will get the type by checking ifthe media
is a string (e.g. img src or dataUri) */
var type = typeof media === 'string'? 'image' : 'video';
/* this will get the height and width of the resized
media and keep the aspect.
@param (int) udateSize = the width the modify
@param (int) width = the old width
@param (int) height = the old height
@return (object) the width and height to modify the
media */
var getModifySize = function(updateSize, width, height)
{
var getModifyAspect = function(max, min, value)
{
var ratio = max / min;
return value * ratio;
};
return {
width: updateSize,
height: getModifyAspect(updateSize, width, height)
};
};
/* this will create a canvas and draw the media
on the canvas.
@param (object) media = the image or video
object
@param (int) width = the canvas width
@param (int) height = the canvas height
@return (object) the new canvas */
var createCanvas = function(media, width, height)
{
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.mozImageSmoothingEnabled = true;
ctx.webkitImageSmoothingEnabled = true;
ctx.msImageSmoothingEnabled = true;
ctx.imageSmoothingEnabled = true;
/* we need to draw on load to make sure
the image is ready to be used */
ctx.drawImage(media, 0, 0, width, height);
/* this will convert the canvas to a data uri
using jpeg to speed up the process. if you need
to keep transparency remove the mime type
and it will default to png */
callBack(canvas.toDataURL('image/jpeg'));
return canvas;
};
if(type === 'image')
{
var img = new window.Image();
img.crossOrigin = "anonymous";
img.addEventListener('load', function loadImage()
{
var modify = getModifySize(width, img.width, img.height);
createCanvas(img, modify.width, modify.height);
img.removeEventListener('load', loadImage);
});
img.src = media;
}
else if(type === 'video')
{
var modify = getModifySize(width, media.videoWidth, media.videoHeight);
createCanvas(media, modify.width, modify.height);
}
};
You can also "clip" directly a centered square in the image onto the canvas with drawImage(), you simply have to put theses parameters :
canvas.getContext("2d").drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
sx Optional. The x coordinate where to start clipping
sy Optional. The y coordinate where to start clipping
swidth Optional. The width of the clipped image
sheight Optional. The height of the clipped image
x The x coordinate where to place the image on the canvas
y The y coordinate where to place the image on the canvas
width Optional. The width of the image to use (stretch or reduce the image)
height Optional. The height of the image to use (stretch or reduce the image)
Regards,
Pierrick
精彩评论