Class: PNGlitch::Scanline

Inherits:
Object
  • Object
show all
Defined in:
lib/pnglitch/scanline.rb

Overview

Scanline is the class that represents a particular PNG image scanline.

It consists of a filter type and a filtered pixel data.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io, start_at, data_size, at, &block) ⇒ Scanline

Instanciate.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/pnglitch/scanline.rb', line 14

def initialize io, start_at, data_size, at, &block
  @index = at
  @io = io
  @start_at = start_at
  @data_size = data_size

  pos = @io.pos
  @io.pos = @start_at
  @filter_type = @io.read(1).unpack('C').first
  @io.pos = pos

  @data = nil
  @prev_filter_type = nil
  @filter_codec = { encoder: nil, decoder: nil }

  if block_given?
    @callback = block
  end
end

Instance Attribute Details

#filter_codecObject (readonly)

Returns the value of attribute filter_codec.



9
10
11
# File 'lib/pnglitch/scanline.rb', line 9

def filter_codec
  @filter_codec
end

#filter_typeObject (readonly)

Returns the value of attribute filter_type.



9
10
11
# File 'lib/pnglitch/scanline.rb', line 9

def filter_type
  @filter_type
end

#indexObject (readonly)

Returns the value of attribute index.



9
10
11
# File 'lib/pnglitch/scanline.rb', line 9

def index
  @index
end

#prev_filter_typeObject (readonly)

Returns the value of attribute prev_filter_type.



9
10
11
# File 'lib/pnglitch/scanline.rb', line 9

def prev_filter_type
  @prev_filter_type
end

Instance Method Details

#change_filter(new_filter) ⇒ Object Also known as: filter_type=

Replace the filter type with new_filter, and it will compute the filters again.

This operation will be a legal way to change filter types.



85
86
87
88
89
# File 'lib/pnglitch/scanline.rb', line 85

def change_filter new_filter
  @prev_filter_type = @filter_type
  @filter_type = new_filter
  self.save
end

#dataObject

Returns data of the scanline.



37
38
39
40
41
42
43
44
45
# File 'lib/pnglitch/scanline.rb', line 37

def data
  if @data.nil?
    pos = @io.pos
    @io.pos = @start_at + 1
    @data = @io.read @data_size
    @io.pos = pos
  end
  @data
end

#graft(new_filter) ⇒ Object

Replace the filter type with new_filter, and it will not compute the filters again.

It means the scanline might get wrong filter type. It will be the efficient way to break the PNG image.



75
76
77
78
# File 'lib/pnglitch/scanline.rb', line 75

def graft new_filter
  @filter_type = new_filter
  save
end

#gsub!(pattern, replacement) ⇒ Object

Replaces data with given Regexp pattern and replacement.

It is same as scanline.replace_data(scanline.data.gsub(pattern, replacement)). When the data size has changed, the data will be chopped or padded with null string in original size.



54
55
56
# File 'lib/pnglitch/scanline.rb', line 54

def gsub! pattern, replacement
  self.replace_data self.data.gsub(pattern, replacement)
end

#register_filter_decoder(decoder = nil, &block) ⇒ Object

Registers a custom filter function to decode data.

With this operation, it will be able to change filter decoding behavior despite the specified filter type value. It takes a Proc object or a block.



112
113
114
115
116
117
118
119
# File 'lib/pnglitch/scanline.rb', line 112

def register_filter_decoder decoder = nil, &block
  if !decoder.nil? && decoder.is_a?(Proc)
    @filter_codec[:decoder] = decoder
  elsif block_given?
    @filter_codec[:decoder] = block
  end
  save
end

#register_filter_encoder(encoder = nil, &block) ⇒ Object

Registers a custom filter function to encode data.

With this operation, it will be able to change filter encoding behavior despite the specified filter type value. It takes a Proc object or a block.



97
98
99
100
101
102
103
104
# File 'lib/pnglitch/scanline.rb', line 97

def register_filter_encoder encoder = nil, &block
  if !encoder.nil? && encoder.is_a?(Proc)
    @filter_codec[:encoder] = encoder
  elsif block_given?
    @filter_codec[:encoder] = block
  end
  save
end

#replace_data(new_data) ⇒ Object Also known as: data=

Replace the data with new_data.

When its size has changed, the data will be chopped or padded with null string in original size.



64
65
66
67
# File 'lib/pnglitch/scanline.rb', line 64

def replace_data new_data
  @data = new_data
  save
end

#saveObject

Save the changes.



124
125
126
127
128
129
130
131
132
# File 'lib/pnglitch/scanline.rb', line 124

def save
  pos = @io.pos
  @io.pos = @start_at
  @io << [Filter.guess(@filter_type)].pack('C')
  @io << self.data.slice(0, @data_size).ljust(@data_size, "\0")
  @io.pos = pos
  @callback.call(self) unless @callback.nil?
  self
end