Class: VNCRec::RFB::EncZRLE::Stream

Inherits:
Object
  • Object
show all
Defined in:
lib/vncrec/rfb/enczrle.rb

Instance Method Summary collapse

Constructor Details

#initialize(io, bitspp, depth) ⇒ Stream


8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/vncrec/rfb/enczrle.rb', line 8

def initialize(io,bitspp,depth)
  @io = io
  @zstream = Zlib::Inflate.new
  @bpp_orig = (bitspp.to_f/8.0).ceil
  @bpp = case bitspp
         when 32 then 
           @depth <= 24 ? 3 : 4
         when 8 then
           1
         else
           raise "Cannot handle such pixel format"
         end
  @depth = depth
end

Instance Method Details

#handle_ZRLE_packed_palette(stream, psize, tw = 64, th = 64) ⇒ Object


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
184
185
186
187
188
# File 'lib/vncrec/rfb/enczrle.rb', line 151

def handle_ZRLE_packed_palette(stream, psize, tw=64, th=64)
  pixels = Array.new(tw*th, 0)
  bitspp = case psize
           when 2 then 1
           when 3..4 then 2
           when 5..16 then 4
           else 
             return pixels
           end
  palette = []
  psize.times do
    palette << stream.read(@bpp).unpack("C*")
  end
  count = case psize
          when 2 then th*((tw+7)/8)
          when 3..4 then th*((tw+3)/4)
          when 5..16 then th*((tw+1)/2)
          end
  off_bits = 0
  bits_per_row = bitspp * tw
  padding_bits = bits_per_row % 8
  encoded_len_bits = 64 * (bits_per_row + padding_bits)
  encoded = stream.read(count).unpack("C*")
  pixnum = 0
  while off_bits < (encoded_len_bits - padding_bits - bitspp)
    b1 = encoded[off_bits/8]
    b2 = encoded[off_bits/8 + 1] || 0
    b1 <<= 8
    pixels[pixnum] = palette[h_bitmask(b2 + b1, bitspp, off_bits % 16)].pack("C*")
    off_bits += if (off_bits % bits_per_row) > (bits_per_row - padding_bits) and (padding_bits > 0)
                  bitspp + padding_bits
                else
                  bitspp
                end
    pixnum += 1
  end
  pixels
end

#handle_ZRLE_palette_RLE_tile(stream, psize, tw = 64, th = 64) ⇒ Object


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/vncrec/rfb/enczrle.rb', line 92

def handle_ZRLE_palette_RLE_tile(stream,psize,tw=64,th=64)
  palette = []
  pixels = Array.new(tw*th)
  psize.times do
    palette << stream.read(@bpp)
  end
  len = 0
  begin
    while len < tw*th
      id = stream.read(1).unpack("C")[0]
      #
      #+--------+--------+--------+--------+
      #|   id   |   255  |   ..   |  <255  |
      #+--------+--------+--------+--------+
      #
      if (id & 0b10000000) == 0 
        rl = 1
      else
        id -= 128
        rl = 0
        rem = 0
        while (rem = stream.readbyte) == 255
          rl += 255
        end
        rl += rem + 1 
      end
      pixels[len...(len+rl)] = Array.new(rl, palette[id]) #TODO: if rl == 1 
      len += rl
    end
  rescue EOFError
  end
  pixels
end

#handle_ZRLE_plain_RLE_tile(stream, tw = 64, th = 64) ⇒ Object


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/vncrec/rfb/enczrle.rb', line 126

def handle_ZRLE_plain_RLE_tile(stream,tw=64,th=64)
  pixels = Array.new(tw*th)
  len = 0
  begin
    while len < tw*th
      color = stream.read(@bpp)
      #
      #+--------+--------+--------+--------+
      #|  color |   255  |   ..   |  <255  |
      #+--------+--------+--------+--------+
      #
      rl = 0
      rem = 0
      while (rem = stream.readbyte) == 255
        rl += 255
      end
      rl += rem + 1 
      pixels[len...(len+rl)] = Array.new(rl, color) #TODO: if rl == 1 
      len += rl
    end
  rescue EOFError
  end
  pixels
end

#read_rect(w, h) ⇒ Object


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
# File 'lib/vncrec/rfb/enczrle.rb', line 35

def read_rect(w,h)
  fb = Array.new(w*h*@bpp)
  data = ""
  begin
    data = @zstream.inflate(read_zchunk)
  rescue Zlib::DataError
    return
  end

  stream = StringIO.new data

  tile_cols = (w.to_f/64).ceil
  tile_rows = (h.to_f/64).ceil
  tile_cols_rem = w % 64
  tile_rows_rem = h % 64

  tile_rows.times do |tile_row_num|
    tile_cols.times do |tile_col_num|
      th = if ((tile_row_num == tile_rows-1) and (tile_rows_rem > 0)) 
             tile_rows_rem
           else
             64
           end
      tw = if ((tile_col_num == tile_cols-1) and (tile_cols_rem > 0))
             tile_cols_rem 
           else
             64
           end

      subenc = stream.readbyte
      tile = case subenc
             when 0 then 		#Raw
               tile = Array.new(tw*th)
               th.times do
                 tile << (stream.read tw*@bpp_orig).unpack("C*").join
               end
               tile
             when 1 then 		#Solid
               Array.new(tw*th, stream.read(@bpp_orig))
             when 2..16 then 		#Packed palette
               handle_ZRLE_packed_palette(stream, subenc, tw,th)
             when 128 then 		#Plain RLE
               handle_ZRLE_plain_RLE_tile(stream,tw,th)
             when 130..255 then 	#RLE w/ palette
               handle_ZRLE_palette_RLE_tile(stream,subenc-128, tw,th)
             end

      th.times do |y|
        boline = (64 * tile_row_num + y) * w
        offx = 64 * tile_col_num
        fb[(boline+offx)...(boline+offx+tw)] = tile[(tw*y)...(tw*(y+1))]
      end
    end  #tile_col.times
  end#tile_row.times
  return fb.join
end

#read_zchunkObject


23
24
25
26
27
28
29
30
31
32
33
# File 'lib/vncrec/rfb/enczrle.rb', line 23

def read_zchunk
  zdata_len = (@io.readpartial 4).unpack("L>")[0]
  zdata = ""
  to_read = zdata_len

  while zdata.size < zdata_len
    zdata += @io.read(to_read)
    to_read = zdata_len - zdata.size
  end
  return zdata
end