diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index 2119e8e2c1..1da5677939 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -490,6 +490,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Supply the cache tag from the item object to receive strong caching headers.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. The of the returned image.
@@ -528,7 +530,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -549,6 +553,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -570,6 +576,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Supply the cache tag from the item object to receive strong caching headers.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. The of the returned image.
@@ -607,7 +615,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? unplayedCount,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -628,6 +638,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -648,6 +660,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Supply the cache tag from the item object to receive strong caching headers.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Determines the output format of the image - original,gif,jpg,png.
@@ -686,7 +700,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute, Required] int imageIndex)
+ [FromRoute, Required] int imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetItemById(itemId);
if (item == null)
@@ -707,6 +723,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -731,6 +749,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -765,7 +785,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromRoute, Required] int imageIndex)
+ [FromRoute, Required] int imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetArtist(name);
if (item == null)
@@ -786,6 +808,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -810,6 +834,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -844,7 +870,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetGenre(name);
if (item == null)
@@ -865,6 +893,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -890,6 +920,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -923,7 +955,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? addPlayedIndicator,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetGenre(name);
if (item == null)
@@ -944,6 +978,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -968,6 +1004,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1002,7 +1040,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetMusicGenre(name);
if (item == null)
@@ -1023,6 +1063,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1048,6 +1090,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1081,7 +1125,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? addPlayedIndicator,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetMusicGenre(name);
if (item == null)
@@ -1102,6 +1148,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1126,6 +1174,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1160,7 +1210,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetPerson(name);
if (item == null)
@@ -1181,6 +1233,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1206,6 +1260,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1239,7 +1295,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? addPlayedIndicator,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetPerson(name);
if (item == null)
@@ -1260,6 +1318,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1284,6 +1344,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1318,7 +1380,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetStudio(name);
if (item == null)
@@ -1339,6 +1403,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1364,6 +1430,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1397,7 +1465,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? addPlayedIndicator,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var item = _libraryManager.GetStudio(name);
if (item == null)
@@ -1418,6 +1488,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1442,6 +1514,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1476,7 +1550,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
[FromQuery] string? foregroundLayer,
- [FromQuery] int? imageIndex)
+ [FromQuery] int? imageIndex,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var user = _userManager.GetUserById(userId);
if (user?.ProfileImage == null)
@@ -1514,6 +1590,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1540,6 +1618,8 @@ namespace Jellyfin.Api.Controllers
/// The fixed image width to return.
/// The fixed image height to return.
/// Optional. Quality setting, from 0-100. Defaults to 90 and should suffice in most cases.
+ /// Width of box to fill.
+ /// Height of box to fill.
/// Optional. Specify if whitespace should be cropped out of the image. True/False. If unspecified, whitespace will be cropped from logos and clear art.
/// Optional. Add a played indicator.
/// Optional. Blur image.
@@ -1573,7 +1653,9 @@ namespace Jellyfin.Api.Controllers
[FromQuery] bool? addPlayedIndicator,
[FromQuery] int? blur,
[FromQuery] string? backgroundColor,
- [FromQuery] string? foregroundLayer)
+ [FromQuery] string? foregroundLayer,
+ [FromQuery] int? fillHeight,
+ [FromQuery] int? fillWidth)
{
var user = _userManager.GetUserById(userId);
if (user?.ProfileImage == null)
@@ -1611,6 +1693,8 @@ namespace Jellyfin.Api.Controllers
width,
height,
quality,
+ fillHeight,
+ fillWidth,
cropWhitespace,
addPlayedIndicator,
blur,
@@ -1695,6 +1779,8 @@ namespace Jellyfin.Api.Controllers
int? width,
int? height,
int? quality,
+ int? fillHeight,
+ int? fillWidth,
bool? cropWhitespace, // TODO: Remove
bool? addPlayedIndicator,
int? blur,
@@ -1773,7 +1859,9 @@ namespace Jellyfin.Api.Controllers
outputFormats,
cacheDuration,
responseHeaders,
- isHeadRequest).ConfigureAwait(false);
+ isHeadRequest,
+ fillHeight,
+ fillWidth).ConfigureAwait(false);
}
private ImageFormat[] GetOutputFormats(ImageFormat? format)
@@ -1871,7 +1959,9 @@ namespace Jellyfin.Api.Controllers
IReadOnlyCollection supportedFormats,
TimeSpan? cacheDuration,
IDictionary headers,
- bool isHeadRequest)
+ bool isHeadRequest,
+ int? fillHeight,
+ int? fillWidth)
{
if (!imageInfo.IsLocalFile && item != null)
{
@@ -1887,6 +1977,8 @@ namespace Jellyfin.Api.Controllers
ItemId = itemId,
MaxHeight = maxHeight,
MaxWidth = maxWidth,
+ FillHeight = fillHeight,
+ FillWidth = fillWidth,
Quality = quality ?? 100,
Width = width,
AddPlayedIndicator = addPlayedIndicator ?? false,
diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs
index 87c28d5773..7407261196 100644
--- a/MediaBrowser.Controller/Drawing/ImageHelper.cs
+++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Drawing
{
// Determine the output size based on incoming parameters
var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
-
+ newSize = DrawingUtils.ResizeFill(newSize, options.FillWidth, options.FillHeight);
return newSize;
}
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
index 22de9a43e8..4befb29c42 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs
@@ -32,6 +32,10 @@ namespace MediaBrowser.Controller.Drawing
public int? MaxHeight { get; set; }
+ public int? FillWidth { get; set; }
+
+ public int? FillHeight { get; set; }
+
public int Quality { get; set; }
public IReadOnlyCollection SupportedOutputFormats { get; set; }
diff --git a/MediaBrowser.Model/Drawing/DrawingUtils.cs b/MediaBrowser.Model/Drawing/DrawingUtils.cs
index 1512c52337..8fb9bdc0ac 100644
--- a/MediaBrowser.Model/Drawing/DrawingUtils.cs
+++ b/MediaBrowser.Model/Drawing/DrawingUtils.cs
@@ -57,6 +57,54 @@ namespace MediaBrowser.Model.Drawing
return new ImageDimensions(newWidth, newHeight);
}
+ ///
+ /// Resizes to fill box.
+ /// Returns original size if both width and height are null or zero.
+ ///
+ /// The original size object.
+ /// A new fixed width, if desired.
+ /// A new fixed height, if desired.
+ /// A new size object or size.
+ public static ImageDimensions ResizeFill(
+ ImageDimensions size,
+ int? fillWidth,
+ int? fillHeight)
+ {
+ // Return original size if input is invalid.
+ if (
+ (fillWidth == null && fillHeight == null)
+ || (fillWidth == 0 || fillHeight == 0))
+ {
+ return size;
+ }
+
+ if (fillWidth == null || fillWidth == 0)
+ {
+ fillWidth = 1;
+ }
+
+ if (fillHeight == null || fillHeight == 0)
+ {
+ fillHeight = 1;
+ }
+
+ double widthRatio = (double)size.Width / (double)fillWidth;
+ double heightRatio = (double)size.Height / (double)fillHeight!;
+ // min()
+ double scaleRatio = widthRatio > heightRatio ? heightRatio : widthRatio;
+
+ // Clamp to current size.
+ if (scaleRatio < 1)
+ {
+ return size;
+ }
+
+ int newWidth = Convert.ToInt32(Math.Ceiling((double)size.Width / scaleRatio));
+ int newHeight = Convert.ToInt32(Math.Ceiling((double)size.Height / scaleRatio));
+
+ return new ImageDimensions(newWidth, newHeight);
+ }
+
///
/// Gets the new width.
///