diff options
Diffstat (limited to 'Emby.Drawing.Skia/SkiaEncoder.cs')
| -rw-r--r-- | Emby.Drawing.Skia/SkiaEncoder.cs | 244 |
1 files changed, 165 insertions, 79 deletions
diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs index 071c40c29..0eaa96609 100644 --- a/Emby.Drawing.Skia/SkiaEncoder.cs +++ b/Emby.Drawing.Skia/SkiaEncoder.cs @@ -74,8 +74,9 @@ namespace Emby.Drawing.Skia return typeof(SKBitmap).GetTypeInfo().Assembly.GetName().Version.ToString(); } - private static bool IsWhiteSpace(SKColor color) + private static bool IsTransparent(SKColor color) { + return (color.Red == 255 && color.Green == 255 && color.Blue == 255) || color.Alpha == 0; } @@ -96,11 +97,11 @@ namespace Emby.Drawing.Skia } } - private static bool IsAllWhiteRow(SKBitmap bmp, int row) + private static bool IsTransparentRow(SKBitmap bmp, int row) { for (var i = 0; i < bmp.Width; ++i) { - if (!IsWhiteSpace(bmp.GetPixel(i, row))) + if (!IsTransparent(bmp.GetPixel(i, row))) { return false; } @@ -108,11 +109,11 @@ namespace Emby.Drawing.Skia return true; } - private static bool IsAllWhiteColumn(SKBitmap bmp, int col) + private static bool IsTransparentColumn(SKBitmap bmp, int col) { for (var i = 0; i < bmp.Height; ++i) { - if (!IsWhiteSpace(bmp.GetPixel(col, i))) + if (!IsTransparent(bmp.GetPixel(col, i))) { return false; } @@ -125,7 +126,7 @@ namespace Emby.Drawing.Skia var topmost = 0; for (int row = 0; row < bitmap.Height; ++row) { - if (IsAllWhiteRow(bitmap, row)) + if (IsTransparentRow(bitmap, row)) topmost = row + 1; else break; } @@ -133,7 +134,7 @@ namespace Emby.Drawing.Skia int bottommost = bitmap.Height; for (int row = bitmap.Height - 1; row >= 0; --row) { - if (IsAllWhiteRow(bitmap, row)) + if (IsTransparentRow(bitmap, row)) bottommost = row; else break; } @@ -141,7 +142,7 @@ namespace Emby.Drawing.Skia int leftmost = 0, rightmost = bitmap.Width; for (int col = 0; col < bitmap.Width; ++col) { - if (IsAllWhiteColumn(bitmap, col)) + if (IsTransparentColumn(bitmap, col)) leftmost = col + 1; else break; @@ -149,7 +150,7 @@ namespace Emby.Drawing.Skia for (int col = bitmap.Width - 1; col >= 0; --col) { - if (IsAllWhiteColumn(bitmap, col)) + if (IsTransparentColumn(bitmap, col)) rightmost = col; else break; @@ -192,16 +193,31 @@ namespace Emby.Drawing.Skia { using (var stream = new SKFileStream(path)) { - var codec = SKCodec.Create(stream); + using (var codec = SKCodec.Create(stream)) + { + if (codec == null) + { + origin = SKCodecOrigin.TopLeft; + return null; + } - // create the bitmap - var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); - // decode - codec.GetPixels(bitmap.Info, bitmap.GetPixels()); + // create the bitmap + var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); - origin = codec.Origin; + if (bitmap != null) + { + // decode + codec.GetPixels(bitmap.Info, bitmap.GetPixels()); - return bitmap; + origin = codec.Origin; + } + else + { + origin = SKCodecOrigin.TopLeft; + } + + return bitmap; + } } } @@ -238,7 +254,7 @@ namespace Emby.Drawing.Skia return Decode(path, forceAnalyzeBitmap, out origin); } - private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation) + private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient) { SKCodecOrigin origin; @@ -246,11 +262,14 @@ namespace Emby.Drawing.Skia { var bitmap = GetBitmap(path, cropWhitespace, true, out origin); - if (origin != SKCodecOrigin.TopLeft) + if (bitmap != null) { - using (bitmap) + if (origin != SKCodecOrigin.TopLeft) { - return RotateAndFlip(bitmap, origin); + using (bitmap) + { + return OrientImage(bitmap, origin); + } } } @@ -260,82 +279,153 @@ namespace Emby.Drawing.Skia return GetBitmap(path, cropWhitespace, false, out origin); } - private SKBitmap RotateAndFlip(SKBitmap original, SKCodecOrigin origin) + private SKBitmap OrientImage(SKBitmap bitmap, SKCodecOrigin origin) { - // these are the origins that represent a 90 degree turn in some fashion - var differentOrientations = new SKCodecOrigin[] + //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) { - SKCodecOrigin.LeftBottom, - SKCodecOrigin.LeftTop, - SKCodecOrigin.RightBottom, - SKCodecOrigin.RightTop - }; - // check if we need to turn the image - bool isDifferentOrientation = differentOrientations.Any(o => o == origin); + case SKCodecOrigin.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; + } - // define new width/height - var width = isDifferentOrientation ? original.Height : original.Width; - var height = isDifferentOrientation ? original.Width : original.Height; + case SKCodecOrigin.BottomRight: + { + var rotated = new SKBitmap(bitmap.Width, bitmap.Height); + using (var surface = new SKCanvas(rotated)) + { + float px = bitmap.Width; + px /= 2; - var bitmap = new SKBitmap(width, height, true); + float py = bitmap.Height; + py /= 2; - // todo: the stuff in this switch statement should be rewritten to use pointers - switch (origin) - { - case SKCodecOrigin.LeftBottom: + surface.RotateDegrees(180, px, py); + surface.DrawBitmap(bitmap, 0, 0); + } - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(y, original.Width - 1 - x, original.GetPixel(x, y)); - break; + return rotated; + } - case SKCodecOrigin.RightTop: + case SKCodecOrigin.BottomLeft: + { + var rotated = new SKBitmap(bitmap.Width, bitmap.Height); + using (var surface = new SKCanvas(rotated)) + { + float px = bitmap.Width; + px /= 2; - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(original.Height - 1 - y, x, original.GetPixel(x, y)); - break; + float py = bitmap.Height; + py /= 2; - case SKCodecOrigin.RightBottom: + surface.Translate(rotated.Width, 0); + surface.Scale(-1, 1); - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(original.Height - 1 - y, original.Width - 1 - x, original.GetPixel(x, y)); + surface.RotateDegrees(180, px, py); + surface.DrawBitmap(bitmap, 0, 0); + } - break; + return rotated; + } case SKCodecOrigin.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); - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(y, x, original.GetPixel(x, y)); - break; + surface.RotateDegrees(90); - case SKCodecOrigin.BottomLeft: + surface.DrawBitmap(bitmap, 0, 0); - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(x, original.Height - 1 - y, original.GetPixel(x, y)); - break; + } - case SKCodecOrigin.BottomRight: + 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); + } - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(original.Width - 1 - x, original.Height - 1 - y, original.GetPixel(x, y)); - break; + return flippedBitmap; + } + } - case SKCodecOrigin.TopRight: + case SKCodecOrigin.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); + } - for (var x = 0; x < original.Width; x++) - for (var y = 0; y < original.Height; y++) - bitmap.SetPixel(original.Width - 1 - x, y, original.GetPixel(x, y)); - break; + return rotated; + } - } + case SKCodecOrigin.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 bitmap; + return flippedBitmap; + } + } + + case SKCodecOrigin.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) @@ -356,11 +446,11 @@ namespace Emby.Drawing.Skia 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)) + using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient)) { if (bitmap == null) { - throw new Exception(string.Format("Skia unable to read image {0}", inputPath)); + throw new ArgumentOutOfRangeException(string.Format("Skia unable to read image {0}", inputPath)); } //_logger.Info("Color type {0}", bitmap.Info.ColorType); @@ -504,10 +594,6 @@ namespace Emby.Drawing.Skia get { return "Skia"; } } - public void Dispose() - { - } - public bool SupportsImageCollageCreation { get { return true; } |
