diff --git a/Marechai/Areas/Admin/Controllers/CompanyLogosController.cs b/Marechai/Areas/Admin/Controllers/CompanyLogosController.cs deleted file mode 100644 index 1966423e..00000000 --- a/Marechai/Areas/Admin/Controllers/CompanyLogosController.cs +++ /dev/null @@ -1,395 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml; -using Marechai.Areas.Admin.Models; -using Marechai.Database.Models; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Query; -using SkiaSharp; -using Svg.Skia; - -namespace Marechai.Areas.Admin.Controllers -{ - [Area("Admin"), Authorize] - public class CompanyLogosController : Controller - { - readonly MarechaiContext _context; - readonly IWebHostEnvironment hostingEnvironment; - - public CompanyLogosController(MarechaiContext context, IWebHostEnvironment env) - { - _context = context; - hostingEnvironment = env; - } - - // GET: CompanyLogos - public async Task Index() - { - IIncludableQueryable marechaiContext = _context.CompanyLogos.Include(c => c.Company); - - return View(await marechaiContext.OrderBy(l => l.Company.Name).ThenBy(l => l.Year). - Select(l => new CompanyLogoViewModel - { - Company = l.Company.Name, Id = l.Id, Year = l.Year - }).ToListAsync()); - } - - // GET: CompanyLogos/Details/5 - public async Task Details(int? id) - { - if(id == null) - return NotFound(); - - CompanyLogo companyLogo = - await _context.CompanyLogos.Include(c => c.Company).FirstOrDefaultAsync(m => m.Id == id); - - if(companyLogo == null) - return NotFound(); - - return View(companyLogo); - } - - // GET: CompanyLogos/Create - // TODO: Upload - public IActionResult Create() - { - ViewData["CompanyId"] = new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name"); - - return View(); - } - - // POST: CompanyLogos/Create - // To protect from overposting attacks, please enable the specific properties you want to bind to, for - // more details see http://go.microsoft.com/fwlink/?LinkId=317598. - // TODO: Upload - [HttpPost, ValidateAntiForgeryToken] - public async Task Create([Bind("Id,CompanyId,Year,SvgLogo")] CompanyLogo companyLogo) - { - if(!ModelState.IsValid) - { - ViewData["CompanyId"] = new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - using(var svgMs = new MemoryStream()) - { - await companyLogo.SvgLogo.CopyToAsync(svgMs); - - svgMs.Position = 0; - - try - { - var sr = new StreamReader(svgMs, Encoding.UTF8); - string svgStr = await sr.ReadToEndAsync(); - var xml = new XmlDocument(); - xml.LoadXml(svgStr); - } - catch(XmlException) - { - companyLogo.SvgLogo = null; - companyLogo.ErrorMessage = "Not a valid SVG file."; - - ViewData["CompanyId"] = new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - svgMs.Position = 0; - companyLogo.Guid = Guid.NewGuid(); - - string vectorial = Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", - companyLogo.Guid + ".svg"); - - if(System.IO.File.Exists(vectorial)) - { - companyLogo.SvgLogo = null; - companyLogo.ErrorMessage = "GUID clash, please retry and report to the administrator."; - - ViewData["CompanyId"] = new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - var outSvg = new FileStream(vectorial, FileMode.CreateNew); - await svgMs.CopyToAsync(outSvg); - svgMs.Position = 0; - - SKSvg svg = null; - - try - { - foreach(string format in new[] - { - "png", "webp" - }) - { - if(!Directory.Exists(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", format))) - Directory.CreateDirectory(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", - format)); - - SKEncodedImageFormat skFormat; - - switch(format) - { - case"webp": - skFormat = SKEncodedImageFormat.Webp; - - break; - default: - skFormat = SKEncodedImageFormat.Png; - - break; - } - - foreach(int multiplier in new[] - { - 1, 2, 3 - }) - { - if(!Directory.Exists(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", format, - $"{multiplier}x"))) - Directory.CreateDirectory(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", - format, $"{multiplier}x")); - - string rendered = Path.Combine(hostingEnvironment.WebRootPath, "assets/logos", format, - $"{multiplier}x", companyLogo.Guid + $".{format}"); - - if(System.IO.File.Exists(rendered)) - { - companyLogo.SvgLogo = null; - companyLogo.ErrorMessage = "GUID clash, please retry and report to the administrator."; - - ViewData["CompanyId"] = - new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - Console.WriteLine("Rendering {0}", rendered); - - if(svg == null) - { - svg = new SKSvg(); - svg.Load(svgMs); - } - - SKRect svgSize = svg.Picture.CullRect; - var matrix = SKMatrix.MakeScale(multiplier, multiplier); - - var bitmap = new SKBitmap((int)(svgSize.Width * multiplier), - (int)(svgSize.Height * multiplier)); - - var canvas = new SKCanvas(bitmap); - canvas.DrawPicture(svg.Picture, ref matrix); - canvas.Flush(); - var image = SKImage.FromBitmap(bitmap); - SKData data = image.Encode(skFormat, 100); - var outfs = new FileStream(rendered, FileMode.CreateNew); - data.SaveTo(outfs); - outfs.Close(); - - svgMs.Position = 0; - } - } - - foreach(string format in new[] - { - "png", "webp" - }) - { - if(!Directory.Exists(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos/thumbs", - format))) - Directory.CreateDirectory(Path.Combine(hostingEnvironment.WebRootPath, - "assets/logos/thumbs", format)); - - SKEncodedImageFormat skFormat; - - switch(format) - { - case"webp": - skFormat = SKEncodedImageFormat.Webp; - - break; - default: - skFormat = SKEncodedImageFormat.Png; - - break; - } - - foreach(int multiplier in new[] - { - 1, 2, 3 - }) - { - if(!Directory.Exists(Path.Combine(hostingEnvironment.WebRootPath, "assets/logos/thumbs", - format, $"{multiplier}x"))) - Directory.CreateDirectory(Path.Combine(hostingEnvironment.WebRootPath, - "assets/logos/thumbs", format, - $"{multiplier}x")); - - string rendered = Path.Combine(hostingEnvironment.WebRootPath, "assets/logos/thumbs", - format, $"{multiplier}x", companyLogo.Guid + $".{format}"); - - if(System.IO.File.Exists(rendered)) - { - companyLogo.SvgLogo = null; - companyLogo.ErrorMessage = "GUID clash, please retry and report to the administrator."; - - ViewData["CompanyId"] = - new SelectList(_context.Companies.Select(c => new CompanyViewModel - { - Name = c.Name, Id = c.Id - }).OrderBy(c => c.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - Console.WriteLine("Rendering {0}", rendered); - - if(svg == null) - { - svg = new SKSvg(); - svg.Load(svgMs); - } - - SKRect svgSize = svg.Picture.CullRect; - float svgMax = Math.Max(svgSize.Width, svgSize.Height); - float canvasMin = 32 * multiplier; - float scale = canvasMin / svgMax; - var matrix = SKMatrix.MakeScale(scale, scale); - - var bitmap = new SKBitmap((int)(svgSize.Width * scale), (int)(svgSize.Height * scale)); - - var canvas = new SKCanvas(bitmap); - canvas.DrawPicture(svg.Picture, ref matrix); - canvas.Flush(); - var image = SKImage.FromBitmap(bitmap); - SKData data = image.Encode(skFormat, 100); - var outfs = new FileStream(rendered, FileMode.CreateNew); - data.SaveTo(outfs); - outfs.Close(); - - svgMs.Position = 0; - } - } - } - catch(IOException e) - { - Console.WriteLine(e); - - throw; - } - } - - _context.Add(companyLogo); - await _context.SaveChangesAsync(); - - return RedirectToAction(nameof(Index)); - } - - // GET: CompanyLogos/Edit/5 - public async Task Edit(int? id) - { - if(id == null) - return NotFound(); - - CompanyLogo companyLogo = await _context.CompanyLogos.FirstOrDefaultAsync(c => c.Id == id); - - if(companyLogo == null) - return NotFound(); - - ViewData["CompanyId"] = - new SelectList(_context.Companies.OrderBy(l => l.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - // POST: CompanyLogos/Edit/5 - // To protect from overposting attacks, please enable the specific properties you want to bind to, for - // more details see http://go.microsoft.com/fwlink/?LinkId=317598. - [HttpPost, ValidateAntiForgeryToken] - public async Task Edit(int id, [Bind("Id,CompanyId,Year,Guid")] CompanyLogo companyLogo) - { - if(id != companyLogo.Id) - return NotFound(); - - if(ModelState.IsValid) - { - try - { - _context.Update(companyLogo); - await _context.SaveChangesAsync(); - } - catch(DbUpdateConcurrencyException) - { - if(!CompanyLogoExists(companyLogo.Id)) - return NotFound(); - - throw; - } - - return RedirectToAction(nameof(Index)); - } - - ViewData["CompanyId"] = - new SelectList(_context.Companies.OrderBy(l => l.Name), "Id", "Name", companyLogo.CompanyId); - - return View(companyLogo); - } - - // GET: CompanyLogos/Delete/5 - public async Task Delete(int? id) - { - if(id == null) - return NotFound(); - - CompanyLogo companyLogo = - await _context.CompanyLogos.Include(c => c.Company).FirstOrDefaultAsync(m => m.Id == id); - - if(companyLogo == null) - return NotFound(); - - return View(companyLogo); - } - - // POST: CompanyLogos/Delete/5 - [HttpPost, ActionName("Delete"), ValidateAntiForgeryToken] - public async Task DeleteConfirmed(int id) - { - CompanyLogo companyLogo = await _context.CompanyLogos.FirstOrDefaultAsync(m => m.Id == id); - - if(companyLogo == null) - return NotFound(); - - _context.CompanyLogos.Remove(companyLogo); - await _context.SaveChangesAsync(); - - return RedirectToAction(nameof(Index)); - } - - bool CompanyLogoExists(int id) => _context.CompanyLogos.Any(e => e.Id == id); - } -} \ No newline at end of file diff --git a/Marechai/Areas/Admin/Views/CompanyLogos/Create.cshtml b/Marechai/Areas/Admin/Views/CompanyLogos/Create.cshtml deleted file mode 100644 index e890eb6f..00000000 --- a/Marechai/Areas/Admin/Views/CompanyLogos/Create.cshtml +++ /dev/null @@ -1,51 +0,0 @@ -@model Marechai.Database.Models.CompanyLogo -@{ - ViewData["Title"] = "Create"; -} -

Create

-

Company logo

-
-
-
-
-
-
-
- - -
-
- - - - -
-
-
- - - - - @if (Model?.ErrorMessage != null) - { - @Model.ErrorMessage - } -
-
- -
-
-
- -@section Scripts { - @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } -} \ No newline at end of file diff --git a/Marechai/Helpers/SvgRender.cs b/Marechai/Helpers/SvgRender.cs index 964455f6..8ee7e656 100644 --- a/Marechai/Helpers/SvgRender.cs +++ b/Marechai/Helpers/SvgRender.cs @@ -95,20 +95,8 @@ namespace Marechai.Helpers svg.Load(file); } - SKRect svgSize = svg.Picture.CullRect; - float svgMax = Math.Max(svgSize.Width, svgSize.Height); - float canvasMin = 32 * multiplier; - float scale = canvasMin / svgMax; - var matrix = SKMatrix.MakeScale(scale, scale); - var bitmap = new SKBitmap((int)(svgSize.Width * scale), (int)(svgSize.Height * scale)); - var canvas = new SKCanvas(bitmap); - canvas.Clear(); - canvas.DrawPicture(svg.Picture, ref matrix); - canvas.Flush(); - var image = SKImage.FromBitmap(bitmap); - SKData data = image.Encode(skFormat, 100); - var outFs = new FileStream(rendered, FileMode.CreateNew); - data.SaveTo(outFs); + var outFs = new FileStream(rendered, FileMode.CreateNew); + RenderSvg(svg, outFs, skFormat, 32, multiplier); outFs.Close(); } } @@ -210,20 +198,8 @@ namespace Marechai.Helpers svg.Load(file); } - SKRect svgSize = svg.Picture.CullRect; - float svgMax = Math.Max(svgSize.Width, svgSize.Height); - float canvasMin = minSize * multiplier; - float scale = canvasMin / svgMax; - var matrix = SKMatrix.MakeScale(scale, scale); - var bitmap = new SKBitmap((int)(svgSize.Width * scale), (int)(svgSize.Height * scale)); - var canvas = new SKCanvas(bitmap); - canvas.Clear(); - canvas.DrawPicture(svg.Picture, ref matrix); - canvas.Flush(); - var image = SKImage.FromBitmap(bitmap); - SKData data = image.Encode(skFormat, 100); - var outFs = new FileStream(rendered, FileMode.CreateNew); - data.SaveTo(outFs); + var outFs = new FileStream(rendered, FileMode.CreateNew); + RenderSvg(svg, outFs, skFormat, minSize, multiplier); outFs.Close(); } } @@ -232,5 +208,89 @@ namespace Marechai.Helpers File.Move(file, $"wwwroot/assets/logos/{guid}.svg"); } } + + public static void RenderSvg(SKSvg svg, Stream outStream, SKEncodedImageFormat skFormat, int minSize, + int multiplier) + { + SKRect svgSize = svg.Picture.CullRect; + float svgMax = Math.Max(svgSize.Width, svgSize.Height); + float canvasMin = minSize * multiplier; + float scale = canvasMin / svgMax; + var matrix = SKMatrix.MakeScale(scale, scale); + var bitmap = new SKBitmap((int)(svgSize.Width * scale), (int)(svgSize.Height * scale)); + var canvas = new SKCanvas(bitmap); + canvas.Clear(); + canvas.DrawPicture(svg.Picture, ref matrix); + canvas.Flush(); + var image = SKImage.FromBitmap(bitmap); + SKData data = image.Encode(skFormat, 100); + data.SaveTo(outStream); + } + + // TODO: Reduce code duplication + public static void RenderCompanyLogo(Guid guid, Stream svgStream, string wwwroot) + { + SKSvg svg = null; + + foreach(int minSize in new[] + { + 256, 32 + }) + { + foreach(string format in new[] + { + "png", "webp" + }) + { + string outDir = minSize == 32 ? Path.Combine(wwwroot, "assets/logos/thumbs", format) + : Path.Combine(wwwroot, "assets/logos", format); + + if(!Directory.Exists(outDir)) + Directory.CreateDirectory(outDir); + + SKEncodedImageFormat skFormat; + + switch(format) + { + case"webp": + skFormat = SKEncodedImageFormat.Webp; + + break; + default: + skFormat = SKEncodedImageFormat.Png; + + break; + } + + foreach(int multiplier in new[] + { + 1, 2, 3 + }) + { + string outPath = Path.Combine(outDir, $"{multiplier}x"); + + if(!Directory.Exists(outPath)) + Directory.CreateDirectory(outPath); + + string rendered = Path.Combine(outPath, $"{guid}.{format}"); + + if(File.Exists(rendered)) + continue; + + Console.WriteLine("Rendering {0}", rendered); + + if(svg == null) + { + svg = new SKSvg(); + svg.Load(svgStream); + } + + var outFs = new FileStream(rendered, FileMode.CreateNew); + RenderSvg(svg, outFs, skFormat, minSize, multiplier); + outFs.Close(); + } + } + } + } } } \ No newline at end of file diff --git a/Marechai/Marechai.csproj b/Marechai/Marechai.csproj index 92ab17b2..5c1e8e2c 100644 --- a/Marechai/Marechai.csproj +++ b/Marechai/Marechai.csproj @@ -2,7 +2,7 @@ netcoreapp3.1 - 3.0.99.1275 + 3.0.99.1364 Canary Islands Computer Museum Copyright © 2003-2020 Natalia Portillo Canary Islands Computer Museum Website @@ -31,6 +31,7 @@ + @@ -142,5 +143,6 @@ <_ContentIncludedByDefault Remove="Areas\Admin\Views\Processors\Create.cshtml" /> <_ContentIncludedByDefault Remove="Areas\Admin\Views\Screens\Create.cshtml" /> <_ContentIncludedByDefault Remove="Areas\Admin\Views\SoundSynths\Create.cshtml" /> + <_ContentIncludedByDefault Remove="Areas\Admin\Views\CompanyLogos\Create.cshtml" /> \ No newline at end of file diff --git a/Marechai/Pages/Admin/Details/Company.razor b/Marechai/Pages/Admin/Details/Company.razor index 79db29d1..c5498d48 100644 --- a/Marechai/Pages/Admin/Details/Company.razor +++ b/Marechai/Pages/Admin/Details/Company.razor @@ -40,7 +40,10 @@ @inject NavigationManager NavigationManager @inject CompanyLogosService CompanyLogosService @inject IWebHostEnvironment Host +@inject IFileReaderService FileReaderService; @attribute [Authorize(Roles = "UberAdmin, Admin")] + +

