Как обрезать картинку
Как обрезать изображение в соответствии с установленными пропорциями с помощью JavaScript
Сегодня мы напишем крошечную JavaScript-функцию, с помощью которой, мы сможем обрезать картинки в соответствии с установленными пропорциями. Эта функция очень полезна, например, при обработке фотографий перед размещением в ленте социальной сети или перед загрузкой изображения для профиля в личном кабинете, то есть в тех случаях, когда необходимые картинки должны иметь строго определенные соотношения сторон (пропорции).
Таким образом, с помощью JavaScript мы изменим исходное изображение.
Если Вам нужно привести картинку в соответствие с установленными пропорциями, не модифицируя исходный файл, обратитесь к статье “Пропорции для IMG”.
Содержание
Загрузка информации об изображении
Для начала нам потребуется источник данных. Пусть это будет ссылка на исходное изображение:
const imageURL = 'path/to/our/image.jpeg';
Чтобы обрезать изображение до нужных пропорций, нужен доступ к его исходным параметрам. Получим эту информацию, загрузив URL в элемент <img>
:
const inputImage = new Image();
inputImage.src = imageURL;
Следующим шагом перенесем картинку на холст (canvas), <canvas>
позволит нам манипулировать параметрами изображения.
Добавим обработчик события onload
до определения src
- так мы сможем перехватить момент загрузки изображения.
// this image will hold our source image data
const inputImage = new Image();
// we want to wait for our image to load
inputImage.onload = () => {
// create a canvas that will present the output image
const outputImage = document.createElement('canvas');
// set it to the same size as the image
outputImage.width = inputImage.naturalWidth;
outputImage.height = inputImage.naturalHeight;
// draw our image at position 0, 0 on the canvas
const ctx = outputImage.getContext('2d');
ctx.drawImage(inputImage, 0, 0);
// show both the image and the canvas
document.body.appendChild(inputImage);
document.body.appendChild(outputImage);
};
// start loading our image
inputImage.src = imageURL;
Результат выполнения вышеприведенного кода - создание элемента canvas
, являющегося копией изображения, загруженного по ссылке.
Приведение пропорций изображения к квадрату
Итак, мы получили доступ к параметрам изображения. Приступим к их модификации.
Для начала, обрежем картинку до квадрата. Соотношение сторон квадрата 1:1. Это означает, что все стороны изображения должны иметь одинаковые размеры. Иными словами, в данном случае соотношение сторон будет равняться 1. Например, соотношение сторон фотографии с шириной 200px и высотой 200px равно 1 (200⁄200), соотношение сторон 400px и 300px даст результат 1.3333 (400⁄300). Заметьте, во всех случаях для получения соотношения сторон достаточно разделить ширину объекта на его высоту.
Получается вот такой код:
// the desired aspect ratio of our output image (width / height)
const outputImageAspectRatio = 1;
// this image will hold our source image data
const inputImage = new Image();
// we want to wait for our image to load
inputImage.onload = () => {
// let's store the width and height of our image
const inputWidth = inputImage.naturalWidth;
const inputHeight = inputImage.naturalHeight;
// get the aspect ratio of the input image
const inputImageAspectRatio = inputWidth / inputHeight;
// if it's bigger than our target aspect ratio
let outputWidth = inputWidth;
let outputHeight = inputHeight;
if (inputImageAspectRatio > outputImageAspectRatio) {
outputWidth = inputHeight * outputImageAspectRatio;
} else if (inputImageAspectRatio < outputImageAspectRatio) {
outputHeight = inputHeight / outputImageAspectRatio;
}
// create a canvas that will present the output image
const outputImage = document.createElement('canvas');
// set it to the same size as the image
outputImage.width = outputWidth;
outputImage.height = outputHeight;
// draw our image at position 0, 0 on the canvas
const ctx = outputImage.getContext('2d');
ctx.drawImage(inputImage, 0, 0);
// show both the image and the canvas
document.body.appendChild(inputImage);
document.body.appendChild(outputImage);
};
// start loading our image
inputImage.src = imageURL;
В результате мы получаем квадратное изображение. Это великолепно! Но давайте присмотримся к полученным результатам. Кажется, результирующее изображение расположено не по центру относительно исходного. Так происходит потому, что мы не обновили drawImage
. Метод drawImage
содержит не менее трех аргументов: исходное изображение inputImage
, x
и y
- координаты стартовых точек отрисовки.
Стартовые точки для нашего изображения: 0
, 0
. Таким образом, выравнивание идет не по центру, а от левого верхнего края.
Чтобы получить необходимый результат, мы должны сместить изображение немного влево. Предположим, что ширина нашей исходной картинки 400px, а результирующей - 300px. Для выравнивания финального изображения по центру мы должны сделать смещение на 50 пикселей влево (смещение с отрицательным значением). То есть, мы вычитаем из результирующей ширины (300px) исходную (400px) и делим результат на 2 - получаем -50px:
const outputX = (outputWidth - inputWidth) * .5
Давайте обновим наш код, применив только что полученные знания как к ширине (x), так и к высоте (y):
// the desired aspect ratio of our output image (width / height)
const outputImageAspectRatio = 1;
// this image will hold our source image data
const inputImage = new Image();
// we want to wait for our image to load
inputImage.onload = () => {
// let's store the width and height of our image
const inputWidth = inputImage.naturalWidth;
const inputHeight = inputImage.naturalHeight;
// get the aspect ratio of the input image
const inputImageAspectRatio = inputWidth / inputHeight;
// if it's bigger than our target aspect ratio
let outputWidth = inputWidth;
let outputHeight = inputHeight;
if (inputImageAspectRatio > outputImageAspectRatio) {
outputWidth = inputHeight * outputImageAspectRatio;
} else if (inputImageAspectRatio < outputImageAspectRatio) {
outputHeight = inputHeight / outputImageAspectRatio;
}
// calculate the position to draw the image at
const outputX = (outputWidth - inputWidth) * .5;
const outputY = (outputHeight - inputHeight) * .5;
// create a canvas that will present the output image
const outputImage = document.createElement('canvas');
// set it to the same size as the image
outputImage.width = outputWidth;
outputImage.height = outputHeight;
// draw our image at position 0, 0 on the canvas
const ctx = outputImage.getContext('2d');
ctx.drawImage(inputImage, outputX, outputY);
// show both the image and the canvas
document.body.appendChild(inputImage);
document.body.appendChild(outputImage);
};
// start loading our image
inputImage.src = imageURL;
Теперь результирующее изображение находится по центру относительно исходного.
Функция преобразования пропорций изображения с изменяемыми параметрами
Наконец, преобразуем наш код в функцию преобразования изображения с изменяемыми входными параметрами. Мы сможем изменять соотношение сторон в соответствии с нашими потребностями. Кстати, наш код уже можно использовать именно для этих целей, а не только для создания квадратных картинок:
/**
* @param {string} url - The source image
* @param {number} aspectRatio - The aspect ratio
* @return {Promise<HTMLCanvasElement>} A Promise that resolves with the resulting image as a canvas element
*/
function crop(url, aspectRatio) {
// we return a Promise that gets resolved with our canvas element
return new Promise(resolve => {
// this image will hold our source image data
const inputImage = new Image();
// we want to wait for our image to load
inputImage.onload = () => {
// let's store the width and height of our image
const inputWidth = inputImage.naturalWidth;
const inputHeight = inputImage.naturalHeight;
// get the aspect ratio of the input image
const inputImageAspectRatio = inputWidth / inputHeight;
// if it's bigger than our target aspect ratio
let outputWidth = inputWidth;
let outputHeight = inputHeight;
if (inputImageAspectRatio > aspectRatio) {
outputWidth = inputHeight * aspectRatio;
} else if (inputImageAspectRatio < aspectRatio) {
outputHeight = inputHeight / aspectRatio;
}
// calculate the position to draw the image at
const outputX = (outputWidth - inputWidth) * .5;
const outputY = (outputHeight - inputHeight) * .5;
// create a canvas that will present the output image
const outputImage = document.createElement('canvas');
// set it to the same size as the image
outputImage.width = outputWidth;
outputImage.height = outputHeight;
// draw our image at position 0, 0 on the canvas
const ctx = outputImage.getContext('2d');
ctx.drawImage(inputImage, outputX, outputY);
resolve(outputImage);
};
// start loading our image
inputImage.src = url;
})
}
Теперь мы можем вызвать полученную функцию и получить квадратную картинку:
crop('path/to/our/image.jpeg', 1)
или установить соотношение сторон 16:9:
crop('path/to/our/image.jpeg', 16/9)
так как функция возвращает промисы (Promise) мы можем воспользоваться и таким синтаксисом:
crop('path/to/our/image.jpeg', 16/9).then(canvas => {
// `canvas` is the resulting image
})
или испоьзовать async/await:
const canvas = await crop('path/to/our/image.jpeg', 16/9)
И вот наш результат:
Заключение
С помощью HTML canvas API и базовых математических знаний мы создали функцию, которая значительно облегчает приведение изображений к различных пропорциям. Данная функция полезна при подготовке фотографий и иллюстраций для размещения в социальных сетях, профиле пользователя, документах и, конечно же, для других целей.
Следует заметить, что данное решение не охватывает следующие случаи:
- могут возникнуть затруднения, если браузер мобильного устройства считывает параметры изображения из EXIF заголовков,
- при использовании слишком большого изображения происходит переполнение памяти для элемента canvas,
- изменение размеров маленьких картинок приводит к значительному ухудшению их качества.
Спасибо за внимание.
Перевод статьи Rik Schennink “Cropping Images to a specific Aspect Ratio with JavaScript”