add fixes for dng images

pull/1154/head
Luke Pulverenti 7 years ago
parent 2d29d903be
commit 31b01cbb56

@ -1141,17 +1141,17 @@ namespace Emby.Dlna.Didl
int? width = null;
int? height = null;
try
{
var size = _imageProcessor.GetImageSize(imageInfo);
//try
//{
// var size = _imageProcessor.GetImageSize(imageInfo);
width = Convert.ToInt32(size.Width);
height = Convert.ToInt32(size.Height);
}
catch
{
// width = Convert.ToInt32(size.Width);
// height = Convert.ToInt32(size.Height);
//}
//catch
//{
}
//}
var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty)
.TrimStart('.')

@ -148,7 +148,6 @@ namespace Emby.Drawing.ImageMagick
}
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
{
@ -182,7 +181,6 @@ namespace Emby.Drawing.ImageMagick
using (var originalImage = new MagickWand(inputPath))
{
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);

@ -40,7 +40,9 @@ namespace Emby.Drawing.Skia
"jpeg",
"jpg",
"png",
"dng",
"webp",
"gif",
"bmp",
@ -459,7 +461,6 @@ namespace Emby.Drawing.Skia
//_logger.Info("Color type {0}", bitmap.Info.ColorType);
var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient)
{

@ -35,11 +35,6 @@ namespace Emby.Drawing
/// </summary>
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
/// The _cached imaged sizes
/// </summary>
private readonly ConcurrentDictionary<Guid, ImageSize> _cachedImagedSizes;
/// <summary>
/// Gets the list of currently registered image processors
/// Image processors are specialized metadata providers that run after the normal ones
@ -75,34 +70,7 @@ namespace Emby.Drawing
_appPaths = appPaths;
ImageEnhancers = new IImageEnhancer[] { };
_saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
ImageHelper.ImageProcessor = this;
Dictionary<Guid, ImageSize> sizeDictionary;
try
{
sizeDictionary = jsonSerializer.DeserializeFromFile<Dictionary<Guid, ImageSize>>(ImageSizeFile) ??
new Dictionary<Guid, ImageSize>();
}
catch (FileNotFoundException)
{
// No biggie
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
catch (IOException)
{
// No biggie
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
catch (Exception ex)
{
logger.ErrorException("Error parsing image size cache file", ex);
sizeDictionary = new Dictionary<Guid, ImageSize>();
}
_cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
}
public IImageEncoder ImageEncoder
@ -133,7 +101,6 @@ namespace Emby.Drawing
"aiff",
"cr2",
"crw",
"dng",
// Remove until supported
//"nef",
@ -275,15 +242,15 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
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);
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
//ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
//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);
// return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
//}
var newSize = ImageHelper.GetNewImageSize(options, originalImageSize);
var newSize = ImageHelper.GetNewImageSize(options, null);
var quality = options.Quality;
var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
@ -477,98 +444,30 @@ namespace Emby.Drawing
public ImageSize GetImageSize(ItemImageInfo info, bool allowSlowMethods)
{
return GetImageSize(info.Path, info.DateModified, allowSlowMethods);
return GetImageSize(info.Path, allowSlowMethods);
}
public ImageSize GetImageSize(ItemImageInfo info)
{
return GetImageSize(info.Path, info.DateModified, false);
return GetImageSize(info.Path, false);
}
public ImageSize GetImageSize(string path)
{
return GetImageSize(path, _fileSystem.GetLastWriteTimeUtc(path), false);
return GetImageSize(path, false);
}
/// <summary>
/// Gets the size of the image.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="imageDateModified">The image date modified.</param>
/// <param name="allowSlowMethod">if set to <c>true</c> [allow slow method].</param>
/// <returns>ImageSize.</returns>
/// <exception cref="System.ArgumentNullException">path</exception>
private ImageSize GetImageSize(string path, DateTime imageDateModified, bool allowSlowMethod)
private ImageSize GetImageSize(string path, bool allowSlowMethod)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
ImageSize size;
var cacheHash = GetImageSizeKey(path, imageDateModified);
if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
{
size = GetImageSizeInternal(path, allowSlowMethod);
SaveImageSize(size, cacheHash, false);
}
return size;
}
public void SaveImageSize(string path, DateTime imageDateModified, ImageSize size)
{
var cacheHash = GetImageSizeKey(path, imageDateModified);
SaveImageSize(size, cacheHash, true);
}
private void SaveImageSize(ImageSize size, Guid cacheHash, bool checkExists)
{
if (size.Width <= 0 || size.Height <= 0)
{
return;
}
if (checkExists && _cachedImagedSizes.ContainsKey(cacheHash))
{
return;
}
if (checkExists)
{
if (_cachedImagedSizes.TryAdd(cacheHash, size))
{
StartSaveImageSizeTimer();
}
}
else
{
StartSaveImageSizeTimer();
_cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
}
}
private Guid GetImageSizeKey(string path, DateTime imageDateModified)
{
var name = path + "datemodified=" + imageDateModified.Ticks;
return name.GetMD5();
}
public ImageSize? GetSavedImageSize(string path, DateTime imageDateModified)
{
ImageSize size;
var cacheHash = GetImageSizeKey(path, imageDateModified);
if (_cachedImagedSizes.TryGetValue(cacheHash, out size))
{
return size;
}
return null;
return GetImageSizeInternal(path, allowSlowMethod);
}
/// <summary>
@ -619,39 +518,6 @@ namespace Emby.Drawing
}
}
private readonly ITimer _saveImageSizeTimer;
private const int SaveImageSizeTimeout = 5000;
private readonly object _saveImageSizeLock = new object();
private void StartSaveImageSizeTimer()
{
_saveImageSizeTimer.Change(SaveImageSizeTimeout, Timeout.Infinite);
}
private void SaveImageSizeCallback(object state)
{
lock (_saveImageSizeLock)
{
try
{
var path = ImageSizeFile;
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
_jsonSerializer.SerializeToFile(_cachedImagedSizes, path);
}
catch (Exception ex)
{
_logger.ErrorException("Error saving image size file", ex);
}
}
}
private string ImageSizeFile
{
get
{
return Path.Combine(_appPaths.DataPath, "imagesizes.json");
}
}
/// <summary>
/// Gets the image cache tag.
/// </summary>
@ -1016,7 +882,6 @@ namespace Emby.Drawing
disposable.Dispose();
}
_saveImageSizeTimer.Dispose();
GC.SuppressFinalize(this);
}

