CodeBeam.MudBlazor.Extensions
CodeBeam.MudBlazor.Extensions copied to clipboard
New Component? Mud Blazor Image Uploader and Resize
Blazor Image Uploader and Resize component?? I have a decent start and use it internally. This requires a bit more complexity with server side and client side.
Another blog with their take on it.
Here is my code for example reference
<ImageUploader @bind-ImageUrl="@easyButtonDto.Image3" Label="Additional Marketing Image 2" MaxWidth="1900" MaxHeight="1200" PlaceHolder="Enter in the link for your additional marketing image 1" AcceptedFileExtenstions=".jpg,.png,.svg" Required="true" />
DTO handling the file and the details for server side:
public class FileUploadDto
{
public byte[] FileContent { get; set; }
public string FileType { get; set; }
public long FileSize { get; set; }
public bool Uploaded { get; set; }
public string FileName { get; set; }
public string StoredFileName { get; set; }
public string Folder { get; set; }
public int ErrorCode { get; set; }
public string Link { get; set; }
public int MaxWidth { get; set; }
public int MaxHeight { get; set; }
public async Task WriteToStreamAsync(IBrowserFile fileUploadEntry)
{
using var stream = new MemoryStream();
var buffer = new byte[fileUploadEntry.Size];
using var newFileStream = fileUploadEntry.OpenReadStream(104857600);
int bytesRead;
double totalRead = 0;
while ((bytesRead = await newFileStream.ReadAsync(buffer)) != 0)
{
totalRead += bytesRead;
await stream.WriteAsync(buffer, 0, bytesRead);
}
FileContent = stream.GetBuffer();
}
Here is my Image component:
@*ImageUploader*@
@using BlazorBoilerplate.Shared.Dto.FileUpload
@inject AppState appState
@inject Microsoft.JSInterop.IJSRuntime js
@inject NavigationManager navigationManager
@inject IApiClient apiClient
@inject IViewNotifier viewNotifier
<h3>@Label</h3>
@if (MaxWidth > 0 && MaxHeight > 0)
{
<sup>Suggested / Max Dimensions: @MaxHeight x @MaxWidth pixels</sup>
}
@if (!string.IsNullOrEmpty(@ImageUrl))
{
<div style="padding: 10px; text-align:center; background:#f1f1f1;">
<img src="@(ImageUrl)" style="max-height:150px"/>
</div>
}
<br />
<MudTextField Value="@ImageUrl" Label="@(Label + " Url")" AdornmentIcon="@Icons.Material.Filled.Image" Adornment="Adornment.End" ValueChanged="ImageUrlChanged" FullWidth="true" Required="@Required" RequiredError="Required"
Placeholder="@PlaceHolder" HelperText="@($"Enter in the url link to your {Label}")" HelperTextOnFocus="true" Clearable="true"></MudTextField>
<MudPaper @ondragenter="@(()=>_dragEnterStyle="drag-enter")" @ondragleave="@(()=>_dragEnterStyle=null)" @ondragend="@(()=>_dragEnterStyle=null)" Class=@("drag-drop-zone "+ _dragEnterStyle)>
<InputFile OnChange="ImageFilesReady" class="drag-drop-input" accept="@AcceptedFileExtenstions" />
Drop a single @AcceptedFileExtenstions file here or click to browse<MudIcon Icon="@Icons.Material.Filled.AttachFile"></MudIcon>
</MudPaper>
<MudOverlay @bind-Visible="isBusy" DarkBackground="true">
<MudProgressCircular Color="Color.Secondary" Size="Size.Large" Indeterminate="true" />
</MudOverlay>
@code {
[Parameter]
public string ImageUrl { get; set; } = "";
[Parameter]
public bool Required { get; set; } = false;
[Parameter]
public string AcceptedFileExtenstions { get; set; } = ".png,.svg";
[Parameter]
public string Label { get; set; } = "Image Url / Uploader";
[Parameter]
public string PlaceHolder { get; set; } = "Enter in your Image URL Path or Upload";
[Parameter]
public int MaxWidth { get; set; }
[Parameter]
public int MaxHeight { get; set; }
[Parameter]
public EventCallback<String> ImageUrlChanged { get; set; }
string _dragEnterStyle;
public bool isBusy = false;
List<string> fileStringList = new List<string>();
public async Task ImageFilesReady(InputFileChangeEventArgs e)
{
await FilesReady(e);
}
private async Task FilesReady(InputFileChangeEventArgs e)
{
viewNotifier.Show("Uploading your img file", ViewNotifierType.Info);
isBusy = true;
StateHasChanged();
try
{
var files = e.GetMultipleFiles();
foreach (var file in files)
{
fileStringList.Add($"Name: {file.Name} - Size: {file.Size}");
List<string> extensions = AcceptedFileExtenstions.Split(",").ToList();
bool isValid = false;
foreach (string ext in extensions){
if (file?.Name.EndsWith(ext.ToLower()) == true)
{
isValid = true;
break;
}
}
if (!isValid)
{
viewNotifier.Show($"The accepted file types are: {AcceptedFileExtenstions}", ViewNotifierType.Error, "Incorrect File Type");
fileStringList.Clear();
return;
}
FileUploadDto fileUpload = new FileUploadDto();
await fileUpload.WriteToStreamAsync(file);
fileUpload.FileName = file.Name;
fileUpload.FileSize = file.Size;
fileUpload.FileType = file.ContentType;
fileUpload.MaxHeight = MaxHeight;
fileUpload.MaxWidth = MaxWidth;
ApiResponseDto apiResponse = await apiClient.FileUpload(fileUpload);
if (apiResponse.StatusCode == 200)
{
FileUploadDto fileUploadDto = Newtonsoft.Json.JsonConvert.DeserializeObject<FileUploadDto>(apiResponse.Result.ToString());
if (fileUploadDto.Uploaded)
{
ImageUrl = fileUploadDto.Link;
await ImageUrlChanged.InvokeAsync(ImageUrl);
StateHasChanged();
return;
}
}
else
{
viewNotifier.Show(apiResponse.Message + " : " + apiResponse.StatusCode, ViewNotifierType.Error, "Upload Operation Failed");
}
};
}
catch (Exception ex)
{
viewNotifier.Show(ex.Message, ViewNotifierType.Error, "Error");
}
finally
{
isBusy = false;
StateHasChanged();
}
return;
}
protected override async Task OnInitializedAsync()
{
await OnValueChanged(ImageUrl);
await base.OnInitializedAsync();
}
private async Task ClearImageValue()
{
ImageUrl = "";
await OnValueChanged(null);
}
private async Task OnValueChanged(string imageUrl)
{
if (imageUrl == null)
{
await ImageUrlChanged.InvokeAsync(null);
return;
}
ImageUrl = imageUrl;
await ImageUrlChanged.InvokeAsync(imageUrl);
StateHasChanged();
}
}
Server side:
[HttpPost]
public async Task<ApiResponse> Upload([FromBody] FileUploadDto fileUpload)
{
string trustedFileNameForFileStorage;
var untrustedFileName = fileUpload.FileName;
var trustedFileNameForDisplay = WebUtility.HtmlEncode(untrustedFileName);
string ext = Path.GetExtension(fileUpload.FileName);
if (fileUpload.FileSize == 0)
{
fileUpload.ErrorCode = 1;
return new ApiResponse(Status404NotFound, L["File not selected"]);
}
if (fileUpload.FileSize > 1024 * 1024 * 20)
{
fileUpload.ErrorCode = 2;
return new ApiResponse(Status400BadRequest, L["File too Large"]);
}
switch (fileUpload.FileType)
{
case "text/csv":
break;
case "image/png":
case "image/jpg":
case "image/jpeg":
try
{
trustedFileNameForFileStorage = Path.GetRandomFileName().Replace(".", "_") + Path.GetExtension(fileUpload.FileName);
var path = Path.Combine(_env.ContentRootPath, "cdn", trustedFileNameForFileStorage);
ImageConverter imageConverter = new System.Drawing.ImageConverter();
System.Drawing.Image image = imageConverter.ConvertFrom(fileUpload.FileContent) as System.Drawing.Image;
//TODO Image REsize
if (ext == ".jpg") image.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
if (ext == ".png") image.Save(path, System.Drawing.Imaging.ImageFormat.Png);
fileUpload.Uploaded = true;
fileUpload.Folder = "cdn";
fileUpload.StoredFileName = trustedFileNameForFileStorage;
fileUpload.Link = $"YOURPUBLICDOMAINFOLDER/{fileUpload.Folder}/{fileUpload.StoredFileName}";
}
catch (Exception ex)
{
fileUpload.ErrorCode = 3;
return new ApiResponse(Status400BadRequest, $"Could not Save Image: {ex.Message}");
}
break;
case "image/svg+xml":
try
{
trustedFileNameForFileStorage = Path.GetRandomFileName().Replace(".", "_") + Path.GetExtension(fileUpload.FileName);
var path = Path.Combine(_env.ContentRootPath, "cdn", trustedFileNameForFileStorage);
string svgString = "";
using (var reader = new StreamReader(new MemoryStream(fileUpload.FileContent), Encoding.Default))
{
svgString = await reader.ReadToEndAsync();
}
int length = svgString.Length;
var svgEndIndex = svgString.LastIndexOf("</svg>");
if (svgEndIndex > 0) svgString = svgString.Substring(0, svgEndIndex + 6);
StreamWriter streamWriter = new StreamWriter(path);
streamWriter.AutoFlush = true;
try
{
streamWriter.Write(svgString);
}
finally
{
streamWriter.Flush();
streamWriter.Close();
streamWriter.Dispose();
}
fileUpload.Uploaded = true;
fileUpload.Folder = "cdn";
fileUpload.StoredFileName = trustedFileNameForFileStorage;
fileUpload.Link = $"YOURPUBLICDOMAINFOLDER/{fileUpload.Folder}/{fileUpload.StoredFileName}";
}
catch (IOException ex)
{
fileUpload.ErrorCode = 3;
}
break;
default:
return new ApiResponse(Status400BadRequest, L["Unknown file type"]);
}
return new ApiResponse(Status200OK, null, fileUpload);
}