Изменение размера изображений перед загрузкой в Blazor Web Assembly
Итак, вы разрешаете пользователям загружать изображения на сервер из вашего приложения Blazor WASM, но по какой-то причине хотите ограничить фактические размеры изображения. Вместо того, чтобы просить пользователя отредактировать изображение перед загрузкой, вы решаете позаботиться о применении этого требования в приложении. И вы также решаете изменить размер в браузере перед загрузкой, чтобы итоговая загрузка была меньше, и вам не приходилось тратить ресурсы сервера на эту процедуру. В этой статье я расскажу, как это сделать и как получить размеры файла изображения.
При изменении размера файлов изображений в Blazor Web Assembly мы можем использовать метод расширения для IBrowserFile
типа, который представляет файл, представленный элементу управления загрузкой файлов в приложении Blazor, RequestImageFileAsync
. Этот метод был представлен в .NET 5, поэтому он не будет работать в приложениях, созданных с использованием .NET 3.2 (если они действительно существуют).
В качестве аргументов метод принимает формат файла (тип содержимого), максимальную ширину и максимальную высоту. Внутри метод использует слой JavaScript для изменения размера изображения. В частности, он использует API холста HTML5. Он сравнивает фактические размеры изображения с аргументами максимальной ширины и высоты и применяет меньшее соотношение к обоим размерам при изменении размера, тем самым сохраняя исходные пропорции изображения.
В следующем коде используется компонент Razor, который действует как страница с возможностью навигации. Он включает InputFile
компонент, к которому применен accept
атрибут для ограничения типов файлов, доступных для встроенного средства выбора файлов. Это удобно для пользователя, и на него не следует полагаться при проверке загружаемых типов файлов. Когда содержимое элемента управления загрузкой файла изменяется, HandleChange
вызывается обратный вызов. Это подтверждает, что отправленный файл на самом деле является файлом изображения, проверяя его тип содержимого с помощью массива разрешенных значений, а затем для RequestImageFileAsync
него вызывается метод. В этом примере я решил, что максимальная ширина любого изображения должна составлять 300 пикселей. Они могут быть любой высоты, поэтому int.MaxValue
передаются в maxHeight
параметр.
@page "/resize-image-demo"
@inject HttpClient http
Resize Image
@code {
string[] imageTypes = new[] { "image.jpeg", "image/png" };
async Task HandleChange(InputFileChangeEventArgs e)
{
if (imageTypes.Contains(e.File.ContentType))
{
var resized = await e.File.RequestImageFileAsync(e.File.ContentType, 300, int.MaxValue);
var formContent = new MultipartFormDataContent
{
{ new StreamContent(e.File.OpenReadStream(e.File.Size)), "upload", e.File.Name },
{ new StringContent(e.File.ContentType), "content-type" }
};
await http.PostAsync("/upload", formContent);
}
}
}
При использовании RequestImageFileAsync
метода будут обработаны все файлы независимо от их исходного размера и типа. Если методу передается тип файла, который не поддерживается реализацией холста в вашем браузере, приложение тихо падает (в моем тестировании). Если исходная ширина загруженного изображения составляет 300 пикселей или меньше, оно все равно обрабатывается, и возвращается новое изображение того же размера. Вместо того, чтобы отправлять каждый файл в процесс изменения размера, независимо от размера, вы можете проверить размеры изображения, чтобы увидеть, не превышают ли они ваш максимум, так как же получить ширину и высоту файла изображения?
Получение размеров изображения
Вы можете рассмотреть возможность использования кроссплатформенной библиотеки изображений C# в своем проекте WASM, такой как ImageSharp , и хотя я обнаружил, что простое получение размеров изображения прекрасно работает с этой библиотекой, ImageSharp не рекомендуется использовать в среде Blazor WASM . Вместо этого вы можете использовать взаимодействие JavaScript, чтобы вместо этого использовать API-интерфейсы браузера. Следующий код JavaScript написан в виде модуля, чтобы мы могли воспользоваться преимуществами поддержки изоляции JavaScript в Blazor . Функция принимает поток в качестве параметра и использует его для создания BLOB-объекта, из которого создается URL-адрес объекта. URL-адрес объекта назначается как src
файл Image
. Мы подключаемся к onload
событию изображения и получаем размеры загруженного изображения. Мы используемPromise
чтобы разрешить возвращаемое значение onload
обработчика событий изображения и сериализовать его в JSON. Мы сохраняем этот модуль как fileSize.js в папке wwwroot/js .
export async function getImageDimensions(content) {
const url = URL.createObjectURL(new Blob([await content.arrayBuffer()]))
const dimensions = await new Promise(resolve => {
const img = new Image();
img.onload = function () {
const data = { Width: img.naturalWidth, Height: img.naturalHeight };
resolve(data);
};
img.src = url;
});
return JSON.stringify(dimensions);
}
Далее нам нужно изменить наш компонент для работы с внедренным файлом IJSRuntime
. Нам также нужно добавить using
директиву для System.Text.Json
. Мы добавляем IJSObjectReference
поле, представляющее ссылку на модуль JavaScript, и создаем его экземпляр при первом отображении компонента. Мы также добавляем тип, представляющий изображение и ширину изображения. Это объявлено как record
тип с именем ImageDimensions
.
В этом HandleChange
случае мы передаем содержимое загруженного файла как DotNetStreamReference
модуль JS. Мы десериализуем возвращаемое значение как экземпляр ImageDimensions
и проверяем, превышает ли ширина 300. Только если это так, мы изменяем размер изображения.
@page "/image-file-tests"
@using System.Text.Json
@inject IJSRuntime JS
@inject HttpClient http
Image File Tests
@code {
IJSObjectReference module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync("import","./js/fileSize.js");
}
}
async Task HandleChange(InputFileChangeEventArgs e)
{
var file = e.File;
var streamRef = new DotNetStreamReference(file.OpenReadStream(file.Size));
var json = await module.InvokeAsync("getImageDimensions", streamRef);
var dimensions = JsonSerializer.Deserialize(json);
if(dimensions.Width > 300)
{
file = await file.RequestImageFileAsync(file.ContentType, 300, int.MaxValue);
}
var formContent = new MultipartFormDataContent
{
{ new StreamContent(file.OpenReadStream(file.Size)), "upload", file.Name },
{ new StringContent(file.ContentType), "content-type" }
};
await http.PostAsync("/upload", formContent);
}
record ImageDimensions(int Width, int Height);
}
Резюме
В этом посте я рассмотрел RequestImageFileAsync
метод, который используется для изменения размера изображений в приложении Blazor Web Assembly. Я также посмотрел на получение размеров изображения. Я рассматривал возможность использования ImageSharp, кроссплатформенной библиотеки изображений C#, но прислушался к предупреждению проектной группы об использовании этой библиотеки в браузере и в конечном итоге остановился на использовании собственных API-интерфейсов браузера через взаимодействие с JavaScript.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.