fix photo orientation

pull/1154/head
Luke Pulverenti 7 years ago
parent e2ec83cbaa
commit d76bcd8473

@ -130,7 +130,7 @@ namespace Emby.Drawing.ImageMagick
string.Equals(ext, ".webp", StringComparison.OrdinalIgnoreCase);
}
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{
// Even if the caller specified 100, don't use it because it takes forever
quality = Math.Min(quality, 99);

@ -184,7 +184,7 @@ namespace Emby.Drawing.Skia
}
private string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
private SKBitmap Decode(string path, bool forceCleanBitmap = false)
private SKBitmap Decode(string path, bool forceCleanBitmap, out SKCodecOrigin origin)
{
var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
@ -199,6 +199,8 @@ namespace Emby.Drawing.Skia
// decode
codec.GetPixels(bitmap.Info, bitmap.GetPixels());
origin = codec.Origin;
return bitmap;
}
}
@ -207,7 +209,7 @@ namespace Emby.Drawing.Skia
if (resultBitmap == null)
{
return Decode(path, true);
return Decode(path, true, out origin);
}
// If we have to resize these they often end up distorted
@ -215,27 +217,128 @@ namespace Emby.Drawing.Skia
{
using (resultBitmap)
{
return Decode(path, true);
return Decode(path, true, out origin);
}
}
origin = SKCodecOrigin.TopLeft;
return resultBitmap;
}
private SKBitmap GetBitmap(string path, bool cropWhitespace)
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool forceAnalyzeBitmap, out SKCodecOrigin origin)
{
if (cropWhitespace)
{
using (var bitmap = Decode(path))
using (var bitmap = Decode(path, forceAnalyzeBitmap, out origin))
{
return CropWhiteSpace(bitmap);
}
}
return Decode(path);
return Decode(path, forceAnalyzeBitmap, out origin);
}
private SKBitmap GetBitmap(string path, bool cropWhitespace, bool autoOrient, ImageOrientation? orientation)
{
SKCodecOrigin origin;
if (autoOrient)
{
var bitmap = GetBitmap(path, cropWhitespace, true, out origin);
if (origin != SKCodecOrigin.TopLeft)
{
using (bitmap)
{
return RotateAndFlip(bitmap, origin);
}
}
return bitmap;
}
return GetBitmap(path, cropWhitespace, false, out origin);
}
private SKBitmap RotateAndFlip(SKBitmap original, SKCodecOrigin origin)
{
// these are the origins that represent a 90 degree turn in some fashion
var differentOrientations = new SKCodecOrigin[]
{
SKCodecOrigin.LeftBottom,
SKCodecOrigin.LeftTop,
SKCodecOrigin.RightBottom,
SKCodecOrigin.RightTop
};
// check if we need to turn the image
bool isDifferentOrientation = differentOrientations.Any(o => o == origin);
// define new width/height
var width = isDifferentOrientation ? original.Height : original.Width;
var height = isDifferentOrientation ? original.Width : original.Height;
var bitmap = new SKBitmap(width, height, true);
// todo: the stuff in this switch statement should be rewritten to use pointers
switch (origin)
{
case SKCodecOrigin.LeftBottom:
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;
case SKCodecOrigin.RightTop:
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;
case SKCodecOrigin.RightBottom:
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));
break;
case SKCodecOrigin.LeftTop:
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;
case SKCodecOrigin.BottomLeft:
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:
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;
case SKCodecOrigin.TopRight:
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 bitmap;
}
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{
if (string.IsNullOrWhiteSpace(inputPath))
{
@ -253,7 +356,7 @@ 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))
using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace, autoOrient, orientation))
{
if (bitmap == null)
{
@ -265,7 +368,7 @@ namespace Emby.Drawing.Skia
var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient)
{
// Just spit out the original file if all the options are default
return inputPath;

@ -217,14 +217,23 @@ namespace Emby.Drawing
dateModified = tuple.Item2;
}
if (options.HasDefaultOptions(originalImagePath))
var photo = item as Photo;
var autoOrient = false;
ImageOrientation? orientation = null;
if (photo != null && photo.Orientation.HasValue && photo.Orientation.Value != ImageOrientation.TopLeft)
{
autoOrient = true;
orientation = photo.Orientation;
}
if (options.HasDefaultOptions(originalImagePath) && !autoOrient)
{
// Just spit out the original file if all the options are default
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value))
if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value) && !autoOrient)
{
// Just spit out the original file if all the options are default
_logger.Info("Returning original image {0}", originalImagePath);
@ -243,7 +252,6 @@ namespace Emby.Drawing
if (!_fileSystem.FileExists(cacheFilePath))
{
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
@ -252,13 +260,14 @@ namespace Emby.Drawing
item = _libraryManager().GetItemById(options.ItemId);
}
var resultPath =_imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, AutoOrient(item), quality, options, outputFormat);
var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat);
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
CopyFile(tmpPath, cacheFilePath);
return new Tuple<string, string, DateTime>(tmpPath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(tmpPath));
@ -288,17 +297,6 @@ namespace Emby.Drawing
}
}
private bool AutoOrient(IHasImages item)
{
var photo = item as Photo;
if (photo != null && photo.Orientation.HasValue)
{
return true;
}
return false;
}
//private static int[][] OPERATIONS = new int[][] {
// TopLeft
//new int[] { 0, NONE},

@ -32,7 +32,7 @@ namespace Emby.Drawing
throw new NotImplementedException();
}
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{
throw new NotImplementedException();
}

@ -19,7 +19,7 @@ namespace MediaBrowser.Controller.Drawing
/// <summary>
/// Encodes the image.
/// </summary>
string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
/// <summary>
/// Creates the image collage.

Loading…
Cancel
Save