public async Task <IActionResult> UploadImage(UploadViewModel model, string albumId) { var album = await _context.Albums .Include(a => a.Images) .SingleAsync(a => a.Id == albumId); if (album == null) { return(BadRequest()); } if (!await HasPermissionTo(album)) { return(Forbid()); } #region Compress and copy var compressedByTinify = false; var file = model.File; var appTinifyEnabled = bool.Parse(await _settingsHelper.Get(Settings.EnableTinifyCompress)); var canCompressByTinify = new string[] { "image/jpeg", "image/png" }.Any(s => s.Contains(file.ContentType)); MemoryStream imageStream; if (model.Compress && appTinifyEnabled && canCompressByTinify) { using (var ms = new MemoryStream()) { await file.CopyToAsync(ms); var byteFile = ms.ToArray(); var tinifyKey = await _settingsHelper.Get(Settings.TinifyApiKey); var tinify = new Tinify(tinifyKey); _logger.LogDebug("Starting upload to Tinify..."); var tinifyWatch = System.Diagnostics.Stopwatch.StartNew(); byteFile = await tinify.Compress(byteFile); tinifyWatch.Stop(); _logger.LogDebug($"Upload to Tinify used: {tinifyWatch.ElapsedMilliseconds}ms"); imageStream = new MemoryStream(byteFile); compressedByTinify = true; } } else { _logger.LogWarning("Image will not compress by Tinify"); imageStream = new MemoryStream(); await file.CopyToAsync(imageStream); } #endregion #region Internal operation bool hasThumbnail; System.Drawing.Image tempThumbImage = null; imageStream.Position = 0; using (var image = System.Drawing.Image.FromStream(imageStream)) { hasThumbnail = image.Width > 255; if (hasThumbnail) { tempThumbImage = ImageToThumbnail(image); } } imageStream.Position = 0; var hash = (new SHA1CryptoServiceProvider()).ComputeHash(imageStream); var imageModel = new Image { Name = file.FileName, MimeType = file.ContentType, Sha1 = BitConverter.ToString(hash).Replace("-", ""), FileSize = imageStream.Length, OwnBy = await _userManager.GetUserAsync(User), Album = album, HasThumbnail = hasThumbnail, Compressed = compressedByTinify }; // May not work if compress enabled? var dup = _context.Images.Where(image => image.Sha1 == imageModel.Sha1).ToList(); if (dup.Count > 0) { var dupImage = dup[0]; StatusMessage = $"Image with SHA1 \"{dupImage.Sha1}\" already exist in album \"{dupImage.Album.Name}\""; return(RedirectToAction(nameof(Detail), new { id = albumId })); } if (string.IsNullOrEmpty(_bucketName)) { throw new Exception("No S3 bucket name was set."); } #endregion #region Upload to S3 imageStream.Position = 0; var s3 = await _awsHelper.GetS3Client(); _logger.LogDebug("Starting upload to S3..."); var s3Watch = System.Diagnostics.Stopwatch.StartNew(); await s3.PutObjectAsync(new PutObjectRequest { BucketName = _bucketName, Key = imageModel.Id, InputStream = imageStream, ContentType = imageModel.MimeType }); if (hasThumbnail) { await s3.PutObjectAsync(new PutObjectRequest { BucketName = _bucketName, Key = $"thumbnail/{imageModel.Id}", InputStream = ImageToStream(tempThumbImage), ContentType = GetMimeTypeFromImageFormat(ImageFormat.Jpeg) }); } s3Watch.Stop(); _logger.LogDebug($"Upload to S3 used: {s3Watch.ElapsedMilliseconds}ms"); _context.Images.Add(imageModel); await _context.SaveChangesAsync(); #endregion return(RedirectToAction(nameof(Detail), new { id = albumId })); }