У меня есть ввод типа файла со свойством множественного выбора. Когда пользователь выбирает файл, я сжимаю файлы с помощью функции JavaScript. Теперь я хотел изменить длину и ширину изображений с помощью этой функции. Что мне для этого добавить в функцию?
Моя функция заключается в следующем
const compressImage = async (file, { quality = 1, type = file.type }) => {
// Get as image data
const imageBitmap = await createImageBitmap(file);
// Draw to canvas
const canvas = document.createElement('canvas');
canvas.width = imageBitmap.width;
canvas.height = imageBitmap.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(imageBitmap, 0, 0);
// Turn into Blob
const blob = await new Promise((resolve) =>
canvas.toBlob(resolve, type, quality)
);
// Turn Blob into File
return new File([blob], file.name, {
type: blob.type,
});
};
// Get the selected file from the file input
const input = document.querySelector('.my-image-field');
input.addEventListener('change', async (e) => {
// Get the files
const { files } = e.target;
// No files selected
if (!files.length) return;
// We'll store the files in this data transfer object
const dataTransfer = new DataTransfer();
// For every file in the files list
for (const file of files) {
// We don't have to compress files that aren't images
if (!file.type.startsWith('image')) {
// Ignore this file, but do add it to our result
dataTransfer.items.add(file);
continue;
}
// We compress the file by 50%
const compressedFile = await compressImage(file, {
quality: 0.3,
type: 'image/jpeg',
});
// Save back the compressed file instead of the original file
dataTransfer.items.add(compressedFile);
}
// Set value of the file input to our new files list
e.target.files = dataTransfer.files;
});
Есть как минимум два варианта:
Метод CanvasRenderingContext2D.scale() API Canvas 2D добавляет преобразование масштабирования к единицам холста по горизонтали и/или вертикали.
drawImage(image, dx, dy, dWidth, dHeight)
Ширина для рисования изображения на целевом холсте. Это позволяет масштабировать нарисованное изображение.
Высота рисования изображения на целевом холсте. Это позволяет масштабировать нарисованное изображение.
В следующем примере используется метод scale()
с одинаковым коэффициентом масштабирования для ширины и высоты. Модификация ввода изображения files
отключена, чтобы избежать повторного масштабирования, но ее можно снова включить, раскомментировав e.target.files = dataTransfer.files;
.
const compressImage = async(file, {
quality = 1,
type = file.type,
scalingFactor = 1
}) => {
// Get as image data
const imageBitmap = await createImageBitmap(file);
// Draw to canvas
const canvas = document.createElement('canvas');
canvas.width = imageBitmap.width * scalingFactor;
canvas.height = imageBitmap.height * scalingFactor;
const ctx = canvas.getContext('2d');
ctx.scale(scalingFactor, scalingFactor);
ctx.drawImage(imageBitmap, 0, 0);
// Turn into Blob
const blob = await new Promise((resolve) =>
canvas.toBlob(resolve, type, quality)
);
// Turn Blob into File
return new File([blob], file.name, {
type: blob.type,
});
};
// Get the selected file from the file input
const input = document.querySelector('.my-image-field');
input.addEventListener('change', async(e) => {
// Get the files
const {
files
} = e.target;
// No files selected
if (!files.length) return;
// We'll store the files in this data transfer object
const dataTransfer = new DataTransfer();
// Clear the image previews container
previewsContainer.innerHTML = '';
// For every file in the files list
for (const file of files) {
// We don't have to compress files that aren't images
if (!file.type.startsWith('image')) {
// Ignore this file, but do add it to our result
dataTransfer.items.add(file);
continue;
}
// We compress the file by 50%
const compressedFile = await compressImage(file, {
quality: parseFloat(qualityInput.value),
type: 'image/jpeg',
scalingFactor: parseFloat(scalingInput.value)
});
// Save back the compressed file instead of the original file
dataTransfer.items.add(compressedFile);
// Show scaled images
const img = document.createElement('img');
img.src = URL.createObjectURL(compressedFile);
previewsContainer.appendChild(img);
}
// UNCOMMENT TO:
// Set value of the file input to our new files list
// e.target.files = dataTransfer.files;
});
const previewsContainer = document.querySelector('.image-previews');
const scalingInput = document.querySelector('.scaling-factor');
const qualityInput = document.querySelector('.quality');
const updateRangeOutput = (inp) => {
inp.nextElementSibling.innerText = inp.value;
};
[scalingInput, qualityInput].forEach(inp => {
inp.addEventListener('change', () => {
updateRangeOutput(inp);
input.dispatchEvent(new Event('change'));
});
updateRangeOutput(inp);
});
<p>
Choose images:
<input type = "file" accept = "image/*" multiple class = "my-image-field">
</p>
<p>
Scaling factor:
<input type = "range" class = "scaling-factor" value = "0.5" min = "0.1" max = "2" step = "0.1">
<span>0.5</span>
</p>
<p>
Quality:
<input type = "range" class = "quality" value = "0.5" min = "0.1" max = "1" step = "0.1">
<span>0.5</span>
</p>
<p class = "image-previews"></p>
Я бы предложил провести небольшое исследование, чтобы найти существующую библиотеку манипуляций с изображениями. Масштабирование/обрезание изображений в JS — нетривиальная задача.