mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
move crop whitespace directly to encode image
This commit is contained in:
parent
4569b6b491
commit
f49d20033d
@ -105,17 +105,6 @@ namespace Emby.Drawing.ImageMagick
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CropWhiteSpace(string inputPath, string outputPath)
|
|
||||||
{
|
|
||||||
CheckDisposed();
|
|
||||||
|
|
||||||
using (var wand = new MagickWand(inputPath))
|
|
||||||
{
|
|
||||||
wand.CurrentImage.TrimImage(10);
|
|
||||||
wand.SaveImage(outputPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSize GetImageSize(string path)
|
public ImageSize GetImageSize(string path)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
@ -150,6 +139,11 @@ namespace Emby.Drawing.ImageMagick
|
|||||||
{
|
{
|
||||||
using (var originalImage = new MagickWand(inputPath))
|
using (var originalImage = new MagickWand(inputPath))
|
||||||
{
|
{
|
||||||
|
if (options.CropWhiteSpace)
|
||||||
|
{
|
||||||
|
originalImage.CurrentImage.TrimImage(10);
|
||||||
|
}
|
||||||
|
|
||||||
ScaleImage(originalImage, width, height, options.Blur ?? 0);
|
ScaleImage(originalImage, width, height, options.Blur ?? 0);
|
||||||
|
|
||||||
if (autoOrient)
|
if (autoOrient)
|
||||||
|
@ -75,27 +75,24 @@ namespace Emby.Drawing.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CropWhiteSpace(string inputPath, string outputPath)
|
private Image GetImage(string path, bool cropWhitespace)
|
||||||
{
|
{
|
||||||
using (var image = (Bitmap)Image.FromFile(inputPath))
|
if (cropWhitespace)
|
||||||
{
|
{
|
||||||
using (var croppedImage = image.CropWhitespace())
|
using (var originalImage = (Bitmap)Image.FromFile(path))
|
||||||
{
|
{
|
||||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
|
return originalImage.CropWhitespace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using (var outputStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false))
|
return Image.FromFile(path);
|
||||||
{
|
|
||||||
croppedImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EncodeImage(string inputPath, string cacheFilePath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
public void EncodeImage(string inputPath, string cacheFilePath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
||||||
{
|
{
|
||||||
var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
|
var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
|
||||||
|
|
||||||
using (var originalImage = Image.FromFile(inputPath))
|
using (var originalImage = GetImage(inputPath, options.CropWhiteSpace))
|
||||||
{
|
{
|
||||||
var newWidth = Convert.ToInt32(width);
|
var newWidth = Convert.ToInt32(width);
|
||||||
var newHeight = Convert.ToInt32(height);
|
var newHeight = Convert.ToInt32(height);
|
||||||
|
@ -66,7 +66,15 @@ namespace Emby.Drawing.Skia
|
|||||||
|
|
||||||
public static string GetVersion()
|
public static string GetVersion()
|
||||||
{
|
{
|
||||||
return typeof(SKCanvas).GetTypeInfo().Assembly.GetName().Version.ToString();
|
using (var bitmap = new SKBitmap())
|
||||||
|
{
|
||||||
|
return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWhiteSpace(SKColor color)
|
||||||
|
{
|
||||||
|
return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat)
|
public static SKEncodedImageFormat GetImageFormat(ImageFormat selectedFormat)
|
||||||
@ -81,22 +89,88 @@ namespace Emby.Drawing.Skia
|
|||||||
return SKEncodedImageFormat.Gif;
|
return SKEncodedImageFormat.Gif;
|
||||||
case ImageFormat.Webp:
|
case ImageFormat.Webp:
|
||||||
return SKEncodedImageFormat.Webp;
|
return SKEncodedImageFormat.Webp;
|
||||||
case ImageFormat.Png:
|
|
||||||
default:
|
default:
|
||||||
return SKEncodedImageFormat.Png;
|
return SKEncodedImageFormat.Png;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CropWhiteSpace(string inputPath, string outputPath)
|
private static bool IsAllWhiteRow(SKBitmap bmp, int row)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < bmp.Width; ++i)
|
||||||
|
{
|
||||||
|
if (!IsWhiteSpace(bmp.GetPixel(i, row)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsAllWhiteColumn(SKBitmap bmp, int col)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < bmp.Height; ++i)
|
||||||
|
{
|
||||||
|
if (!IsWhiteSpace(bmp.GetPixel(col, i)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SKBitmap CropWhiteSpace(SKBitmap bitmap)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
using (var bitmap = SKBitmap.Decode(inputPath))
|
var topmost = 0;
|
||||||
|
for (int row = 0; row < bitmap.Height; ++row)
|
||||||
{
|
{
|
||||||
// @todo
|
if (IsAllWhiteRow(bitmap, row))
|
||||||
|
topmost = row;
|
||||||
|
else break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fileSystem.CopyFile(inputPath, outputPath, true);
|
int bottommost = 0;
|
||||||
|
for (int row = bitmap.Height - 1; row >= 0; --row)
|
||||||
|
{
|
||||||
|
if (IsAllWhiteRow(bitmap, row))
|
||||||
|
bottommost = row;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int leftmost = 0, rightmost = 0;
|
||||||
|
for (int col = 0; col < bitmap.Width; ++col)
|
||||||
|
{
|
||||||
|
if (IsAllWhiteColumn(bitmap, col))
|
||||||
|
leftmost = col;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int col = bitmap.Width - 1; col >= 0; --col)
|
||||||
|
{
|
||||||
|
if (IsAllWhiteColumn(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);
|
||||||
|
//using (var data = subset.Encode(StripCollageBuilder.GetEncodedFormat(outputPath), 90))
|
||||||
|
//{
|
||||||
|
// using (var fileStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||||
|
// {
|
||||||
|
// data.AsStream().CopyTo(fileStream);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageSize GetImageSize(string path)
|
public ImageSize GetImageSize(string path)
|
||||||
@ -118,6 +192,19 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SKBitmap GetBitmap(string path, bool cropWhitespace)
|
||||||
|
{
|
||||||
|
if (cropWhitespace)
|
||||||
|
{
|
||||||
|
using (var bitmap = SKBitmap.Decode(path))
|
||||||
|
{
|
||||||
|
return CropWhiteSpace(bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SKBitmap.Decode(path);
|
||||||
|
}
|
||||||
|
|
||||||
public void EncodeImage(string inputPath, string outputPath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
public void EncodeImage(string inputPath, string outputPath, bool autoOrient, int width, int height, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(inputPath))
|
if (string.IsNullOrWhiteSpace(inputPath))
|
||||||
@ -129,12 +216,34 @@ namespace Emby.Drawing.Skia
|
|||||||
throw new ArgumentNullException("outputPath");
|
throw new ArgumentNullException("outputPath");
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var bitmap = SKBitmap.Decode(inputPath))
|
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))
|
||||||
{
|
{
|
||||||
using (var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType))
|
using (var resizedBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType))
|
||||||
{
|
{
|
||||||
// scale image
|
// scale image
|
||||||
bitmap.Resize(resizedBitmap, SKBitmapResizeMethod.Lanczos3);
|
var resizeMethod = options.Image.Type == MediaBrowser.Model.Entities.ImageType.Logo ||
|
||||||
|
options.Image.Type == MediaBrowser.Model.Entities.ImageType.Art
|
||||||
|
? SKBitmapResizeMethod.Lanczos3
|
||||||
|
: SKBitmapResizeMethod.Lanczos3;
|
||||||
|
|
||||||
|
bitmap.Resize(resizedBitmap, resizeMethod);
|
||||||
|
|
||||||
|
// If all we're doing is resizing then we can stop now
|
||||||
|
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
|
||||||
|
{
|
||||||
|
using (var outputStream = new SKFileWStream(outputPath))
|
||||||
|
{
|
||||||
|
resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create bitmap to use for canvas drawing
|
// create bitmap to use for canvas drawing
|
||||||
using (var saveBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType))
|
using (var saveBitmap = new SKBitmap(width, height, bitmap.ColorType, bitmap.AlphaType))
|
||||||
@ -143,13 +252,13 @@ namespace Emby.Drawing.Skia
|
|||||||
using (var canvas = new SKCanvas(saveBitmap))
|
using (var canvas = new SKCanvas(saveBitmap))
|
||||||
{
|
{
|
||||||
// set background color if present
|
// set background color if present
|
||||||
if (!string.IsNullOrWhiteSpace(options.BackgroundColor))
|
if (hasBackgroundColor)
|
||||||
{
|
{
|
||||||
canvas.Clear(SKColor.Parse(options.BackgroundColor));
|
canvas.Clear(SKColor.Parse(options.BackgroundColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add blur if option is present
|
// Add blur if option is present
|
||||||
if (options.Blur > 0)
|
if (blur > 0)
|
||||||
{
|
{
|
||||||
using (var paint = new SKPaint())
|
using (var paint = new SKPaint())
|
||||||
{
|
{
|
||||||
@ -168,20 +277,23 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If foreground layer present then draw
|
// If foreground layer present then draw
|
||||||
if (!string.IsNullOrWhiteSpace(options.ForegroundLayer))
|
if (hasForegroundColor)
|
||||||
{
|
{
|
||||||
Double opacity;
|
Double opacity;
|
||||||
if (!Double.TryParse(options.ForegroundLayer, out opacity)) opacity = .4;
|
if (!Double.TryParse(options.ForegroundLayer, out opacity)) opacity = .4;
|
||||||
|
|
||||||
var foregroundColor = String.Format("#{0:X2}000000", (Byte)((1-opacity) * 0xFF));
|
var foregroundColor = String.Format("#{0:X2}000000", (Byte)((1 - opacity) * 0xFF));
|
||||||
canvas.DrawColor(SKColor.Parse(foregroundColor), SKBlendMode.SrcOver);
|
canvas.DrawColor(SKColor.Parse(foregroundColor), SKBlendMode.SrcOver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasIndicator)
|
||||||
|
{
|
||||||
DrawIndicator(canvas, width, height, options);
|
DrawIndicator(canvas, width, height, options);
|
||||||
|
}
|
||||||
|
|
||||||
using (var outputStream = new SKFileWStream(outputPath))
|
using (var outputStream = new SKFileWStream(outputPath))
|
||||||
{
|
{
|
||||||
saveBitmap.Encode(outputStream, GetImageFormat(selectedOutputFormat), quality);
|
saveBitmap.Encode(outputStream, skiaOutputFormat, quality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,17 +316,13 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
|
// @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)
|
private void DrawIndicator(SKCanvas canvas, int imageWidth, int imageHeight, ImageProcessingOptions options)
|
||||||
{
|
{
|
||||||
if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentImageSize = new ImageSize(imageWidth, imageHeight);
|
var currentImageSize = new ImageSize(imageWidth, imageHeight);
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
|
||||||
using MediaBrowser.Common.IO;
|
|
||||||
using MediaBrowser.Controller.IO;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace Emby.Drawing.Skia
|
namespace Emby.Drawing.Skia
|
||||||
@ -20,7 +17,7 @@ namespace Emby.Drawing.Skia
|
|||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKEncodedImageFormat GetEncodedFormat(string outputPath)
|
public static SKEncodedImageFormat GetEncodedFormat(string outputPath)
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(outputPath).ToLower();
|
var ext = Path.GetExtension(outputPath).ToLower();
|
||||||
|
|
||||||
@ -42,13 +39,7 @@ namespace Emby.Drawing.Skia
|
|||||||
|
|
||||||
public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
|
public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
|
||||||
{
|
{
|
||||||
using (var bitmap = BuildPosterCollageBitmap(paths, width, height))
|
// @todo
|
||||||
{
|
|
||||||
using (var outputStream = new SKFileWStream(outputPath))
|
|
||||||
{
|
|
||||||
bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
|
public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
|
||||||
@ -73,127 +64,49 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap BuildPosterCollageBitmap(string[] paths, int width, int height)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
/* var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
|
|
||||||
using (var wandImages = new MagickWand(inputPaths.ToArray()))
|
|
||||||
{
|
|
||||||
var wand = new MagickWand(width, height);
|
|
||||||
wand.OpenImage("gradient:#111111-#111111");
|
|
||||||
using (var draw = new DrawingWand())
|
|
||||||
{
|
|
||||||
var iSlice = Convert.ToInt32(width * 0.3);
|
|
||||||
int iTrans = Convert.ToInt32(height * .25);
|
|
||||||
int iHeight = Convert.ToInt32(height * .65);
|
|
||||||
var horizontalImagePadding = Convert.ToInt32(width * 0.0366);
|
|
||||||
|
|
||||||
foreach (var element in wandImages.ImageList)
|
|
||||||
{
|
|
||||||
using (var blackPixelWand = new PixelWand(ColorName.Black))
|
|
||||||
{
|
|
||||||
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
|
|
||||||
element.Gravity = GravityType.CenterGravity;
|
|
||||||
element.BackgroundColor = blackPixelWand;
|
|
||||||
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
|
|
||||||
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
|
|
||||||
element.CropImage(iSlice, iHeight, ix, 0);
|
|
||||||
|
|
||||||
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wandImages.SetFirstIterator();
|
|
||||||
using (var wandList = wandImages.AppendImages())
|
|
||||||
{
|
|
||||||
wandList.CurrentImage.TrimImage(1);
|
|
||||||
using (var mwr = wandList.CloneMagickWand())
|
|
||||||
{
|
|
||||||
using (var blackPixelWand = new PixelWand(ColorName.Black))
|
|
||||||
{
|
|
||||||
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
|
|
||||||
{
|
|
||||||
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
|
|
||||||
mwr.CurrentImage.FlipImage();
|
|
||||||
|
|
||||||
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
|
|
||||||
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
|
|
||||||
|
|
||||||
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
|
|
||||||
{
|
|
||||||
mwg.OpenImage("gradient:black-none");
|
|
||||||
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
|
|
||||||
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
|
|
||||||
|
|
||||||
wandList.AddImage(mwr);
|
|
||||||
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
|
|
||||||
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .05));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return wand;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
|
private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
|
||||||
{
|
{
|
||||||
return null;
|
var bitmap = new SKBitmap(width, height);
|
||||||
/*var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
|
|
||||||
using (var wandImages = new MagickWand(inputPaths.ToArray()))
|
using (var canvas = new SKCanvas(bitmap))
|
||||||
{
|
|
||||||
var wand = new MagickWand(width, height);
|
|
||||||
wand.OpenImage("gradient:#111111-#111111");
|
|
||||||
using (var draw = new DrawingWand())
|
|
||||||
{
|
{
|
||||||
|
canvas.Clear(SKColors.Black);
|
||||||
|
|
||||||
var iSlice = Convert.ToInt32(width * 0.24125);
|
var iSlice = Convert.ToInt32(width * 0.24125);
|
||||||
int iTrans = Convert.ToInt32(height * .25);
|
int iTrans = Convert.ToInt32(height * .25);
|
||||||
int iHeight = Convert.ToInt32(height * .70);
|
int iHeight = Convert.ToInt32(height * .70);
|
||||||
var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
|
var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
|
||||||
|
|
||||||
foreach (var element in wandImages.ImageList)
|
|
||||||
{
|
|
||||||
using (var blackPixelWand = new PixelWand(ColorName.Black))
|
|
||||||
{
|
|
||||||
int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
|
|
||||||
element.Gravity = GravityType.CenterGravity;
|
|
||||||
element.BackgroundColor = blackPixelWand;
|
|
||||||
element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
|
|
||||||
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
|
|
||||||
element.CropImage(iSlice, iHeight, ix, 0);
|
|
||||||
|
|
||||||
element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wandImages.SetFirstIterator();
|
|
||||||
using (var wandList = wandImages.AppendImages())
|
|
||||||
{
|
|
||||||
wandList.CurrentImage.TrimImage(1);
|
|
||||||
using (var mwr = wandList.CloneMagickWand())
|
|
||||||
{
|
|
||||||
using (var blackPixelWand = new PixelWand(ColorName.Black))
|
|
||||||
{
|
|
||||||
using (var greyPixelWand = new PixelWand(ColorName.Grey70))
|
|
||||||
{
|
|
||||||
mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
|
|
||||||
mwr.CurrentImage.FlipImage();
|
|
||||||
|
|
||||||
mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
|
|
||||||
mwr.CurrentImage.ColorizeImage(blackPixelWand, greyPixelWand);
|
|
||||||
|
|
||||||
using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
|
|
||||||
{
|
|
||||||
mwg.OpenImage("gradient:black-none");
|
|
||||||
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
|
var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
|
||||||
mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
|
int imageIndex = 0;
|
||||||
|
|
||||||
wandList.AddImage(mwr);
|
for (int i = 0; i < 4; i++)
|
||||||
int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
|
{
|
||||||
wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .045));
|
using (var currentBitmap = SKBitmap.Decode(paths[imageIndex]))
|
||||||
|
{
|
||||||
|
int iWidth = (int)Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
|
||||||
|
using (var resizeBitmap = new SKBitmap(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
|
||||||
|
{
|
||||||
|
currentBitmap.Resize(resizeBitmap, SKBitmapResizeMethod.Lanczos3);
|
||||||
|
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)))
|
||||||
|
{
|
||||||
|
canvas.DrawImage(subset, (horizontalImagePadding * (i + 1)) + (iSlice * i), 0);
|
||||||
|
|
||||||
|
using (var croppedBitmap = SKBitmap.FromImage(subset))
|
||||||
|
{
|
||||||
|
using (var flipped = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType))
|
||||||
|
{
|
||||||
|
croppedBitmap.Resize(flipped, SKBitmapResizeMethod.Lanczos3);
|
||||||
|
|
||||||
|
using (var gradient = new SKPaint())
|
||||||
|
{
|
||||||
|
var matrix = SKMatrix.MakeScale(1, -1);
|
||||||
|
matrix.SetScaleTranslate(1, -1, 0, flipped.Height);
|
||||||
|
gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, flipped.Height), new[] { new SKColor(0, 0, 0, 0), SKColors.Black }, null, SKShaderTileMode.Clamp, matrix);
|
||||||
|
canvas.DrawBitmap(flipped, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + verticalSpacing, gradient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,8 +114,14 @@ namespace Emby.Drawing.Skia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return wand;
|
imageIndex++;
|
||||||
}*/
|
|
||||||
|
if (imageIndex >= paths.Length)
|
||||||
|
imageIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height)
|
private SKBitmap BuildSquareCollageBitmap(string[] paths, int width, int height)
|
||||||
|
@ -136,14 +136,6 @@ namespace Emby.Drawing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CroppedWhitespaceImageCachePath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.Combine(_appPaths.ImageCachePath, "cropped-images");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddParts(IEnumerable<IImageEnhancer> enhancers)
|
public void AddParts(IEnumerable<IImageEnhancer> enhancers)
|
||||||
{
|
{
|
||||||
ImageEnhancers = enhancers.ToArray();
|
ImageEnhancers = enhancers.ToArray();
|
||||||
@ -186,14 +178,6 @@ namespace Emby.Drawing
|
|||||||
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
|
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), 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)
|
if (options.Enhancers.Count > 0)
|
||||||
{
|
{
|
||||||
var tuple = await GetEnhancedImage(new ItemImageInfo
|
var tuple = await GetEnhancedImage(new ItemImageInfo
|
||||||
@ -400,46 +384,6 @@ namespace Emby.Drawing
|
|||||||
return requestedFormat;
|
return requestedFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Crops whitespace from an image, caches the result, and returns the cached path
|
|
||||||
/// </summary>
|
|
||||||
private async Task<Tuple<string, DateTime>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified)
|
|
||||||
{
|
|
||||||
var name = originalImagePath;
|
|
||||||
name += "datemodified=" + dateModified.Ticks;
|
|
||||||
|
|
||||||
var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath));
|
|
||||||
|
|
||||||
// Check again in case of contention
|
|
||||||
if (_fileSystem.FileExists(croppedImagePath))
|
|
||||||
{
|
|
||||||
return GetResult(croppedImagePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(croppedImagePath));
|
|
||||||
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(croppedImagePath));
|
|
||||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
|
|
||||||
|
|
||||||
_imageEncoder.CropWhiteSpace(originalImagePath, tmpPath);
|
|
||||||
CopyFile(tmpPath, croppedImagePath);
|
|
||||||
return GetResult(tmpPath);
|
|
||||||
}
|
|
||||||
catch (NotImplementedException)
|
|
||||||
{
|
|
||||||
// No need to spam the log with an error message
|
|
||||||
return new Tuple<string, DateTime>(originalImagePath, dateModified);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// We have to have a catch-all here because some of the .net image methods throw a plain old Exception
|
|
||||||
_logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
|
|
||||||
|
|
||||||
return new Tuple<string, DateTime>(originalImagePath, dateModified);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Tuple<string, DateTime> GetResult(string path)
|
private Tuple<string, DateTime> GetResult(string path)
|
||||||
{
|
{
|
||||||
return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
|
return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
|
||||||
|
@ -16,12 +16,6 @@ namespace MediaBrowser.Controller.Drawing
|
|||||||
/// <value>The supported output formats.</value>
|
/// <value>The supported output formats.</value>
|
||||||
ImageFormat[] SupportedOutputFormats { get; }
|
ImageFormat[] SupportedOutputFormats { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Crops the white space.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputPath">The input path.</param>
|
|
||||||
/// <param name="outputPath">The output path.</param>
|
|
||||||
void CropWhiteSpace(string inputPath, string outputPath);
|
|
||||||
/// <summary>
|
|
||||||
/// Encodes the image.
|
/// Encodes the image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputPath">The input path.</param>
|
/// <param name="inputPath">The input path.</param>
|
||||||
|
@ -86,6 +86,7 @@ namespace MediaBrowser.Controller.Drawing
|
|||||||
PercentPlayed.Equals(0) &&
|
PercentPlayed.Equals(0) &&
|
||||||
!UnplayedCount.HasValue &&
|
!UnplayedCount.HasValue &&
|
||||||
!Blur.HasValue &&
|
!Blur.HasValue &&
|
||||||
|
!CropWhiteSpace &&
|
||||||
string.IsNullOrEmpty(BackgroundColor) &&
|
string.IsNullOrEmpty(BackgroundColor) &&
|
||||||
string.IsNullOrEmpty(ForegroundLayer);
|
string.IsNullOrEmpty(ForegroundLayer);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace MediaBrowser.Server.Startup.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new SkiaEncoder(logManager.GetLogger("ImageMagick"), appPaths, httpClient, fileSystem);
|
//return new SkiaEncoder(logManager.GetLogger("ImageMagick"), appPaths, httpClient, fileSystem);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user