public void EncodeImage(string inputPath, string cacheFilePath, int width, int height, int quality, ImageProcessingOptions options) { var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0; using (var originalImage = Image.FromFile(inputPath)) { var newWidth = Convert.ToInt32(width); var newHeight = Convert.ToInt32(height); var selectedOutputFormat = options.OutputFormat; // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here // Also, Webp only supports Format32bppArgb and Format32bppRgb var pixelFormat = selectedOutputFormat == ImageFormat.Webp ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppPArgb; using (var thumbnail = new Bitmap(newWidth, newHeight, pixelFormat)) { // Mono throw an exeception if assign 0 to SetResolution if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0) { // Preserve the original resolution thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution); } using (var thumbnailGraph = Graphics.FromImage(thumbnail)) { thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; thumbnailGraph.CompositingMode = !hasPostProcessing ? CompositingMode.SourceCopy : CompositingMode.SourceOver; SetBackgroundColor(thumbnailGraph, options); thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight); DrawIndicator(thumbnailGraph, newWidth, newHeight, options); var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); // Save to the cache location using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false)) { // Save to the memory stream thumbnail.Save(outputFormat, cacheFileStream, quality); } } } } }
/// <summary> /// Draws the indicator. /// </summary> /// <param name="wand">The wand.</param> /// <param name="imageWidth">Width of the image.</param> /// <param name="imageHeight">Height of the image.</param> /// <param name="options">The options.</param> private void DrawIndicator(MagickWand wand, int imageWidth, int imageHeight, ImageProcessingOptions options) { if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0)) { return; } try { if (options.AddPlayedIndicator) { var currentImageSize = new ImageSize(imageWidth, imageHeight); var task = new PlayedIndicatorDrawer(_appPaths, _httpClient, _fileSystem).DrawPlayedIndicator(wand, currentImageSize); Task.WaitAll(task); } else if (options.UnplayedCount.HasValue) { var currentImageSize = new ImageSize(imageWidth, imageHeight); new UnplayedCountIndicator(_appPaths, _fileSystem).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value); } if (options.PercentPlayed > 0) { new PercentPlayedDrawer().Process(wand, options.PercentPlayed); } } catch (Exception ex) { _logger.ErrorException("Error drawing indicator overlay", ex); } }
public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { // Even if the caller specified 100, don't use it because it takes forever quality = Math.Min(quality, 99); if (string.IsNullOrWhiteSpace(options.BackgroundColor) || !HasTransparency(inputPath)) { using (var originalImage = new MagickWand(inputPath)) { ScaleImage(originalImage, width, height); DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; originalImage.CurrentImage.StripImage(); originalImage.SaveImage(outputPath); } } else { using (var wand = new MagickWand(width, height, options.BackgroundColor)) { using (var originalImage = new MagickWand(inputPath)) { ScaleImage(originalImage, width, height); wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0); DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; wand.CurrentImage.StripImage(); wand.SaveImage(outputPath); } } } SaveDelay(); }
public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) { throw new NotImplementedException(); }
/// <summary> /// Writes to async. /// </summary> /// <param name="responseStream">The response stream.</param> /// <returns>Task.</returns> private Task WriteToAsync(Stream responseStream) { var cropwhitespace = Request.Type == ImageType.Logo || Request.Type == ImageType.Art; if (Request.CropWhitespace.HasValue) { cropwhitespace = Request.CropWhitespace.Value; } var options = new ImageProcessingOptions { CropWhiteSpace = cropwhitespace, Enhancers = Enhancers, Height = Request.Height, ImageIndex = Request.Index ?? 0, ImageType = Request.Type, Item = Item, MaxHeight = Request.MaxHeight, MaxWidth = Request.MaxWidth, OriginalImageDateModified = OriginalImageDateModified, OriginalImagePath = OriginalImagePath, Quality = Request.Quality, Width = Request.Width, OutputFormat = Request.Format, AddPlayedIndicator = Request.AddPlayedIndicator, PercentPlayed = Request.PercentPlayed, UnplayedCount = Request.UnplayedCount, BackgroundColor = Request.BackgroundColor }; return ImageProcessor.ProcessImage(options, responseStream); }
/// <summary> /// Draws the indicator. /// </summary> /// <param name="graphics">The graphics.</param> /// <param name="imageWidth">Width of the image.</param> /// <param name="imageHeight">Height of the image.</param> /// <param name="options">The options.</param> private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options) { if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0)) { return; } try { if (options.AddPlayedIndicator) { var currentImageSize = new Size(imageWidth, imageHeight); new PlayedIndicatorDrawer().DrawPlayedIndicator(graphics, currentImageSize); } else if (options.UnplayedCount.HasValue) { var currentImageSize = new Size(imageWidth, imageHeight); new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value); } if (options.PercentPlayed > 0) { var currentImageSize = new Size(imageWidth, imageHeight); new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed); } } catch (Exception ex) { _logger.ErrorException("Error drawing indicator overlay", ex); } }
public async Task<string> ProcessImage(ImageProcessingOptions options) { if (options == null) { throw new ArgumentNullException("options"); } var originalImagePath = options.Image.Path; if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) { // Just spit out the original file if all the options are default return originalImagePath; } var dateModified = options.Image.DateModified; if (options.CropWhiteSpace) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(options.Image, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } var originalImageSize = GetImageSize(originalImagePath, dateModified); // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); if (options.HasDefaultOptionsWithoutSize(originalImagePath) && newSize.Equals(originalImageSize) && options.Enhancers.Count == 0) { // Just spit out the original file if the new size equals the old return originalImagePath; } var quality = options.Quality ?? 90; var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); await semaphore.WaitAsync().ConfigureAwait(false); // Check again in case of lock contention try { if (File.Exists(cacheFilePath)) { semaphore.Release(); return cacheFilePath; } } catch { semaphore.Release(); throw; } try { var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0; using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { // Copy to memory stream to avoid Image locking file using (var memoryStream = new MemoryStream()) { await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false); using (var originalImage = Image.FromStream(memoryStream, true, false)) { var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); var selectedOutputFormat = options.OutputFormat; _logger.Debug("Processing image to {0}", selectedOutputFormat); // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here // Also, Webp only supports Format32bppArgb and Format32bppRgb var pixelFormat = selectedOutputFormat == Model.Drawing.ImageFormat.Webp ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppPArgb; using (var thumbnail = new Bitmap(newWidth, newHeight, pixelFormat)) { // Mono throw an exeception if assign 0 to SetResolution if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0) { // Preserve the original resolution thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution); } using (var thumbnailGraph = Graphics.FromImage(thumbnail)) { thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; thumbnailGraph.CompositingMode = !hasPostProcessing ? CompositingMode.SourceCopy : CompositingMode.SourceOver; SetBackgroundColor(thumbnailGraph, options); thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight); DrawIndicator(thumbnailGraph, newWidth, newHeight, options); var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); // Save to the cache location using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false)) { if (selectedOutputFormat == Model.Drawing.ImageFormat.Webp) { SaveToWebP(thumbnail, cacheFileStream, quality); } else { // Save to the memory stream thumbnail.Save(outputFormat, cacheFileStream, quality); } } return cacheFilePath; } } } } } } finally { semaphore.Release(); } }
private ImageSize GetNewImageSize(ImageProcessingOptions options, ImageSize? originalImageSize) { if (originalImageSize.HasValue) { // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width, options.Height, options.MaxWidth, options.MaxHeight); return newSize; } return GetSizeEstimate(options); }
private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options) { if (string.IsNullOrWhiteSpace(options.ForegroundLayer)) { return; } Double opacity; if (!Double.TryParse(options.ForegroundLayer, out opacity)) opacity = .4; using (var pixel = new PixelWand("#000", opacity)) using (var overlay = new MagickWand(wand.CurrentImage.Width, wand.CurrentImage.Height, pixel)) { wand.CurrentImage.CompositeImage(overlay, CompositeOperator.OverCompositeOp, 0, 0); } }
public async Task<string> ProcessImage(ImageProcessingOptions options) { if (options == null) { throw new ArgumentNullException("options"); } var originalImagePath = options.Image.Path; if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) { // Just spit out the original file if all the options are default return originalImagePath; } var dateModified = options.Image.DateModified; if (options.CropWhiteSpace) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(new ItemImageInfo { DateModified = dateModified, Type = options.Image.Type, Path = originalImagePath }, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } var originalImageSize = GetImageSize(originalImagePath, dateModified, true); // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); if (options.HasDefaultOptionsWithoutSize(originalImagePath) && newSize.Equals(originalImageSize) && options.Enhancers.Count == 0) { // Just spit out the original file if the new size equals the old return originalImagePath; } var quality = options.Quality ?? 90; var outputFormat = GetOutputFormat(options.OutputFormat); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); await semaphore.WaitAsync().ConfigureAwait(false); var imageProcessingLockTaken = false; try { CheckDisposed(); if (!File.Exists(cacheFilePath)) { var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); imageProcessingLockTaken = true; _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options); } } finally { if (imageProcessingLockTaken) { _imageProcessingSemaphore.Release(); } semaphore.Release(); } return cacheFilePath; }
public async Task ProcessImage(ImageProcessingOptions options, Stream toStream) { if (options == null) { throw new ArgumentNullException("options"); } if (toStream == null) { throw new ArgumentNullException("toStream"); } var originalImagePath = options.OriginalImagePath; if (options.HasDefaultOptions() && options.Enhancers.Count == 0 && !options.CropWhiteSpace) { // Just spit out the original file if all the options are default using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); return; } } var dateModified = options.OriginalImageDateModified; if (options.CropWhiteSpace) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(originalImagePath, dateModified, options.Item, options.ImageType, options.ImageIndex, options.Enhancers).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } var originalImageSize = GetImageSize(originalImagePath, dateModified); // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); if (options.HasDefaultOptionsWithoutSize() && newSize.Equals(originalImageSize) && options.Enhancers.Count == 0) { // Just spit out the original file if the new size equals the old using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); return; } } var quality = options.Quality ?? 90; var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); try { using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); return; } } catch (IOException) { // Cache file doesn't exist or is currently being written to } var semaphore = GetLock(cacheFilePath); await semaphore.WaitAsync().ConfigureAwait(false); // Check again in case of lock contention try { using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); semaphore.Release(); return; } } catch (IOException) { // Cache file doesn't exist or is currently being written to } catch { semaphore.Release(); throw; } try { using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { // Copy to memory stream to avoid Image locking file using (var memoryStream = new MemoryStream()) { await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false); using (var originalImage = Image.FromStream(memoryStream, true, false)) { var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here using (var thumbnail = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppPArgb)) { // Mono throw an exeception if assign 0 to SetResolution if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0) { // Preserve the original resolution thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution); } using (var thumbnailGraph = Graphics.FromImage(thumbnail)) { thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality; thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality; thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic; thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; thumbnailGraph.CompositingMode = string.IsNullOrEmpty(options.BackgroundColor) && !options.UnplayedCount.HasValue && !options.AddPlayedIndicator && !options.PercentPlayed.HasValue ? CompositingMode.SourceCopy : CompositingMode.SourceOver; SetBackgroundColor(thumbnailGraph, options); thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight); DrawIndicator(thumbnailGraph, newWidth, newHeight, options); var outputFormat = GetOutputFormat(originalImage, options.OutputFormat); using (var outputMemoryStream = new MemoryStream()) { // Save to the memory stream thumbnail.Save(outputFormat, outputMemoryStream, quality); var bytes = outputMemoryStream.ToArray(); await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); // kick off a task to cache the result CacheResizedImage(cacheFilePath, bytes, semaphore); } } } } } } } catch { semaphore.Release(); throw; } }
private Tuple<ImageSize, bool> GetNewImageSize(string originalImagePath, DateTime dateModified, ImageProcessingOptions options) { try { var originalImageSize = GetImageSize(originalImagePath, dateModified, true); // Determine the output size based on incoming parameters var newSize = DrawingUtils.Resize(originalImageSize, options.Width, options.Height, options.MaxWidth, options.MaxHeight); return new Tuple<ImageSize, bool>(newSize, !newSize.Equals(originalImageSize)); } catch { return new Tuple<ImageSize, bool>(GetSizeEstimage(options), true); } }
public async Task<string> ProcessImage(ImageProcessingOptions options) { if (options == null) { throw new ArgumentNullException("options"); } var originalImage = options.Image; if (!originalImage.IsLocalFile) { originalImage = await _libraryManager().ConvertImageToLocal(options.Item, originalImage, options.ImageIndex).ConfigureAwait(false); } var originalImagePath = originalImage.Path; if (!_imageEncoder.SupportsImageEncoding) { return originalImagePath; } if (options.HasDefaultOptions(originalImagePath) && options.Enhancers.Count == 0 && !options.CropWhiteSpace) { // Just spit out the original file if all the options are default return originalImagePath; } var dateModified = originalImage.DateModified; if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(new ItemImageInfo { DateModified = dateModified, Type = originalImage.Type, Path = originalImagePath }, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } var newSizeInfo = GetNewImageSize(originalImagePath, dateModified, options); var newSize = newSizeInfo.Item1; var isSizeChanged = newSizeInfo.Item2; if (options.HasDefaultOptionsWithoutSize(originalImagePath) && !isSizeChanged && options.Enhancers.Count == 0) { // Just spit out the original file if the new size equals the old return originalImagePath; } var quality = options.Quality ?? 90; var outputFormat = GetOutputFormat(options.OutputFormat); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); await semaphore.WaitAsync().ConfigureAwait(false); var imageProcessingLockTaken = false; try { CheckDisposed(); if (!_fileSystem.FileExists(cacheFilePath)) { var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); imageProcessingLockTaken = true; _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, newWidth, newHeight, quality, options); } } finally { if (imageProcessingLockTaken) { _imageProcessingSemaphore.Release(); } semaphore.Release(); } return cacheFilePath; }
/// <summary> /// Draws the indicator. /// </summary> /// <param name="graphics">The graphics.</param> /// <param name="imageWidth">Width of the image.</param> /// <param name="imageHeight">Height of the image.</param> /// <param name="options">The options.</param> private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options) { if (!options.AddPlayedIndicator && !options.PercentPlayed.HasValue) { return; } try { var percentOffset = 0; if (options.AddPlayedIndicator) { var currentImageSize = new Size(imageWidth, imageHeight); new WatchedIndicatorDrawer().Process(graphics, currentImageSize); percentOffset = 0 - WatchedIndicatorDrawer.IndicatorWidth; } if (options.PercentPlayed.HasValue) { var currentImageSize = new Size(imageWidth, imageHeight); new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed.Value, percentOffset); } } catch (Exception ex) { _logger.ErrorException("Error drawing indicator overlay", ex); } }
public async Task ProcessImage(ImageProcessingOptions options, Stream toStream) { var file = await ProcessImage(options).ConfigureAwait(false); using (var fileStream = _fileSystem.GetFileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { await fileStream.CopyToAsync(toStream).ConfigureAwait(false); } }
public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options) { if (string.IsNullOrWhiteSpace(options.BackgroundColor) || !HasTransparency(inputPath)) { using (var originalImage = new MagickWand(inputPath)) { originalImage.CurrentImage.ResizeImage(width, height); DrawIndicator(originalImage, width, height, options); originalImage.CurrentImage.CompressionQuality = quality; originalImage.SaveImage(outputPath); } } else { using (var wand = new MagickWand(width, height, options.BackgroundColor)) { using (var originalImage = new MagickWand(inputPath)) { originalImage.CurrentImage.ResizeImage(width, height); wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0); DrawIndicator(wand, width, height, options); wand.CurrentImage.CompressionQuality = quality; wand.SaveImage(outputPath); } } } SaveDelay(); }
public async Task<Tuple<string, string>> ProcessImage(ImageProcessingOptions options) { if (options == null) { throw new ArgumentNullException("options"); } var originalImage = options.Image; if (!originalImage.IsLocalFile) { originalImage = await _libraryManager().ConvertImageToLocal(options.Item, originalImage, options.ImageIndex).ConfigureAwait(false); } var originalImagePath = originalImage.Path; if (!_imageEncoder.SupportsImageEncoding) { return new Tuple<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } var dateModified = originalImage.DateModified; if (options.CropWhiteSpace && _imageEncoder.SupportsImageEncoding) { var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.Enhancers.Count > 0) { var tuple = await GetEnhancedImage(new ItemImageInfo { DateModified = dateModified, Type = originalImage.Type, Path = originalImagePath }, options.Item, options.ImageIndex, options.Enhancers).ConfigureAwait(false); originalImagePath = tuple.Item1; dateModified = tuple.Item2; } if (options.HasDefaultOptions(originalImagePath)) { // Just spit out the original file if all the options are default return new Tuple<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } ImageSize? originalImageSize; try { originalImageSize = GetImageSize(originalImagePath, dateModified, true); if (options.HasDefaultOptions(originalImagePath, originalImageSize.Value)) { // Just spit out the original file if all the options are default return new Tuple<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } } catch { originalImageSize = null; } var newSize = GetNewImageSize(options, originalImageSize); var quality = options.Quality; var outputFormat = GetOutputFormat(options.SupportedOutputFormats[0]); var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor); var semaphore = GetLock(cacheFilePath); await semaphore.WaitAsync().ConfigureAwait(false); var imageProcessingLockTaken = false; try { CheckDisposed(); if (!_fileSystem.FileExists(cacheFilePath)) { var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); await _imageProcessingSemaphore.WaitAsync().ConfigureAwait(false); imageProcessingLockTaken = true; _imageEncoder.EncodeImage(originalImagePath, cacheFilePath, AutoOrient(options.Item), newWidth, newHeight, quality, options, outputFormat); } return new Tuple<string, string>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath)); } catch (Exception ex) { // If it fails for whatever reason, return the original image _logger.ErrorException("Error encoding image", ex); // Just spit out the original file if all the options are default return new Tuple<string, string>(originalImagePath, MimeTypes.GetMimeType(originalImagePath)); } finally { if (imageProcessingLockTaken) { _imageProcessingSemaphore.Release(); } semaphore.Release(); } }
/// <summary> /// Sets the color of the background. /// </summary> /// <param name="graphics">The graphics.</param> /// <param name="options">The options.</param> private void SetBackgroundColor(Graphics graphics, ImageProcessingOptions options) { var color = options.BackgroundColor; if (!string.IsNullOrEmpty(color)) { Color drawingColor; try { drawingColor = ColorTranslator.FromHtml(color); } catch { drawingColor = ColorTranslator.FromHtml("#" + color); } graphics.Clear(drawingColor); } }
private ImageSize GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) { return new ImageSize(options.Width.Value, options.Height.Value); } var aspect = GetEstimatedAspectRatio(options.Image.Type); var width = options.Width ?? options.MaxWidth; if (width.HasValue) { var heightValue = aspect / width.Value; return new ImageSize(width.Value, Convert.ToInt32(heightValue)); } var height = options.Height ?? options.MaxHeight ?? 200; var widthValue = aspect * height; return new ImageSize(Convert.ToInt32(widthValue), height); }
public void EncodeImage(string inputPath, string outputPath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) { throw new NotImplementedException(); }