123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- using MediaBrowser.Controller.Drawing;
- using MediaBrowser.Model.Drawing;
- using Microsoft.Extensions.Logging;
- using System;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Linq;
- using MediaBrowser.Common.IO;
- using MediaBrowser.Controller.IO;
- using MediaBrowser.Model.IO;
- using ImageFormat = MediaBrowser.Model.Drawing.ImageFormat;
- using Emby.Drawing;
- namespace Emby.Drawing.Net
- {
- public class GDIImageEncoder : IImageEncoder
- {
- private readonly IFileSystem _fileSystem;
- private readonly ILogger _logger;
- public GDIImageEncoder(IFileSystem fileSystem, ILogger logger)
- {
- _fileSystem = fileSystem;
- _logger = logger;
- LogInfo();
- }
- private void LogInfo()
- {
- _logger.LogInformation("GDIImageEncoder starting");
- using (var stream = GetType().Assembly.GetManifestResourceStream(GetType().Namespace + ".empty.png"))
- {
- using (var img = Image.FromStream(stream))
- {
- }
- }
- _logger.LogInformation("GDIImageEncoder started");
- }
- public string[] SupportedInputFormats
- {
- get
- {
- return new[]
- {
- "png",
- "jpeg",
- "jpg",
- "gif",
- "bmp"
- };
- }
- }
- public ImageFormat[] SupportedOutputFormats
- {
- get
- {
- return new[] { ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
- }
- }
- public ImageSize GetImageSize(string path)
- {
- using (var image = Image.FromFile(path))
- {
- return new ImageSize
- {
- Width = image.Width,
- Height = image.Height
- };
- }
- }
- private Image GetImage(string path, bool cropWhitespace)
- {
- if (cropWhitespace)
- {
- using (var originalImage = (Bitmap)Image.FromFile(path))
- {
- return originalImage.CropWhitespace();
- }
- }
- return Image.FromFile(path);
- }
- public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
- {
- using (var originalImage = GetImage(inputPath, options.CropWhiteSpace))
- {
- if (options.CropWhiteSpace || !originalImageSize.HasValue)
- {
- originalImageSize = new ImageSize(originalImage.Width, originalImage.Height);
- }
- var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
- var newWidth = Convert.ToInt32(Math.Round(newImageSize.Width));
- var newHeight = Convert.ToInt32(Math.Round(newImageSize.Height));
- // 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;
- // SourceCopy causes the image to be blank in OSX
- //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);
- // Save to the cache location
- using (var cacheFileStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false))
- {
- // Save to the memory stream
- thumbnail.Save(outputFormat, cacheFileStream, quality);
- }
- }
- }
- }
- }
- /// <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);
- }
- }
- /// <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.LogError(ex, "Error drawing indicator overlay");
- }
- }
- /// <summary>
- /// Gets the output format.
- /// </summary>
- /// <param name="image">The image.</param>
- /// <param name="outputFormat">The output format.</param>
- /// <returns>ImageFormat.</returns>
- private System.Drawing.Imaging.ImageFormat GetOutputFormat(Image image, ImageFormat outputFormat)
- {
- switch (outputFormat)
- {
- case ImageFormat.Bmp:
- return System.Drawing.Imaging.ImageFormat.Bmp;
- case ImageFormat.Gif:
- return System.Drawing.Imaging.ImageFormat.Gif;
- case ImageFormat.Jpg:
- return System.Drawing.Imaging.ImageFormat.Jpeg;
- case ImageFormat.Png:
- return System.Drawing.Imaging.ImageFormat.Png;
- default:
- return image.RawFormat;
- }
- }
- public void CreateImageCollage(ImageCollageOptions options)
- {
- double ratio = options.Width;
- ratio /= options.Height;
- if (ratio >= 1.4)
- {
- DynamicImageHelpers.CreateThumbCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Height);
- }
- else if (ratio >= .9)
- {
- DynamicImageHelpers.CreateSquareCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Height);
- }
- else
- {
- DynamicImageHelpers.CreateSquareCollage(options.InputPaths.ToList(), _fileSystem, options.OutputPath, options.Width, options.Width);
- }
- }
- public void Dispose()
- {
- }
- public string Name
- {
- get { return "GDI"; }
- }
- public bool SupportsImageCollageCreation
- {
- get { return true; }
- }
- public bool SupportsImageEncoding
- {
- get { return true; }
- }
- }
- }
|