@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@ -20,134 +21,152 @@ namespace Emby.Photos
{
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private IImageProcessor _imageProcessor;
public PhotoProvider(ILogger logger, IFileSystem fileSystem)
public PhotoProvider(ILogger logger, IFileSystem fileSystem, IImageProcessor imageProcessor)
{
_logger = logger;
_fileSystem = fileSystem;
_imageProcessor = imageProcessor;
}
// These are causing taglib to hang
private string[] _excludeExtensions = new string[] { ".dng" };
public Task<ItemUpdateType> FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
item.SetImagePath(ImageType.Primary, item.Path);
// Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs
try
if (!_excludeExtensions.Contains(Path.GetExtension(item.Path) ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
using (var fileStream = _fileSystem.OpenRead(item.Path))
try
{
using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null)))
using (var fileStream = _fileSystem.OpenRead(item.Path))
{
var image = file as TagLib.Image.File;
var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
if (tag != null)
using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null)))
{
var structure = tag.Structure;
var image = file as TagLib.Image.File;
if (structure != null)
var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag;
if (tag != null)
{
var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
var structure = tag.Structure;
if (exif != null)
if (structure != null)
{
var exifStructure = exif.Structure;
var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry;
if (exifStructure != null)
if (exif != null)
{
var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
var exifStructure = exif.Structure;
if (entry != null)
if (exifStructure != null)
{
double val = entry.Value.Numerator;
val /= entry.Value.Denominator;
item.Aperture = val;
}
entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
if (entry != null)
{
double val = entry.Value.Numerator;
val /= entry.Value.Denominator;
item.ShutterSpeed = val;
var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry;
if (entry != null)
{
double val = entry.Value.Numerator;
val /= entry.Value.Denominator;
item.Aperture = val;
}
entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry;
if (entry != null)
{
double val = entry.Value.Numerator;
val /= entry.Value.Denominator;
item.ShutterSpeed = val;
}
}
}
}
}
}
item.CameraMake = image.ImageTag.Make;
item.CameraModel = image.ImageTag.Model;
if (image != null)
{
item.CameraMake = image.ImageTag.Make;
item.CameraModel = image.ImageTag.Model;
item.Width = image.Properties.PhotoWidth;
item.Height = image.Properties.PhotoHeight;
item.Width = image.Properties.PhotoWidth;
item.Height = image.Properties.PhotoHeight;
var rating = image.ImageTag.Rating;
if (rating.HasValue)
{
item.CommunityRating = rating;
}
else
{
item.CommunityRating = null;
}
var rating = image.ImageTag.Rating;
if (rating.HasValue)
{
item.CommunityRating = rating;
}
else
{
item.CommunityRating = null;
}
item.Overview = image.ImageTag.Comment;
item.Overview = image.ImageTag.Comment;
if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
{
item.Name = image.ImageTag.Title;
}
if (!string.IsNullOrWhiteSpace(image.ImageTag.Title))
{
item.Name = image.ImageTag.Title;
}
var dateTaken = image.ImageTag.DateTime;
if (dateTaken.HasValue)
{
item.DateCreated = dateTaken.Value;
item.PremiereDate = dateTaken.Value;
item.ProductionYear = dateTaken.Value.Year;
}
var dateTaken = image.ImageTag.DateTime;
if (dateTaken.HasValue)
{
item.DateCreated = dateTaken.Value;
item.PremiereDate = dateTaken.Value;
item.ProductionYear = dateTaken.Value.Year;
}
item.Genres = image.ImageTag.Genres.ToList();
item.Tags = image.ImageTag.Keywords;
item.Software = image.ImageTag.Software;
item.Genres = image.ImageTag.Genres.ToList();
item.Tags = image.ImageTag.Keywords;
item.Software = image.ImageTag.Software;
if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
{
item.Orientation = null;
}
else
{
MediaBrowser.Model.Drawing.ImageOrientation orientation;
if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
{
item.Orientation = orientation;
}
}
if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None)
{
item.Orientation = null;
}
else
{
MediaBrowser.Model.Drawing.ImageOrientation orientation;
if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation))
{
item.Orientation = orientation;
}
}
item.ExposureTime = image.ImageTag.ExposureTime;
item.FocalLength = image.ImageTag.FocalLength;
item.ExposureTime = image.ImageTag.ExposureTime;
item.FocalLength = image.ImageTag.FocalLength;
item.Latitude = image.ImageTag.Latitude;
item.Longitude = image.ImageTag.Longitude;
item.Altitude = image.ImageTag.Altitude;
item.Latitude = image.ImageTag.Latitude;
item.Longitude = image.ImageTag.Longitude;
item.Altitude = image.ImageTag.Altitude;
if (image.ImageTag.ISOSpeedRatings.HasValue)
{
item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
}
else
{
item.IsoSpeedRating = null;
if (image.ImageTag.ISOSpeedRatings.HasValue)
{
item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
}
else
{
item.IsoSpeedRating = null;
}
}
}
}
}
catch (Exception e)
{
_logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
}
}
catch (Exception e)
if (!item.Width.HasValue || !item.Height.HasValue)
{
_logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
var size = _imageProcessor.GetImageSize(item.Path);
item.Width = Convert.ToInt32(size.Width);
item.Height = Convert.ToInt32(size.Height);
}
const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;