@L["Company details"]


@@ -316,7 +319,7 @@ @L["Back to list"] @if (!_editing) { - @L["Upload new logo"] + } @if (_logos.Count > 0) @@ -385,7 +388,14 @@ - @string.Format(@L["Are you sure you want to delete the company logo introduced in {0}?"], _currentLogo?.Year) + @if (_currentLogo?.Year != null) + { + @string.Format(L["Are you sure you want to delete the company logo introduced in {0}?"], _currentLogo?.Year) + } + else + { + @L["Are you sure you want to delete the company logo you selected?"] + } @@ -436,3 +446,89 @@ + + + + + + @L["Upload new logo"] + + + + + @if (!_uploaded) + { + @if (!_uploading) + { + @L["Choose SVG (version 1.1 or lower) logo file"] +
+
+ } + else + { + @L["Uploading..."] +
+
@($"{_progressValue:F2}")%
+
+ } + @if (_uploadError) + { + @_uploadErrorMessage + } + } + else + { + + + + + + + + + + + + + + + + + + + + +
@L["SVG"]@L["PNG"]@L["WebP"]
+ @L["May not show properly"] + + @L["May not show properly"] +
+ + + + + +
+ + @L["Year logo came in use"] + @L["Unknown (logo year)"] + @if (!_unknownLogoYear) + { + + + + @L["Please enter a valid year."] + + + + } + + } +
+
+ + + + +
+
\ No newline at end of file diff --git a/Marechai/Pages/Admin/Details/Company.razor.cs b/Marechai/Pages/Admin/Details/Company.razor.cs index 0ebd963d..8864d975 100644 --- a/Marechai/Pages/Admin/Details/Company.razor.cs +++ b/Marechai/Pages/Admin/Details/Company.razor.cs @@ -1,18 +1,25 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; +using Blazor.FileReader; using Blazorise; using Marechai.Database; using Marechai.Database.Models; +using Marechai.Helpers; using Marechai.Shared; using Marechai.ViewModels; using Microsoft.AspNetCore.Components; +using SkiaSharp; +using Svg.Skia; namespace Marechai.Pages.Admin.Details { public partial class Company { + const int _maxUploadSize = 5 * 1048576; List _companies; List _countries; bool _creating; @@ -22,23 +29,35 @@ namespace Marechai.Pages.Admin.Details bool _editing; Modal _frmDelete; Modal _frmLogoYear; + Modal _frmUpload; + ElementReference _inputUpload; bool _loaded; List _logos; CompanyViewModel _model; - bool _unknownAddress; - bool _unknownCity; - bool _unknownCountry; - bool _unknownFacebook; - bool _unknownFounded; - bool _unknownLogoYear; - bool _unknownPostalCode; - bool _unknownProvince; - bool _unknownSold; - bool _unknownSoldTo; - bool _unknownTwitter; - bool _unknownWebsite; + double _progressValue; - bool _yearChangeInProgress; + bool _savingLogo; + bool _unknownAddress; + bool _unknownCity; + bool _unknownCountry; + bool _unknownFacebook; + bool _unknownFounded; + bool _unknownLogoYear; + bool _unknownPostalCode; + bool _unknownProvince; + bool _unknownSold; + bool _unknownSoldTo; + bool _unknownTwitter; + bool _unknownWebsite; + bool _uploaded; + string _uploadedPngData; + string _uploadedSvgData; + string _uploadedWebpData; + bool _uploadError; + string _uploadErrorMessage; + bool _uploading; + MemoryStream _uploadMs; + bool _yearChangeInProgress; [Parameter] public int Id { get; set; } @@ -323,5 +342,216 @@ namespace Marechai.Pages.Admin.Details else e.Status = ValidationStatus.Success; } + + void ShowUploadModal() + { + _uploadError = false; + _uploadErrorMessage = ""; + _uploading = false; + _uploadMs = null; + _uploaded = false; + _progressValue = 0; + _uploadedSvgData = ""; + _uploadedPngData = ""; + _uploadedWebpData = ""; + _savingLogo = false; + _frmUpload.Show(); + } + + void HideUploadModal() => _frmUpload.Hide(); + + void UploadModalClosing(ModalClosingEventArgs e) + { + _uploadError = false; + _uploadErrorMessage = ""; + _uploading = false; + _uploadMs = null; + _uploaded = false; + _progressValue = 0; + _uploadedSvgData = ""; + _uploadedPngData = ""; + _uploadedWebpData = ""; + _savingLogo = false; + } + + async Task UploadFile() + { + IFileReference file = (await FileReaderService.CreateReference(_inputUpload).EnumerateFilesAsync()). + FirstOrDefault(); + + if(file is null) + return; + + IFileInfo fileInfo = await file.ReadFileInfoAsync(); + + if(fileInfo.Size > _maxUploadSize) + { + _uploadError = true; + _uploadErrorMessage = L["The selected file is too big."]; + + return; + } + + _uploading = true; + + await using AsyncDisposableStream fs = await file.OpenReadAsync(); + byte[] buffer = new byte[20480]; + + try + { + double lastProgress = 0; + int count; + _uploadMs = new MemoryStream(); + + while((count = await fs.ReadAsync(buffer, 0, buffer.Length)) != 0) + { + await _uploadMs.WriteAsync(buffer, 0, count); + + double progress = ((double)fs.Position * 100) / fs.Length; + + if(!(progress > lastProgress + 0.01)) + continue; + + _progressValue = progress; + await InvokeAsync(StateHasChanged); + await Task.Yield(); + lastProgress = progress; + } + } + catch(Exception) + { + _uploading = false; + _uploadError = true; + _uploadErrorMessage = L["There was an error uploading the file."]; + + return; + } + + _uploading = false; + await InvokeAsync(StateHasChanged); + await Task.Yield(); + + bool validSvg = true; + + buffer = new byte[6]; + + _uploadMs.Position = 0; + _uploadMs.Read(buffer, 0, 6); + + if(!Encoding.UTF8.GetString(buffer).StartsWith("", StringComparison.InvariantCulture)) + validSvg = false; + + if(!validSvg) + { + _uploadMs = null; + _uploadError = true; + _uploadErrorMessage = L["The uploaded file is not a SVG file."]; + + return; + } + + _uploadMs.Position = 0; + + var svg = new SKSvg(); + + try + { + svg.Load(_uploadMs); + } + catch(Exception) + { + _uploadMs = null; + _uploadError = true; + _uploadErrorMessage = L["The uploaded file could not be loaded. Is it a correct SVG file?"]; + + return; + } + + var pngStream = new MemoryStream(); + var webpStream = new MemoryStream(); + + try + { + SvgRender.RenderSvg(svg, pngStream, SKEncodedImageFormat.Png, 256, 1); + SvgRender.RenderSvg(svg, webpStream, SKEncodedImageFormat.Webp, 256, 1); + } + catch(Exception) + { + _uploadMs = null; + _uploadError = true; + _uploadErrorMessage = L["An error occuring rendering the uploaded file. Is it a correct SVG file?"]; + + return; + } + + _uploadMs.Position = 0; + pngStream.Position = 0; + webpStream.Position = 0; + + _uploadedSvgData = $"data:image/svg+xml;base64,{Convert.ToBase64String(_uploadMs.ToArray())}"; + _uploadedPngData = $"data:image/png;base64,{Convert.ToBase64String(pngStream.ToArray())}"; + _uploadedWebpData = $"data:image/webp;base64,{Convert.ToBase64String(webpStream.ToArray())}"; + + _unknownLogoYear = true; + _uploaded = true; + } + + async Task ConfirmUpload() + { + _savingLogo = true; + _uploadMs.Position = 0; + var guid = Guid.NewGuid(); + + try + { + SvgRender.RenderCompanyLogo(guid, _uploadMs, Host.WebRootPath); + + var fs = new FileStream(Path.Combine(Host.WebRootPath, "assets/logos", $"{guid}.svg"), FileMode.OpenOrCreate, FileAccess.ReadWrite); + _uploadMs.Position = 0; + _uploadMs.WriteTo(fs); + fs.Close(); + } + catch(Exception) + { + _savingLogo = false; + _uploadError = true; + _uploadErrorMessage = L["An error occuring rendering the uploaded file. Is it a correct SVG file?"]; + + return; + } + + await CompanyLogosService.CreateAsync(Id, guid, _unknownLogoYear ? null : _currentLogoYear); + + _logos = await CompanyLogosService.GetByCompany(Id); + + _frmUpload.Hide(); + + // Yield thread to let UI to update + await Task.Yield(); + + // Tell we finished loading + StateHasChanged(); + } } } \ No newline at end of file diff --git a/Marechai/Resources/Services/CompaniesService.es.resx b/Marechai/Resources/Services/CompaniesService.es.resx index f29e8cfb..608a9fee 100644 --- a/Marechai/Resources/Services/CompaniesService.es.resx +++ b/Marechai/Resources/Services/CompaniesService.es.resx @@ -446,4 +446,56 @@ Por favor introduce un año válido. Please enter a valid year. + + ¿Estás seguro de que quieres borrar el logo de la compañía que has seleccionado? + Are you sure you want to delete the company logo you selected? + + + Elige un archivo con el logo en format SVG (versión 1.1 o inferior) + Choose SVG (version 1.1 or lower) logo file + + + Subir + Upload + + + Subiendo... + Uploading... + + + SVG + SVG + + + PNG + PNG + + + WebP + WebP + + + Puede que no se muestre correctamente + May not show properly + + + El archivo seleccionado es demasiado grande. + The selected file is too big. + + + Hubo un error subiendo el archivo. + There was an error uploading the file. + + + El archivo que has subido no es un archivo SVG. + The uploaded file is not a SVG file. + + + No se pudo cargar el archivo que has subido. ¿Es un SVG correcto? + The uploaded file could not be loaded. Is it a correct SVG file? + + + Ocurrió un error renderizando el archivo subido. ¿Es un SVG correcto? + An error occuring rendering the uploaded file. Is it a correct SVG file? + \ No newline at end of file diff --git a/Marechai/Services/CompanyLogosService.cs b/Marechai/Services/CompanyLogosService.cs index 0969b6ed..cc68f84a 100644 --- a/Marechai/Services/CompanyLogosService.cs +++ b/Marechai/Services/CompanyLogosService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -84,5 +85,18 @@ namespace Marechai.Services logo.Year = year; await _context.SaveChangesAsync(); } + + public async Task CreateAsync(int companyId, Guid guid, int? year) + { + var logo = new CompanyLogo + { + Guid = guid, Year = year, CompanyId = companyId + }; + + await _context.CompanyLogos.AddAsync(logo); + await _context.SaveChangesAsync(); + + return logo.Id; + } } } \ No newline at end of file diff --git a/Marechai/Startup.cs b/Marechai/Startup.cs index b7346f01..82f886f6 100644 --- a/Marechai/Startup.cs +++ b/Marechai/Startup.cs @@ -29,6 +29,7 @@ *******************************************************************************/ using System.Globalization; +using Blazor.FileReader; using Blazorise; using Blazorise.Bootstrap; using Blazorise.Icons.FontAwesome; @@ -83,6 +84,8 @@ namespace Marechai services.AddLocalization(options => options.ResourcesPath = "Resources"); + services.AddFileReaderService(); + Register.RegisterServices(services); } diff --git a/Marechai/_Imports.razor b/Marechai/_Imports.razor index 0d7c0f41..8d41025b 100644 --- a/Marechai/_Imports.razor +++ b/Marechai/_Imports.razor @@ -12,4 +12,5 @@ @using Microsoft.Extensions.Localization @using System.IO @using Microsoft.AspNetCore.Hosting -@using Blazorise \ No newline at end of file +@using Blazorise +@using Blazor.FileReader