|
@@ -31,7 +31,7 @@ namespace MediaBrowser.Controller.Drawing
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <value>The image enhancers.</value>
|
|
/// <value>The image enhancers.</value>
|
|
public IEnumerable<IImageEnhancer> ImageEnhancers { get; set; }
|
|
public IEnumerable<IImageEnhancer> ImageEnhancers { get; set; }
|
|
-
|
|
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Gets the image size cache.
|
|
/// Gets the image size cache.
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -106,9 +106,10 @@ namespace MediaBrowser.Controller.Drawing
|
|
/// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
|
|
/// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
|
|
/// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
|
|
/// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
|
|
/// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
|
|
/// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
|
|
|
|
+ /// <param name="enhancers">The enhancers.</param>
|
|
/// <returns>Task.</returns>
|
|
/// <returns>Task.</returns>
|
|
/// <exception cref="System.ArgumentNullException">entity</exception>
|
|
/// <exception cref="System.ArgumentNullException">entity</exception>
|
|
- public async Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, bool cropWhitespace, DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality)
|
|
|
|
|
|
+ public async Task ProcessImage(BaseItem entity, ImageType imageType, int imageIndex, bool cropWhitespace, DateTime dateModified, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality, List<IImageEnhancer> enhancers)
|
|
{
|
|
{
|
|
if (entity == null)
|
|
if (entity == null)
|
|
{
|
|
{
|
|
@@ -127,28 +128,13 @@ namespace MediaBrowser.Controller.Drawing
|
|
originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
|
|
originalImagePath = await GetCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
|
|
- var supportedEnhancers = ImageEnhancers.Where(i =>
|
|
|
|
- {
|
|
|
|
- try
|
|
|
|
- {
|
|
|
|
- return i.Supports(entity, imageType);
|
|
|
|
- }
|
|
|
|
- catch (Exception ex)
|
|
|
|
- {
|
|
|
|
- _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
|
|
|
|
-
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }).ToList();
|
|
|
|
-
|
|
|
|
// No enhancement - don't cache
|
|
// No enhancement - don't cache
|
|
- if (supportedEnhancers.Count > 0)
|
|
|
|
|
|
+ if (enhancers.Count > 0)
|
|
{
|
|
{
|
|
try
|
|
try
|
|
{
|
|
{
|
|
// Enhance if we have enhancers
|
|
// Enhance if we have enhancers
|
|
- var ehnancedImagePath = await GetEnhancedImage(originalImagePath, dateModified, entity, imageType, imageIndex, supportedEnhancers).ConfigureAwait(false);
|
|
|
|
|
|
+ var ehnancedImagePath = await GetEnhancedImage(originalImagePath, dateModified, entity, imageType, imageIndex, enhancers).ConfigureAwait(false);
|
|
|
|
|
|
// If the path changed update dateModified
|
|
// If the path changed update dateModified
|
|
if (!ehnancedImagePath.Equals(originalImagePath, StringComparison.OrdinalIgnoreCase))
|
|
if (!ehnancedImagePath.Equals(originalImagePath, StringComparison.OrdinalIgnoreCase))
|
|
@@ -175,6 +161,19 @@ namespace MediaBrowser.Controller.Drawing
|
|
|
|
|
|
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality.Value, dateModified);
|
|
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality.Value, dateModified);
|
|
|
|
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
|
|
|
|
+ {
|
|
|
|
+ await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch (IOException)
|
|
|
|
+ {
|
|
|
|
+ // Cache file doesn't exist or is currently being written ro
|
|
|
|
+ }
|
|
|
|
+
|
|
var semaphore = GetLock(cacheFilePath);
|
|
var semaphore = GetLock(cacheFilePath);
|
|
|
|
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
@@ -262,6 +261,13 @@ namespace MediaBrowser.Controller.Drawing
|
|
/// <param name="bytes">The bytes.</param>
|
|
/// <param name="bytes">The bytes.</param>
|
|
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
|
|
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
|
|
{
|
|
{
|
|
|
|
+ var parentPath = Path.GetDirectoryName(cacheFilePath);
|
|
|
|
+
|
|
|
|
+ if (!Directory.Exists(parentPath))
|
|
|
|
+ {
|
|
|
|
+ Directory.CreateDirectory(parentPath);
|
|
|
|
+ }
|
|
|
|
+
|
|
// Save to the cache location
|
|
// Save to the cache location
|
|
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
|
|
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
|
|
{
|
|
{
|
|
@@ -323,7 +329,7 @@ namespace MediaBrowser.Controller.Drawing
|
|
}
|
|
}
|
|
|
|
|
|
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
|
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
|
-
|
|
|
|
|
|
+
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Gets the size of the image.
|
|
/// Gets the size of the image.
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -335,25 +341,53 @@ namespace MediaBrowser.Controller.Drawing
|
|
// Now check the file system cache
|
|
// Now check the file system cache
|
|
var fullCachePath = ImageSizeCache.GetResourcePath(keyName, ".txt");
|
|
var fullCachePath = ImageSizeCache.GetResourcePath(keyName, ".txt");
|
|
|
|
|
|
|
|
+ try
|
|
|
|
+ {
|
|
|
|
+ var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
|
|
|
+
|
|
|
|
+ return new ImageSize { Width = result[0], Height = result[1] };
|
|
|
|
+ }
|
|
|
|
+ catch (IOException)
|
|
|
|
+ {
|
|
|
|
+ // Cache file doesn't exist or is currently being written to
|
|
|
|
+ }
|
|
|
|
+
|
|
var semaphore = GetLock(fullCachePath);
|
|
var semaphore = GetLock(fullCachePath);
|
|
|
|
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
|
|
|
|
try
|
|
try
|
|
{
|
|
{
|
|
- try
|
|
|
|
- {
|
|
|
|
- var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
|
|
|
|
|
+ var result = File.ReadAllText(fullCachePath).Split('|').Select(i => double.Parse(i, UsCulture)).ToArray();
|
|
|
|
|
|
- return new ImageSize { Width = result[0], Height = result[1] };
|
|
|
|
- }
|
|
|
|
- catch (FileNotFoundException)
|
|
|
|
- {
|
|
|
|
- // Cache file doesn't exist no biggie
|
|
|
|
- }
|
|
|
|
|
|
+ return new ImageSize { Width = result[0], Height = result[1] };
|
|
|
|
+ }
|
|
|
|
+ catch (FileNotFoundException)
|
|
|
|
+ {
|
|
|
|
+ // Cache file doesn't exist no biggie
|
|
|
|
+ }
|
|
|
|
+ catch (DirectoryNotFoundException)
|
|
|
|
+ {
|
|
|
|
+ // Cache file doesn't exist no biggie
|
|
|
|
+ }
|
|
|
|
+ catch
|
|
|
|
+ {
|
|
|
|
+ semaphore.Release();
|
|
|
|
+
|
|
|
|
+ throw;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ try
|
|
|
|
+ {
|
|
var size = await ImageHeader.GetDimensions(imagePath, _logger).ConfigureAwait(false);
|
|
var size = await ImageHeader.GetDimensions(imagePath, _logger).ConfigureAwait(false);
|
|
|
|
|
|
|
|
+ var parentPath = Path.GetDirectoryName(fullCachePath);
|
|
|
|
+
|
|
|
|
+ if (!Directory.Exists(parentPath))
|
|
|
|
+ {
|
|
|
|
+ Directory.CreateDirectory(parentPath);
|
|
|
|
+ }
|
|
|
|
+
|
|
// Update the file system cache
|
|
// Update the file system cache
|
|
File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture));
|
|
File.WriteAllText(fullCachePath, size.Width.ToString(UsCulture) + @"|" + size.Height.ToString(UsCulture));
|
|
|
|
|
|
@@ -490,12 +524,12 @@ namespace MediaBrowser.Controller.Drawing
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
|
|
|
|
// Check again in case of contention
|
|
// Check again in case of contention
|
|
- if (CroppedImageCache.ContainsFilePath(croppedImagePath))
|
|
|
|
|
|
+ if (File.Exists(croppedImagePath))
|
|
{
|
|
{
|
|
semaphore.Release();
|
|
semaphore.Release();
|
|
return croppedImagePath;
|
|
return croppedImagePath;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
try
|
|
try
|
|
{
|
|
{
|
|
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
|
|
using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
|
|
@@ -511,6 +545,13 @@ namespace MediaBrowser.Controller.Drawing
|
|
|
|
|
|
using (var croppedImage = originalImage.CropWhitespace())
|
|
using (var croppedImage = originalImage.CropWhitespace())
|
|
{
|
|
{
|
|
|
|
+ var parentPath = Path.GetDirectoryName(croppedImagePath);
|
|
|
|
+
|
|
|
|
+ if (!Directory.Exists(parentPath))
|
|
|
|
+ {
|
|
|
|
+ Directory.CreateDirectory(parentPath);
|
|
|
|
+ }
|
|
|
|
+
|
|
using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
{
|
|
{
|
|
croppedImage.Save(outputFormat, outputStream, 100);
|
|
croppedImage.Save(outputFormat, outputStream, 100);
|
|
@@ -568,7 +609,7 @@ namespace MediaBrowser.Controller.Drawing
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
await semaphore.WaitAsync().ConfigureAwait(false);
|
|
|
|
|
|
// Check again in case of contention
|
|
// Check again in case of contention
|
|
- if (EnhancedImageCache.ContainsFilePath(enhancedImagePath))
|
|
|
|
|
|
+ if (File.Exists(enhancedImagePath))
|
|
{
|
|
{
|
|
semaphore.Release();
|
|
semaphore.Release();
|
|
return enhancedImagePath;
|
|
return enhancedImagePath;
|
|
@@ -588,6 +629,13 @@ namespace MediaBrowser.Controller.Drawing
|
|
//Pass the image through registered enhancers
|
|
//Pass the image through registered enhancers
|
|
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false))
|
|
using (var newImage = await ExecuteImageEnhancers(supportedEnhancers, originalImage, item, imageType, imageIndex).ConfigureAwait(false))
|
|
{
|
|
{
|
|
|
|
+ var parentDirectory = Path.GetDirectoryName(enhancedImagePath);
|
|
|
|
+
|
|
|
|
+ if (!Directory.Exists(parentDirectory))
|
|
|
|
+ {
|
|
|
|
+ Directory.CreateDirectory(parentDirectory);
|
|
|
|
+ }
|
|
|
|
+
|
|
//And then save it in the cache
|
|
//And then save it in the cache
|
|
using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
{
|
|
{
|