@ -1642,6 +1642,8 @@ namespace Emby.Server.Implementations.Dto
return null;
}
_logger.Info("Getting image size for item type {0}", item.GetType().Name);
try
{
size = _imageProcessor.GetImageSize(imageInfo);
@ -1673,22 +1675,6 @@ namespace Emby.Server.Implementations.Dto
return null;
}
var photo = item as Photo;
if (photo != null && photo.Orientation.HasValue)
{
switch (photo.Orientation.Value)
{
case ImageOrientation.LeftBottom:
case ImageOrientation.LeftTop:
case ImageOrientation.RightBottom:
case ImageOrientation.RightTop:
var temp = height;
height = width;
width = temp;
break;
}
}
return width / height;
}
}

@ -360,7 +360,7 @@ namespace Emby.Server.Implementations.HttpServer
if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration))
{
AddAgeHeader(responseHeaders, lastDateModified);
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache);
AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified);
@ -370,7 +370,7 @@ namespace Emby.Server.Implementations.HttpServer
}
}
AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache);
AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration);
return null;
}
@ -555,7 +555,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Adds the caching responseHeaders.
/// </summary>
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache)
private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration)
{
// Don't specify both last modified and Etag, unless caching unconditionally. They are redundant
// https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching
@ -565,11 +565,11 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r");
}
if (!noCache && cacheDuration.HasValue)
if (cacheDuration.HasValue)
{
responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
}
else if (!noCache && !string.IsNullOrEmpty(cacheKey))
else if (!string.IsNullOrEmpty(cacheKey))
{
responseHeaders["Cache-Control"] = "public";
}
@ -579,15 +579,15 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
}
AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache);
AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
}
/// <summary>
/// Adds the expires header.
/// </summary>
private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache)
private void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
{
if (!noCache && cacheDuration.HasValue)
if (cacheDuration.HasValue)
{
responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
}

@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Channels
return base.IsVisible(user);
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
value /= 9;
return value;
}
[IgnoreDataMember]
public override bool SupportsInheritedParentImages
{

@ -117,8 +117,6 @@ namespace MediaBrowser.Controller.Drawing
IImageEncoder ImageEncoder { get; set; }
void SaveImageSize(string path, DateTime imageDateModified, ImageSize size);
bool SupportsTransparency(string path);
}
}

