void NegotiateDesktop() { byte shareDesktopSetting = _c.ReceiveByte();//是否同意分享屏幕 bool shareDesktop = shareDesktopSetting != 0; var e = new CreatingDesktopEventArgs(shareDesktop); OnCreatingDesktop(e); var fbSource = _fbSource; Framebuffer = fbSource != null?fbSource.Capture() : null; VncStream.Require(Framebuffer != null, "No framebuffer. Make sure you've called SetFramebufferSource. It can be set to a VncFramebuffer.", VncFailureReason.SanityCheckFailed); _clientPixelFormat = Framebuffer.PixelFormat; _clientWidth = Framebuffer.Width; _clientHeight = Framebuffer.Height; _fbuAutoCache = null; _c.SendUInt16BE((ushort)Framebuffer.Width); _c.SendUInt16BE((ushort)Framebuffer.Height); var pixelFormat = new byte[VncPixelFormat.Size]; Framebuffer.PixelFormat.Encode(pixelFormat, 0); _c.Send(pixelFormat); _c.SendString(Framebuffer.Name, true); }
/// <inheritdoc/> public void FramebufferManualInvalidate(VncRectangle region) { var fb = this.Framebuffer; var cpf = this.clientPixelFormat; region = VncRectangle.Intersect(region, new VncRectangle(0, 0, this.clientWidth, this.clientHeight)); if (region.IsEmpty) { return; } int x = region.X, y = region.Y, w = region.Width, h = region.Height, bpp = cpf.BytesPerPixel; var contents = new byte[w * h * bpp]; VncPixelFormat.Copy( fb.GetBuffer(), fb.Width, fb.Stride, fb.PixelFormat, region, contents, w, w * bpp, cpf); this.AddRegion(region, VncEncoding.Raw, contents); }
private void NegotiateDesktop() { this.logger?.Log(LogLevel.Info, () => "Negotiating desktop settings"); byte shareDesktopSetting = this.c.ReceiveByte(); bool shareDesktop = shareDesktopSetting != 0; var e = new CreatingDesktopEventArgs(shareDesktop); this.OnCreatingDesktop(e); var fbSource = this.fbSource; this.Framebuffer = fbSource != null?fbSource.Capture() : null; VncStream.Require( this.Framebuffer != null, "No framebuffer. Make sure you've called SetFramebufferSource. It can be set to a VncFramebuffer.", VncFailureReason.SanityCheckFailed); this.clientPixelFormat = this.Framebuffer.PixelFormat; this.clientWidth = this.Framebuffer.Width; this.clientHeight = this.Framebuffer.Height; this.fbuAutoCache = null; this.c.SendUInt16BE((ushort)this.Framebuffer.Width); this.c.SendUInt16BE((ushort)this.Framebuffer.Height); var pixelFormat = new byte[VncPixelFormat.Size]; this.Framebuffer.PixelFormat.Encode(pixelFormat, 0); this.c.Send(pixelFormat); this.c.SendString(this.Framebuffer.Name, true); this.logger?.Log(LogLevel.Info, () => $"The desktop {this.Framebuffer.Name} has initialized with pixel format {this.clientPixelFormat}; the screen size is {this.clientWidth}x{this.clientHeight}"); }
/// <summary> /// Copies a region of the framebuffer into a bitmap. /// </summary> /// <param name="source">The framebuffer to read.</param> /// <param name="sourceRectangle">The framebuffer region to copy.</param> /// <param name="target">The bitmap to copy into.</param> /// <param name="targetX">The leftmost X coordinate of the bitmap to draw to.</param> /// <param name="targetY">The topmost Y coordinate of the bitmap to draw to.</param> public unsafe static void CopyFromFramebuffer(VncFramebuffer source, VncRectangle sourceRectangle, Bitmap target, int targetX, int targetY) { Throw.If.Null(source, "source").Null(target, "target"); if (sourceRectangle.IsEmpty) { return; } var winformsRect = new Rectangle(targetX, targetY, sourceRectangle.Width, sourceRectangle.Height); var data = target.LockBits(winformsRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); try { fixed(byte *framebufferData = source.GetBuffer()) { VncPixelFormat.Copy((IntPtr)framebufferData, source.Stride, source.PixelFormat, sourceRectangle, data.Scan0, data.Stride, new VncPixelFormat()); } } finally { target.UnlockBits(data); } }
public void DecodeTest() { var buffer = new byte[] { 32, 24, 0, 1, 0, 255, 0, 255, 0, 255, 16, 8, 0, 0, 0, 0 }; var pixelFormat = VncPixelFormat.Decode(buffer, 0); Assert.Equal(VncPixelFormat.RGB32, pixelFormat); }
/// <summary> /// 将需要更新位图的区域复制到framebuffer中 /// </summary> /// <param name="source">图片源.</param> /// <param name="sourceRectangle">要复制的位图区域.</param> /// <param name="target">目标帧缓冲区</param> /// <param name="targetX">帧缓冲区的左顶点X坐标</param> /// <param name="targetY">帧缓冲区的左顶点Y坐标</param> public unsafe static void CopyToFramebuffer(Bitmap source, VncRectangle sourceRectangle, VncFramebuffer target, int targetX, int targetY) { Throw.If.Null(source, "source").Null(target, "target"); if (sourceRectangle.IsEmpty) { return; } var winformsRect = new Rectangle(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height); var data = source.LockBits(winformsRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); try { fixed(byte *framebufferData = target.GetBuffer()) { VncPixelFormat.Copy(data.Scan0, data.Stride, new VncPixelFormat(32, 24, 8, 16, 8, 8, 8, 0), sourceRectangle, (IntPtr)framebufferData, target.Stride, target.PixelFormat, targetX, targetY); } } finally { source.UnlockBits(data); } }
void HandleSetPixelFormat() { _c.Receive(3); var pixelFormat = _c.Receive(VncPixelFormat.Size); _clientPixelFormat = VncPixelFormat.Decode(pixelFormat, 0); }
private void HandleSetPixelFormat() { this.c.Receive(3); var pixelFormat = this.c.Receive(VncPixelFormat.Size); this.clientPixelFormat = VncPixelFormat.Decode(pixelFormat, 0); }
private void UpdateServerFormat(VncPixelFormat pixelFormat) { var serverFormat = this.server.ServerFormat; serverFormat.RedShift = (byte)pixelFormat.RedShift; serverFormat.GreenShift = (byte)pixelFormat.GreenShift; serverFormat.BlueShift = (byte)pixelFormat.BlueShift; this.server.ServerFormat = serverFormat; }
public bool RespondToUpdateRequest(VncServerSession session) { var fb = Framebuffer; var fbr = session.FramebufferUpdateRequest; if (fb == null || fbr == null) { return(false); } var incremental = fbr.Incremental; var region = fbr.Region; session.FramebufferManualBeginUpdate(); var buffer = fb.GetBuffer(); int bpp = fb.PixelFormat.BytesPerPixel; lock (fb.SyncRoot) { int ymax = Math.Min(region.Y + region.Height, fb.Height); int xmax = Math.Min(region.X + region.Width, fb.Width); for (int y = region.Y; y < ymax; y += TileSize) { for (int x = region.X; x < xmax; x += TileSize) { int w = Math.Min(TileSize, xmax - x); int h = Math.Min(TileSize, ymax - y); var subregion = new VncRectangle(x, y, w, h); VncPixelFormat.Copy(buffer, fb.Stride, fb.PixelFormat, subregion, _pixelBuffer, w * bpp, Framebuffer.PixelFormat); int ix = x / TileSize, iy = y / TileSize; var tileHash = _hash.ComputeHash(_pixelBuffer, 0, w * h * bpp); if (_hashes[iy, ix] == null || !_hashes[iy, ix].SequenceEqual(tileHash)) { _hashes[iy, ix] = tileHash; if (incremental) { session.FramebufferManualInvalidate(subregion); } } } } } if (!incremental) { session.FramebufferManualInvalidate(region); } return(session.FramebufferManualEndUpdate()); }
public void EncodeTest() { var pixelFormat = new VncPixelFormat(); var buffer = new byte[VncPixelFormat.Size]; pixelFormat.Encode(buffer, 0); var expected = new byte[] { 32, 24, 0, 1, 0, 255, 0, 255, 0, 255, 16, 8, 0, 0, 0, 0 }; Assert.Equal(expected, buffer); }
/// <inheritdoc/> public override void Send(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents) { this.buffer.SetLength(0); this.deflater.Write(contents, 0, contents.Length); this.deflater.Flush(); this.buffer.Position = 0; byte[] length = new byte[4]; VncUtility.EncodeUInt32BE(length, 0, (uint)this.buffer.Length); stream.Write(length, 0, 4); this.buffer.CopyTo(stream); }
/// <inheritdoc/> public void FramebufferManualInvalidate(VncRectangle region) { var fb = this.Framebuffer; var cpf = this.clientPixelFormat; region = VncRectangle.Intersect(region, new VncRectangle(0, 0, this.clientWidth, this.clientHeight)); if (region.IsEmpty) { return; } int x = region.X, y = region.Y, w = region.Width, h = region.Height, bpp = cpf.BytesPerPixel; var contents = new byte[w * h * bpp]; VncPixelFormat.Copy( fb.GetBuffer(), fb.Width, fb.Stride, fb.PixelFormat, region, contents, w, w * bpp, cpf); #if DEFLATESTREAM_FLUSH_WORKS if (_clientEncoding.Contains(VncEncoding.Zlib)) { _zlibMemoryStream.Position = 0; _zlibMemoryStream.SetLength(0); _zlibMemoryStream.Write(new byte[4], 0, 4); if (_zlibDeflater == null) { _zlibMemoryStream.Write(new[] { (byte)120, (byte)218 }, 0, 2); _zlibDeflater = new DeflateStream(_zlibMemoryStream, CompressionMode.Compress, false); } _zlibDeflater.Write(contents, 0, contents.Length); _zlibDeflater.Flush(); contents = _zlibMemoryStream.ToArray(); VncUtility.EncodeUInt32BE(contents, 0, (uint)(contents.Length - 4)); AddRegion(region, VncEncoding.Zlib, contents); } else #endif { this.AddRegion(region, VncEncoding.Raw, contents); } }
/// <summary> /// Copies a region of a bitmap into the framebuffer. /// </summary> /// <param name="source">The bitmap to read.</param> /// <param name="sourceRectangle">The bitmap region to copy.</param> /// <param name="target">The framebuffer to copy into.</param> /// <param name="targetX">The leftmost X coordinate of the framebuffer to draw to.</param> /// <param name="targetY">The topmost Y coordinate of the framebuffer to draw to.</param> public static unsafe void CopyToFramebuffer( Bitmap source, VncRectangle sourceRectangle, VncFramebuffer target, int targetX, int targetY) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (sourceRectangle.IsEmpty) { return; } var winformsRect = new Rectangle(sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height); var data = source.LockBits(winformsRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); try { fixed(byte *framebufferData = target.GetBuffer()) { VncPixelFormat.Copy( data.Scan0, data.Stride, new VncPixelFormat(), sourceRectangle, (IntPtr)framebufferData, target.Stride, target.PixelFormat, targetX, targetY); } } finally { source.UnlockBits(data); } }
/// <summary> /// Sends a rectangle using JPEG compression. /// </summary> /// <param name="stream"> /// The <see cref="Stream"/> which represents connectivity with the client. /// </param> /// <param name="pixelFormat"> /// The pixel format to use. This must be <see cref="VncPixelFormat.RGB32"/>. /// </param> /// <param name="region"> /// The rectangle to send. /// </param> /// <param name="contents"> /// A buffer holding the raw pixel data for the rectangle. /// </param> /// <param name="jpegQualityLevel"> /// The JPEG quality level to use. /// </param> protected int SendWithJpegCompression(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents, int jpegQualityLevel) { var subsamplingOption = TJSubsamplingOption.Chrominance420; var size = this.compressor.GetBufferSize(region.Width, region.Height, subsamplingOption) + 5; byte[] buffer = null; try { // The first 5 bytes will hold the compression control byte and the size of the // JPEG buffer. buffer = ArrayPool <byte> .Shared.Rent(size); var qualityLevel = GetQualityLevel(this.VncServerSession); var jpeg = this.compressor.Compress( contents.AsSpan(), buffer.AsSpan(5), 0, /* auto-calculate pitch */ region.Width, region.Height, TJPixelFormat.BGRA, subsamplingOption, jpegQualityLevel, TJFlags.NoRealloc); // Write the JPEG compression control byte and the size of the JPEG buffer. buffer[0] = (byte)TightCompressionControl.JpegCompression; var length = WriteEncodedValue(buffer, 1, jpeg.Length); stream.Write(buffer, 0, length); stream.Write(buffer, 5, jpeg.Length); return(jpeg.Length + 5); } finally { if (buffer != null) { ArrayPool <byte> .Shared.Return(buffer); } } }
/// <inheritdoc/> public override int Send(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents) { var jpegQualityLevel = GetQualityLevel(this.VncServerSession); // The JPEG compression currently assumes a RGB32 pixel format, fall back to basic compression // when this pixel format is not available. // Additionally, a minimal JPEG image is at least ~128 bytes in size, so only compress to JPEG // when the uncompressed file significantly larger. if (this.Compression != TightCompression.Jpeg || !VncPixelFormat.RGB32.Equals(pixelFormat) || region.IsEmpty || contents.Length < 256 || jpegQualityLevel == 0) { return(this.SendWithBasicCompression(stream, pixelFormat, region, contents)); } else { return(this.SendWithJpegCompression(stream, pixelFormat, region, contents, jpegQualityLevel)); } }
/// <inheritdoc/> public void FramebufferManualInvalidate(VncRectangle region) { var fb = this.Framebuffer; var cpf = this.clientPixelFormat; region = VncRectangle.Intersect(region, new VncRectangle(0, 0, this.clientWidth, this.clientHeight)); if (region.IsEmpty) { return; } int x = region.X, y = region.Y, w = region.Width, h = region.Height, bpp = cpf.BytesPerPixel; var contents = new byte[w * h * bpp]; VncPixelFormat.Copy( fb.GetBuffer(), fb.Width, fb.Stride, fb.PixelFormat, region, contents, w, w * bpp, cpf); if (clientEncoding.Contains(VncEncoding.Zlib)) { byte[] zlibContents = Compress(contents); var lenArray = new byte[4]; VncUtility.EncodeUInt32BE(lenArray, 0, (uint)(zlibContents.Length)); var finArray = Combine(lenArray, zlibContents); AddRegion(region, VncEncoding.Zlib, finArray); } else { this.AddRegion(region, VncEncoding.Raw, contents); } }
public void ConstructorTest() { // Default pixel format should be RGB32. var pixelFormat = new VncPixelFormat(); Assert.Equal(24, pixelFormat.BitDepth); Assert.Equal(32, pixelFormat.BitsPerPixel); Assert.Equal(4, pixelFormat.BytesPerPixel); Assert.True(pixelFormat.IsLittleEndian); Assert.False(pixelFormat.IsPalettized); Assert.Equal(8, pixelFormat.BlueBits); Assert.Equal(255, pixelFormat.BlueMax); Assert.Equal(0, pixelFormat.BlueShift); Assert.Equal(8, pixelFormat.GreenBits); Assert.Equal(255, pixelFormat.GreenMax); Assert.Equal(8, pixelFormat.GreenShift); Assert.Equal(8, pixelFormat.RedBits); Assert.Equal(255, pixelFormat.RedMax); Assert.Equal(16, pixelFormat.RedShift); }
/// <summary> /// Copies a region of the framebuffer into a bitmap. /// </summary> /// <param name="source">The framebuffer to read.</param> /// <param name="sourceRectangle">The framebuffer region to copy.</param> /// <param name="target">The bitmap to copy into.</param> /// <param name="targetX">The leftmost X coordinate of the bitmap to draw to.</param> /// <param name="targetY">The topmost Y coordinate of the bitmap to draw to.</param> public static unsafe void CopyFromFramebuffer( VncFramebuffer source, VncRectangle sourceRectangle, Bitmap target, int targetX, int targetY) { if (target == null) { throw new ArgumentNullException(nameof(target)); } var winformsRect = new Rectangle(targetX, targetY, sourceRectangle.Width, sourceRectangle.Height); var data = target.LockBits(winformsRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); try { VncPixelFormat.CopyFromFramebuffer(source, sourceRectangle, data.Scan0, data.Stride, targetX, targetY); } finally { target.UnlockBits(data); } }
private void NegotiateDesktop() { Logger.Info("Negotiating desktop settings"); byte shareDesktopSetting = this.c.ReceiveByte(); bool shareDesktop = shareDesktopSetting != 0; var e = new CreatingDesktopEventArgs(shareDesktop); this.OnCreatingDesktop(e); var fbSource = this.fbSource; this.Framebuffer = fbSource != null ? fbSource.Capture() : null; VncStream.Require( this.Framebuffer != null, "No framebuffer. Make sure you've called SetFramebufferSource. It can be set to a VncFramebuffer.", VncFailureReason.SanityCheckFailed); this.clientPixelFormat = this.Framebuffer.PixelFormat; this.clientWidth = this.Framebuffer.Width; this.clientHeight = this.Framebuffer.Height; this.fbuAutoCache = null; this.c.SendUInt16BE((ushort)this.Framebuffer.Width); this.c.SendUInt16BE((ushort)this.Framebuffer.Height); var pixelFormat = new byte[VncPixelFormat.Size]; this.Framebuffer.PixelFormat.Encode(pixelFormat, 0); this.c.Send(pixelFormat); this.c.SendString(this.Framebuffer.Name, true); Logger.Info($"The desktop {this.Framebuffer.Name} has initialized with pixel format {this.clientPixelFormat}; the screen size is {this.clientWidth}x{this.clientHeight}"); }
/// <summary> /// Sends the contents of a rectangle to the client. /// </summary> /// <param name="stream"> /// A <see cref="Stream"/> which represents the connection to the VNC client. /// </param> /// <param name="pixelFormat"> /// The <see cref="VncPixelFormat"/> being used. /// </param> /// <param name="region"> /// The dimesions of the rectangle. /// </param> /// <param name="contents"> /// The contents of the rectangle, in raw pixel format. /// </param> public abstract void Send(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents);
/// <inheritdoc/> public override void Send(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents) { stream.Write(contents, 0, contents.Length); }
/// <summary> /// Sends a rectangle using basic compression. /// </summary> /// <param name="stream"> /// The <see cref="Stream"/> which represents connectivity with the client. /// </param> /// <param name="pixelFormat"> /// The pixel format to use. /// </param> /// <param name="region"> /// The rectangle to send. /// </param> /// <param name="contents"> /// A buffer holding the raw pixel data for the rectangle. /// </param> protected int SendWithBasicCompression(Stream stream, VncPixelFormat pixelFormat, VncRectangle region, byte[] contents) { if (contents.Length < 12) { var compressionControl = TightCompressionControl.BasicCompression; stream.WriteByte((byte)compressionControl); // If the data size after applying the filter but before the compression is less then 12, then the data is sent as is, uncompressed. byte[] encodedBuffer = new byte[4]; var length = WriteEncodedValue(encodedBuffer, 0, (int)contents.Length); stream.Write(encodedBuffer, 0, length); stream.Write(contents, 0, contents.Length); return(1 + length + contents.Length); } else { var compressionControl = TightCompressionControl.BasicCompression | TightCompressionControl.ResetStream0 | TightCompressionControl.UseStream0; var compressionLevel = GetCompressionLevel(this.VncServerSession); stream.WriteByte((byte)compressionControl); using (var buffer = new MemoryStream()) using (var deflater = new ZlibStream(buffer, CompressionMode.Compress, compressionLevel)) { // The Tight encoding makes use of a new type TPIXEL (Tight pixel). This is the same as a PIXEL for the agreed // pixel format, except where true-colour-flag is non-zero, bits-per-pixel is 32, depth is 24 and all of the bits // making up the red, green and blue intensities are exactly 8 bits wide. // In this case a TPIXEL is only 3 bytes long, where the first byte is the red component, the second byte is the // green component, and the third byte is the blue component of the pixel color value. if (pixelFormat.BitsPerPixel == 32 && pixelFormat.BitDepth == 24 && pixelFormat.BlueBits == 8 && pixelFormat.RedBits == 8 && pixelFormat.GreenBits == 8 && !pixelFormat.IsPalettized) { Debug.Assert(contents.Length % 4 == 0, "The size of the raw pixel data must be a multiple of 4 when using a 32bpp pixel format."); int redOffset = pixelFormat.RedShift / 8; int blueOffset = pixelFormat.BlueShift / 8; int greenOffset = pixelFormat.GreenShift / 8; for (int i = 0; i < contents.Length; i += 4) { if (i == contents.Length - 4) { deflater.FlushMode = FlushType.Full; } // The first byte is the red component, the second byte is the // green component, and the third byte is the blue component of the pixel color value. deflater.Write(contents, i + redOffset, 1); deflater.Write(contents, i + greenOffset, 1); deflater.Write(contents, i + blueOffset, 1); } } else { deflater.FlushMode = FlushType.Finish; deflater.Write(contents, 0, contents.Length); } deflater.Flush(); byte[] encodedBuffer = new byte[4]; var length = WriteEncodedValue(encodedBuffer, 0, (int)buffer.Length); stream.Write(encodedBuffer, 0, length); buffer.Position = 0; buffer.CopyTo(stream); return((int)buffer.Length + 1); } } }