using System.Collections.Generic;
public const int MAX_IMAGE_WIDTH = 1920;
public const int VARIATIONS_INCREMENT = 75;
public const int MAX_VARIANT_RETURNS = 8;
public const string OPTIMIZE_MIME = "jpg";
public class ImageMetaData {
public int Width {get;set;}
public int Height {get;set;}
public string MimeType {get;set;}
public class VariationInfo {
public int Width {get;set;}
public int Height {get;set;}
public string MimeType {get;set;}
public static void Main(string[] args){
var smallerMetadata = new ImageMetaData {
var largerMetadata = new ImageMetaData {
TryOut.GetVariants(largerMetadata, 868, 1299, new VariationInfo[] {});
TryOut.GetVariants(smallerMetadata, 343, 2000, new VariationInfo[] {});
TryOut.GetVariants(largerMetadata, 50, 1500, new VariationInfo[] {});
public static class TryOut {
public static IEnumerable<VariationInfo> GetVariants(ImageMetaData metaData, int requestedMinWidth, int requestedMaxWidth, IEnumerable<VariationInfo> existingVariants, bool optimize = true)
return Enumerable.Empty<VariationInfo>();
var mime = optimize ? Constants.OPTIMIZE_MIME : metaData.MimeType;
if( metaData?.Width == null) {
return Enumerable.Empty<VariationInfo>();
maxImageSize = Math.Min(Constants.MAX_IMAGE_WIDTH, metaData.Width);
var neededSizes = GetNeededVariantSizes( requestedMinWidth, requestedMaxWidth, maxImageSize );
Console.WriteLine("max image size : " + maxImageSize);
Console.WriteLine("min requested : " + requestedMinWidth);
Console.WriteLine("max requested : " + requestedMaxWidth);
Console.WriteLine(string.Join(", ", neededSizes.Select( size => size.ToString())));
Console.WriteLine(string.Join(", ", neededSizes.Select( size => size.ToString())));
return neededSizes.Select(size =>
existingVariants.FirstOrDefault( variant => variant.Width == size && variant.MimeType == mime )
?? new VariationInfo { Width = size, MimeType = mime }
public static IEnumerable<int> GetNeededVariantSizes( int neededMin, int neededMax, int maxSize = Constants.MAX_IMAGE_WIDTH, List<int> allVariantSizes = null )
if( allVariantSizes == null )
allVariantSizes = GenerateAllVariantSizes( maxSize )
var allLength = allVariantSizes.Count();
var closestMinIndex = allVariantSizes.ClosestLargerIndex( neededMin, allLength );
var closestMaxIndex = allVariantSizes.ClosestLargerIndex( neededMax, allLength );
var numNeeded = closestMaxIndex - closestMinIndex;
if( numNeeded > Constants.MAX_VARIANT_RETURNS )
step = Math.Max((double)step, numNeeded / ((double)Constants.MAX_VARIANT_RETURNS - 1));
var aproxIndex = (double)closestMinIndex;
var index = (int)aproxIndex;
var stepSize = allVariantSizes[index];
} while ( index <= closestMaxIndex);
public static IEnumerable<int> GenerateAllVariantSizes( int fromMax, int toMin = 0 ) {
size -= Constants.VARIATIONS_INCREMENT;
public static int ClosestLargerIndex(this List<int> ascOrderedList, int number, int? listLength = null) {
var index = ascOrderedList.BinarySearch(number);
index = Math.Min(index, ((listLength ?? ascOrderedList.Count()) - 1));