これが私のコードです。これが SO コミュニティの誰かに役立つことを願っています。
スクリプト呼び出しで、ターゲット イメージのサイズをパラメーターとして含めることができます。これは、画像の幅または高さのどちらか大きい方の結果の値になります。小さい方のサイズは、画像の縦横比を変更せずにサイズ変更されます。スクリプトでデフォルトのターゲット サイズをハードコーディングすることもできます。
出力に必要な画像タイプ (デフォルトは「image/png」) など、特定のニーズに合わせてスクリプトを簡単に変更し、より細かい結果を得るために画像のサイズをパーセント単位で何段階変更するかを決定できます (を参照)。 const percentStep コード)。
const ResizeImage = ( _ => {
const MAX_LENGTH = 260; // default target size of largest dimension, either witdth or height
const percentStep = .3; // resizing steps until reaching target size in percents (30% default)
const canvas = document.createElement("canvas");
const canvasContext = canvas.getContext("2d");
const image = new Image();
const doResize = (callback, maxLength) => {
// abort with error if image has a dimension equal to zero
if(image.width == 0 || image.height == 0) {
return {blob: null, error: "either image width or height was zero "};
}
// use caller dimension or default length if none provided
const length = maxLength == null ? MAX_LENGTH : maxLength;
canvas.width = image.width;
canvas.height = image.height;
canvasContext.drawImage(image, 0, 0, image.width, image.height);
// if image size already within target size, just copy and return blob
if(image.width <= length && image.height <= length) {
canvas.toBlob( blob => {
callback({ blob: blob, error: null });
}, "image/png", 1);
return;
}
var startDim = Math.max(image.width, image.height);
var startSmallerDim = Math.min(image.width, image.height);
// gap to decrease in size until we reach the target size,
// be it by decreasing the image width or height,
// whichever is largest
const gap = startDim - length;
// step length of each resizing iteration
const step = parseInt(percentStep*gap);
// no. of iterations
var nSteps = 0;
if(step == 0) {
step = 1;
} else {
nSteps = parseInt(gap/step);
}
// length of last additional resizing step, if needed
const lastStep = gap % step;
// aspect ratio = value by which we'll multiply the smaller dimension
// in order to keep the aspect ratio unchanged in each iteration
const ratio = startSmallerDim/startDim;
var newDim; // calculated new length for the bigger dimension of the image, be it image width or height
var smallerDim; // length along the smaller dimension of the image, width or height
for(var i = 0; i < nSteps; i++) {
// decrease longest dimension one step in pixels
newDim = startDim - step;
// decrease shortest dimension proportionally, so as to keep aspect ratio
smallerDim = parseInt(ratio*newDim);
// assign calculated vars to their corresponding canvas dimension, width or height
if(image.width > image.height) {
[canvas.width, canvas.height] = [newDim, smallerDim];
} else {
[canvas.width, canvas.height] = [smallerDim, newDim];
}
// draw image one step smaller
canvasContext.drawImage(canvas, 0, 0, canvas.width, canvas.height);
// cycle var startDim for new loop
startDim = newDim;
}
// do last missing resizing step to finally reach target image size
if(lastStep > 0) {
if(image.width > image.height) {
[canvas.width, canvas.height] = [startDim - lastStep, parseInt(ratio*(startDim - lastStep))];
} else {
[canvas.width, canvas.height] = [parseInt(ratio*(startDim -lastStep)), startDim - lastStep];
}
canvasContext.drawImage(image, 0, 0, canvas.width, canvas.height);
}
// send blob to caller
canvas.toBlob( blob => {
callback({blob: blob, error: null});
}, "image/png", 1);
};
const resize = async (imgSrc, callback, maxLength) => {
image.src = imgSrc;
image.onload = _ => {
doResize(callback, maxLength);
};
};
return { resize: resize }
})();
使用法:
ResizeImage.resize("./path/to/image/or/blob/bytes/to/resize", imageObject => {
if(imageObject.error != null) {
// handle errors here
console.log(imageObject.error);
return;
}
// do whatever you want with the blob, like assinging it to
// an img element, or uploading it to a database
// ...
document.querySelector("#my-image").src = imageObject.blob;
// ...
}, 300);