ソースを参照

LibGfx/CCITT: Abstract the code to read a single CCITT 2D line

Lucas CHOLLET 1 年間 前
コミット
e9dd1cda3e
1 ファイル変更86 行追加81 行削除
  1. 86 81
      Userland/Libraries/LibGfx/ImageFormats/CCITTDecoder.cpp

+ 86 - 81
Userland/Libraries/LibGfx/ImageFormats/CCITTDecoder.cpp

@@ -413,6 +413,89 @@ enum class Search : u8 {
     B2,
 };
 
+ErrorOr<ReferenceLine> decode_single_ccitt_2d_line(BigEndianInputBitStream& input_bit_stream, BigEndianOutputBitStream& decoded_bits, ReferenceLine&& reference_line, u32 image_width)
+{
+    ReferenceLine current_line {};
+    Color current_color { ccitt_white };
+    u32 column {};
+
+    auto const next_change_on_reference_line = [&](Search search = Search::B1) -> ErrorOr<Change> {
+        // 4.2.1.3.1 Definition of changing picture elements
+        Optional<Change> next_change {}; // This is referred to as b1 in the spec.
+        while (!next_change.has_value()) {
+            if (reference_line.is_empty())
+                return Error::from_string_literal("CCITTDecoder: Corrupted stream");
+            auto const change = reference_line.take_first();
+            if (change.column < column)
+                continue;
+            if ((search == Search::B1 && change.color != current_color)
+                || (search == Search::B2 && change.color == current_color))
+                next_change = change;
+        }
+        return *next_change;
+    };
+
+    auto const encode_for = [&](Change change, i8 offset = 0) -> ErrorOr<void> {
+        auto const to_encode = change.column - column + offset;
+        for (u32 i {}; i < to_encode; ++i)
+            TRY(decoded_bits.write_bits(current_color == ccitt_white ? 0u : 1u, 1));
+
+        column += to_encode;
+        current_color = change.color;
+
+        TRY(current_line.try_empend(change.color, change.column + offset));
+        return {};
+    };
+
+    while (column < image_width) {
+        auto const mode = TRY(read_mode(input_bit_stream));
+
+        // Behavior are described here 4.2.1.3.2 Coding modes.
+        switch (mode.mode) {
+        case Mode::Pass:
+            TRY(next_change_on_reference_line(Search::B2));
+            break;
+        case Mode::Horizontal: {
+            // a0a1
+            auto run_length = TRY(read_run_length(input_bit_stream, OptionalNone {}, current_color, image_width, column));
+            TRY(encode_for({ invert(current_color), column + run_length }));
+
+            // a1a2
+            run_length = TRY(read_run_length(input_bit_stream, OptionalNone {}, current_color, image_width, column));
+            TRY(encode_for({ invert(current_color), column + run_length }));
+            break;
+        }
+        case Mode::Vertical_0:
+            TRY(encode_for(TRY(next_change_on_reference_line())));
+            break;
+        case Mode::Vertical_R1:
+            TRY(encode_for(TRY(next_change_on_reference_line()), 1));
+            break;
+        case Mode::Vertical_R2:
+            TRY(encode_for(TRY(next_change_on_reference_line()), 2));
+            break;
+        case Mode::Vertical_R3:
+            TRY(encode_for(TRY(next_change_on_reference_line()), 3));
+            break;
+        case Mode::Vertical_L1:
+            TRY(encode_for(TRY(next_change_on_reference_line()), -1));
+            break;
+        case Mode::Vertical_L2:
+            TRY(encode_for(TRY(next_change_on_reference_line()), -2));
+            break;
+        case Mode::Vertical_L3:
+            TRY(encode_for(TRY(next_change_on_reference_line()), -3));
+            break;
+        default:
+            return Error::from_string_literal("CCITTDecoder: Unsupported mode for 2D decoding");
+        }
+    }
+
+    TRY(decoded_bits.align_to_byte_boundary());
+
+    return current_line;
+}
+
 ErrorOr<void> decode_single_ccitt3_2d_block(BigEndianInputBitStream& input_bit_stream, BigEndianOutputBitStream& decoded_bits, u32 image_width, u32 image_height, Group3Options::UseFillBits use_fill_bits)
 {
     ReferenceLine reference_line;
@@ -420,90 +503,12 @@ ErrorOr<void> decode_single_ccitt3_2d_block(BigEndianInputBitStream& input_bit_s
         TRY(read_eol(input_bit_stream, use_fill_bits));
         bool const next_is_1D = TRY(input_bit_stream.read_bit()) == 1;
 
-        if (next_is_1D) {
+        if (next_is_1D)
             reference_line = TRY(decode_single_ccitt3_1d_line(input_bit_stream, decoded_bits, image_width));
-        } else {
-            ReferenceLine current_line {};
-            Color current_color { ccitt_white };
-            u32 column {};
-
-            auto const next_change_on_reference_line = [&](Search search = Search::B1) -> ErrorOr<Change> {
-                // 4.2.1.3.1 Definition of changing picture elements
-                Optional<Change> next_change {}; // This is referred to as b1 in the spec.
-                while (!next_change.has_value()) {
-                    if (reference_line.is_empty())
-                        return Error::from_string_literal("CCITTDecoder: Corrupted stream");
-                    auto const change = reference_line.take_first();
-                    if (change.column < column)
-                        continue;
-                    if ((search == Search::B1 && change.color != current_color)
-                        || (search == Search::B2 && change.color == current_color))
-                        next_change = change;
-                }
-                return *next_change;
-            };
-
-            auto const encode_for = [&](Change change, i8 offset = 0) -> ErrorOr<void> {
-                auto const to_encode = change.column - column + offset;
-                for (u32 i {}; i < to_encode; ++i)
-                    TRY(decoded_bits.write_bits(current_color == ccitt_white ? 0u : 1u, 1));
-
-                column += to_encode;
-                current_color = change.color;
-
-                TRY(current_line.try_empend(change.color, change.column + offset));
-                return {};
-            };
-
-            while (column < image_width) {
-                auto const mode = TRY(read_mode(input_bit_stream));
-
-                // Behavior are described here 4.2.1.3.2 Coding modes.
-                switch (mode.mode) {
-                case Mode::Pass:
-                    TRY(next_change_on_reference_line(Search::B2));
-                    break;
-                case Mode::Horizontal: {
-                    // a0a1
-                    auto run_length = TRY(read_run_length(input_bit_stream, OptionalNone {}, current_color, image_width, column));
-                    TRY(encode_for({ invert(current_color), column + run_length }));
-
-                    // a1a2
-                    run_length = TRY(read_run_length(input_bit_stream, OptionalNone {}, current_color, image_width, column));
-                    TRY(encode_for({ invert(current_color), column + run_length }));
-                    break;
-                }
-                case Mode::Vertical_0:
-                    TRY(encode_for(TRY(next_change_on_reference_line())));
-                    break;
-                case Mode::Vertical_R1:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), 1));
-                    break;
-                case Mode::Vertical_R2:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), 2));
-                    break;
-                case Mode::Vertical_R3:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), 3));
-                    break;
-                case Mode::Vertical_L1:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), -1));
-                    break;
-                case Mode::Vertical_L2:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), -2));
-                    break;
-                case Mode::Vertical_L3:
-                    TRY(encode_for(TRY(next_change_on_reference_line()), -3));
-                    break;
-                default:
-                    return Error::from_string_literal("CCITTDecoder: Unsupported mode for 2D decoding");
-                }
-            }
-            reference_line = move(current_line);
-        }
+        else
+            reference_line = TRY(decode_single_ccitt_2d_line(input_bit_stream, decoded_bits, move(reference_line), image_width));
     }
 
-    TRY(decoded_bits.align_to_byte_boundary());
-
     return {};
 }