update image encoding

This commit is contained in:
Luke Pulverenti 2017-05-17 14:18:18 -04:00
parent 1be515ddf7
commit 9cd2d793be
9 changed files with 141 additions and 44 deletions

View File

@ -130,7 +130,7 @@ namespace Emby.Drawing.ImageMagick
string.Equals(ext, ".webp", StringComparison.OrdinalIgnoreCase);
}
public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, 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);
@ -144,9 +144,13 @@ namespace Emby.Drawing.ImageMagick
originalImage.CurrentImage.TrimImage(10);
}
if (options.CropWhiteSpace || !originalImageSize.HasValue)
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize))
{
originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
// Just spit out the original file if all the options are default
return inputPath;
}
var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@ -174,10 +178,8 @@ namespace Emby.Drawing.ImageMagick
{
using (var originalImage = new MagickWand(inputPath))
{
if (options.CropWhiteSpace || !originalImageSize.HasValue)
{
originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
}
var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height);
ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize);
var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@ -205,6 +207,8 @@ namespace Emby.Drawing.ImageMagick
}
}
}
return outputPath;
}
private void AddForegroundLayer(MagickWand wand, ImageProcessingOptions options)

View File

@ -191,18 +191,18 @@ namespace Emby.Drawing.Skia
}
private string[] TransparentImageTypes = new string[] { ".png", ".gif", ".webp" };
private SKBitmap Decode(string path)
private SKBitmap Decode(string path, bool forceCleanBitmap = false)
{
var requiresTransparencyHack = TransparentImageTypes.Contains(Path.GetExtension(path) ?? string.Empty);
if (requiresTransparencyHack)
if (requiresTransparencyHack || forceCleanBitmap)
{
using (var stream = new SKFileStream(path))
{
var codec = SKCodec.Create(stream);
// create the bitmap
var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height);
var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
// decode
codec.GetPixels(bitmap.Info, bitmap.GetPixels());
@ -210,7 +210,18 @@ namespace Emby.Drawing.Skia
}
}
return SKBitmap.Decode(path);
var resultBitmap = SKBitmap.Decode(path);
// If we have to resize these they often end up distorted
if (resultBitmap.ColorType == SKColorType.Gray8)
{
using (resultBitmap)
{
return Decode(path, true);
}
}
return resultBitmap;
}
private SKBitmap GetBitmap(string path, bool cropWhitespace)
@ -226,7 +237,7 @@ namespace Emby.Drawing.Skia
return Decode(path);
}
public void EncodeImage(string inputPath, ImageSize? originalImageSize, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
public string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, int quality, ImageProcessingOptions options, ImageFormat selectedOutputFormat)
{
if (string.IsNullOrWhiteSpace(inputPath))
{
@ -246,9 +257,20 @@ namespace Emby.Drawing.Skia
using (var bitmap = GetBitmap(inputPath, options.CropWhiteSpace))
{
if (options.CropWhiteSpace || !originalImageSize.HasValue)
if (bitmap == null)
{
originalImageSize = new ImageSize(bitmap.Width, bitmap.Height);
throw new Exception(string.Format("Skia unable to read image {0}", inputPath));
}
//_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))
{
// Just spit out the original file if all the options are default
return inputPath;
}
var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize);
@ -269,7 +291,7 @@ namespace Emby.Drawing.Skia
using (var outputStream = new SKFileWStream(outputPath))
{
resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
return;
return outputPath;
}
}
@ -326,6 +348,7 @@ namespace Emby.Drawing.Skia
}
}
}
return outputPath;
}
public void CreateImageCollage(ImageCollageOptions options)

View File

@ -75,6 +75,7 @@ namespace Emby.Drawing
ImageEnhancers = new List<IImageEnhancer>();
_saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
ImageHelper.ImageProcessor = this;
Dictionary<Guid, ImageSize> sizeDictionary;
@ -212,19 +213,12 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
ImageSize? originalImageSize = null;
try
ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified);
if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value))
{
originalImageSize = GetImageSize(originalImagePath, dateModified, true);
if (options.HasDefaultOptions(originalImagePath, originalImageSize.Value))
{
// Just spit out the original file if all the options are default
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
}
catch
{
originalImageSize = null;
// 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);
@ -243,7 +237,13 @@ namespace Emby.Drawing
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
_imageEncoder.EncodeImage(originalImagePath, originalImageSize, tmpPath, AutoOrient(options.Item), quality, options, outputFormat);
var resultPath =_imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, AutoOrient(options.Item), quality, options, outputFormat);
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
}
CopyFile(tmpPath, cacheFilePath);
return new Tuple<string, string, DateTime>(tmpPath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(tmpPath));
@ -422,26 +422,72 @@ namespace Emby.Drawing
throw new ArgumentNullException("path");
}
var name = path + "datemodified=" + imageDateModified.Ticks;
ImageSize size;
var cacheHash = name.GetMD5();
var cacheHash = GetImageSizeKey(path, imageDateModified);
if (!_cachedImagedSizes.TryGetValue(cacheHash, out size))
{
size = GetImageSizeInternal(path, allowSlowMethod);
if (size.Width > 0 && size.Height > 0)
{
StartSaveImageSizeTimer();
_cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size);
}
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;
}
/// <summary>
/// Gets the image size internal.
/// </summary>

View File

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

View File

@ -167,10 +167,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var programEntry = programDict[schedule.programID];
var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
data = data.OrderByDescending(GetSizeOrder).ToList();
var allImages = (images[imageIndex].data ?? new List<ScheduleDirect.ImageData>()).OrderByDescending(GetSizeOrder).ToList();
var imagesWithText = allImages.Where(i => string.Equals(i.text, "yes", StringComparison.OrdinalIgnoreCase)).ToList();
programEntry.primaryImage = GetProgramImage(ApiUrl, imagesWithText, "Logo", true, 600) ??
GetProgramImage(ApiUrl, allImages, "Logo", true, 600);
programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600);
//programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
//programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??

View File

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

View File

@ -114,5 +114,7 @@ namespace MediaBrowser.Controller.Drawing
bool SupportsImageCollageCreation { get; }
IImageEncoder ImageEncoder { get; set; }
void SaveImageSize(string path, DateTime imageDateModified, ImageSize size);
}
}

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Entities;
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
@ -18,6 +19,13 @@ namespace MediaBrowser.Controller.Drawing
return GetSizeEstimate(options);
}
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)

View File

@ -968,7 +968,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (bitrate.HasValue && videoStream.BitRate.HasValue)
{
bitrate = Math.Min(bitrate.Value, videoStream.BitRate.Value);
bitrate = GetMinBitrate(bitrate.Value, videoStream.BitRate.Value);
}
}
}
@ -981,13 +981,25 @@ namespace MediaBrowser.Controller.MediaEncoding
// If a max bitrate was requested, don't let the scaled bitrate exceed it
if (request.VideoBitRate.HasValue)
{
bitrate = Math.Min(bitrate.Value, request.VideoBitRate.Value);
bitrate = GetMinBitrate(bitrate.Value, request.VideoBitRate.Value);
}
}
return bitrate;
}
private int GetMinBitrate(int sourceBitrate, int requestedBitrate)
{
if (sourceBitrate <= 2000000)
{
sourceBitrate *= 2;
}
var bitrate = Math.Min(sourceBitrate, requestedBitrate);
return bitrate;
}
public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream)
{
if (request.AudioBitRate.HasValue)