Fix CompressionLevel.Optimal for Brotli (#72266)
authorStephen Toub <stoub@microsoft.com>
Fri, 15 Jul 2022 19:14:32 +0000 (15:14 -0400)
committerGitHub <noreply@github.com>
Fri, 15 Jul 2022 19:14:32 +0000 (15:14 -0400)
The intent of Optimal is to be a balanced trade-off between compression ratio and speed, but whereas DeflateStream, GZipStream, and ZLibStream all treat Optimal as such (using zlib's default setting for such a balanced tradeoff), Brotli treats Optimal the same as maximum compression, which is very slow.  Especially now that maximum compression is expressible as CompressionLevel.SmallestSize, it's even more valuable for Optimal to represent that balanced tradeoff.  Based on a variety of sources around the net and some local testing, I've changed the Optimal value from 11 to 4.  This is also more important now that we've fixed the argument validation bug that allowed arbitrary numerical values to be passed through unvalidated (DeflateStream, GZipStream, and ZLibStream all properly validate).

src/libraries/System.IO.Compression.Brotli/src/System/IO/Compression/BrotliStream.cs
src/libraries/System.IO.Compression.Brotli/src/System/IO/Compression/BrotliUtils.cs
src/libraries/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs

index 979d011..7e313a4 100644 (file)
@@ -33,12 +33,21 @@ namespace System.IO.Compression
             {
                 case CompressionMode.Compress:
                     if (!stream.CanWrite)
+                    {
                         throw new ArgumentException(SR.Stream_FalseCanWrite, nameof(stream));
+                    }
+
+                    _encoder.SetQuality(BrotliUtils.Quality_Default);
+                    _encoder.SetWindow(BrotliUtils.WindowBits_Default);
                     break;
+
                 case CompressionMode.Decompress:
                     if (!stream.CanRead)
+                    {
                         throw new ArgumentException(SR.Stream_FalseCanRead, nameof(stream));
+                    }
                     break;
+
                 default:
                     throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(mode));
             }
index 52c5c39..2e8e55a 100644 (file)
@@ -9,16 +9,16 @@ namespace System.IO.Compression
         public const int WindowBits_Default = 22;
         public const int WindowBits_Max = 24;
         public const int Quality_Min = 0;
-        public const int Quality_Default = 11;
+        public const int Quality_Default = 4;
         public const int Quality_Max = 11;
         public const int MaxInputSize = int.MaxValue - 515; // 515 is the max compressed extra bytes
 
         internal static int GetQualityFromCompressionLevel(CompressionLevel compressionLevel) =>
             compressionLevel switch
             {
-                CompressionLevel.Optimal => Quality_Default,
                 CompressionLevel.NoCompression => Quality_Min,
                 CompressionLevel.Fastest => 1,
+                CompressionLevel.Optimal => Quality_Default,
                 CompressionLevel.SmallestSize => Quality_Max,
                 _ => throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(compressionLevel))
             };
index 5591199..9f2c84d 100644 (file)
@@ -17,6 +17,7 @@ namespace System.IO.Compression
         /// <param name="stream">The stream to compress.</param>
         /// <param name="compressionLevel">One of the enumeration values that indicates whether to emphasize speed or compression efficiency when compressing the stream.</param>
         public BrotliStream(Stream stream, CompressionLevel compressionLevel) : this(stream, compressionLevel, leaveOpen: false) { }
+
         /// <summary>Initializes a new instance of the <see cref="System.IO.Compression.BrotliStream" /> class by using the specified stream and compression level, and optionally leaves the stream open.</summary>
         /// <param name="stream">The stream to compress.</param>
         /// <param name="compressionLevel">One of the enumeration values that indicates whether to emphasize speed or compression efficiency when compressing the stream.</param>