/// <summary> /// Computes the weights to apply at each pixel when resizing. /// </summary> /// <param name="sampler">The <see cref="IResampler"/></param> /// <param name="destinationSize">The destination size</param> /// <param name="sourceSize">The source size</param> /// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param> /// <returns>The <see cref="ResizeKernelMap"/></returns> public static ResizeKernelMap Calculate( IResampler sampler, int destinationSize, int sourceSize, MemoryAllocator memoryAllocator) { double ratio = (double)sourceSize / destinationSize; double scale = ratio; if (scale < 1) { scale = 1; } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); // 'ratio' is a rational number. // Multiplying it by LCM(sourceSize, destSize)/sourceSize will result in a whole number "again". // This value is determining the length of the periods in repeating kernel map rows. int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; // the center position at i == 0: double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; // The number of rows building a "stairway" at the top and the bottom of the kernel map // corresponding to the corners of the image. // If we do not normalize the kernel values, these rows also fit the periodic logic, // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); // If firstNonNegativeLeftVal was an integral value, we need firstNonNegativeLeftVal+1 // instead of Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } // If 'cornerInterval' is too big compared to 'period', we can't apply the periodic optimization. // If we don't have at least 2 periods, we go with the basic implementation: bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = hasAtLeast2Periods ? new PeriodicKernelMap( memoryAllocator, sampler, sourceSize, destinationSize, ratio, scale, radius, period, cornerInterval) : new ResizeKernelMap( memoryAllocator, sampler, sourceSize, destinationSize, destinationSize, ratio, scale, radius); result.Initialize(); return(result); }
public void LeastCommonMultiple(int a, int b, int expected) { int actual = ImageMaths.LeastCommonMultiple(a, b); Assert.Equal(expected, actual); }