Class: Net::RFB::FrameBuffer

Inherits:
Object
  • Object
show all
Defined in:
lib/net/rfb/frame_buffer.rb

Overview

Manage FrameBuffer pixel data for RFB protocol This is a little wrapper for the ‘Proxy` class in vncrec-ruby github.com/d-theus/vncrec-ruby

Defined Under Namespace

Classes: VNCRecAuthStub

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io, w, h, bpp, encodings = nil) ⇒ FrameBuffer

Returns a new instance of FrameBuffer.

Parameters:

  • io (IO, #read, #sysread, #syswrite, #read_nonblock)

    string stream from VNC server.

  • w (Integer)

    width of the screen area

  • h (Integer)

    height of the screen area

  • bpp (Symbol)

    bits per pixel (BGR8 or BGRA)

  • encodings (Array<Symbol>) (defaults to: nil)

    encoding (RAW or HEXTILE or ZRLE) default: RAW



17
18
19
20
21
22
23
24
25
26
27
# File 'lib/net/rfb/frame_buffer.rb', line 17

def initialize(io, w, h, bpp, encodings = nil)
  @cb_mutex = Monitor.new
  @cb_cv = @cb_mutex.new_cond

  @encodings = encodings

  @vnc_rec_pix_fmt = convert_to_vnc_rec_pix_fmt bpp

  @proxy = VNCRec::RFB::Proxy.new(io, nil, nil, nil, [VNCRecAuthStub, nil])
  @proxy.prepare_framebuffer w, h, @vnc_rec_pix_fmt[:bpp]
end

Class Method Details

.convert_raw_pixel_data_to_rgba(px, pix_fmt) ⇒ Array<Integer>

convert raw pixel data to 32bit RGBA values according to VNC pixel format

Parameters:

  • px (String)

    binary pixel data

  • pix_fmt (String)

    pixel format (bgra, bgr8)

Returns:

  • (Array<Integer>)

    array of 32bit pixel data



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/net/rfb/frame_buffer.rb', line 57

def self.convert_raw_pixel_data_to_rgba(px, pix_fmt)
  # see https://github.com/d-theus/vncrec-ruby/blob/master/lib/vncrec/constants.rb
  case pix_fmt.to_s
  when 'bgra'
    # convert 32bit BGRA -> 32bit RGBA
    px = px.unpack('V*')
    px.map! { |p| (p << 8) | 0xff }
  when 'bgr8'
    # convert 8bit BGR -> 32bit RGBA
    px = px.unpack('C*')
    px.map! do |p|
      r = (p & 0b00000111)
      g = (p & 0b00111000) >> 3
      b = (p & 0b11000000) >> 6
      ((r * 36) << 24) | ((g * 36) << 16) | ((b * 85) << 8) | 0xff
    end
  else
    raise "unknown pixel format #{pix_fmt.inspect}"
  end
end

Instance Method Details

#handle_response(t) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/net/rfb/frame_buffer.rb', line 112

def handle_response(t)
  case t
  when 0 # ----------------------------------------------- FramebufferUpdate
    ret = handle_fb_update
    @cb_mutex.synchronize do
      @cb_cv.broadcast
    end
    ret
  when 1 # --------------------------------------------- SetColourMapEntries
    handle_set_colormap_entries
  end
end

#pixel_dataObject

raw pixel data of screen



41
42
43
# File 'lib/net/rfb/frame_buffer.rb', line 41

def pixel_data
  @proxy.data
end

#request_update_fb(incremental: true, x: nil, y: nil, w: nil, h: nil, wait_for_response: false) ⇒ Object

Send request for update framebuffer.

if block given, called it with pixel data after the response received.

Parameters:

  • incremental (Boolean) (defaults to: true)

    incremental, request just difference between previous and current framebuffer state.

  • x (Integer) (defaults to: nil)
  • y (Integer) (defaults to: nil)
  • w (Integer) (defaults to: nil)
  • h (Integer) (defaults to: nil)
  • wait_for_response (Boolean) (defaults to: false)

    if true, wait for a FramebufferUpdate response



104
105
106
107
108
109
110
# File 'lib/net/rfb/frame_buffer.rb', line 104

def request_update_fb(incremental: true, x: nil, y: nil, w: nil, h: nil, wait_for_response: false)
  @cb_mutex.synchronize do
    @proxy.fb_update_request incremental ? 1 : 0, x || 0, y || 0, w || @proxy.w, h || @proxy.h

    @cb_cv.wait if wait_for_response
  end
end

#rgba_pixel_dataObject

32bit RGBA pixel data of screen



46
47
48
49
50
51
# File 'lib/net/rfb/frame_buffer.rb', line 46

def rgba_pixel_data
  px = pixel_data
  raise 'Error in get raw pixel_data.' unless px

  self.class.convert_raw_pixel_data_to_rgba px, @vnc_rec_pix_fmt[:string]
end

#save_pixel_data_as_png(dest = nil) ⇒ String

save current screen pixel data as PNG image

Parameters:

  • dest (String|IO|nil) (defaults to: nil)

    destination file path, or IO-object, or nil

Returns:

  • (String)

    PNG binary data as string when dest is null

    true

    else case



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/net/rfb/frame_buffer.rb', line 129

def save_pixel_data_as_png(dest = nil)
  request_update_fb(wait_for_response: true)

  image = ChunkyPNG::Image.new(@proxy.w, @proxy.h, rgba_pixel_data)

  if dest.is_a? IO
    # write to IO-object
    image.write dest
  elsif dest.is_a?(String) || dest.is_a?(Pathname)
    # write to file
    image.save dest.to_s
  elsif dest.nil?
    # return binary data as string
    return image.to_blob
  else
    raise ArgumentError, "Unsupported destination type #{dest.inspect}"
  end
  true
end

#send_initial_dataObject



29
30
31
32
33
34
35
36
37
38
# File 'lib/net/rfb/frame_buffer.rb', line 29

def send_initial_data
  # set encoding
  raise 'Error while setting encoding' unless set_encodings @encodings

  # set pixel format
  set_pixel_format @vnc_rec_pix_fmt

  # request all pixel data
  request_update_fb incremental: false
end

#set_encodings(*encodings) ⇒ Object

Set way of encoding video frames.

Parameters:

  • encodings (Symbol|String)

    list of encoding of video data used to transfer.

    • :RAW

    • :HEXTILE

    • :ZRLE



91
92
93
# File 'lib/net/rfb/frame_buffer.rb', line 91

def set_encodings(*encodings)
  @proxy.set_encodings [encodings].flatten.compact.map { |sym| VNCRec.const_get "ENC_#{sym}" }
end

#set_pixel_format(format) ⇒ Object

Set a way that server should use to represent pixel data

Parameters:

  • pixel (Symbol|String)

    format:

    • :BGR8

    • :BGRA



82
83
84
# File 'lib/net/rfb/frame_buffer.rb', line 82

def set_pixel_format(format)
  @proxy.set_pixel_format convert_to_vnc_rec_pix_fmt(format)
end