diff options
| author | Bond_009 <bond.009@outlook.com> | 2019-01-26 20:43:13 +0100 |
|---|---|---|
| committer | Bond_009 <bond.009@outlook.com> | 2019-01-26 20:43:13 +0100 |
| commit | ce11869a1acf8b31316b41c28f4bf7acb1a08959 (patch) | |
| tree | 8471bf8a2c7a52c68aa2d794bac747cfa0b5b31e /Emby.Drawing | |
| parent | e3b19c22a7506d6e03d6519b50797c1f49c70034 (diff) | |
Move Skia back into it's own project
Diffstat (limited to 'Emby.Drawing')
| -rw-r--r-- | Emby.Drawing/Emby.Drawing.csproj | 6 | ||||
| -rw-r--r-- | Emby.Drawing/PercentPlayedDrawer.cs | 31 | ||||
| -rw-r--r-- | Emby.Drawing/PlayedIndicatorDrawer.cs | 44 | ||||
| -rw-r--r-- | Emby.Drawing/SkiaEncoder.cs | 653 | ||||
| -rw-r--r-- | Emby.Drawing/StripCollageBuilder.cs | 234 | ||||
| -rw-r--r-- | Emby.Drawing/UnplayedCountIndicator.cs | 51 |
6 files changed, 0 insertions, 1019 deletions
diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index c36d42194..9f97baf77 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -6,12 +6,6 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="SkiaSharp" Version="1.68.0" /> - <PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="1.68.0" /> - <PackageReference Include="Jellyfin.SkiaSharp.NativeAssets.LinuxArm" Version="1.68.0" /> - </ItemGroup> - - <ItemGroup> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" /> diff --git a/Emby.Drawing/PercentPlayedDrawer.cs b/Emby.Drawing/PercentPlayedDrawer.cs deleted file mode 100644 index 3ce46bc12..000000000 --- a/Emby.Drawing/PercentPlayedDrawer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using MediaBrowser.Model.Drawing; -using SkiaSharp; - -namespace Emby.Drawing -{ - public static class PercentPlayedDrawer - { - private const int IndicatorHeight = 8; - - public static void Process(SKCanvas canvas, ImageDimensions imageSize, double percent) - { - using (var paint = new SKPaint()) - { - var endX = imageSize.Width - 1; - var endY = imageSize.Height - 1; - - paint.Color = SKColor.Parse("#99000000"); - paint.Style = SKPaintStyle.Fill; - canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, (float)endX, (float)endY), paint); - - double foregroundWidth = endX; - foregroundWidth *= percent; - foregroundWidth /= 100; - - paint.Color = SKColor.Parse("#FF52B54B"); - canvas.DrawRect(SKRect.Create(0, (float)endY - IndicatorHeight, Convert.ToInt32(foregroundWidth), (float)endY), paint); - } - } - } -} diff --git a/Emby.Drawing/PlayedIndicatorDrawer.cs b/Emby.Drawing/PlayedIndicatorDrawer.cs deleted file mode 100644 index 38b5edc92..000000000 --- a/Emby.Drawing/PlayedIndicatorDrawer.cs +++ /dev/null @@ -1,44 +0,0 @@ -using MediaBrowser.Model.Drawing; -using SkiaSharp; - -namespace Emby.Drawing -{ - public static class PlayedIndicatorDrawer - { - private const int OffsetFromTopRightCorner = 38; - - public static void DrawPlayedIndicator(SKCanvas canvas, ImageDimensions imageSize) - { - var x = imageSize.Width - OffsetFromTopRightCorner; - - using (var paint = new SKPaint()) - { - paint.Color = SKColor.Parse("#CC52B54B"); - paint.Style = SKPaintStyle.Fill; - canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint); - } - - using (var paint = new SKPaint()) - { - paint.Color = new SKColor(255, 255, 255, 255); - paint.Style = SKPaintStyle.Fill; - - paint.TextSize = 30; - paint.IsAntialias = true; - - var text = "✔️"; - var emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32); - // or: - //var emojiChar = 0x1F680; - - // ask the font manager for a font with that character - var fontManager = SKFontManager.Default; - var emojiTypeface = fontManager.MatchCharacter(emojiChar); - - paint.Typeface = emojiTypeface; - - canvas.DrawText(text, (float)x - 20, OffsetFromTopRightCorner + 12, paint); - } - } - } -} diff --git a/Emby.Drawing/SkiaEncoder.cs b/Emby.Drawing/SkiaEncoder.cs deleted file mode 100644 index aae10f6cc..000000000 --- a/Emby.Drawing/SkiaEncoder.cs +++ /dev/null @@ -1,653 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Controller.Extensions; -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; -using SkiaSharp; - -namespace Emby.Drawing -{ - public class SkiaEncoder : IImageEncoder - { - private readonly ILogger _logger; - private static IApplicationPaths _appPaths; - private readonly IFileSystem _fileSystem; - private static ILocalizationManager _localizationManager; - - public SkiaEncoder( - ILoggerFactory loggerFactory, - IApplicationPaths appPaths, - IFileSystem fileSystem, - ILocalizationManager localizationManager) - { - _logger = loggerFactory.CreateLogger("ImageEncoder"); - _appPaths = appPaths; - _fileSystem = fileSystem; - _localizationManager = localizationManager; - - LogVersion(); - } - - public string[] SupportedInputFormats => - new[] - { - "jpeg", - "jpg", - "png", - - "dng", - - "webp", - "gif", - "bmp", - "ico", - "astc", - "ktx", - "pkm", - "wbmp", - - // TODO - // Are all of these supported? https://github.com/google/skia/blob/master/infra/bots/recipes/test.py#L454 - - // working on windows at least - "cr2", - "nef", - "arw" - }; - - public ImageFormat[] SupportedOutputFormats => new[] { ImageFormat.Webp, ImageFormat.Jpg, ImageFormat.Png }; - - private void LogVersion() - { - // test an operation that requires the native library - SKPMColor.PreMultiply(SKColors.Black); - - _logger.LogInformation("SkiaSharp version: " + GetVersion()); - } - - public static string GetVersion() - { - return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString(); - } - - private static bool IsTransparent(SKColor color) - { - - return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0; - } - - public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat) - { - switch (selectedFormat) - { - case ImageFormat.Bmp: - return SKEncodedImageFormat.Bmp; - case ImageFormat.Jpg: - return SKEncodedImageFormat.Jpeg; - case ImageFormat.Gif: - return SKEncodedImageFormat.Gif; - case ImageFormat.Webp: - return SKEncodedImageFormat.Webp; - default: - return SKEncodedImageFormat.Png; - } - } - - private static bool IsTransparentRow(SKBitmap bmp, int row) - { - for (var i = 0; i < bmp.Width; ++i) - { - if (!IsTransparent(bmp.GetPixel(i, row))) - { - return false; - } - } - return true; - } - - private static bool IsTransparentColumn(SKBitmap bmp, int col) - { - for (var i = 0; i < bmp.Height; ++i) - { - if (!IsTransparent(bmp.GetPixel(col, i))) - { - return false; - } - } - return true; - } - - private SKBitmap CropWhiteSpace(SKBitmap bitmap) - { - var topmost = 0; - for (int row = 0; row < bitmap.Height; ++row) - { - if (IsTransparentRow(bitmap, row)) - topmost = row + 1; - else break; - } - - int bottommost = bitmap.Height; - for (int row = bitmap.Height - 1; row >= 0; --row) - { - if (IsTransparentRow(bitmap, row)) - bottommost = row; - else break; - } - - int leftmost = 0, rightmost = bitmap.Width; - for (int col = 0; col < bitmap.Width; ++col) - { - if (IsTransparentColumn(bitmap, col)) - leftmost = col + 1; - else - break; - } - - for (int col = bitmap.Width - 1; col >= 0; --col) - { - if (IsTransparentColumn(bitmap, col)) - rightmost = col; - else - break; - } - - var newRect = SKRectI.Create(leftmost, topmost, rightmost - leftmost, bottommost - topmost); - - using (var image = SKImage.FromBitmap(bitmap)) - using (var subset = image.Subset(newRect)) - { - return SKBitmap.FromImage(subset); - } - } - - public ImageDimensions GetImageSize(string path) - { - using (var s = new SKFileStream(path)) - using (var codec = SKCodec.Create(s)) - { - var info = codec.Info; - - return new ImageDimensions(info.Width, info.Height); - } - } - - private static bool HasDiacritics(string text) - { - return !string.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal); - } - - private static bool RequiresSpecialCharacterHack(string path) - { - if (_localizationManager.HasUnicodeCategory(path, UnicodeCategory.OtherLetter)) - { - return true; - } - - if (HasDiacritics(path)) - { - return true; - } - - return false; - } - - private static string NormalizePath(string path, IFileSystem fileSystem) - { - if (!RequiresSpecialCharacterHack(path)) - { - return path; - } - - var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + Path.GetExtension(path) ?? string.Empty); - - fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath)); - fileSystem.CopyFile(path, tempPath, true); - - return tempPath; - } - - private static SKEncodedOrigin GetSKEncodedOrigin(ImageOrientation? orientation) - { - if (!orientation.HasValue) - { - return SKEncodedOrigin.TopLeft; - } - - switch (orientation.Value) - { - case ImageOrientation.TopRight: - return SKEncodedOrigin.TopRight; - case ImageOrientation.RightTop: - return SKEncodedOrigin.RightTop; - case ImageOrientation.RightBottom: - return SKEncodedOrigin.RightBottom; - case ImageOrientation.LeftTop: - return SKEncodedOrigin.LeftTop; - case ImageOrientation.LeftBottom: - return SKEncodedOrigin.LeftBottom; - case ImageOrientation.BottomRight: - return SKEncodedOrigin.BottomRight; - case ImageOrientation.BottomLeft: - return SKEncodedOrigin.BottomLeft; - default: - return SKEncodedOrigin.TopLeft; - } - } - - private static string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" }; - internal static SKBitmap Decode(string path, bool forceCleanBitmap, IFileSystem fileSystem, ImageOrientation? orientation, out SKEncodedOrigin origin) - { - if (!fileSystem.FileExists(path)) - { - throw new FileNotFoundException("File not found", path); - } - - var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty); - - if (requiresTransparencyHack || forceCleanBitmap) - { - using (var stream = new SKFileStream(NormalizePath(path, fileSystem))) - using (var codec = SKCodec.Create(stream)) - { - if (codec == null) - { - origin = GetSKEncodedOrigin(orientation); - return null; - } - - // create the bitmap - var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); - - // decode - codec.GetPixels(bitmap.Info, bitmap.GetPixels()); - - origin = codec.EncodedOrigin; - - return bitmap; - } - } - - var resultBitmap = SKBitmap.Decode(NormalizePath(path, fileSystem)); - - if (resultBitmap == null) - { - return Decode(path, true, fileSystem, orientation, out origin); - } - - // If we have to resize these they often end up distorted - if (resultBitmap.ColorType == SKColorType.Gray8) - { - using (resultBitmap) - { - return Decode(path, true, fileSystem, orientation, out origin); - } - } - - origin = SKEncodedOrigin.TopLeft; - return resultBitmap; - } - - private SKBitmap GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, ImageOrientation? orientation, out SKEncodedOrigin origin) - { - if (cropWhitespace) - { - using (var bitmap = Decode(path, forceAnalyzeBitmap, _fileSystem, orientation, out origin)) - { - return CropWhiteSpace(bitmap); - } - } - - return Decode(path, forceAnalyzeBitmap, _fileSystem, orientation, out origin); - } - - private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation) - { - SKEncodedOrigin origin; - - if (autoOrient) - { - var bitmap = GetBitmap(path, cropWhitespace, true, orientation, out origin); - - if (bitmap != null) - { - if (origin != SKEncodedOrigin.TopLeft) - { - using (bitmap) - { - return OrientImage(bitmap, origin); - } - } - } - - return bitmap; - } - - return GetBitmap(path, cropWhitespace, false, orientation, out origin); - } - - private SKBitmap OrientImage(SKBitmap bitmap, SKEncodedOrigin origin) - { - //var transformations = { - // 2: { rotate: 0, flip: true}, - // 3: { rotate: 180, flip: false}, - // 4: { rotate: 180, flip: true}, - // 5: { rotate: 90, flip: true}, - // 6: { rotate: 90, flip: false}, - // 7: { rotate: 270, flip: true}, - // 8: { rotate: 270, flip: false}, - //} - - switch (origin) - { - - case SKEncodedOrigin.TopRight: - { - var rotated = new SKBitmap(bitmap.Width, bitmap.Height); - using (var surface = new SKCanvas(rotated)) - { - surface.Translate(rotated.Width, 0); - surface.Scale(-1, 1); - surface.DrawBitmap(bitmap, 0, 0); - } - - return rotated; - } - - case SKEncodedOrigin.BottomRight: - { - var rotated = new SKBitmap(bitmap.Width, bitmap.Height); - using (var surface = new SKCanvas(rotated)) - { - float px = bitmap.Width; - px /= 2; - - float py = bitmap.Height; - py /= 2; - - surface.RotateDegrees(180, px, py); - surface.DrawBitmap(bitmap, 0, 0); - } - - return rotated; - } - - case SKEncodedOrigin.BottomLeft: - { - var rotated = new SKBitmap(bitmap.Width, bitmap.Height); - using (var surface = new SKCanvas(rotated)) - { - float px = bitmap.Width; - px /= 2; - - float py = bitmap.Height; - py /= 2; - - surface.Translate(rotated.Width, 0); - surface.Scale(-1, 1); - - surface.RotateDegrees(180, px, py); - surface.DrawBitmap(bitmap, 0, 0); - } - - return rotated; - } - - case SKEncodedOrigin.LeftTop: - { - // TODO: Remove dual canvases, had trouble with flipping - using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width)) - { - using (var surface = new SKCanvas(rotated)) - { - surface.Translate(rotated.Width, 0); - - surface.RotateDegrees(90); - - surface.DrawBitmap(bitmap, 0, 0); - - } - - var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height); - using (var flippedCanvas = new SKCanvas(flippedBitmap)) - { - flippedCanvas.Translate(flippedBitmap.Width, 0); - flippedCanvas.Scale(-1, 1); - flippedCanvas.DrawBitmap(rotated, 0, 0); - } - - return flippedBitmap; - } - } - - case SKEncodedOrigin.RightTop: - { - var rotated = new SKBitmap(bitmap.Height, bitmap.Width); - using (var surface = new SKCanvas(rotated)) - { - surface.Translate(rotated.Width, 0); - surface.RotateDegrees(90); - surface.DrawBitmap(bitmap, 0, 0); - } - - return rotated; - } - - case SKEncodedOrigin.RightBottom: - { - // TODO: Remove dual canvases, had trouble with flipping - using (var rotated = new SKBitmap(bitmap.Height, bitmap.Width)) - { - using (var surface = new SKCanvas(rotated)) - { - surface.Translate(0, rotated.Height); - surface.RotateDegrees(270); - surface.DrawBitmap(bitmap, 0, 0); - } - - var flippedBitmap = new SKBitmap(rotated.Width, rotated.Height); - using (var flippedCanvas = new SKCanvas(flippedBitmap)) - { - flippedCanvas.Translate(flippedBitmap.Width, 0); - flippedCanvas.Scale(-1, 1); - flippedCanvas.DrawBitmap(rotated, 0, 0); - } - - return flippedBitmap; - } - } - - case SKEncodedOrigin.LeftBottom: - { - var rotated = new SKBitmap(bitmap.Height, bitmap.Width); - using (var surface = new SKCanvas(rotated)) - { - surface.Translate(0, rotated.Height); - surface.RotateDegrees(270); - surface.DrawBitmap(bitmap, 0, 0); - } - - return rotated; - } - - default: - return bitmap; - } - } - - public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat) - { - if (string.IsNullOrWhiteSpace(inputPath)) - { - throw new ArgumentNullException(nameof(inputPath)); - } - if (string.IsNullOrWhiteSpace(inputPath)) - { - throw new ArgumentNullException(nameof(outputPath)); - } - - var skiaOutputFormat = GetImageFormat(selectedOutputFormat); - - var hasBackgroundColor = !string.IsNullOrWhiteSpace(options.BackgroundColor); - var hasForegroundColor = !string.IsNullOrWhiteSpace(options.ForegroundLayer); - var blur = options.Blur ?? 0; - var hasIndicator = options.AddPlayedIndicator || options.UnplayedCount.HasValue || !options.PercentPlayed.Equals(0); - - using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation)) - { - if (bitmap == null) - { - throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath)); - } - - //_logger.LogInformation("Color type {0}", bitmap.Info.ColorType); - - var originalImageSize = new ImageDimensions(bitmap.Width, bitmap.Height); - - if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient) - { - // Just spit out the original file if all the options are default - return inputPath; - } - - var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize); - - var width = newImageSize.Width; - var height = newImageSize.Height; - - using (var resizedBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType)) - { - // scale image - bitmap.ScalePixels(resizedBitmap, SKFilterQuality.High); - - // If all we're doing is resizing then we can stop now - if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) - { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); - using (var outputStream = new SKFileWStream(outputPath)) - { - using (var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels())) - { - pixmap.Encode(outputStream, skiaOutputFormat, quality); - return outputPath; - } - } - } - - // create bitmap to use for canvas drawing used to draw into bitmap - using (var saveBitmap = new SKBitmap(width, height))//, bitmap.ColorType, bitmap.AlphaType)) - using (var canvas = new SKCanvas(saveBitmap)) - { - // set background color if present - if (hasBackgroundColor) - { - canvas.Clear(SKColor.Parse(options.BackgroundColor)); - } - - // Add blur if option is present - if (blur > 0) - { - // create image from resized bitmap to apply blur - using (var paint = new SKPaint()) - using (var filter = SKImageFilter.CreateBlur(blur, blur)) - { - paint.ImageFilter = filter; - canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height), paint); - } - } - else - { - // draw resized bitmap onto canvas - canvas.DrawBitmap(resizedBitmap, SKRect.Create(width, height)); - } - - // If foreground layer present then draw - if (hasForegroundColor) - { - if (!double.TryParse(options.ForegroundLayer, out double opacity)) - { - opacity = .4; - } - - canvas.DrawColor(new SKColor(0, 0, 0, (byte)((1 - opacity) * 0xFF)), SKBlendMode.SrcOver); - } - - if (hasIndicator) - { - DrawIndicator(canvas, width, height, options); - } - - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); - using (var outputStream = new SKFileWStream(outputPath)) - { - using (var pixmap = new SKPixmap(new SKImageInfo(width, height), saveBitmap.GetPixels())) - { - pixmap.Encode(outputStream, skiaOutputFormat, quality); - } - } - } - } - } - return outputPath; - } - - public void CreateImageCollage(ImageCollageOptions options) - { - double ratio = options.Width; - ratio /= options.Height; - - if (ratio >= 1.4) - { - new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height); - } - else if (ratio >= .9) - { - new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height); - } - else - { - // @todo create Poster collage capability - new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height); - } - } - - private void DrawIndicator(SKCanvas canvas, int imageWidth, int imageHeight, ImageProcessingOptions options) - { - try - { - var currentImageSize = new ImageDimensions(imageWidth, imageHeight); - - if (options.AddPlayedIndicator) - { - PlayedIndicatorDrawer.DrawPlayedIndicator(canvas, currentImageSize); - } - else if (options.UnplayedCount.HasValue) - { - UnplayedCountIndicator.DrawUnplayedCountIndicator(canvas, currentImageSize, options.UnplayedCount.Value); - } - - if (options.PercentPlayed > 0) - { - PercentPlayedDrawer.Process(canvas, currentImageSize, options.PercentPlayed); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error drawing indicator overlay"); - } - } - - public string Name => "Skia"; - - public bool SupportsImageCollageCreation => true; - - public bool SupportsImageEncoding => true; - } -} diff --git a/Emby.Drawing/StripCollageBuilder.cs b/Emby.Drawing/StripCollageBuilder.cs deleted file mode 100644 index dd342998b..000000000 --- a/Emby.Drawing/StripCollageBuilder.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.IO; -using SkiaSharp; - -namespace Emby.Drawing -{ - public class StripCollageBuilder - { - private readonly IApplicationPaths _appPaths; - private readonly IFileSystem _fileSystem; - - public StripCollageBuilder(IApplicationPaths appPaths, IFileSystem fileSystem) - { - _appPaths = appPaths; - _fileSystem = fileSystem; - } - - public static SKEncodedImageFormat GetEncodedFormat(string outputPath) - { - if (outputPath == null) - { - throw new ArgumentNullException(nameof(outputPath)); - } - - var ext = Path.GetExtension(outputPath).ToLower(); - - if (ext == ".jpg" || ext == ".jpeg") - return SKEncodedImageFormat.Jpeg; - - if (ext == ".webp") - return SKEncodedImageFormat.Webp; - - if (ext == ".gif") - return SKEncodedImageFormat.Gif; - - if (ext == ".bmp") - return SKEncodedImageFormat.Bmp; - - // default to png - return SKEncodedImageFormat.Png; - } - - public void BuildPosterCollage(string[] paths, string outputPath, int width, int height) - { - // @todo - } - - public void BuildSquareCollage(string[] paths, string outputPath, int width, int height) - { - using (var bitmap = BuildSquareCollageBitmap(paths, width, height)) - { - using (var outputStream = new SKFileWStream(outputPath)) - { - using (var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels())) - { - pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90); - } - } - } - } - - public void BuildThumbCollage(string[] paths, string outputPath, int width, int height) - { - using (var bitmap = BuildThumbCollageBitmap(paths, width, height)) - { - using (var outputStream = new SKFileWStream(outputPath)) - { - using (var pixmap = new SKPixmap(new SKImageInfo(width, height), bitmap.GetPixels())) - { - pixmap.Encode(outputStream, GetEncodedFormat(outputPath), 90); - } - } - } - } - - private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height) - { - var bitmap = new SKBitmap(width, height); - - using (var canvas = new SKCanvas(bitmap)) - { - canvas.Clear(SKColors.Black); - - // determine sizes for each image that will composited into the final image - var iSlice = Convert.ToInt32(width * 0.23475); - int iTrans = Convert.ToInt32(height * .25); - int iHeight = Convert.ToInt32(height * .70); - var horizontalImagePadding = Convert.ToInt32(width * 0.0125); - var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); - int imageIndex = 0; - - for (int i = 0; i < 4; i++) - { - - using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) - { - imageIndex = newIndex; - - if (currentBitmap == null) - { - continue; - } - - // resize to the same aspect as the original - int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height); - using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType)) - { - currentBitmap.ScalePixels(resizeBitmap, SKFilterQuality.High); - // crop image - int ix = (int)Math.Abs((iWidth - iSlice) / 2); - using (var image = SKImage.FromBitmap(resizeBitmap)) - using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight))) - { - // draw image onto canvas - canvas.DrawImage(subset ?? image, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing); - - if (subset == null) - { - continue; - } - // create reflection of image below the drawn image - using (var croppedBitmap = SKBitmap.FromImage(subset)) - using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType)) - { - // resize to half height - currentBitmap.ScalePixels(reflectionBitmap, SKFilterQuality.High); - - using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType)) - using (var flippedCanvas = new SKCanvas(flippedBitmap)) - { - // flip image vertically - var matrix = SKMatrix.MakeScale(1, -1); - matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height); - flippedCanvas.SetMatrix(matrix); - flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0); - flippedCanvas.ResetMatrix(); - - // create gradient to make image appear as a reflection - var remainingHeight = height - (iHeight + (2 * verticalSpacing)); - flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight)); - using (var gradient = new SKPaint()) - { - gradient.IsAntialias = true; - gradient.BlendMode = SKBlendMode.SrcOver; - gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp); - flippedCanvas.DrawPaint(gradient); - } - - // finally draw reflection onto canvas - canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing)); - } - } - } - } - } - } - } - - return bitmap; - } - - private SKBitmap GetNextValidImage(string[] paths, int currentIndex, out int newIndex) - { - var imagesTested = new Dictionary<int, int>(); - SKBitmap bitmap = null; - - while (imagesTested.Count < paths.Length) - { - if (currentIndex >= paths.Length) - { - currentIndex = 0; - } - - bitmap = SkiaEncoder.Decode(paths[currentIndex], false, _fileSystem, null, out var origin); - - imagesTested[currentIndex] = 0; - - currentIndex++; - - if (bitmap != null) - { - break; - } - } - - newIndex = currentIndex; - return bitmap; - } - - private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height) - { - var bitmap = new SKBitmap(width, height); - var imageIndex = 0; - var cellWidth = width / 2; - var cellHeight = height / 2; - - using (var canvas = new SKCanvas(bitmap)) - { - for (var x = 0; x < 2; x++) - { - for (var y = 0; y < 2; y++) - { - - using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) - { - imageIndex = newIndex; - - if (currentBitmap == null) - { - continue; - } - - using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType)) - { - // scale image - currentBitmap.ScalePixels(resizedBitmap, SKFilterQuality.High); - - // draw this image into the strip at the next position - var xPos = x * cellWidth; - var yPos = y * cellHeight; - canvas.DrawBitmap(resizedBitmap, xPos, yPos); - } - } - } - } - } - - return bitmap; - } - } -} diff --git a/Emby.Drawing/UnplayedCountIndicator.cs b/Emby.Drawing/UnplayedCountIndicator.cs deleted file mode 100644 index 4d0cc9d40..000000000 --- a/Emby.Drawing/UnplayedCountIndicator.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Globalization; -using MediaBrowser.Model.Drawing; -using SkiaSharp; - -namespace Emby.Drawing -{ - public static class UnplayedCountIndicator - { - private const int OffsetFromTopRightCorner = 38; - - public static void DrawUnplayedCountIndicator(SKCanvas canvas, ImageDimensions imageSize, int count) - { - var x = imageSize.Width - OffsetFromTopRightCorner; - var text = count.ToString(CultureInfo.InvariantCulture); - - using (var paint = new SKPaint()) - { - paint.Color = SKColor.Parse("#CC52B54B"); - paint.Style = SKPaintStyle.Fill; - canvas.DrawCircle((float)x, OffsetFromTopRightCorner, 20, paint); - } - using (var paint = new SKPaint()) - { - paint.Color = new SKColor(255, 255, 255, 255); - paint.Style = SKPaintStyle.Fill; - - paint.TextSize = 24; - paint.IsAntialias = true; - - var y = OffsetFromTopRightCorner + 9; - - if (text.Length == 1) - { - x -= 7; - } - if (text.Length == 2) - { - x -= 13; - } - else if (text.Length >= 3) - { - x -= 15; - y -= 2; - paint.TextSize = 18; - } - - canvas.DrawText(text, (float)x, y, paint); - } - } - } -} |
