diff --git a/.editorconfig b/.editorconfig index 7009128..631e54d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,13 +11,26 @@ indent_style = space indent_size = 2 [*.cs] -file_header_template = Copyright © Clinton Ingram and Contributors. Licensed under the MIT License. +file_header_template = Copyright © Clinton Ingram and Contributors\r\nSPDX-License-Identifier: MIT + +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = true +csharp_style_var_elsewhere = true + +csharp_prefer_braces = false +csharp_indent_labels = one_less_than_current +csharp_new_line_before_open_brace = types, methods, properties, events, accessors, control_blocks, local_functions + +csharp_style_expression_bodied_local_functions = true +csharp_style_expression_bodied_constructors = true +csharp_style_expression_bodied_operators = true +csharp_style_expression_bodied_methods = true csharp_style_prefer_tuple_swap = true:silent csharp_style_prefer_range_operator = true:silent csharp_style_prefer_utf8_string_literals = true:silent csharp_style_deconstructed_variable_declaration = true:silent -csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_namespace_declarations = file_scoped:warning dotnet_diagnostic.CA1031.severity = silent dotnet_diagnostic.CA1308.severity = silent @@ -26,9 +39,15 @@ dotnet_diagnostic.CA2255.severity = silent dotnet_diagnostic.CS3016.severity = silent ; https://github.com/dotnet/runtime/issues/40461 dotnet_diagnostic.CS1573.severity = silent ; https://github.com/dotnet/roslyn/issues/40325 +dotnet_separate_import_directive_groups = true; dotnet_style_namespace_match_folder = false -dotnet_naming_rule.private_non_field_members_should_be_camel_case.severity = suggestion +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent + +dotnet_naming_rule.private_non_field_members_should_be_camel_case.severity = warning dotnet_naming_rule.private_non_field_members_should_be_camel_case.symbols = private_non_field_members dotnet_naming_rule.private_non_field_members_should_be_camel_case.style = camel_case diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a0b53a1..a3b0005 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,4 @@ # switch to file-scoped namespaces 9bd127e20ffe2923033ea5cd09495977bb893a1a +# add SPDX headers +45fec581eae583daeb0264e504e8dbc025851f3f diff --git a/readme.md b/readme.md index de764fb..0a64ded 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -[![NuGet](https://buildstats.info/nuget/PhotoSauce.MagicScaler)](https://www.nuget.org/packages/PhotoSauce.MagicScaler/) [![Build Status](https://dev.azure.com/saucecontrol/PhotoSauce/_apis/build/status/saucecontrol.PhotoSauce?branchName=master)](https://dev.azure.com/saucecontrol/PhotoSauce/_build/latest?definitionId=1&branchName=master) [![CI NuGet](https://img.shields.io/badge/nuget-CI%20builds-4da2db?logo=azure-devops)](https://dev.azure.com/saucecontrol/PhotoSauce/_packaging?_a=feed&feed=photosauce_ci) +[![NuGet](https://img.shields.io/nuget/dt/PhotoSauce.MagicScaler?logo=nuget&label=NuGet)](https://www.nuget.org/packages/PhotoSauce.MagicScaler/) [![Build Status](https://dev.azure.com/saucecontrol/PhotoSauce/_apis/build/status/saucecontrol.PhotoSauce?branchName=master)](https://dev.azure.com/saucecontrol/PhotoSauce/_build/latest?definitionId=1&branchName=master) [![CI NuGet](https://img.shields.io/badge/NuGet-CI%20builds-4da2db?logo=azure-devops)](https://dev.azure.com/saucecontrol/PhotoSauce/_packaging?_a=feed&feed=photosauce_ci) PhotoSauce.MagicScaler ====================== diff --git a/src/MagicScaler/Color/ColorParser.cs b/src/MagicScaler/Color/ColorParser.cs index 4cac7bb..441e195 100644 --- a/src/MagicScaler/Color/ColorParser.cs +++ b/src/MagicScaler/Color/ColorParser.cs @@ -32,7 +32,7 @@ public static bool TryParse(string value, out Color color) if (value[0] == '#') value = value[1..]; - if (value.Length != 6 && value.Length != 8) + if (value.Length is not (6 or 8)) return false; if (!uint.TryParse(value, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out uint ival)) diff --git a/src/MagicScaler/Color/ColorProfile.cs b/src/MagicScaler/Color/ColorProfile.cs index 0a1497f..e645f2e 100644 --- a/src/MagicScaler/Color/ColorProfile.cs +++ b/src/MagicScaler/Color/ColorProfile.cs @@ -138,7 +138,7 @@ private static ProfileCurve curveFromPower(double gamma) // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf const double limit = 32; - var igt = new float[LookupTables.InverseGammaLength]; + float[] igt = new float[LookupTables.InverseGammaLength]; for (int i = 0; i < igt.Length; i++) { double val = (double)i / LookupTables.InverseGammaScale; @@ -147,7 +147,7 @@ private static ProfileCurve curveFromPower(double gamma) gamma = 1d / gamma; - var gt = new float[LookupTables.GammaLengthFloat]; + float[] gt = new float[LookupTables.GammaLengthFloat]; for (int i = 0; i < gt.Length; i++) { double val = (double)i / LookupTables.GammaScaleFloat; @@ -169,7 +169,7 @@ private static ProfileCurve curveFromPoints(ReadOnlySpan points, bool in curve[i] = (double)points[i] / ushort.MaxValue; double cscal = curve.Length - 1; - var igt = new float[LookupTables.InverseGammaLength]; + float[] igt = new float[LookupTables.InverseGammaLength]; for (int i = 0; i <= LookupTables.InverseGammaScale; i++) { double val = (double)i / LookupTables.InverseGammaScale; @@ -185,7 +185,7 @@ private static ProfileCurve curveFromPoints(ReadOnlySpan points, bool in if (inverse) curve.Reverse(); - var gt = new float[LookupTables.GammaLengthFloat]; + float[] gt = new float[LookupTables.GammaLengthFloat]; for (int i = 0; i <= LookupTables.GammaScaleFloat; i++) { double val = (double)i / LookupTables.GammaScaleFloat; @@ -234,7 +234,7 @@ private static ProfileCurve curveFromParameters(double a, double b, double c, do c.IsRoughlyEqualTo(1.000/12.92) ) return sRGB.Curve; - var igt = new float[LookupTables.InverseGammaLength]; + float[] igt = new float[LookupTables.InverseGammaLength]; for (int i = 0; i < igt.Length; i++) { double val = (double)i / LookupTables.InverseGammaScale; @@ -248,7 +248,7 @@ private static ProfileCurve curveFromParameters(double a, double b, double c, do g = 1d / g; - var gt = new float[LookupTables.GammaLengthFloat]; + float[] gt = new float[LookupTables.GammaLengthFloat]; for (int i = 0; i < gt.Length; i++) { double val = (double)i / LookupTables.GammaScaleFloat; @@ -507,7 +507,7 @@ public static ColorProfile Parse(ReadOnlySpan prof) _ => ProfileColorSpace.Other }; - if (pcsColorSpace is not ProfileColorSpace.Xyz || (dataColorSpace is not (ProfileColorSpace.Rgb or ProfileColorSpace.Grey))) + if (pcsColorSpace is not ProfileColorSpace.Xyz || dataColorSpace is not (ProfileColorSpace.Rgb or ProfileColorSpace.Grey)) return new ColorProfile(prof.ToArray(), dataColorSpace, pcsColorSpace, ColorProfileType.Unknown); uint tagCount = ReadUInt32BigEndian(prof[headerLength..]); @@ -730,20 +730,13 @@ protected ColorProfile(byte[] bytes, ProfileColorSpace dataSpace, ProfileColorSp public record struct ProfileCurve(float[] Gamma, float[] InverseGamma); } -internal class CurveProfile : ColorProfile +internal class CurveProfile(byte[] bytes, byte[]? compact, ColorProfile.ProfileCurve? curve, ColorProfile.ProfileColorSpace dataSpace, ColorProfile.ProfileColorSpace pcsSpace) : ColorProfile(bytes, dataSpace, pcsSpace, ColorProfileType.Curve) { private readonly ConcurrentDictionary<(Type tfrom, Type tto, Type tenc, Type trng, CurveProfile profile), IConverter> converterCache = new(); - public bool IsLinear { get; } - public ProfileCurve Curve { get; } - public byte[]? CompactProfile { get; } - - public CurveProfile(byte[] bytes, byte[]? compact, ProfileCurve? curve, ProfileColorSpace dataSpace, ProfileColorSpace pcsSpace) : base(bytes, dataSpace, pcsSpace, ColorProfileType.Curve) - { - IsLinear = curve is null; - Curve = curve ?? new ProfileCurve(null!, LookupTables.Alpha); - CompactProfile = compact; - } + public bool IsLinear { get; } = curve is null; + public ProfileCurve Curve { get; } = curve ?? new ProfileCurve(null!, LookupTables.Alpha); + public byte[]? CompactProfile { get; } = compact; private IConverter addConverter(in (Type, Type, Type, Type, CurveProfile) cacheKey) => converterCache.GetOrAdd(cacheKey, static key => { if (key.profile.IsLinear) @@ -760,12 +753,12 @@ private IConverter addConverter(in (Type, Type, Type, Type, CurveProfile) cacheK if (key.tenc == typeof(EncodingType.Linear)) { - var gt = key.profile.Curve.Gamma; + float[] gt = key.profile.Curve.Gamma; if (key.tfrom == typeof(float) && key.tto == typeof(float)) return new ConverterFromLinear(gt); gt = key.trng == typeof(EncodingRange.Video) ? LookupTables.MakeVideoGamma(gt) : gt; - var bgt = gt == LookupTables.SrgbGamma ? LookupTables.SrgbGammaUQ15 : LookupTables.MakeUQ15Gamma(gt); + byte[] bgt = gt == LookupTables.SrgbGamma ? LookupTables.SrgbGammaUQ15 : LookupTables.MakeUQ15Gamma(gt); if (key.tfrom == typeof(ushort) && key.tto == typeof(byte)) return new ConverterFromLinear(bgt); if (key.tfrom == typeof(float) && key.tto == typeof(byte)) @@ -774,7 +767,7 @@ private IConverter addConverter(in (Type, Type, Type, Type, CurveProfile) cacheK if (key.tenc == typeof(EncodingType.Companded)) { - var igt = key.profile.Curve.InverseGamma; + float[] igt = key.profile.Curve.InverseGamma; if (key.tfrom == typeof(float) && key.tto == typeof(float)) return new ConverterToLinear(igt); @@ -823,7 +816,7 @@ private static byte[] getResourceBinary(string name) string resName = $"{nameof(PhotoSauce)}.{nameof(MagicScaler)}.Resources.{name}"; using var stm = typeof(IccProfiles).Assembly.GetManifestResourceStream(resName)!; - var buff = new byte[(int)stm.Length]; + byte[] buff = new byte[(int)stm.Length]; stm.FillBuffer(buff); return buff; diff --git a/src/MagicScaler/Core/BitmapPixelSource.cs b/src/MagicScaler/Core/BitmapPixelSource.cs index c7fd717..1541597 100644 --- a/src/MagicScaler/Core/BitmapPixelSource.cs +++ b/src/MagicScaler/Core/BitmapPixelSource.cs @@ -9,35 +9,26 @@ namespace PhotoSauce.MagicScaler; /// A base implementation for wrapping a fully-decoded image bitmap in memory. -public abstract class BitmapPixelSource : IPixelSource, IDisposable +/// The format of the bitmap pixels. +/// The bitmap width, in pixels. +/// The bitmap height, in pixels. +/// The number of bytes between pixels in adjacent bitmap rows. +public abstract class BitmapPixelSource(Guid format, int width, int height, int stride) : IPixelSource, IDisposable { /// - public virtual Guid Format { get; } + public virtual Guid Format { get; } = format; /// - public virtual int Width { get; } + public virtual int Width { get; } = width; /// - public virtual int Height { get; } + public virtual int Height { get; } = height; /// The number of bytes between pixels in adjacent bitmap rows. - protected virtual int Stride { get; } + protected virtual int Stride { get; } = stride; /// Exposes the pixel data in the backing bitmap. /// A instance that exposes the pixel data in memory. protected abstract ReadOnlySpan Span { get; } - /// Sets base properties of the implementation. - /// The format of the bitmap pixels. - /// The bitmap width, in pixels. - /// The bitmap height, in pixels. - /// The number of bytes between pixels in adjacent bitmap rows. - protected BitmapPixelSource(Guid format, int width, int height, int stride) - { - Format = format; - Width = width; - Height = height; - Stride = stride; - } - /// public virtual void CopyPixels(Rectangle sourceArea, int cbStride, Span buffer) { diff --git a/src/MagicScaler/Core/Enums.cs b/src/MagicScaler/Core/Enums.cs index a1cae24..b7167b9 100644 --- a/src/MagicScaler/Core/Enums.cs +++ b/src/MagicScaler/Core/Enums.cs @@ -133,10 +133,6 @@ public enum OrientationMode : byte [Flags] public enum ChromaPosition { - /// Chroma components are offset between luma rows and columns, as in JPEG images. - Jpeg = Center, - /// Chroma components are aligned with luma columns and offset between luma rows, as in most modern video formats. - Video = Left, /// Chroma components are offset between luma rows/columns. Center = 0, /// Chroma components are aligned with even luma columns. @@ -144,7 +140,11 @@ public enum ChromaPosition /// Chroma components are aligned with even luma rows. Top = 2, /// Chroma components are aligned with odd luma rows. - Bottom = 4 + Bottom = 4, + /// Chroma components are offset between luma rows and columns, as in JPEG images. + Jpeg = Center, + /// Chroma components are aligned with luma columns and offset between luma rows, as in most modern video formats. + Video = Left } /// Defines the modes that control chroma subsampling for output image formats that support it. diff --git a/src/MagicScaler/Core/Interpolators.cs b/src/MagicScaler/Core/Interpolators.cs index dccc53a..cc88544 100644 --- a/src/MagicScaler/Core/Interpolators.cs +++ b/src/MagicScaler/Core/Interpolators.cs @@ -136,7 +136,7 @@ public sealed class QuadraticInterpolator : IInterpolator, IUniquelyIdentifiable /// A value between 0.5 and 1.5, where lower values produce a smoother filter and higher values produce a sharper filter. public QuadraticInterpolator(double r = 1.0) { - if (r < 0.5 || r > 1.5) throw new ArgumentOutOfRangeException(nameof(r), "Value must be between 0.5 and 1.5"); + if (r is < 0.5 or > 1.5) throw new ArgumentOutOfRangeException(nameof(r), "Value must be between 0.5 and 1.5"); this.r = r; r0 = -2.0 * r; diff --git a/src/MagicScaler/Core/LookupTables.cs b/src/MagicScaler/Core/LookupTables.cs index a1c2f18..b5e8c02 100644 --- a/src/MagicScaler/Core/LookupTables.cs +++ b/src/MagicScaler/Core/LookupTables.cs @@ -20,7 +20,7 @@ internal static class LookupTables public const int InverseGammaLength = InverseGammaScale + 2; private static readonly Lazy alphaTable = new(() => { - var tbl = new float[InverseGammaLength]; + float[] tbl = new float[InverseGammaLength]; for (int i = 0; i < tbl.Length; i++) tbl[i] = (float)((double)i / byte.MaxValue); @@ -32,12 +32,12 @@ internal static class LookupTables //http://www.w3.org/Graphics/Color/srgb private static readonly Lazy> gammaTable = new(() => { - var tbl = new float[GammaLengthFloat]; + float[] tbl = new float[GammaLengthFloat]; for (int i = 0; i < tbl.Length; i++) { double d = (double)i / GammaScaleFloat; - if (d <= (0.04045 / 12.92)) + if (d <= 0.04045 / 12.92) d *= 12.92; else d = 1.055 * Pow(d, 1.0 / 2.4) - 0.055; @@ -51,8 +51,8 @@ internal static class LookupTables }); private static readonly Lazy> inverseGammaTable = new(() => { - var igtf = new float[InverseGammaLength]; - var igtq = new ushort[InverseGammaLength]; + float[] igtf = new float[InverseGammaLength]; + ushort[] igtq = new ushort[InverseGammaLength]; for (int i = 0; i < igtf.Length; i++) { @@ -73,7 +73,7 @@ internal static class LookupTables }); private static readonly Lazy octreeIndexTable = new(() => { - var tbl = new uint[256 * 3]; + uint[] tbl = new uint[256 * 3]; for (uint i = 0; i < 256; i++) { @@ -122,7 +122,7 @@ public static void Fixup(T[] t, int maxValid) public static byte[] MakeUQ15Gamma(float[] gt) { - var gtq = new byte[GammaLengthUQ15]; + byte[] gtq = new byte[GammaLengthUQ15]; for (int i = 0; i < gtq.Length; i++) { double val = (double)i / GammaScaleUQ15; @@ -144,7 +144,7 @@ public static ushort[] MakeUQ15InverseGamma(float[] igt) if (igt == SrgbInverseGamma) return SrgbInverseGammaUQ15; - var igtq = new ushort[InverseGammaLength]; + ushort[] igtq = new ushort[InverseGammaLength]; for (int i = 0; i < igtq.Length; i++) igtq[i] = FixToUQ15One(igt[i]); @@ -158,7 +158,7 @@ public static float[] MakeVideoGamma(float[] gt) const int minVal = VideoLumaMin << 2; const int maxVal = VideoLumaMax << 2; - var gtv = new float[gt.Length]; + float[] gtv = new float[gt.Length]; for (int i = 0; i < gtv.Length; i++) gtv[i] = (float)(((double)gt[i] * (maxVal - minVal) + minVal) / GammaScaleFloat); @@ -172,7 +172,7 @@ public static float[] MakeVideoInverseGamma(float[] igt) const int minVal = VideoLumaMin; const int maxVal = VideoLumaMax; - var igtv = new float[igt.Length]; + float[] igtv = new float[igt.Length]; for (int i = 0; i < igtv.Length; i++) { double val = (double)(i.Clamp(minVal, maxVal) - minVal) / (maxVal - minVal); diff --git a/src/MagicScaler/Core/PipelineContext.cs b/src/MagicScaler/Core/PipelineContext.cs index 220c7b7..e33015e 100644 --- a/src/MagicScaler/Core/PipelineContext.cs +++ b/src/MagicScaler/Core/PipelineContext.cs @@ -29,7 +29,7 @@ internal sealed class PipelineContext(ProcessImageSettings settings, IImageConta public ColorProfile? SourceColorProfile { get; set; } public ColorProfile? DestColorProfile { get; set; } - public IEnumerable Stats => profilers?.OfType().Select(static p => p.Stats) ?? Enumerable.Empty(); + public IEnumerable Stats => profilers?.OfType().Select(static p => p.Stats) ?? [ ]; public WicPipelineContext WicContext => wicContext ??= new(); diff --git a/src/MagicScaler/Core/PixelFormats.cs b/src/MagicScaler/Core/PixelFormats.cs index 945eea1..fe4bcc8 100644 --- a/src/MagicScaler/Core/PixelFormats.cs +++ b/src/MagicScaler/Core/PixelFormats.cs @@ -501,8 +501,8 @@ private static unsafe Dictionary getFormatCache() name.ContainsOrdinal("CMYK") ? PixelColorRepresentation.Cmyk : name.ContainsOrdinal("Gray") || name.EndsWithOrdinal(" Y") ? PixelColorRepresentation.Grey : PixelColorRepresentation.Unspecified; - var valEncoding = colorRep == PixelColorRepresentation.Grey || colorRep == PixelColorRepresentation.Bgr || colorRep == PixelColorRepresentation.Rgb ? - numericRep == PixelNumericRepresentation.Fixed || numericRep == PixelNumericRepresentation.Float ? PixelValueEncoding.scRgb : + var valEncoding = colorRep is PixelColorRepresentation.Grey or PixelColorRepresentation.Bgr or PixelColorRepresentation.Rgb ? + numericRep is PixelNumericRepresentation.Fixed or PixelNumericRepresentation.Float ? PixelValueEncoding.scRgb : PixelValueEncoding.Companded : PixelValueEncoding.Unspecified; diff --git a/src/MagicScaler/Core/ProcessImageSettings.cs b/src/MagicScaler/Core/ProcessImageSettings.cs index 74a71cb..e91ed97 100644 --- a/src/MagicScaler/Core/ProcessImageSettings.cs +++ b/src/MagicScaler/Core/ProcessImageSettings.cs @@ -91,7 +91,7 @@ public InterpolationSettings(IInterpolator weighting, double blur) { ThrowHelper.ThrowIfNull(weighting); - if (blur < 0.5 || blur > 1.5) throw new ArgumentOutOfRangeException(nameof(blur), "Value must be between 0.5 and 1.5"); + if (blur is < 0.5 or > 1.5) throw new ArgumentOutOfRangeException(nameof(blur), "Value must be between 0.5 and 1.5"); WeightingFunction = weighting; this.blur = blur; @@ -199,7 +199,7 @@ DecoderOptions is null /// A list of metadata policy names or explicit metadata paths to be copied from the input image to the output image. /// /// Default value: - public IEnumerable MetadataNames { get; set; } = Enumerable.Empty(); + public IEnumerable MetadataNames { get; set; } = [ ]; /// Codec options to be passed to the image encoder. /// Default value: calculated based on input image properties and ouput size, or taken from the codec's configuration. public IEncoderOptions? EncoderOptions { get; set; } @@ -316,13 +316,13 @@ public static ProcessImageSettings FromDictionary(IDictionary d if (cropExpression.Value.IsMatch(dic.GetValueOrDefault("crop") ?? string.Empty)) { - var ps = dic["crop"]!.Split(','); + string[] ps = dic["crop"]!.Split(','); s.Crop = new Rectangle(int.Parse(ps[0], ni), int.Parse(ps[1], ni), int.Parse(ps[2], ni), int.Parse(ps[3], ni)); } if (cropBasisExpression.Value.IsMatch(dic.GetValueOrDefault("cropbasis") ?? string.Empty)) { - var ps = dic["cropbasis"]!.Split(','); + string[] ps = dic["cropbasis"]!.Split(','); s.CropBasis = new Size(int.Parse(ps[0], ni), int.Parse(ps[1], ni)); } @@ -495,7 +495,7 @@ internal void Fixup(int inWidth, int inHeight, bool swapDimensions = false) wrat = width > 0 ? (double)Crop.Width / width : (double)Crop.Height / height; hrat = height > 0 ? (double)Crop.Height / height : wrat; - if (ResizeMode == CropScaleMode.Contain || ResizeMode == CropScaleMode.Max || ResizeMode == CropScaleMode.Pad) + if (ResizeMode is CropScaleMode.Contain or CropScaleMode.Max or CropScaleMode.Pad) { int dim = Math.Max(width, height); @@ -510,7 +510,7 @@ internal void Fixup(int inWidth, int inHeight, bool swapDimensions = false) InnerSize.Width = width > 0 ? width : Math.Max((int)Math.Round(Crop.Width / wrat), 1); InnerSize.Height = height > 0 ? height : Math.Max((int)Math.Round(Crop.Height / hrat), 1); - if (ResizeMode == CropScaleMode.Crop || ResizeMode == CropScaleMode.Contain || ResizeMode == CropScaleMode.Max) + if (ResizeMode is CropScaleMode.Crop or CropScaleMode.Contain or CropScaleMode.Max) OuterSize = InnerSize; } @@ -578,7 +578,7 @@ internal string GetCacheHash() hash.Update(LossyQuality); } - foreach (string m in MetadataNames ?? Enumerable.Empty()) + foreach (string m in MetadataNames ?? [ ]) hash.Update(m.AsSpan()); var hbuff = (Span)stackalloc byte[hash.DigestLength]; diff --git a/src/MagicScaler/Experimental/TransformFactory.cs b/src/MagicScaler/Experimental/TransformFactory.cs index 89f87b6..a272d16 100644 --- a/src/MagicScaler/Experimental/TransformFactory.cs +++ b/src/MagicScaler/Experimental/TransformFactory.cs @@ -16,10 +16,8 @@ public static class TransformFactory /// The ICC color profile to use for the . If null, sRGB will be used. /// The ICC color profile to use for the resulting pixel data. If null, sRGB will be used. /// An that provides the resulting pixel data. - public static IPixelSource CreateConversionTransform(IPixelSource source, Guid destFormat, IColorProfileHandle? sourceProfile = null, IColorProfileHandle? destProfile = null) - { - return new ConversionTransform(source.AsPixelSource(), PixelFormat.FromGuid(destFormat), sourceProfile?.ColorProfile, destProfile?.ColorProfile); - } + public static IPixelSource CreateConversionTransform(IPixelSource source, Guid destFormat, IColorProfileHandle? sourceProfile = null, IColorProfileHandle? destProfile = null) => + new ConversionTransform(source.AsPixelSource(), PixelFormat.FromGuid(destFormat), sourceProfile?.ColorProfile, destProfile?.ColorProfile); /// Creates a transform that resizes an to the given size, optionally using a specific interpolator. /// The to retrieve pixels from. @@ -32,7 +30,7 @@ public static IPixelSource CreateScaleTransform(IPixelSource source, int newWidt if (settings.WeightingFunction is null) { double scaleRatio = Math.Min( - source.Width > 0 ? (double)newWidth / source.Width : 0, + source.Width > 0 ? (double)newWidth / source.Width : 0, source.Height > 0 ? (double)newHeight / source.Height : 0); settings = SettingsUtil.GetDefaultInterpolation(scaleRatio); } diff --git a/src/MagicScaler/GDI/GdiImageProcessor.cs b/src/MagicScaler/GDI/GdiImageProcessor.cs index f87fa70..4f86f75 100644 --- a/src/MagicScaler/GDI/GdiImageProcessor.cs +++ b/src/MagicScaler/GDI/GdiImageProcessor.cs @@ -46,7 +46,7 @@ internal static void ExifRotate(this Image img) internal static Image HybridScale(this Image img, ProcessImageSettings s, InterpolationMode mode) { - if (s.HybridScaleRatio == 1 || (mode != InterpolationMode.HighQualityBicubic && mode != InterpolationMode.HighQualityBilinear)) + if (s.HybridScaleRatio == 1 || mode is not (InterpolationMode.HighQualityBicubic or InterpolationMode.HighQualityBilinear)) return img; int intw = (int)Math.Ceiling((double)img.Width / s.HybridScaleRatio); @@ -154,7 +154,7 @@ private static ProcessImageResult processImage(Stream istm, Stream ostm, Process bmp.Save(ostm, ImageFormat.Png); } - return new ProcessImageResult(usedSettings, Enumerable.Empty()); + return new ProcessImageResult(usedSettings, [ ]); } } #endif \ No newline at end of file diff --git a/src/MagicScaler/Magic/AnimationEncoder.cs b/src/MagicScaler/Magic/AnimationEncoder.cs index 3f5c851..7418715 100644 --- a/src/MagicScaler/Magic/AnimationEncoder.cs +++ b/src/MagicScaler/Magic/AnimationEncoder.cs @@ -151,7 +151,7 @@ private void moveToFrame(int index, out AnimationFrame anifrm) else context.Source = context.ImageFrame.PixelSource.AsPixelSource(); - if (context.ImageFrame is not IMetadataSource fmsrc || !fmsrc.TryGetMetadata(out anifrm)) + if (context.ImageFrame is not IMetadataSource fmsrc || !fmsrc.TryGetMetadata(out anifrm)) anifrm = AnimationFrame.Default; MagicTransforms.AddAnimationTransforms(context, anicnt, anifrm); diff --git a/src/MagicScaler/Magic/ColorProfileTransform.cs b/src/MagicScaler/Magic/ColorProfileTransform.cs index 6802b59..d86078a 100644 --- a/src/MagicScaler/Magic/ColorProfileTransform.cs +++ b/src/MagicScaler/Magic/ColorProfileTransform.cs @@ -43,7 +43,7 @@ public static bool TryCreate(PixelSource src, PixelFormat dstfmt, ColorProfile s void* hndsrc = cmsOpenProfileFromMem(srcBytes, (uint)srcProfile.ProfileBytes.Length); if (hndsrc is null && src.Format.ColorRepresentation is PixelColorRepresentation.Cmyk) { - var cmyk = ColorProfile.CmykDefault.ProfileBytes; + byte[] cmyk = ColorProfile.CmykDefault.ProfileBytes; fixed (byte* pcmyk = cmyk) hndsrc = cmsOpenProfileFromMem(pcmyk, (uint)cmyk.Length); } diff --git a/src/MagicScaler/Magic/ConvolutionTransform.cs b/src/MagicScaler/Magic/ConvolutionTransform.cs index 4b92c59..1fcd927 100644 --- a/src/MagicScaler/Magic/ConvolutionTransform.cs +++ b/src/MagicScaler/Magic/ConvolutionTransform.cs @@ -73,7 +73,7 @@ protected ConvolutionTransform(PixelSource source, KernelMap mapx, Kern var workfmt = infmt; if (typeof(TConv) == typeof(ConvolutionType.Buffered)) { - if (infmt.ColorRepresentation != PixelColorRepresentation.Grey && infmt.ColorRepresentation != PixelColorRepresentation.Bgr) + if (infmt.ColorRepresentation is not (PixelColorRepresentation.Grey or PixelColorRepresentation.Bgr)) throw new NotSupportedException("Unsupported pixel format: " + infmt.Name); workfmt = infmt.NumericRepresentation == PixelNumericRepresentation.Float ? PixelFormat.Grey32Float : diff --git a/src/MagicScaler/Magic/IndexedColorTransform.cs b/src/MagicScaler/Magic/IndexedColorTransform.cs index 708b132..a0f1215 100644 --- a/src/MagicScaler/Magic/IndexedColorTransform.cs +++ b/src/MagicScaler/Magic/IndexedColorTransform.cs @@ -68,16 +68,16 @@ public IndexedColorTransform(PixelSource source) : base(source) public void SetPalette(ReadOnlySpan pal, bool isExact) { - if (pal.Length < 1 || pal.Length > maxPaletteSize) throw new ArgumentException($"Palette must have between 1 and {maxPaletteSize} entries.", nameof(pal)); + if (pal.Length is < 2 or > maxPaletteSize) throw new ArgumentException($"Palette must have between 2 and {maxPaletteSize} entries.", nameof(pal)); pal.CopyTo(palBuff.Span); pal.CopyTo(palBuff.Span[maxPaletteSize..]); dither = !isExact; - hasAlpha = pal[^1] < 0x00ffffffu; + hasAlpha = pal[^1] <= 0x00ffffffu; paletteLength = pal.Length; - palBuff.Span[paletteLength..maxPaletteSize].Fill(MemoryMarshal.GetReference(pal)); + palBuff.Span[paletteColors..maxPaletteSize].Fill(MemoryMarshal.GetReference(pal)); mapNextFree = seedPaletteMap(mapBuff.Span); } @@ -85,6 +85,7 @@ public void SetPalette(ReadOnlySpan pal, bool isExact) protected override void CopyPixelsInternal(in PixelArea prc, int cbStride, int cbBufferSize, byte* pbBuffer) { if (palBuff.IsEmpty) ThrowHelper.ThrowObjectDisposed(nameof(IndexedColorTransform)); + if (paletteColors is 0) throw new InvalidOperationException("No palette has been set."); if (isFixedGrey) copyPixelsDirect(prc, cbStride, cbBufferSize, pbBuffer); @@ -103,8 +104,6 @@ private unsafe void copyPixelsDirect(in PixelArea prc, int cbStride, int cbBuffe private unsafe void copyPixelsBuffered(in PixelArea prc, nint cbStride, byte* pbBuffer) where TAlpha : struct, AlphaType { - if (paletteLength == 0) throw new InvalidOperationException("No palette has been set."); - nint lstride = 0; var lspan = lineBuff.Span; if (PrevSource is FrameBufferSource fbuff) @@ -285,9 +284,9 @@ private uint seedPaletteMap(Span palMap) private void remapDitherSse41(byte* pimage, short* perror, byte* pout, uint* pilut, PaletteMapNode* pmap, uint* ppal, nint cp) where TAlpha : struct, AlphaType { nuint nextFree = mapNextFree; - nuint maxcol = (uint)paletteColors - 1; nuint level = leafLevel; - nuint pidx = maxcol; + nuint cpal = (uint)paletteColors; + nuint pidx = 0; var vpmax = Vector128.Create((short)byte.MaxValue); var vprnd = Vector128.Create((short)7); @@ -306,7 +305,7 @@ private void remapDitherSse41(byte* pimage, short* perror, byte* pout, u if (typeof(TAlpha) == typeof(AlphaType.Present) && ip[3] < alphaThreshold) { vppix = vzero; - pidx = maxcol + 1; + pidx = cpal; goto FoundExact; } @@ -351,7 +350,7 @@ private void remapDitherSse41(byte* pimage, short* perror, byte* pout, u break; } - pidx = getPaletteIndexSse41(ppal, node, idx & 7, vppix, maxcol); + pidx = getPaletteIndexSse41(ppal, cpal, node, idx & 7, vppix); var vdiff = Sse2.Subtract(vppix, Sse41.ConvertToVector128Int16((byte*)(ppal + pidx))); Sse2.StoreScalar((long*)(ep - channels), Sse2.Add(vperr, Sse2.Add(vdiff, vdiff)).AsInt64()); @@ -380,9 +379,9 @@ private void remapDitherSse41(byte* pimage, short* perror, byte* pout, u private void remapDitherScalar(byte* pimage, short* perror, byte* pout, uint* pilut, PaletteMapNode* pmap, uint* ppal, nint cp) where TAlpha : struct, AlphaType { nuint nextFree = mapNextFree; - nuint maxcol = (uint)paletteColors - 1; nuint level = leafLevel; - nuint pidx = maxcol; + nuint cpal = (uint)paletteColors; + nuint pidx = 0; byte* ip = pimage, ipe = ip + cp * sizeof(uint); byte* op = pout; @@ -397,7 +396,7 @@ private void remapDitherScalar(byte* pimage, short* perror, byte* pout, if (typeof(TAlpha) == typeof(AlphaType.Present) && ip[3] < alphaThreshold) { ppix = 0; - pidx = maxcol + 1; + pidx = cpal; goto FoundExact; } @@ -439,7 +438,7 @@ private void remapDitherScalar(byte* pimage, short* perror, byte* pout, break; } - pidx = getPaletteIndex(ppal, node, idx & 7, ppix, maxcol); + pidx = getPaletteIndex(ppal, cpal, node, idx & 7, ppix); byte* pcol = (byte*)(ppal + pidx); int db = (byte)(ppix ) - pcol[0]; @@ -487,9 +486,9 @@ private void remapDitherScalar(byte* pimage, short* perror, byte* pout, private void remap(byte* pimage, byte* pout, uint* pilut, PaletteMapNode* pmap, uint* ppal, nint cp) where TAlpha : struct, AlphaType { nuint nextFree = mapNextFree; - nuint maxcol = (uint)paletteColors - 1; nuint level = leafLevel; - nuint pidx = maxcol; + nuint cpal = (uint)paletteColors; + nuint pidx = 0; byte* ip = pimage, ipe = ip + cp * sizeof(uint); byte* op = pout; @@ -500,7 +499,7 @@ private void remap(byte* pimage, byte* pout, uint* pilut, PaletteMapNode if (typeof(TAlpha) == typeof(AlphaType.Present) && ip[3] < alphaThreshold) { ppix = 0; - pidx = maxcol + 1; + pidx = cpal; goto Found; } @@ -538,7 +537,7 @@ private void remap(byte* pimage, byte* pout, uint* pilut, PaletteMapNode break; } - pidx = getPaletteIndex(ppal, node, idx & 7, ppix, maxcol); + pidx = getPaletteIndex(ppal, cpal, node, idx & 7, ppix); Found: ip += channels; @@ -551,12 +550,12 @@ private void remap(byte* pimage, byte* pout, uint* pilut, PaletteMapNode #if HWINTRINSICS [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static nuint getPaletteIndexSse41(uint* ppal, PaletteMapNode* node, nuint idx, Vector128 vpix, nuint maxidx) + private static nuint getPaletteIndexSse41(uint* ppal, nuint cpal, PaletteMapNode* node, nuint idx, Vector128 vpix) { if (PaletteMapNode.HasPaletteEntry(node, idx)) return PaletteMapNode.GetPaletteIndex(node, idx); - nuint pidx = findNearestColorSse41(ppal, maxidx, vpix); + nuint pidx = findNearestColorSse41(ppal, cpal, vpix); PaletteMapNode.SetPaletteIndex(node, idx, pidx); return pidx; @@ -564,7 +563,7 @@ private static nuint getPaletteIndexSse41(uint* ppal, PaletteMapNode* node, nuin #endif [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static nuint getPaletteIndex(uint* ppal, PaletteMapNode* node, nuint idx, nuint pix, nuint maxidx) + private static nuint getPaletteIndex(uint* ppal, nuint cpal, PaletteMapNode* node, nuint idx, nuint pix) { if (PaletteMapNode.HasPaletteEntry(node, idx)) return PaletteMapNode.GetPaletteIndex(node, idx); @@ -572,10 +571,10 @@ private static nuint getPaletteIndex(uint* ppal, PaletteMapNode* node, nuint idx nuint pidx; #if HWINTRINSICS if (Sse41.IsSupported) - pidx = findNearestColorSse41(ppal, maxidx, Sse41.ConvertToVector128Int16(Vector128.CreateScalarUnsafe((uint)pix).AsByte())); + pidx = findNearestColorSse41(ppal, cpal, Sse41.ConvertToVector128Int16(Vector128.CreateScalarUnsafe((uint)pix).AsByte())); else #endif - pidx = findNearestColor(ppal, maxidx, (uint)pix); + pidx = findNearestColor(ppal, cpal, (uint)pix); PaletteMapNode.SetPaletteIndex(node, idx, pidx); @@ -584,25 +583,22 @@ private static nuint getPaletteIndex(uint* ppal, PaletteMapNode* node, nuint idx #if HWINTRINSICS [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static nuint findNearestColorSse41(uint* ppal, nuint maxidx, Vector128 vpix) + private static nuint findNearestColorSse41(uint* ppal, nuint cpal, Vector128 vpix) { - Vector128 vdst; - Vector128 vidx; + Vector128 vdst, vidx; if (Avx2.IsSupported) { - var wmul = Vector256.Create(-1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0); - var wadd = Vector256.Create(0x60, 0x80, 0x40, 0, 0x60, 0x80, 0x40, 0, 0x60, 0x80, 0x40, 0, 0x60, 0x80, 0x40, 0); + var wmul = Vector256.Create(0x0001_0000_ffff).AsInt16(); + var wadd = Vector256.Create(0x0040_0080_0060).AsInt16(); - var widm = HWIntrinsics.CreateVector256(maxidx).AsUInt32(); - var wdsm = HWIntrinsics.CreateVector256(int.MaxValue).AsInt32(); - var winc = Vector256.Create(4u, 0, 4u, 0, 4u, 0, 4u, 0); - var wcnt = Vector256.Create(0u, 0, 1u, 0, 2u, 0, 3u, 0); - var widx = widm; - var wdst = wdsm; + var winc = Vector256.Create((ulong)Vector256.Count).AsInt32(); + var wcnt = Vector256.Create(0ul, 1ul, 2ul, 3ul).AsInt32(); + var widx = Vector256.Create(0ul).AsInt32(); + var wdst = Vector256.Create((ulong)int.MaxValue).AsInt32(); var wppix = Avx2.BroadcastScalarToVector256(vpix.AsUInt64()).AsInt16(); - byte* pp = (byte*)ppal, ppe = (byte*)(ppal + maxidx); + byte* pp = (byte*)ppal, ppe = (byte*)(ppal + cpal); do { @@ -617,31 +613,29 @@ private static nuint findNearestColorSse41(uint* ppal, nuint maxidx, Vector128.Count).AsInt32(); + var vcnt = Vector128.Create(0ul, 1ul).AsInt32(); + vidx = Vector128.Create(0ul).AsInt32(); + vdst = Vector128.Create((ulong)int.MaxValue).AsInt32(); var vppix = Sse2.UnpackLow(vpix.AsUInt64(), vpix.AsUInt64()).AsInt16(); - byte* pp = (byte*)ppal, ppe = (byte*)(ppal + maxidx); + byte* pp = (byte*)ppal, ppe = (byte*)(ppal + cpal); do { @@ -656,30 +650,30 @@ private static nuint findNearestColorSse41(uint* ppal, nuint maxidx, Vector128> 8); int cr = (byte)(color >> 16); - for (nuint i = 0; i <= maxidx; i++) + for (nuint i = 0; i < cpal; i++) { byte* pc = (byte*)(ppal + i); int db = pc[0] - cb; @@ -736,42 +730,31 @@ public static bool HasChildren(PaletteMapNode* node) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint GetChild(PaletteMapNode* node, nuint idx) - { - return *((ushort*)node + idx); - } + public static nuint GetChild(PaletteMapNode* node, nuint idx) => + *((ushort*)node + idx); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetChild(PaletteMapNode* node, nuint idx, nuint child) - { + public static void SetChild(PaletteMapNode* node, nuint idx, nuint child) => *((ushort*)node + idx) = (ushort)child; - } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsLeaf(PaletteMapNode* node) - { - return *((uint*)node + 3) == LeafMarker; - } + public static bool IsLeaf(PaletteMapNode* node) => + *((uint*)node + 3) == LeafMarker; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetLeaf(PaletteMapNode* node) - { + public static void SetLeaf(PaletteMapNode* node) => *((uint*)node + 3) = LeafMarker; - } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool HasPaletteEntry(PaletteMapNode* node, nuint idx) - { + public static bool HasPaletteEntry(PaletteMapNode* node, nuint idx) => #pragma warning disable IDE0075 // https://github.com/dotnet/runtime/issues/4207 - return ((1u << (int)idx) & *((byte*)node + 8)) != 0 ? true : false; + ((1u << (int)idx) & *((byte*)node + 8)) != 0 ? true : false; #pragma warning restore IDE0075 - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint GetPaletteIndex(PaletteMapNode* node, nuint idx) - { - return *((byte*)node + idx); - } + public static nuint GetPaletteIndex(PaletteMapNode* node, nuint idx) => + *((byte*)node + idx); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SetPaletteIndex(PaletteMapNode* node, nuint idx, nuint pidx) diff --git a/src/MagicScaler/Magic/KernelMap.cs b/src/MagicScaler/Magic/KernelMap.cs index a675be8..c8c28a6 100644 --- a/src/MagicScaler/Magic/KernelMap.cs +++ b/src/MagicScaler/Magic/KernelMap.cs @@ -169,7 +169,7 @@ private static unsafe KernelMap create(int isize, int osize, InterpolationSet var kcache = kbuff.Span.Slice(buffLen - cacheLen, cacheLen); var kernel = kbuff.Span.Slice(buffLen - klen - cacheLen, klen); - var mbuff = MemoryMarshal.Cast(kbuff.Span.Slice(0, Math.Min(klen, isize) * channels)); + var mbuff = MemoryMarshal.Cast(kbuff.Span[..(Math.Min(klen, isize) * channels)]); var mbytes = MemoryMarshal.AsBytes(mbuff); if (cacheLen > 0) diff --git a/src/MagicScaler/Magic/MagicImageProcessor.cs b/src/MagicScaler/Magic/MagicImageProcessor.cs index 206edda..8bbdf30 100644 --- a/src/MagicScaler/Magic/MagicImageProcessor.cs +++ b/src/MagicScaler/Magic/MagicImageProcessor.cs @@ -16,7 +16,7 @@ public static class MagicImageProcessor /// Overrides the default SIMD support detection to force floating point processing on or off. /// Default value: if the runtime/JIT and hardware support hardware-accelerated , otherwise [Obsolete($"This feature will be removed in a future version."), EditorBrowsable(EditorBrowsableState.Never)] - public static bool EnableSimd { get; set; } = Vector.IsHardwareAccelerated && (Vector.Count is 4 or 8); + public static bool EnableSimd { get; set; } = Vector.IsHardwareAccelerated && Vector.Count is 4 or 8; /// All-in-one processing of an image according to the specified . /// The path to a file containing the input image. diff --git a/src/MagicScaler/Magic/MagicTransforms.cs b/src/MagicScaler/Magic/MagicTransforms.cs index 17b68ab..bfc9b78 100644 --- a/src/MagicScaler/Magic/MagicTransforms.cs +++ b/src/MagicScaler/Magic/MagicTransforms.cs @@ -283,7 +283,7 @@ public static void AddHighQualityScaler(PipelineContext ctx, bool useSubsample = public static void AddHybridScaler(PipelineContext ctx) { - var ratio = ctx.Settings.HybridScaleRatio; + int ratio = ctx.Settings.HybridScaleRatio; if (ratio == 1 || ctx.Settings.Interpolation.IsPointSampler || ctx.Source.Format.BitsPerPixel / ctx.Source.Format.ChannelCount != 8) return; @@ -381,7 +381,7 @@ public static void AddNativeScaler(PipelineContext ctx) if ((ctx.Source is PlanarPixelSource pps ? pps.SourceY : ctx.Source) is not IFramePixelSource fps || fps.Frame is not IScaledDecoder sdec) return; - var ratio = ctx.Settings.HybridScaleRatio; + int ratio = ctx.Settings.HybridScaleRatio; if (ratio == 1) return; diff --git a/src/MagicScaler/Magic/MatteTransform.cs b/src/MagicScaler/Magic/MatteTransform.cs index 1acf751..65d92c2 100644 --- a/src/MagicScaler/Magic/MatteTransform.cs +++ b/src/MagicScaler/Magic/MatteTransform.cs @@ -40,7 +40,7 @@ public MatteTransform(PixelSource source, Color color, bool discardAlpha) : base Format = PixelFormat.Bgrx32; } - var igtq = LookupTables.SrgbInverseGammaUQ15; + ushort[] igtq = LookupTables.SrgbInverseGammaUQ15; matteB = igtq[color.B]; matteG = igtq[color.G]; @@ -50,8 +50,8 @@ public MatteTransform(PixelSource source, Color color, bool discardAlpha) : base matteValue32 = (uint)color.ToArgb(); matteValue64 = ((ulong)matteA << 48) | ((ulong)UnFix15(matteR * (uint)matteA) << 32) | ((ulong)UnFix15(matteG * (uint)matteA) << 16) | UnFix15(matteB * (uint)matteA); - var igtf = LookupTables.SrgbInverseGamma; - var atf = LookupTables.Alpha; + float[] igtf = LookupTables.SrgbInverseGamma; + float[] atf = LookupTables.Alpha; float mr = igtf[color.R], mg = igtf[color.G], mb = igtf[color.B], maa = atf[color.A]; vmatte = new Vector4(mb, mg, mr, 1f) * new Vector4(maa); diff --git a/src/MagicScaler/Magic/OctreeQuantizer.cs b/src/MagicScaler/Magic/OctreeQuantizer.cs index e939cbe..1bd6df9 100644 --- a/src/MagicScaler/Magic/OctreeQuantizer.cs +++ b/src/MagicScaler/Magic/OctreeQuantizer.cs @@ -45,7 +45,7 @@ public OctreeQuantizer(IProfiler? prof = null) public bool CreatePalette(int targetColors, bool hasAlpha, Span image, nint width, nint height, nint stride) { - if (targetColors < 2 || targetColors > maxPaletteSize) throw new ArgumentOutOfRangeException(nameof(targetColors), $"Target palette size must be between 2 and {maxPaletteSize}"); + if (targetColors is < 2 or > maxPaletteSize) throw new ArgumentOutOfRangeException(nameof(targetColors), $"Target palette size must be between 2 and {maxPaletteSize}"); Profiler.ResumeTiming(PixelArea.FromSize((int)width, (int)height)); using var nodeBuffer = BufferPool.RentLocalAligned(maxHistogramSize, true); @@ -628,28 +628,20 @@ public static bool HasChildren(HistogramNode* node) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint GetLevel(HistogramNode* node) - { - return *((uint*)node + 3) >> 29; - } + public static uint GetLevel(HistogramNode* node) => + *((uint*)node + 3) >> 29; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetLevel(HistogramNode* node, uint level) - { + public static void SetLevel(HistogramNode* node, uint level) => *((uint*)node + 3) = level << 29; - } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static nuint GetChild(HistogramNode* node, nuint idx) - { - return (uint)*((ushort*)node + idx) & ChildMask; - } + public static nuint GetChild(HistogramNode* node, nuint idx) => + (uint)*((ushort*)node + idx) & ChildMask; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetChild(HistogramNode* node, nuint idx, nuint child) - { + public static void SetChild(HistogramNode* node, nuint idx, nuint child) => *((ushort*)node + idx) |= (ushort)child; - } } private readonly record struct WeightedNode(float Weight, uint Node) : IComparable diff --git a/src/MagicScaler/Magic/OrientationTransform.cs b/src/MagicScaler/Magic/OrientationTransform.cs index 5130992..0032766 100644 --- a/src/MagicScaler/Magic/OrientationTransform.cs +++ b/src/MagicScaler/Magic/OrientationTransform.cs @@ -23,7 +23,7 @@ internal sealed class OrientationTransformInternal : ChainedPixelSource public OrientationTransformInternal(PixelSource source, Orientation orientation) : base(source) { bytesPerPixel = source.Format.BytesPerPixel; - if (!(bytesPerPixel == 1 || bytesPerPixel == 3 || bytesPerPixel == 4)) + if (bytesPerPixel is not (1 or 3 or 4)) throw new NotSupportedException("Pixel format not supported."); Width = source.Width; @@ -66,7 +66,7 @@ private unsafe void copyPixelsDirect(in PixelArea prc, int cbStride, int cbBuffe } } - private unsafe void copyPixelsBuffered(in PixelArea prc, int cbStride, int cbBufferSize, byte* pbBuffer) + private unsafe void copyPixelsBuffered(in PixelArea prc, int cbStride, int _, byte* pbBuffer) { if (outBuff is null) ThrowHelper.ThrowObjectDisposed(nameof(OrientationTransformInternal)); @@ -122,13 +122,13 @@ private unsafe void loadBufferTransposed(byte* bstart) nint rowStride = bytesPerPixel; nint bufStride = lineBuffStride; - if (orient == Orientation.Transverse || orient == Orientation.Rotate270) + if (orient is Orientation.Transverse or Orientation.Rotate270) { bp += (PrevSource.Width - 1) * colStride; colStride = -colStride; } - if (orient == Orientation.Transverse || orient == Orientation.Rotate90) + if (orient is Orientation.Transverse or Orientation.Rotate90) { bp += (PrevSource.Height - 1) * rowStride; lp += (lineBuffHeight - 1) * bufStride; diff --git a/src/MagicScaler/Magic/OverlayTransform.cs b/src/MagicScaler/Magic/OverlayTransform.cs index bab3650..09f0650 100644 --- a/src/MagicScaler/Magic/OverlayTransform.cs +++ b/src/MagicScaler/Magic/OverlayTransform.cs @@ -16,7 +16,7 @@ namespace PhotoSauce.MagicScaler.Transforms; internal sealed class OverlayTransform : ChainedPixelSource { - const int bytesPerPixel = 4; + private const int bytesPerPixel = 4; private PixelSource overSource; private PixelArea overArea; diff --git a/src/MagicScaler/Magic/PixelSource.cs b/src/MagicScaler/Magic/PixelSource.cs index 0c2dc09..3a09270 100644 --- a/src/MagicScaler/Magic/PixelSource.cs +++ b/src/MagicScaler/Magic/PixelSource.cs @@ -108,14 +108,12 @@ internal sealed class PixelSourceContainer(IPixelSource source) : IImageContaine void IDisposable.Dispose() { } } -internal abstract class ChainedPixelSource : PixelSource +internal abstract class ChainedPixelSource(PixelSource source) : PixelSource() { - protected PixelSource PrevSource { get; private set; } + protected PixelSource PrevSource { get; private set; } = source; protected int BufferStride => MathUtil.PowerOfTwoCeiling(PrevSource.Width * PrevSource.Format.BytesPerPixel, IntPtr.Size); - protected ChainedPixelSource(PixelSource source) : base() => PrevSource = source; - public override PixelFormat Format => PrevSource.Format; public override int Width => PrevSource.Width; public override int Height => PrevSource.Height; diff --git a/src/MagicScaler/Magic/Processors/Converters.cs b/src/MagicScaler/Magic/Processors/Converters.cs index f45bbe4..9b6aa3f 100644 --- a/src/MagicScaler/Magic/Processors/Converters.cs +++ b/src/MagicScaler/Magic/Processors/Converters.cs @@ -262,7 +262,7 @@ public static void InvertLine(byte* istart, nint cb) convertIntrinsic(ip, ipe); else #endif - convertScalar(ip, ipe); + convertScalar(ip, ipe); } #if HWINTRINSICS diff --git a/src/MagicScaler/Magic/Processors/ConvertersFloat.cs b/src/MagicScaler/Magic/Processors/ConvertersFloat.cs index 7a8fb62..bf49261 100644 --- a/src/MagicScaler/Magic/Processors/ConvertersFloat.cs +++ b/src/MagicScaler/Magic/Processors/ConvertersFloat.cs @@ -63,7 +63,7 @@ private sealed unsafe class WideningImpl(int offset, int scale) : IConversionPro private static float[] makeTable(int offset, int scale) { - var tbl = new float[256]; + float[] tbl = new float[256]; for (int i = 0; i < tbl.Length; i++) tbl[i] = (float)((double)(i - offset) / scale); diff --git a/src/MagicScaler/Magic/Processors/ConvertersVideo.cs b/src/MagicScaler/Magic/Processors/ConvertersVideo.cs index b1429f1..776e87d 100644 --- a/src/MagicScaler/Magic/Processors/ConvertersVideo.cs +++ b/src/MagicScaler/Magic/Processors/ConvertersVideo.cs @@ -21,8 +21,7 @@ private static byte[] makeTable() const int offs = -16; const int rnd = 109; - var tbl = new byte[256]; - + byte[] tbl = new byte[256]; for (int i = 0; i < tbl.Length; i++) { int v = i + offs; @@ -155,8 +154,7 @@ private static byte[] makeTable() const int offs = -16; const int rnd = 127; - var tbl = new byte[256]; - + byte[] tbl = new byte[256]; for (int i = 0; i < tbl.Length; i++) { uint v = (uint)i; @@ -279,8 +277,7 @@ private static byte[] makeTable() const int offs = -128; const int rnd = 56; - var tbl = new byte[256]; - + byte[] tbl = new byte[256]; for (int i = 0; i < tbl.Length; i++) { int v = i + offs; @@ -429,8 +426,7 @@ private static byte[] makeTable() const int offs = -128; const int rnd = 63; - var tbl = new byte[256]; - + byte[] tbl = new byte[256]; for (int i = 0; i < tbl.Length; i++) { int v = i + offs; diff --git a/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.cs b/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.cs index 2db538d..33a92d0 100644 --- a/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.cs +++ b/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.cs @@ -197,7 +197,7 @@ unsafe void IConvolver.WriteDestLine(byte* tstart, byte* ostart, int ox, int ow, internal sealed partial class Convolver4ChanVector : IVectorConvolver { - IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver4ChanIntrinsic.Instance : (IConvolver)this; + IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver4ChanIntrinsic.Instance : this; } internal sealed partial class Convolver3ChanIntrinsic : IConvolver @@ -295,7 +295,7 @@ unsafe void IConvolver.ConvolveSourceLine(byte* istart, byte* tstart, nint cb, b internal sealed partial class Convolver3ChanVector : IVectorConvolver { - IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver3ChanIntrinsic.Instance : (IConvolver)this; + IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver3ChanIntrinsic.Instance : this; } internal sealed partial class Convolver1ChanIntrinsic : IConvolver @@ -476,6 +476,6 @@ unsafe void IConvolver.WriteDestLine(byte* tstart, byte* ostart, int ox, int ow, internal sealed partial class Convolver1ChanVector : IVectorConvolver { - IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver1ChanIntrinsic.Instance : (IConvolver)this; + IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver1ChanIntrinsic.Instance : this; } #endif diff --git a/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.tt b/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.tt index 36b15b2..932051f 100644 --- a/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.tt +++ b/src/MagicScaler/Magic/Processors/ConvolversIntrinsic.tt @@ -416,7 +416,7 @@ if (t.channels == 1) { internal sealed partial class Convolver<#= t.name #>Vector : IVectorConvolver { - IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver<#= t.name #>Intrinsic.Instance : (IConvolver)this; + IConvolver IVectorConvolver.IntrinsicImpl => Sse.IsSupported ? Convolver<#= t.name #>Intrinsic.Instance : this; } <# } diff --git a/src/MagicScaler/Magic/TestPatternPixelSource.cs b/src/MagicScaler/Magic/TestPatternPixelSource.cs index a17f9f2..ade4b8d 100644 --- a/src/MagicScaler/Magic/TestPatternPixelSource.cs +++ b/src/MagicScaler/Magic/TestPatternPixelSource.cs @@ -37,9 +37,9 @@ public sealed class TestPatternPixelSource : IPixelSource, IDisposable public TestPatternPixelSource(int width, int height, Guid pixelFormat) { channels = Array.IndexOf(formats, pixelFormat); - if (channels < 1 || channels == 2) throw new ArgumentException("Unsupported pixel format", nameof(pixelFormat)); - if (width < 1 || width > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(width), $"Value must be between 1 and {ushort.MaxValue}"); - if (height < 1 || height > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(height), $"Value must be between 1 and {ushort.MaxValue}"); + if (channels is < 1 or 2) throw new ArgumentException("Unsupported pixel format", nameof(pixelFormat)); + if (width is < 1 or > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(width), $"Value must be between 1 and {ushort.MaxValue}"); + if (height is < 1 or > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(height), $"Value must be between 1 and {ushort.MaxValue}"); Width = width; Height = height; @@ -54,7 +54,7 @@ private unsafe byte[] getPattern() { const uint mask = 0xf0f0f0f0u; // limits the max intensity of color values - var buff = ArrayPool.Shared.Rent(stride * rows); + byte[] buff = ArrayPool.Shared.Rent(stride * rows); fixed (byte* buffStart = &buff[0]) { uint barVal = mask; diff --git a/src/MagicScaler/Magic/ZonePlatePixelSource.cs b/src/MagicScaler/Magic/ZonePlatePixelSource.cs index 12049ef..237b6b2 100644 --- a/src/MagicScaler/Magic/ZonePlatePixelSource.cs +++ b/src/MagicScaler/Magic/ZonePlatePixelSource.cs @@ -34,9 +34,9 @@ public sealed class ZonePlatePixelSource : IPixelSource, IProfileSource public ZonePlatePixelSource(int width, int height, Guid pixelFormat, double scale = 1.0) { channels = Array.IndexOf(formats, pixelFormat); - if (channels < 1 || channels == 2) throw new ArgumentException("Unsupported pixel format", nameof(pixelFormat)); - if (width < 1 || width > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(width), $"Value must be between 1 and {ushort.MaxValue}"); - if (height < 1 || height > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(height), $"Value must be between 1 and {ushort.MaxValue}"); + if (channels is < 1 or 2) throw new ArgumentException("Unsupported pixel format", nameof(pixelFormat)); + if (width is < 1 or > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(width), $"Value must be between 1 and {ushort.MaxValue}"); + if (height is < 1 or > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(height), $"Value must be between 1 and {ushort.MaxValue}"); Width = width; Height = height; diff --git a/src/MagicScaler/Utilities/BufferPool.cs b/src/MagicScaler/Utilities/BufferPool.cs index 1ccd711..549edde 100644 --- a/src/MagicScaler/Utilities/BufferPool.cs +++ b/src/MagicScaler/Utilities/BufferPool.cs @@ -37,7 +37,7 @@ private static bool hasLargeSharedPool() [Conditional("GUARDRAILS")] private static void addBoundsMarkers(ArraySegment buff) { - var arr = buff.Array!; + byte[] arr = buff.Array!; if (buff.Offset > 0) arr.AsSpan(0, buff.Offset).Fill(marker); @@ -49,7 +49,7 @@ private static void addBoundsMarkers(ArraySegment buff) [Conditional("GUARDRAILS")] private static void checkBounds(ArraySegment buff) { - var arr = buff.Array!; + byte[] arr = buff.Array!; int end = buff.Offset + buff.Count; #if NET7_0_OR_GREATER @@ -82,7 +82,7 @@ private static void checkBounds(ArraySegment buff) public static unsafe ArraySegment RentRaw(int length, bool clear = false) { - var arr = rentBytes(length); + byte[] arr = rentBytes(length); var buff = new ArraySegment(arr, 0, length); addBoundsMarkers(buff); @@ -96,7 +96,7 @@ public static unsafe ArraySegment RentRaw(int length, bool clear = false) public static unsafe ArraySegment RentRawAligned(int length, bool clear = false) { int pad = HWIntrinsics.VectorCount() - sizeof(nuint); - var arr = rentBytes(length + pad); + byte[] arr = rentBytes(length + pad); nint mask = (nint)HWIntrinsics.VectorCount() - 1; nint offs = (mask + 1 - ((nint)Unsafe.AsPointer(ref arr.GetDataRef()) & mask)) & mask; diff --git a/src/MagicScaler/Utilities/HWIntrinsics.cs b/src/MagicScaler/Utilities/HWIntrinsics.cs index 1a58a26..7850eb5 100644 --- a/src/MagicScaler/Utilities/HWIntrinsics.cs +++ b/src/MagicScaler/Utilities/HWIntrinsics.cs @@ -30,7 +30,8 @@ internal static class HWIntrinsics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int VectorCount() where T : struct => #if HWINTRINSICS - Avx.IsSupported ? Vector256.Count : + Avx2.IsSupported ? Vector256.Count : + Avx.IsSupported && typeof(T) == typeof(float) ? Vector256.Count : Sse.IsSupported ? Vector128.Count : #endif Vector.Count; @@ -40,16 +41,23 @@ public static int VectorCount() where T : struct => private static bool getFastGather() { - if (!AppConfig.GdsMitigationsDisabled) + // AMD is still slow as of Zen 5 + if (X86Base.CpuId(0, 0) is not (_, 0x756e6547, 0x6c65746e, 0x49656e69)) // "Genu", "ntel", "ineI" return false; - bool intel = X86Base.CpuId(0, 0) is (_, 0x756e6547, 0x6c65746e, 0x49656e69); // "Genu", "ntel", "ineI" + // Intel has a fast implementation on Skylake and newer, but microcode mitigations for CVE-2022-40982 make it *very* slow. + // We will use gather only on newer non-vulnerable processors or when a flag is set to indicate the mitigations are disabled. + // https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/gather-data-sampling.html uint fms = (uint)X86Base.CpuId(1, 0).Eax; - uint fam = ((fms & 0xfu << 20) >> 16) + ((fms & 0xfu << 8) >> 8); + uint fam = (fms & 0xfu << 8) >> 8; uint mod = ((fms & 0xfu << 16) >> 12) + ((fms & 0xfu << 4) >> 4); - // Intel Skylake and newer -- AMD is still slow as of Zen 4 - return intel && fam == 6 && mod >= 0x4e; + return (fam, mod) switch { + (6, >= 0xaa) => true, // Raptor Cove+ + (6, >= 0x8f and <= 0x9a) => true, // Golden Cove + (6, 0x4e or >= 0x55) => AppConfig.GdsMitigationsDisabled, // Skylake+ + _ => false + }; } private const byte _ = 0x80; @@ -75,19 +83,6 @@ private static bool getFastGather() public static ReadOnlySpan GatherMask3x => [ 0, 0, 0, 0x80, 0, 0, 0, 0x80, 0, 0, 0, 0x80, 0, 0, 0, 0 ]; - // https://github.com/dotnet/runtime/issues/64784 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe Vector128 CreateVector128(ulong val) => - sizeof(nuint) == sizeof(uint) - ? Sse2.UnpackLow(Vector128.Create((uint)val), Vector128.Create((uint)(val >> 32))).AsUInt64() - : Vector128.Create(val); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe Vector256 CreateVector256(ulong val) => - sizeof(nuint) == sizeof(uint) - ? Avx2.UnpackLow(Vector256.Create((uint)val), Vector256.Create((uint)(val >> 32))).AsUInt64() - : Vector256.Create(val); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float HorizontalAdd(this Vector128 v) { // a | b | c | d diff --git a/src/MagicScaler/Utilities/PoolBufferedStream.cs b/src/MagicScaler/Utilities/PoolBufferedStream.cs index ae6b9b0..38c8a5c 100644 --- a/src/MagicScaler/Utilities/PoolBufferedStream.cs +++ b/src/MagicScaler/Utilities/PoolBufferedStream.cs @@ -16,7 +16,7 @@ namespace PhotoSauce.MagicScaler; internal sealed class PoolBufferedStream : Stream { - const int bufflen = 1 << 14; + private const int bufflen = 1 << 14; private readonly Stream backingStream; private readonly bool ownStream; @@ -250,7 +250,7 @@ private void writeSpan(ReadOnlySpan source, ArraySegment array) public override void WriteByte(byte value) { - if (writepos != 0 && writepos < bufflen - 1) + if (writepos is not 0 and < (bufflen - 1)) { Unsafe.Add(ref buffer!.GetDataRef(), writepos++) = value; return; diff --git a/src/MagicScaler/WIC/IWICBitmapSourceImpl.cs b/src/MagicScaler/WIC/IWICBitmapSourceImpl.cs index 42937f4..a0c8bcc 100644 --- a/src/MagicScaler/WIC/IWICBitmapSourceImpl.cs +++ b/src/MagicScaler/WIC/IWICBitmapSourceImpl.cs @@ -131,7 +131,7 @@ private int copyPalette(IWICBitmapSource* pinst, IWICPalette* pIPalette) var pspan = idxs.Palette; fixed (uint* pp = pspan) - pIPalette->InitializeCustom(pp, (uint)pspan.Length); + HRESULT.Check(pIPalette->InitializeCustom(pp, (uint)pspan.Length)); return S_OK; } diff --git a/src/MagicScaler/WIC/WicCodec.cs b/src/MagicScaler/WIC/WicCodec.cs index 6a01415..8b3f00f 100644 --- a/src/MagicScaler/WIC/WicCodec.cs +++ b/src/MagicScaler/WIC/WicCodec.cs @@ -160,7 +160,7 @@ public void WriteAnimationMetadata(IMetadataSource metadata) using var pal = default(ComPtr); HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf())); - pal.Get()->InitializeCustom(&bg, 1); + HRESULT.Check(pal.Get()->InitializeCustom(&bg, 1)); var pvbg = new PROPVARIANT { vt = (ushort)VARENUM.VT_UI1 }; pvbg.Anonymous.bVal = 0; @@ -169,7 +169,7 @@ public void WriteAnimationMetadata(IMetadataSource metadata) HRESULT.Check(encmeta.Get()->SetMetadataByName(Wic.Metadata.Gif.BackgroundColorIndex, &pvbg)); } - if (anicnt.PixelAspectRatio != default && anicnt.PixelAspectRatio != 1f) + if (anicnt.PixelAspectRatio is not (0f or 1f)) { var pvar = new PROPVARIANT { vt = (ushort)VARENUM.VT_UI1 }; pvar.Anonymous.bVal = (byte)((int)(anicnt.PixelAspectRatio * 64f - 15f)).Clamp(byte.MinValue, byte.MaxValue); diff --git a/src/MagicScaler/WIC/WicImageContainer.cs b/src/MagicScaler/WIC/WicImageContainer.cs index 8e22af6..d5798ca 100644 --- a/src/MagicScaler/WIC/WicImageContainer.cs +++ b/src/MagicScaler/WIC/WicImageContainer.cs @@ -128,7 +128,7 @@ public WicGifContainer(IWICBitmapDecoder* dec, IDecoderOptions? options) : base( float pixelAspect = par == default ? 1f : ((par + 15) / 64f); uint fcount; - WicDecoder->GetFrameCount(&fcount); + HRESULT.Check(WicDecoder->GetFrameCount(&fcount)); using var frame = default(ComPtr); HRESULT.Check(WicDecoder->GetFrame(0, frame.GetAddressOf())); diff --git a/src/MagicScaler/WIC/WicImageFrame.cs b/src/MagicScaler/WIC/WicImageFrame.cs index 5a64666..bfdfef4 100644 --- a/src/MagicScaler/WIC/WicImageFrame.cs +++ b/src/MagicScaler/WIC/WicImageFrame.cs @@ -214,7 +214,7 @@ private WicColorProfile getColorProfile() private WicColorProfile matchProfile(ReadOnlySpan profiles, PixelFormat fmt) { var buff = (Span)stackalloc byte[8]; - foreach (var pcc in profiles) + foreach (nuint pcc in profiles) { using var cc = new ComPtr((IWICColorContext*)pcc); var cct = default(WICColorContextType); diff --git a/src/MagicScaler/WIC/WinCodecExtensions.cs b/src/MagicScaler/WIC/WinCodecExtensions.cs index be0a92c..3f8a60d 100644 --- a/src/MagicScaler/WIC/WinCodecExtensions.cs +++ b/src/MagicScaler/WIC/WinCodecExtensions.cs @@ -163,7 +163,7 @@ public static ReadOnlySpan GetValueOrDefault(this ref IWICMetadataQueryRea } else if (pv.vt is (ushort)VARENUM.VT_LPSTR) { - var str = new string(pv.Anonymous.pszVal); + string str = new(pv.Anonymous.pszVal); len = Math.Min(span.Length, str.Length); MemoryMarshal.Cast(str.AsSpan())[..len].CopyTo(span); } diff --git a/src/MagicScaler/WIC/WindowsCodecExtensions.cs b/src/MagicScaler/WIC/WindowsCodecExtensions.cs index b4443d3..944a6af 100644 --- a/src/MagicScaler/WIC/WindowsCodecExtensions.cs +++ b/src/MagicScaler/WIC/WindowsCodecExtensions.cs @@ -40,7 +40,7 @@ public static void UseWicCodecs(this CodecCollection codecs, WicCodecPolicy poli var enumOptions = policy == WicCodecPolicy.BuiltIn ? WICComponentEnumerateOptions.WICComponentEnumerateBuiltInOnly : WICComponentEnumerateOptions.WICComponentEnumerateDefault; HRESULT.Check(Wic.Factory->CreateComponentEnumerator((uint)type, (uint)enumOptions, cenum.GetAddressOf())); - var pbuff = stackalloc char[bch]; + char* pbuff = stackalloc char[bch]; var formats = stackalloc IUnknown*[bcc]; var codecs = new List<(Guid, IImageCodecInfo)>(); @@ -89,8 +89,8 @@ public static void UseWicCodecs(this CodecCollection codecs, WicCodecPolicy poli name = string.Concat(author, " ", name); BOOL anim, mult; - pCod.Get()->DoesSupportAnimation(&anim); - pCod.Get()->DoesSupportMultiframe(&mult); + HRESULT.Check(pCod.Get()->DoesSupportAnimation(&anim)); + HRESULT.Check(pCod.Get()->DoesSupportMultiframe(&mult)); var cuid = default(Guid); HRESULT.Check(pCod.Get()->GetCLSID(&cuid)); @@ -104,7 +104,7 @@ public static void UseWicCodecs(this CodecCollection codecs, WicCodecPolicy poli HRESULT.Check(pCod.Get()->GetPixelFormats(cch, pg, &cch)); if (extensions.Length != 0 && !ImageFileExtensions.All.ContainsInsensitive(extensions[0])) - extensions = extensions.OrderBy(static e => ImageFileExtensions.All.ContainsInsensitive(e) ? 0 : 1).ToArray(); + extensions = [.. extensions.OrderBy(static e => ImageFileExtensions.All.ContainsInsensitive(e) ? 0 : 1)]; if (type is WICComponentType.WICDecoder) { @@ -157,7 +157,7 @@ public static void UseWicCodecs(this CodecCollection codecs, WicCodecPolicy poli if (mime is ImageMimeTypes.Jpeg) { var subs = new[] { ChromaSubsampleMode.Subsample420, ChromaSubsampleMode.Subsample422, ChromaSubsampleMode.Subsample444 }; - pix = pix.Concat([ PixelFormat.Y8.FormatGuid, PixelFormat.Cb8.FormatGuid, PixelFormat.Cr8.FormatGuid ]).ToArray(); + pix = [.. pix, PixelFormat.Y8.FormatGuid, PixelFormat.Cb8.FormatGuid, PixelFormat.Cr8.FormatGuid]; encinfo = new PlanarEncoderInfo(name, mimes, extensions, pix, options, (stm, opt) => new WicImageEncoder(clsid, mime, stm, opt), mult, anim, prof, subs, ChromaPosition.Center, YccMatrix.Rec601, false); } diff --git a/src/NativeCodecs/Giflib/GifCodec.cs b/src/NativeCodecs/Giflib/GifCodec.cs index d1d256a..0344bb0 100644 --- a/src/NativeCodecs/Giflib/GifCodec.cs +++ b/src/NativeCodecs/Giflib/GifCodec.cs @@ -19,7 +19,7 @@ internal static unsafe class GifFactory public const string DisplayName = $"{giflib} 5.2.2"; public const string giflib = nameof(giflib); - enum CodecType { Decoder, Encoder } + private enum CodecType { Decoder, Encoder } private static readonly Lazy dependencyValid = new(() => { #if NETFRAMEWORK @@ -79,10 +79,10 @@ public static void UseGiflib(this CodecCollection codecs, bool removeExisting = GifFactory.DisplayName, gifMime, gifExtension, - new ContainerPattern[] { + [ new(0, [ (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'7', (byte)'a' ], [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ (byte)'G', (byte)'I', (byte)'F', (byte)'8', (byte)'9', (byte)'a' ], [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), - }, + ], null, GifContainer.TryLoad )); diff --git a/src/NativeCodecs/Giflib/GifDecoder.cs b/src/NativeCodecs/Giflib/GifDecoder.cs index 3f40574..94baa18 100644 --- a/src/NativeCodecs/Giflib/GifDecoder.cs +++ b/src/NativeCodecs/Giflib/GifDecoder.cs @@ -432,7 +432,8 @@ private sealed class GifPixelSource : PixelSource, IFramePixelSource, IIndexedPi public ReadOnlySpan Palette { - get { + get + { if (!frame.palette.IsEmpty) return frame.palette.Span[..colorCount]; diff --git a/src/NativeCodecs/Libheif/HeifCodec.cs b/src/NativeCodecs/Libheif/HeifCodec.cs index 98455f0..dafdce9 100644 --- a/src/NativeCodecs/Libheif/HeifCodec.cs +++ b/src/NativeCodecs/Libheif/HeifCodec.cs @@ -65,14 +65,14 @@ public static void UseLibheif(this CodecCollection codecs, bool removeExisting = HeifFactory.DisplayName, [ ImageMimeTypes.Heic, ImageMimeTypes.Avif ], [ ImageFileExtensions.Heic, ImageFileExtensions.Avif ], - new ContainerPattern[] { + [ new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'h', (byte)'e', (byte)'i', (byte)'c' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'h', (byte)'e', (byte)'v', (byte)'c' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'a', (byte)'v', (byte)'i', (byte)'f' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'m', (byte)'i', (byte)'f', (byte)'1' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'m', (byte)'i', (byte)'a', (byte)'f' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), new(0, [ 0, 0, 0, 0, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'1', (byte)'p', (byte)'i', (byte)'c' ], [ 0xff, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]) - }, + ], null, HeifContainer.TryLoad )); diff --git a/src/NativeCodecs/Libheif/HeifDecoder.cs b/src/NativeCodecs/Libheif/HeifDecoder.cs index ffcb0c4..f21fb8d 100644 --- a/src/NativeCodecs/Libheif/HeifDecoder.cs +++ b/src/NativeCodecs/Libheif/HeifDecoder.cs @@ -14,18 +14,17 @@ namespace PhotoSauce.NativeCodecs.Libheif; internal sealed unsafe class HeifContainer : IImageContainer { - private readonly string ftype; private void* handle; private StreamWrapper* stream; private HeifContainer(string mime, StreamWrapper* stm, void* frm) { - ftype = mime; + MimeType = mime; stream = stm; handle = frm; } - public string MimeType => ftype; + public string MimeType { get; } int IImageContainer.FrameCount => 1; diff --git a/src/NativeCodecs/Libjpeg/JpegCodec.cs b/src/NativeCodecs/Libjpeg/JpegCodec.cs index e5609bc..100fb3b 100644 --- a/src/NativeCodecs/Libjpeg/JpegCodec.cs +++ b/src/NativeCodecs/Libjpeg/JpegCodec.cs @@ -69,9 +69,9 @@ public static void UseLibjpeg(this CodecCollection codecs, bool removeExisting = JpegFactory.DisplayName, jpegMime, jpegExtension, - new ContainerPattern[] { + [ new(0, [ 0xff, 0xd8 ], [ 0xff, 0xff ]), - }, + ], null, JpegContainer.TryLoad )); diff --git a/src/NativeCodecs/Libjpeg/JpegEncoder.cs b/src/NativeCodecs/Libjpeg/JpegEncoder.cs index 1e31911..bdf57d0 100644 --- a/src/NativeCodecs/Libjpeg/JpegEncoder.cs +++ b/src/NativeCodecs/Libjpeg/JpegEncoder.cs @@ -80,7 +80,7 @@ public void WriteFrame(IPixelSource source, IMetadataSource metadata, Rectangle handle->raw_data_in = TRUE; } - if (options is JpegEncoderOptions { SuppressApp0: true } || options is JpegOptimizedEncoderOptions { SuppressApp0: true }) + if (options is JpegEncoderOptions { SuppressApp0: true } or JpegOptimizedEncoderOptions { SuppressApp0: true }) { handle->write_JFIF_header = FALSE; } @@ -155,7 +155,7 @@ private void writeIccp(IMetadataSource metadata) if (!metadata.TryGetMetadata(out var prof)) return; - var embed = prof.Embed; + byte[] embed = prof.Embed; fixed (byte* bp = &embed.GetDataRef()) checkResult(JpegWriteIccProfile(handle, bp, (uint)embed.Length)); } @@ -188,12 +188,12 @@ private void writePlanar(PlanarPixelSource src, PixelArea area) byte*** planes = stackalloc[] { pyr, pbr, prr }; for (int i = 0; i < mcuYH; i++) - pyr[i] = py + (strideY * i); + pyr[i] = py + strideY * i; for (int i = 0; i < mcu; i++) { - pbr[i] = pb + (strideC * i); - prr[i] = pr + (strideC * i); + pbr[i] = pb + strideC * i; + prr[i] = pr + strideC * i; } for (int row = 0; row < area.Height; row += mcuYH) diff --git a/src/NativeCodecs/Libjpeg/JpegPlanarCache.cs b/src/NativeCodecs/Libjpeg/JpegPlanarCache.cs index 0ca7d8a..fd8598e 100644 --- a/src/NativeCodecs/Libjpeg/JpegPlanarCache.cs +++ b/src/NativeCodecs/Libjpeg/JpegPlanarCache.cs @@ -130,9 +130,9 @@ private void loadBuffer(JpegPlane plane, int line) for (int i = 0; i < slice; i++) { - pyr[i] = i < heightY ? py + (buffY.Stride * i) : pyr[i - 1]; - pbr[i] = i < heightC ? pb + (buffCb.Stride * i) : pbr[i - 1]; - prr[i] = i < heightC ? pr + (buffCr.Stride * i) : prr[i - 1]; + pyr[i] = i < heightY ? py + buffY.Stride * i : pyr[i - 1]; + pbr[i] = i < heightC ? pb + buffCb.Stride * i : pbr[i - 1]; + prr[i] = i < heightC ? pr + buffCr.Stride * i : prr[i - 1]; } for (int i = 0; i < slice / minslice; i++) diff --git a/src/NativeCodecs/Libjxl/JxlCodec.cs b/src/NativeCodecs/Libjxl/JxlCodec.cs index ccd72eb..a612112 100644 --- a/src/NativeCodecs/Libjxl/JxlCodec.cs +++ b/src/NativeCodecs/Libjxl/JxlCodec.cs @@ -69,10 +69,10 @@ public static void UseLibjxl(this CodecCollection codecs, bool removeExisting = JxlFactory.DisplayName, jxlMime, jxlExtension, - new ContainerPattern[] { + [ new(0, [ 0xff, 0x0a ], [ 0xff, 0xff ]), new(0, [ 0x00, 0x00, 0x00, 0x0c, 0x4a, 0x58, 0x4c, 0x20, 0x0d, 0x0a, 0x87, 0x0a ], [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]) - }, + ], null, JxlContainer.TryLoad )); diff --git a/src/NativeCodecs/Libjxl/JxlDecoder.cs b/src/NativeCodecs/Libjxl/JxlDecoder.cs index cecdece..89bba9b 100644 --- a/src/NativeCodecs/Libjxl/JxlDecoder.cs +++ b/src/NativeCodecs/Libjxl/JxlDecoder.cs @@ -83,7 +83,7 @@ private JxlContainer(Stream stm, long pos, void* dec, IDecoderOptions? opt) if (status is JxlDecoderStatus.JXL_DEC_FRAME) { frameCountRaw++; - JxlDecoderSkipCurrentFrame(dec); + JxlError.Check(JxlDecoderSkipCurrentFrame(dec)); } else if (status is JxlDecoderStatus.JXL_DEC_BOX) { @@ -268,9 +268,9 @@ public bool TryGetMetadata([NotNullWhen(true)] out T? metadata) where T : IMe // JxlDecoderSizeHintBasicInfo gives an initial pessimistic estimate of 98 bytes const int bufflen = 128; - var dec = JxlFactory.CreateDecoder(); + void* dec = JxlFactory.CreateDecoder(); JxlError.Check(JxlDecoderSetKeepOrientation(dec, JXL_TRUE)); - JxlError.Check(JxlDecoderSubscribeEvents(dec, (int)(JxlDecoderStatus.JXL_DEC_COLOR_ENCODING))); + JxlError.Check(JxlDecoderSubscribeEvents(dec, (int)JxlDecoderStatus.JXL_DEC_COLOR_ENCODING)); long stmpos = imgStream.Position; diff --git a/src/NativeCodecs/Libjxl/JxlEncoder.cs b/src/NativeCodecs/Libjxl/JxlEncoder.cs index c8e9d6a..b6faf2f 100644 --- a/src/NativeCodecs/Libjxl/JxlEncoder.cs +++ b/src/NativeCodecs/Libjxl/JxlEncoder.cs @@ -172,7 +172,7 @@ private void writeColorProfile(IMetadataSource metadata, PixelFormat pixfmt) if (metadata.TryGetMetadata(out var prof)) { //TODO use encoded color space for well-known profiles - var embed = prof.Embed; + byte[] embed = prof.Embed; fixed (byte* pp = &embed.GetDataRef()) checkResult(JxlEncoderSetICCProfile(encoder, pp, (uint)embed.Length)); } diff --git a/src/NativeCodecs/Libjxl/JxlOptions.cs b/src/NativeCodecs/Libjxl/JxlOptions.cs index 0aae196..61736b2 100644 --- a/src/NativeCodecs/Libjxl/JxlOptions.cs +++ b/src/NativeCodecs/Libjxl/JxlOptions.cs @@ -41,7 +41,7 @@ public readonly record struct JxlLossyEncoderOptions(float Distance, JxlEncodeSp /// The calculated Butteraugli distance. public static float DistanceFromQuality(int quality) { - if (quality < 0 || quality > 100) + if (quality is < 0 or > 100) throw new ArgumentOutOfRangeException(nameof(quality), "Value must be between 0 and 100"); return JxlEncoderDistanceFromQuality(quality); @@ -104,10 +104,8 @@ public enum JxlDecodeSpeed Speed3 = 3, /// Speed value 4. Speed4 = 4, -#pragma warning disable CA1069 /// The slowest decoding speed. Equivalent to . - Slowest = 0, + Slowest = Speed0, /// The fastest decoding speed. Equivalent to . - Fastest = 4 -#pragma warning restore CA1069 + Fastest = Speed4 } diff --git a/src/NativeCodecs/Libpng/PngCodec.cs b/src/NativeCodecs/Libpng/PngCodec.cs index a5c0d1b..7dee86d 100644 --- a/src/NativeCodecs/Libpng/PngCodec.cs +++ b/src/NativeCodecs/Libpng/PngCodec.cs @@ -73,9 +73,9 @@ public static void UseLibpng(this CodecCollection codecs, bool removeExisting = PngFactory.DisplayName, pngMime, pngExtension, - new ContainerPattern[] { + [ new(0, [ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a ], [ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]), - }, + ], null, PngContainer.TryLoad )); diff --git a/src/NativeCodecs/Libpng/PngEncoder.cs b/src/NativeCodecs/Libpng/PngEncoder.cs index 7e145ed..45dad3a 100644 --- a/src/NativeCodecs/Libpng/PngEncoder.cs +++ b/src/NativeCodecs/Libpng/PngEncoder.cs @@ -120,7 +120,7 @@ private void writeIccp(IMetadataSource metadata) return; } - var embed = prof.Embed; + byte[] embed = prof.Embed; fixed (byte* bp = &embed.GetDataRef()) checkResult(PngWriteIccp(handle, bp)); } diff --git a/src/NativeCodecs/Libwebp/WebpCodec.cs b/src/NativeCodecs/Libwebp/WebpCodec.cs index f87e147..6ca6935 100644 --- a/src/NativeCodecs/Libwebp/WebpCodec.cs +++ b/src/NativeCodecs/Libwebp/WebpCodec.cs @@ -88,9 +88,9 @@ public static void UseLibwebp(this CodecCollection codecs, bool removeExisting = WebpFactory.DisplayName, webpMime, webpExtension, - new ContainerPattern[] { + [ new(0, [ (byte)'R', (byte)'I', (byte)'F', (byte)'F', 0, 0, 0, 0, (byte)'W', (byte)'E', (byte)'B', (byte)'P' ], [ 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff ]) - }, + ], WebpDecoderOptions.Default, WebpContainer.TryLoad )); diff --git a/src/NativeCodecs/Libwebp/WebpDecoder.cs b/src/NativeCodecs/Libwebp/WebpDecoder.cs index 47c2200..eaea1d0 100644 --- a/src/NativeCodecs/Libwebp/WebpDecoder.cs +++ b/src/NativeCodecs/Libwebp/WebpDecoder.cs @@ -150,7 +150,7 @@ public bool TryGetMetadata([NotNullWhen(true)] out T? metadata) where T : IMe var state = default(WebPDemuxState); var flags = default(WebPFeatureFlags); var data = new WebPData { bytes = buff, size = bufflen }; - var demuxer = WebpFactory.CreateDemuxerPartial(&data, &state); + void* demuxer = WebpFactory.CreateDemuxerPartial(&data, &state); if (state >= WebPDemuxState.WEBP_DEMUX_PARSED_HEADER) flags = (WebPFeatureFlags)WebPDemuxGetI(demuxer, WebPFormatFeature.WEBP_FF_FORMAT_FLAGS); diff --git a/src/NativeCodecs/Libwebp/WebpEncoder.cs b/src/NativeCodecs/Libwebp/WebpEncoder.cs index 224cdf4..9d1a013 100644 --- a/src/NativeCodecs/Libwebp/WebpEncoder.cs +++ b/src/NativeCodecs/Libwebp/WebpEncoder.cs @@ -223,7 +223,7 @@ private void writeIccp(IMetadataSource metadata) if (written || !metadata.TryGetMetadata(out var prof)) return; - var embed = prof.Embed; + byte[] embed = prof.Embed; fixed (byte* bp = &embed.GetDataRef()) { var data = new WebPData { size = (uint)embed.Length, bytes = bp };