Module: ZSteg::Extractor::ByteExtractor

Included in:
ZSteg::Extractor
Defined in:
lib/zsteg/extractor/byte_extractor.rb

Overview

ByteExtractor extracts bits from each scanline bytes actual for BMP+wbStego combination

Instance Method Summary collapse

Instance Method Details

#byte_extract(params = {}) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/zsteg/extractor/byte_extractor.rb', line 8

def byte_extract params = {}
  bidxs = bit_indexes params[:bits]

  if params[:prime]
    pregenerate_primes(
      :max   => @image.scanlines[0].size * @image.height,
      :count => (@limit*8.0/bidxs.size).ceil
    )
  end

  data = ''.force_encoding('binary')
  a = [0]*params[:shift].to_i        # prepend :shift zero bits
  byte_iterator(params) do |x,y|
    sl = @image.scanlines[y]

    value = sl.decoded_bytes.getbyte(x)
    bidxs.each do |bidx|
      a << value[bidx]
    end

    if a.size >= 8
      byte = 0
      if params[:bit_order] == :msb
        8.times{ |i| byte |= (a.shift<<i)}
      else
        8.times{ |i| byte |= (a.shift<<(7-i))}
      end
      data << byte.chr
      #a = []
      if data.size >= @limit
        print "[limit #@limit]".gray if @verbose > 1
        break
      end
    end
  end
  if params[:strip_tail_zeroes] != false && data[-1,1] == "\x00"
    oldsz = data.size
    data.sub!(/\x00+\Z/,'')
    print "[zerotail #{oldsz-data.size}]".gray if @verbose > 1
  end
  data
end

#byte_iterator(params) ⇒ Object

‘xy’: b=0,y=0; b=1,y=0; b=2,y=0; … ‘yx’: b=0,y=0; b=0,y=1; b=0,y=2; … … ‘xY’: b=0, y=MAX; b=1, y=MAX; b=2, y=MAX; … ‘XY’: b=MAX,y=MAX; b=MAX-1,y=MAX; b=MAX-2,y=MAX; …



56
57
58
59
60
61
62
63
64
65
66
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/zsteg/extractor/byte_extractor.rb', line 56

def byte_iterator params
  type = params[:order]
  if type.nil? || type == 'auto'
    type = @image.format == :bmp ? 'bY' : 'by'
  end
  raise "invalid iterator type #{type}" unless type =~ /\A(by|yb)\Z/i

  sl0 = @image.scanlines.first

  # XXX don't try to run it on interlaced PNGs!
  x0,x1,xstep =
    if type.index('b')
      [0, sl0.decoded_bytes.size-1, 1]
    else
      [sl0.decoded_bytes.size-1, 0, -1]
    end

  y0,y1,ystep =
    if type.index('y')
      [0, @image.height-1, 1]
    else
      [@image.height-1, 0, -1]
    end

  xstep *= params[:step] if params[:step]
  ystep *= params[:ystep] if params[:ystep]

  # cannot join these lines from ByteExtractor and ColorExtractor into
  # one method for performance reason:
  #   it will require additional yield() for EACH BYTE iterated

  if type[0,1].downcase == 'b'
    # ROW iterator (natural)
    if params[:prime]
      idx = 0
      y0.step(y1,ystep){ |y| x0.step(x1,xstep){ |x|
        yield(x,y) if @primes.include?(idx)
        idx += 1
      }}
    else
      y0.step(y1,ystep){ |y| x0.step(x1,xstep){ |x| yield(x,y) }}
    end
  else
    # COLUMN iterator
    if params[:prime]
      idx = 0
      x0.step(x1,xstep){ |x| y0.step(y1,ystep){ |y|
        yield(x,y) if @primes.include?(idx)
        idx += 1
      }}
    else
      x0.step(x1,xstep){ |x| y0.step(y1,ystep){ |y| yield(x,y) }}
    end
  end
end