public static KernelMap <T> GetOrAdd(int isize, int osize, InterpolationSettings interpolator, int ichannels, double offset) { if (!(interpolator.WeightingFunction is IUniquelyIdentifiable iwf)) { return(KernelMap <T> .create(isize, osize, interpolator, ichannels, offset)); } var hasher = Blake2b.CreateIncrementalHasher(Unsafe.SizeOf <Guid>()); hasher.Update(isize); hasher.Update(osize); hasher.Update(ichannels); hasher.Update(offset); hasher.Update(iwf.UniqueID); hasher.Update(interpolator.Blur); Span <byte> hash = stackalloc byte[Unsafe.SizeOf <Guid>()]; hasher.Finish(hash); var key = MemoryMarshal.Read <Guid>(hash); if (lruCache.TryGet(key, out var map)) { return(map); } return(lruCache.GetOrAdd(key, KernelMap <T> .create(isize, osize, interpolator, ichannels, offset))); }
unsafe public static KernelMap MakeScaleMap(uint isize, uint osize, InterpolationSettings interpolator) { double offs = interpolator.WeightingFunction.Support <= 0.1 ? 0.5 : 0.0; double blur = interpolator.Blur; if (interpolator.WeightingFunction.Support <= 0.5) { blur = 1d; } double wfactor = Math.Min((double)osize / isize, 1d); double wdist = Math.Min(interpolator.WeightingFunction.Support / wfactor * blur, isize / 2d); int wsize = (int)Math.Ceiling(wdist * 2d); var map = new KernelMap((int)isize, (int)osize, wsize); fixed(int *mapstart = map.Map) { double *wp = stackalloc double[wsize]; int * mp = mapstart; double inc = (double)isize / osize; double midpoint = ((double)isize - osize) / (osize * 2d) + offs; for (int i = 0; i < osize; i++) { int end = (int)(midpoint + wdist); int start = end - wsize + 1; *mp++ = start; double weightsum = 0d; for (int j = 0; j < wsize; j++) { double weight = interpolator.WeightingFunction.GetValue(Math.Abs(((double)start + j - midpoint) * wfactor / blur)); weightsum += weight; wp[j] = weight; } for (int j = 0; j < wsize; j++) { *mp++ = MathUtil.ScaleToInt32(wp[j] / weightsum); } midpoint += inc; } } return(map.clamp()); }
unsafe public static KernelMap <T> CreateResample(int isize, int osize, InterpolationSettings interpolator, int ichannels, bool subsampleOffset, bool vectored) { double offs = interpolator.WeightingFunction.Support < 0.1 ? 0.5 : subsampleOffset ? 0.25 : 0.0; double ratio = Math.Min((double)osize / isize, 1d); double cscale = ratio / interpolator.Blur; double support = Math.Min(interpolator.WeightingFunction.Support / cscale, isize / 2d); int channels = vectored ? ichannels : 1; int ksize = (int)Math.Ceiling(support * 2d); int kpad = vectored ? getPadding(isize, ksize, channels) : 0; var map = new KernelMap <T>(osize, ksize + kpad, channels); fixed(byte *mstart = map.Map) { int * mp = (int *)mstart; double inc = (double)isize / osize; double spoint = ((double)isize - osize) / (osize * 2d) + offs; Span <float> kernel = stackalloc float[ksize]; for (int i = 0; i < osize; i++) { int start = (int)(spoint + support) - ksize + 1; fillWeights(kernel, interpolator.WeightingFunction, start, spoint, cscale); spoint += inc; *mp++ = start; for (int j = 0; j < kernel.Length; j++) { var w = convertWeight(kernel[j]); for (int k = 0; k < channels; k++) { Unsafe.Write(mp++, w); } } mp += kpad * channels; } } return(map.clamp(isize)); }
unsafe public static KernelMap <T> MakeScaleMap(uint isize, uint osize, int colorChannels, bool alphaChannel, bool vectored, InterpolationSettings interpolator) { var ainterpolator = interpolator.WeightingFunction.Support > 1d ? InterpolationSettings.Hermite : interpolator; double offs = interpolator.WeightingFunction.Support < 0.1 ? 0.5 : 0.0; double wfactor = Math.Min((double)osize / isize, 1d); double wscale = wfactor / interpolator.Blur; double awscale = wfactor / ainterpolator.Blur; double wdist = Math.Min(interpolator.WeightingFunction.Support / wscale, isize / 2d); int channels = colorChannels + (alphaChannel ? 1 : 0); int wsize = (int)Math.Ceiling(wdist * 2d); if (vectored && wsize * channels % (Vector <T> .Count * channels) >= (Vector <T> .Count * channels) / 2) { wsize = (wsize * channels + (Vector <T> .Count * channels - 1) & ~(Vector <T> .Count * channels - 1)) / channels; } wsize = Math.Min(wsize, (int)isize); var map = new KernelMap <T>((int)isize, (int)osize, wsize, channels); fixed(byte *mapstart = map.Map.Array) { double *wp = stackalloc double[wsize]; double *awp = stackalloc double[wsize]; int * mp = (int *)mapstart; double inc = (double)isize / osize; double spoint = ((double)isize - osize) / (osize * 2d) + offs; for (int i = 0; i < osize; i++) { int start = (int)(spoint + wdist) - wsize + 1; *mp++ = start; double weightsum = 0d; for (int j = 0; j < wsize; j++) { double weight = interpolator.WeightingFunction.GetValue(Math.Abs(((double)start + j - spoint) * wscale)); weightsum += weight; wp[j] = weight; } weightsum = 1d / weightsum; for (int j = 0; j < wsize; j++) { wp[j] *= weightsum; } if (alphaChannel) { double aweightsum = 0d; for (int j = 0; j < wsize; j++) { double weight = ainterpolator.WeightingFunction.GetValue(Math.Abs(((double)start + j - spoint) * awscale)); aweightsum += weight; awp[j] = weight; } aweightsum = 1d / aweightsum; for (int j = 0; j < wsize; j++) { awp[j] *= aweightsum; } } for (int j = 0; j < wsize; j++) { T w = convertWeight(wp[j]); for (int k = 0; k < colorChannels; k++) { Unsafe.Write(mp++, w); } if (alphaChannel) { Unsafe.Write(mp++, convertWeight(awp[j])); } } spoint += inc; } } return(map.clamp()); }
unsafe public static KernelMap <T> MakeScaleMap(uint isize, uint osize, int colorChannels, bool alphaChannel, bool vectored, InterpolationSettings interpolator) { double offs = interpolator.WeightingFunction.Support < 0.1 ? 0.5 : 0.0; double ratio = Math.Min((double)osize / isize, 1d); double cscale = ratio / interpolator.Blur; double support = Math.Min(interpolator.WeightingFunction.Support / cscale, isize / 2d); int channels = colorChannels + (alphaChannel ? 1 : 0); int ksize = (int)Math.Ceiling(support * 2d); int kpad = vectored ? getKernelPadding((int)isize, ksize, channels) : 0; var map = new KernelMap <T>((int)isize, (int)osize, ksize + kpad, channels); fixed(byte *mstart = &map.Map.Array[0]) { int * mp = (int *)mstart; double *kp = stackalloc double[ksize]; double inc = (double)isize / osize; double spoint = ((double)isize - osize) / (osize * 2d) + offs; for (int i = 0; i < osize; i++) { int start = (int)(spoint + support) - ksize + 1; fillKernelWeights(interpolator.WeightingFunction, kp, ksize, start, spoint, cscale); spoint += inc; *mp++ = start; for (int j = 0; j < ksize; j++) { var w = convertWeight(kp[j]); for (int k = 0; k < channels; k++) { Unsafe.Write(mp++, w); } } mp += kpad * channels; } } return(map.clamp()); }