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



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

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



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

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



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/net/rfb/frame_buffer.rb', line 117

def handle_response(t)
  case t
  when 0 # ----------------------------------------------- FramebufferUpdate

    ret = handle_fb_update
    @cb_mutex.synchronize do
      @cb_cv.broadcast
    end
    return ret
  when 1 # --------------------------------------------- SetColourMapEntries

    return handle_set_colormap_entries
  end
end

#pixel_dataObject

raw pixel data of screen



45
46
47
# File 'lib/net/rfb/frame_buffer.rb', line 45

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



107
108
109
110
111
112
113
114
115
# File 'lib/net/rfb/frame_buffer.rb', line 107

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

    if wait_for_response
      @cb_cv.wait
    end
  end
end

#rgba_pixel_dataObject

32bit RGBA pixel data of screen



50
51
52
53
54
# File 'lib/net/rfb/frame_buffer.rb', line 50

def rgba_pixel_data
  px = self.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



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/net/rfb/frame_buffer.rb', line 134

def save_pixel_data_as_png(dest=nil)
  self.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



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/net/rfb/frame_buffer.rb', line 31

def send_initial_data
  # set encoding

  unless self.set_encodings @encodings
    raise 'Error while setting encoding'
  end

  # set pixel format

  self.set_pixel_format @vnc_rec_pix_fmt

  # request all pixel data

  self.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



94
95
96
# File 'lib/net/rfb/frame_buffer.rb', line 94

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



85
86
87
# File 'lib/net/rfb/frame_buffer.rb', line 85

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