@ -21,11 +21,6 @@ namespace MediaBrowser.Controller.Drawing
public static IImageProcessor ImageProcessor { get; set; }
public static void SaveImageSize(string path, DateTime dateModified, ImageSize size)
{
ImageProcessor.SaveImageSize(path, dateModified, size);
}
private static ImageSize GetSizeEstimate(ImageProcessingOptions options)
{
if (options.Width.HasValue && options.Height.HasValue)

@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public override double? GetDefaultPrimaryImageAspectRatio()
{
return null;
return 1;
}
}
}

@ -42,5 +42,13 @@ namespace MediaBrowser.Controller.Entities
return false;
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
value /= 9;
return value;
}
}
}

@ -31,6 +31,14 @@ namespace MediaBrowser.Controller.Entities
PhysicalFolderIds = EmptyGuidArray;
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
value /= 9;
return value;
}
[IgnoreDataMember]
public override bool SupportsPlayedStatus
{

@ -22,6 +22,11 @@ namespace MediaBrowser.Controller.Entities
return GetUserDataKeys()[0];
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
return 1;
}
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself

@ -44,6 +44,14 @@ namespace MediaBrowser.Controller.Entities
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
value /= 9;
return value;
}
/// <summary>
/// Gets or sets the game system.
/// </summary>

@ -25,6 +25,11 @@ namespace MediaBrowser.Controller.Entities
return GetUserDataKeys()[0];
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
return 1;
}
/// <summary>
/// Returns the folder containing the item.
/// If the item is a folder, it returns the folder itself

@ -62,6 +62,35 @@ namespace MediaBrowser.Controller.Entities
return true;
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
if (Width.HasValue && Height.HasValue)
{
double width = Width.Value;
double height = Height.Value;
if (Orientation.HasValue)
{
switch (Orientation.Value)
{
case ImageOrientation.LeftBottom:
case ImageOrientation.LeftTop:
case ImageOrientation.RightBottom:
case ImageOrientation.RightTop:
var temp = height;
height = width;
width = temp;
break;
}
}
width /= Height.Value;
return width;
}
return base.GetDefaultPrimaryImageAspectRatio();
}
public int? Width { get; set; }
public int? Height { get; set; }
public string CameraMake { get; set; }

@ -30,5 +30,10 @@ namespace MediaBrowser.Controller.Entities
return false;
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
return 1;
}
}
}

@ -254,6 +254,11 @@ namespace MediaBrowser.Controller.Entities
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
return 1;
}
/// <summary>
/// Gets the configuration directory path.
/// </summary>

@ -58,6 +58,14 @@ namespace MediaBrowser.Controller.Entities
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
value /= 9;
return value;
}
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count;

@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Entities
}
}
public override double? GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
value /= 3;
return value;
}
[IgnoreDataMember]
public override bool SupportsAncestors
{

Loading…
Cancel
Save