class Origami::Filter::CCF

Class representing a Filter used to encode and decode data with CCITT-facsimile compression algorithm.

Constants

BLACK_CONFIGURATION_DECODE_TABLE
BLACK_CONFIGURATION_ENCODE_TABLE
BLACK_TERMINAL_DECODE_TABLE
BLACK_TERMINAL_ENCODE_TABLE
EOL
RTC
WHITE_CONFIGURATION_DECODE_TABLE
WHITE_CONFIGURATION_ENCODE_TABLE
WHITE_TERMINAL_DECODE_TABLE
WHITE_TERMINAL_ENCODE_TABLE

Public Class Methods

new(parameters = {}) click to toggle source

Creates a new CCITT Fax Filter.

Calls superclass method Origami::Filter::new
# File lib/origami/filters/ccitt.rb, line 58
def initialize(parameters = {})
    super(DecodeParms.new(parameters))
end

Public Instance Methods

decode(stream) click to toggle source

Decodes data using CCITT-facsimile compression method.

# File lib/origami/filters/ccitt.rb, line 117
def decode(stream)
    mode = @params.key?(:K) ? @params.K.value : 0

    unless mode.is_a?(::Integer) and mode <= 0
        raise NotImplementedError.new("CCITT encoding scheme not supported", input_data: stream)
    end

    columns = @params.has_key?(:Columns) ? @params.Columns.value : 1728
    unless columns.is_a?(::Integer) and columns >= 0
        raise CCITTFaxFilterError.new("Invalid value for parameter `Columns'", input_data: stream)
    end

    colors = (@params.BlackIs1 == true) ? [0,1] : [1,0]
    white, _black = colors
    params =
    {
        is_aligned?: (@params.EncodedByteAlign == true),
        has_eob?: (@params.EndOfBlock.nil? or @params.EndOfBlock == true),
        has_eol?: (@params.EndOfLine == true)
    }

    unless params[:has_eob?]
        rows = @params.key?(:Rows) ? @params.Rows.value : 0

        unless rows.is_a?(::Integer) and rows >= 0
            raise CCITTFaxFilterError.new("Invalid value for parameter `Rows'", input_data: stream)
        end
    end

    bitr = Utils::BitReader.new(stream)
    bitw = Utils::BitWriter.new

    # Group 4 requires an imaginary white line
    if columns > 0 and mode < 0
        prev_line = Utils::BitWriter.new
        write_bit_range(prev_line, white, columns)
        prev_line = Utils::BitReader.new(prev_line.final.to_s)
    end

    until bitr.eod? or rows == 0
        # realign the read line on a 8-bit boundary if required
        if params[:is_aligned?] and bitr.pos % 8 != 0
            bitr.pos += 8 - (bitr.pos % 8)
        end

        # received return-to-control code
        if params[:has_eob?] and bitr.peek(RTC[1]) == RTC[0]
            bitr.pos += RTC[1]
            break
        end

        break if columns == 0

        # checking for the presence of EOL
        if bitr.peek(EOL[1]) != EOL[0]
            raise InvalidCCITTFaxDataError.new(
                    "No end-of-line pattern found (at bit pos #{bitr.pos}/#{bitr.size}})",
                    input_data: stream,
                    decoded_data: bitw.final.to_s
            ) if params[:has_eol?]
        else
            bitr.pos += EOL[1]
        end

        begin
            case
            when mode == 0
                decode_one_dimensional_line(bitr, bitw, columns, colors)
            when mode < 0
                decode_two_dimensional_line(bitr, bitw, columns, colors, prev_line)
            end
        rescue DecodeError => error
            error.input_data = stream
            error.decoded_data = bitw.final.to_s

            raise error
        end

        rows -= 1 unless params[:has_eob?]
    end

    bitw.final.to_s
end
encode(stream) click to toggle source

Encodes data using CCITT-facsimile compression method.

# File lib/origami/filters/ccitt.rb, line 65
def encode(stream)
    mode = @params.key?(:K) ? @params.K.value : 0
    colors = (@params.BlackIs1 == true) ? [0,1] : [1,0]
    use_eob = (@params.EndOfBlock.nil? or @params.EndOfBlock == true)
    use_eol = (@params.EndOfLine == true)
    white, _black = colors

    bitr = Utils::BitReader.new(stream)
    bitw = Utils::BitWriter.new

    unless mode.is_a?(::Integer) and mode <= 0
        raise NotImplementedError.new("CCITT encoding scheme not supported", input_data: stream)
    end

    # Use a single row if no width has been set.
    @params[:Columns] ||= stream.size * 8
    columns = @params.Columns.value

    unless columns.is_a?(::Integer) and columns >= 0
        raise CCITTFaxFilterError.new("Invalid value for parameter `Columns'", input_data: stream)
    end

    if columns > 0
        # Group 4 requires an imaginary white line
        if mode < 0
            prev_line = Utils::BitWriter.new
            write_bit_range(prev_line, white, columns)
            prev_line = Utils::BitReader.new(prev_line.final.to_s)
        end

        until bitr.eod?
            # Emit line synchronization code.
            bitw.write(*EOL) if use_eol

            case
            when mode == 0
                encode_one_dimensional_line(bitr, bitw, columns, colors)
            when mode < 0
                encode_two_dimensional_line(bitr, bitw, columns, colors, prev_line)
            end
        end
    end

    # Emit return-to-control code.
    bitw.write(*RTC) if use_eob

    bitw.final.to_s
end

Private Instance Methods

lookup_bits(table, codeword, length) click to toggle source
# File lib/origami/filters/ccitt.rb, line 311
def lookup_bits(table, codeword, length)
    table.rassoc [codeword, length]
end