瀏覽代碼

LibGfx/WebPWriter: Use one-element huffman tree for opaque images

That way, we can write 0 instead of 8 bits for every alpha byte.
Reduces the size of sunset-retro.png when saved as a webp file
from 3 MiB to 2.25 MiB, without affecting encode speed.

Once we use CanonicalCodes we'll get this for free for all channels,
but opaque images are common enough that it feels worth it to do this
before then.
Nico Weber 1 年之前
父節點
當前提交
51fc51d0b5
共有 1 個文件被更改,包括 16 次插入2 次删除
  1. 16 2
      Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp

+ 16 - 2
Userland/Libraries/LibGfx/ImageFormats/WebPWriter.cpp

@@ -116,7 +116,10 @@ static ErrorOr<void> write_VP8L_image_data(Stream& stream, Bitmap const& bitmap)
     if (alphabet_sizes[0] > 288)
         return Error::from_string_literal("Invalid alphabet size");
 
-    for (int i = 0; i < 4; ++i) {
+    bool all_pixels_are_opaque = are_all_pixels_opaque(bitmap);
+
+    int number_of_full_channels = all_pixels_are_opaque ? 3 : 4;
+    for (int i = 0; i < number_of_full_channels; ++i) {
         TRY(bit_stream.write_bits(0u, 1u)); // Normal code length code.
 
         // Write code length codes.
@@ -146,6 +149,14 @@ static ErrorOr<void> write_VP8L_image_data(Stream& stream, Bitmap const& bitmap)
         // (This is different from deflate, which needs 1 bit per element.)
     }
 
+    if (all_pixels_are_opaque) {
+        // Use a simple 1-element code.
+        TRY(bit_stream.write_bits(1u, 1u));   // Simple code length code.
+        TRY(bit_stream.write_bits(0u, 1u));   // num_symbols - 1
+        TRY(bit_stream.write_bits(1u, 1u));   // is_first_8bits
+        TRY(bit_stream.write_bits(255u, 8u)); // symbol0
+    }
+
     // For code #5, use a simple empty code, since we don't use this yet.
     TRY(bit_stream.write_bits(1u, 1u)); // Simple code length code.
     TRY(bit_stream.write_bits(0u, 1u)); // num_symbols - 1
@@ -164,7 +175,10 @@ static ErrorOr<void> write_VP8L_image_data(Stream& stream, Bitmap const& bitmap)
         TRY(bit_stream.write_bits(Compress::reverse8_lookup_table[g], 8u));
         TRY(bit_stream.write_bits(Compress::reverse8_lookup_table[r], 8u));
         TRY(bit_stream.write_bits(Compress::reverse8_lookup_table[b], 8u));
-        TRY(bit_stream.write_bits(Compress::reverse8_lookup_table[a], 8u));
+
+        // If all pixels are opaque, we wrote a one-element huffman table for alpha, which needs 0 bits per element.
+        if (!all_pixels_are_opaque)
+            TRY(bit_stream.write_bits(Compress::reverse8_lookup_table[a], 8u));
     }
 
     // FIXME: Make ~LittleEndianOutputBitStream do this, or make it VERIFY() that it has happened at least.