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);
                        }
                    }
                }

            }
        }
Exemple #2
0
        /// <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);
            }
        }
Exemple #3
0
        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();
        }
Exemple #4
0
 public void EncodeImage(string inputPath, string outputPath, int width, int height, int quality, ImageProcessingOptions options)
 {
     throw new NotImplementedException();
 }
Exemple #5
0
        /// <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);
            }
        }
Exemple #7
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(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);
        }
Exemple #9
0
        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);
            }
        }
Exemple #10
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;
        }
Exemple #11
0
        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;
            }
        }
Exemple #12
0
        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);
            }
        }
Exemple #13
0
        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);
            }
        }
Exemple #15
0
        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);
            }
        }
Exemple #16
0
        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();
        }
Exemple #17
0
        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();
            }
        }
Exemple #18
0
        /// <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);
            }
        }
Exemple #19
0
        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();
 }