jellyfin/Emby.Drawing.Skia/StripCollageBuilder.cs

192 lines
8.9 KiB
C#
Raw Normal View History

2017-05-09 19:53:46 +00:00
using SkiaSharp;
using MediaBrowser.Common.Configuration;
using System;
using System.IO;
using MediaBrowser.Model.IO;
namespace Emby.Drawing.Skia
{
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)
2017-05-09 19:53:46 +00:00
{
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
2017-05-09 19:53:46 +00:00
}
public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
{
using (var bitmap = BuildSquareCollageBitmap(paths, width, height))
{
using (var outputStream = new SKFileWStream(outputPath))
{
bitmap.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))
{
bitmap.Encode(outputStream, GetEncodedFormat(outputPath), 90);
}
}
}
private SKBitmap BuildThumbCollageBitmap(string[] paths, int width, int height)
2017-05-09 19:53:46 +00:00
{
var bitmap = new SKBitmap(width, height);
2017-05-09 19:53:46 +00:00
using (var canvas = new SKCanvas(bitmap))
{
canvas.Clear(SKColors.Black);
2017-05-09 19:53:46 +00:00
2017-05-12 04:57:09 +00:00
// 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;
2017-05-09 19:53:46 +00:00
for (int i = 0; i < 4; i++)
2017-05-09 19:53:46 +00:00
{
2017-07-02 01:22:23 +00:00
SKCodecOrigin origin;
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, out origin))
2017-05-09 19:53:46 +00:00
{
2017-05-12 04:57:09 +00:00
// 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))
2017-05-09 19:53:46 +00:00
{
currentBitmap.Resize(resizeBitmap, SKBitmapResizeMethod.Lanczos3);
2017-05-12 04:57:09 +00:00
// determine how much to crop
2017-05-09 19:53:46 +00:00
int ix = (int)Math.Abs((iWidth - iSlice) / 2);
using (var image = SKImage.FromBitmap(resizeBitmap))
2017-05-09 19:53:46 +00:00
{
2017-05-12 04:57:09 +00:00
// crop image
using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight)))
2017-05-09 19:53:46 +00:00
{
2017-05-12 04:57:09 +00:00
// draw image onto canvas
canvas.DrawImage(subset, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing);
2017-05-09 19:53:46 +00:00
using (var croppedBitmap = SKBitmap.FromImage(subset))
2017-05-09 19:53:46 +00:00
{
2017-05-12 04:57:09 +00:00
// create reflection of image below the drawn image
2017-05-11 14:53:31 +00:00
using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType))
{
2017-05-12 04:57:09 +00:00
// resize to half height
2017-05-11 14:53:31 +00:00
croppedBitmap.Resize(reflectionBitmap, SKBitmapResizeMethod.Lanczos3);
2017-05-12 04:57:09 +00:00
using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType))
{
2017-05-11 14:53:31 +00:00
using (var flippedCanvas = new SKCanvas(flippedBitmap))
{
2017-05-12 04:57:09 +00:00
// flip image vertically
2017-05-11 14:53:31 +00:00
var matrix = SKMatrix.MakeScale(1, -1);
matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height);
flippedCanvas.SetMatrix(matrix);
flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0);
flippedCanvas.ResetMatrix();
2017-05-12 04:57:09 +00:00
// create gradient to make image appear as a reflection
var remainingHeight = height - (iHeight + (2 * verticalSpacing));
flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight));
2017-05-11 14:53:31 +00:00
using (var gradient = new SKPaint())
{
gradient.IsAntialias = true;
2017-05-12 04:57:09 +00:00
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);
2017-05-11 14:53:31 +00:00
flippedCanvas.DrawPaint(gradient);
}
2017-05-12 04:57:09 +00:00
// finally draw reflection onto canvas
canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing));
2017-05-11 14:53:31 +00:00
}
}
}
2017-05-09 19:53:46 +00:00
}
}
}
}
}
imageIndex++;
if (imageIndex >= paths.Length)
imageIndex = 0;
2017-05-09 19:53:46 +00:00
}
}
2017-05-09 19:53:46 +00:00
return bitmap;
2017-05-09 19:53:46 +00:00
}
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++)
{
2017-07-02 01:22:23 +00:00
SKCodecOrigin origin;
using (var currentBitmap = SkiaEncoder.Decode(paths[imageIndex], false, out origin))
2017-05-09 19:53:46 +00:00
{
using (var resizedBitmap = new SKBitmap(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType))
{
// scale image
currentBitmap.Resize(resizedBitmap, SKBitmapResizeMethod.Lanczos3);
2017-05-09 19:53:46 +00:00
// draw this image into the strip at the next position
var xPos = x * cellWidth;
var yPos = y * cellHeight;
canvas.DrawBitmap(resizedBitmap, xPos, yPos);
}
}
imageIndex++;
if (imageIndex >= paths.Length)
imageIndex = 0;
}
}
}
return bitmap;
}
}
}