Class: Origami::Filter::LZW

Inherits:
Object
  • Object
show all
Includes:
Origami::Filter
Defined in:
lib/origami/filters/lzw.rb

Overview

Class representing a filter used to encode and decode data with LZW compression algorithm.

Defined Under Namespace

Classes: DecodeParms

Constant Summary collapse

EOD =

:nodoc:

257
CLEARTABLE =

:nodoc:

256

Constants included from Origami::Filter

A85, AHx, CCF, Fl, RL

Instance Method Summary collapse

Methods included from Origami::Filter

included

Constructor Details

#initialize(parameters = {}) ⇒ LZW

Creates a new LZW Filter.

parameters

A hash of filter options (ignored).



59
60
61
# File 'lib/origami/filters/lzw.rb', line 59

def initialize(parameters = {})
  super(DecodeParms.new(parameters))
end

Instance Method Details

#decode(string) ⇒ Object

Decodes given data using LZW compression method.

stream

The data to decode.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/origami/filters/lzw.rb', line 116

def decode(string)
 
  result = ""
  bstring = Utils::BitReader.new(string)
  codesize = 9
  table = clear(Hash.new)
  prevbyte = nil

  until bstring.eod? do
    byte = bstring.read(codesize)

    case table.size
      when 510 then codesize = 10
      when 1022 then codesize = 11
      when 2046 then codesize = 12
      when 4095
        if byte != CLEARTABLE
        then
          raise InvalidLZWDataError.new(
            "LZW table is full and no clear flag was set (codeword #{byte.to_s(2).rjust(codesize,'0')} at bit #{bstring.pos - codesize}/#{bstring.size})",
            result
          )
        end
    end

    if byte == CLEARTABLE
      codesize = 9
      code = EOD
      clear table
      prevbyte = nil
      redo
    elsif byte == EOD
      break
    else
      if prevbyte.nil?
        prevbyte = byte
        result << table.key(byte)
        redo
      else
        raise InvalidLZWDataError.new(
          "No entry for codeword #{prevbyte.to_s(2).rjust(codesize,'0')}.",
          result
        ) unless table.key(prevbyte)

        if table.has_value?(byte)
          entry = table.key(byte)
        else
          entry = table.key(prevbyte)
          entry += entry[0,1]
        end

        result << entry
        table[table.key(prevbyte) + entry[0,1]] = table.size
        prevbyte = byte
      end
    end
  end
 
  if @params.Predictor.is_a?(Integer)
    colors  = @params.Colors.is_a?(Integer) ?  @params.Colors.to_i : 1
    bpc     = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
    columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1

    result = Predictor.do_post_prediction(result, @params.Predictor.to_i, colors, bpc, columns)
  end

  result
end

#encode(string) ⇒ Object

Encodes given data using LZW compression method.

stream

The data to encode.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/origami/filters/lzw.rb', line 67

def encode(string)
  if @params.Predictor.is_a?(Integer)
    colors  = @params.Colors.is_a?(Integer) ?  @params.Colors.to_i : 1
    bpc     = @params.BitsPerComponent.is_a?(Integer) ? @params.BitsPerComponent.to_i : 8
    columns = @params.Columns.is_a?(Integer) ? @params.Columns.to_i : 1

    string = Predictor.do_pre_prediction(string, @params.Predictor.to_i, colors, bpc, columns)
  end       
  
  codesize = 9
  result = Utils::BitWriter.new
  result.write(CLEARTABLE, codesize)
  table = clear({})
  
  s = ''        
  string.each_byte do |byte|
    char = byte.chr
    
    case table.size
      when 512 then codesize = 10
      when 1024 then codesize = 11
      when 2048 then codesize = 12
      when 4096
        result.write(CLEARTABLE, codesize)
        codesize = 9
        clear table
        redo
    end
   
    it = s + char
    if table.has_key?(it)
      s = it
    else
      result.write(table[s], codesize)
      table[it] = table.size
      s = char
    end
  end
   
  result.write(table[s], codesize)
  result.write(EOD, codesize)
  
  result.final.to_s
end