更新 : 2018-01-22
之前漏掉了一個 image 優化, 就是 progressive jpg
refer :
http://techslides.com/demos/progressive-test.html (online test)
http://magick.codeplex.com/discussions/450804 (Magick)
https://www.imgonline.com.ua/eng/make-jpeg-progressive-without-compression-result.php (online convert)
https://developers.google.com/speed/docs/insights/OptimizeImages (google 優化圖片指南)
image.Settings.SetDefine(MagickFormat.Jpeg, "sampling-factor", "4:2:0"); image.Format = MagickFormat.Pjpeg; // 轉換成 progressive jpg image.Strip(); //這句會把圖片的所有 EXIF 洗掉 image.Quality = 85;
2017-09-25
refer : https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads
https://www.codeproject.com/Articles/1203408/Upload-Download-Files-in-ASP-NET-Core
這里只說說小文件上傳.
先看看前端 js 代碼
<input id="inputFile" type="file" /> <script> document.getElementById('inputFile').addEventListener('change', (e) => { let files = e.target.files; let formData = new FormData(); formData.append("file", files[0]); let http = new XMLHttpRequest(); http.open('POST', '/upload-file', true); http.send(formData); }, false); </script>
如果要上傳多個文件就 append 多幾個就是了
c#
public class UploadFileData { public IFormFile file { get; set; } } [Area("Web")] public class UploadController : Controller { public UploadController( IHostingEnvironment environment ) { this.environment = environment; } private IHostingEnvironment environment { get; set; } [HttpPost("upload-file")] public async Task<IActionResult> uploadFile(UploadFileData data) { var allFiles = Request.Form.Files; // 多文件的話可以直接從 form 拿到完, 或則設置成 List<IFormFile> 就可以了 var root = environment.WebRootPath; var extension = Path.GetExtension(data.file.FileName); var guid = Guid.NewGuid().ToString(); var fullPath = $@"{root}\images\{guid + extension}"; using (FileStream stream = new FileStream(fullPath, FileMode.Create)) { await data.file.CopyToAsync(stream); } return Ok(); } [Route("upload")] public async Task<IActionResult> Index() { return View(); } }
上面的是最簡單的版本,創建 file 然后把 upload file stream 寫入
如果是想直接使用 stream 也是可以
using (var memoryStream = new MemoryStream()) { await model.file.CopyToAsync(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); new FileExtensionContentTypeProvider().TryGetContentType(model.file.FileName, out string contentType); await EmailService.SendAsync( recipients: BusinessConfig.contactEmailHandler, subject: "Contact form from website", templatePath: "~/Email/Contact/Index.cshtml", model: model, attachs: new List<Attachment> { new Attachment(memoryStream, model.file.FileName, contentType ?? "application/octet-stream") } ); }
需要注意的是寫入 stream 后, 如果要讀取 stream 記得, Seek 一下.
還有一個常用的場景是, 上傳圖片要做 EXIF 處理.
可以用 Magick.NET 目前支持 core, 不過呢, 好像只支持 window 場景. 如果你不是 windows 可能要在等等或則用其它插件.
Magick 需要設置, 參考 : https://magick.codeplex.com/documentation
MagickAnyCPU.CacheDirectory = @"C:\MyProgram\MyTempDir"; MagickNET.SetTempDirectory(@"C:\MyProgram\MyTempFiles");
例子
using (var stream = data.file.OpenReadStream()) using (MagickImage image = new MagickImage(stream)) { ExifProfile profile = image.GetExifProfile(); image.Settings.SetDefine(MagickFormat.Jpeg, "sampling-factor", "4:2:0"); image.Strip(); //這句會把圖片的所有 EXIF 洗掉 image.Quality = 85; if (profile != null) { ExifValue orientation = profile.Values.SingleOrDefault(v => v.Tag == ExifTag.Orientation); if (orientation != null) { int orientationInt = Convert.ToInt32(orientation.Value); if (orientationInt == 6) { image.Rotate(90); } else if (orientationInt == 8) { image.Rotate(-90); } else if (orientationInt == 8) { image.Rotate(180); } } image.Write(fullPath); } else { image.Write(fullPath); } }
很簡單吧.
再來一個 zip 的
using (var stream = data.file.OpenReadStream()) using (var compressedFileStream = new FileStream($@"{root}\images\{guid}.zip", FileMode.Create)) using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false)) { var zipEntry = zipArchive.CreateEntry(data.file.FileName); using (var zipEntryStream = zipEntry.Open()) { stream.CopyTo(zipEntryStream); } }
core 支持 ZipArchive 哦
下載也很容易
public UploadController( IHostingEnvironment environment, IContentTypeProvider contentTypeProvider ) { this.environment = environment; this.contentTypeProvider = contentTypeProvider; } private IHostingEnvironment environment { get; set; } private IContentTypeProvider contentTypeProvider { get; set; } [HttpGet("download-file")] public FileResult downloadFile(string name, string display) { string contentType; contentTypeProvider.TryGetContentType(name, out contentType); HttpContext.Response.ContentType = contentType; string path = environment.WebRootPath + @"\images\" + name; // 注意哦, 不要像我這樣直接使用客戶端的值來拼接 path, 危險的 FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes(path), contentType) { FileDownloadName = display };
// return File("~/excels/report.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "report.xlsx"); // 返回 File + 路徑也是可以, 這個路徑是從 wwwroot 走起
// return File(await System.IO.File.ReadAllBytesAsync(path), same...) // 或則我們可以直接返回 byte[], 任意從哪里獲取都可以.
return result; }
html
<a href="/download-file?name=123.jpg&display=aaa.jpg" download >download</a>