/// <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="scan0">The bitmap buffer start address</param> /// <param name="stride">The bitmap width stride</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, IntPtr scan0, int stride, int targetX, int targetY) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (sourceRectangle.IsEmpty) { return; } fixed(byte *framebufferData = source.GetBuffer()) { VncPixelFormat.Copy( (IntPtr)framebufferData, source.Stride, source.PixelFormat, sourceRectangle, scan0, stride, new VncPixelFormat()); } }
/// <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); } }
void NegotiateDesktop() { _c.SendByte((byte)(_options.ShareDesktop ? 1 : 0)); var width = _c.ReceiveUInt16BE(); VncStream.SanityCheck(width > 0 && width < 0x8000); var height = _c.ReceiveUInt16BE(); VncStream.SanityCheck(height > 0 && height < 0x8000); VncPixelFormat pixelFormat; try { pixelFormat = VncPixelFormat.Decode(_c.Receive(VncPixelFormat.Size), 0); } catch (ArgumentException e) { throw new VncException("Unsupported pixel format.", VncFailureReason.UnsupportedPixelFormat, e); } var name = _c.ReceiveString(); Framebuffer = new VncFramebuffer(name, width, height, pixelFormat); }
void HandleFramebufferUpdate() { _c.ReceiveByte(); // padding var numRects = _c.ReceiveUInt16BE(); var rects = new List <VncRectangle>(); for (int i = 0; i < numRects; i++) { var r = _c.ReceiveRectangle(); int x = r.X, y = r.Y, w = r.Width, h = r.Height; VncStream.SanityCheck(w > 0 && w < 0x8000); VncStream.SanityCheck(h > 0 && h < 0x8000); int fbW = Framebuffer.Width, fbH = Framebuffer.Height, bpp = Framebuffer.PixelFormat.BytesPerPixel; var inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h; byte[] pixels; var encoding = (VncEncoding)_c.ReceiveUInt32BE(); switch (encoding) { case VncEncoding.Hextile: // KVM seems to avoid this now that I support Zlib. var background = new byte[bpp]; var foreground = new byte[bpp]; for (int ty = 0; ty < h; ty += 16) { int th = Math.Min(16, h - ty); for (int tx = 0; tx < w; tx += 16) { int tw = Math.Min(16, w - tx); var subencoding = _c.ReceiveByte(); pixels = AllocateFramebufferScratch(tw * th * bpp); if (0 != (subencoding & 1)) // raw { _c.Receive(pixels, 0, tw * th * bpp); if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } else { pixels = AllocateFramebufferScratch(tw * th * bpp); if (0 != (subencoding & 2)) { background = _c.Receive(bpp); } if (0 != (subencoding & 4)) { foreground = _c.Receive(bpp); } int ptr = 0; for (int pp = 0; pp < tw * th; pp++) { for (int pe = 0; pe < bpp; pe++) { pixels[ptr++] = background[pe]; } } int nsubrects = 0 != (subencoding & 8) ? _c.ReceiveByte() : 0; if (nsubrects > 0) { var subrectsColored = 0 != (subencoding & 16); for (int subrect = 0; subrect < nsubrects; subrect++) { var color = subrectsColored ? _c.Receive(bpp) : foreground; var srxy = _c.ReceiveByte(); var srwh = _c.ReceiveByte(); int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1; int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1; if (srx + srw > tw || sry + srh > th) { continue; } for (int py = 0; py < srh; py++) { for (int px = 0; px < srw; px++) { int off = bpp * ((py + sry) * tw + (px + srx)); for (int pe = 0; pe < bpp; pe++) { pixels[off + pe] = color[pe]; } } } } } lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x + tx, y + ty, tw, th, pixels); } } } } break; case VncEncoding.CopyRect: var srcx = (int)_c.ReceiveUInt16BE(); var srcy = (int)_c.ReceiveUInt16BE(); if (srcx + w > fbW) { w = fbW - srcx; } if (srcy + h > fbH) { h = fbH - srcy; } if (w < 1 || h < 1) { continue; } pixels = AllocateFramebufferScratch(w * h * bpp); lock (Framebuffer.SyncRoot) { CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, Framebuffer.GetBuffer(), w, h); CopyToFramebuffer(x, y, w, h, pixels); } break; case VncEncoding.Raw: pixels = AllocateFramebufferScratch(w * h * bpp); _c.Receive(pixels, 0, w * h * bpp); if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.Zlib: int bytesDesired = w * h * bpp; int size = (int)_c.ReceiveUInt32BE(); VncStream.SanityCheck(size >= 0 && size < 0x10000000); VncUtility.AllocateScratch(size, ref _zlibScratch); _c.Receive(_zlibScratch, 0, size); _zlibMemoryStream.Position = 0; _zlibMemoryStream.Write(_zlibScratch, 0, size); _zlibMemoryStream.SetLength(size); _zlibMemoryStream.Position = 0; if (_zlibInflater == null) // Zlib has a two-byte header. { VncStream.SanityCheck(size >= 2); _zlibMemoryStream.Position = 2; _zlibInflater = new DeflateStream(_zlibMemoryStream, CompressionMode.Decompress, false); } pixels = AllocateFramebufferScratch(bytesDesired); for (int j = 0; j < bytesDesired;) { int count = 0; try { count = _zlibInflater.Read(pixels, j, bytesDesired - j); } catch (InvalidDataException) { VncStream.Require(false, "Bad data compressed.", VncFailureReason.UnrecognizedProtocolElement); } VncStream.Require(count > 0, "No data compressed.", VncFailureReason.UnrecognizedProtocolElement); j += count; } if (inRange) { lock (Framebuffer.SyncRoot) { CopyToFramebuffer(x, y, w, h, pixels); } } break; case VncEncoding.PseudoDesktopSize: Framebuffer = new VncFramebuffer(Framebuffer.Name, w, h, Framebuffer.PixelFormat); continue; // Don't call OnFramebufferChanged for this one. default: VncStream.Require(false, "Unsupported encoding.", VncFailureReason.UnrecognizedProtocolElement); break; } rects.Add(new VncRectangle(x, y, w, h)); } if (rects.Count > 0) { OnFramebufferChanged(new FramebufferChangedEventArgs(rects)); } }
/// <summary> /// Captures the screen. /// </summary> /// <returns>A framebuffer corresponding to the screen.</returns> public VncFramebuffer Capture() { var bounds = _getScreenBounds(); int w = bounds.Width, h = bounds.Height; if (_bitmap == null || _bitmap.Width != w || _bitmap.Height != h) { _bitmap = new Bitmap(w, h); _framebuffer = new VncFramebuffer(_name, w, h, new VncPixelFormat()); } using (var g = Graphics.FromImage(_bitmap)) { g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size); lock (_framebuffer.SyncRoot) { VncBitmap.CopyToFramebuffer(_bitmap, new VncRectangle(0, 0, w, h), _framebuffer, 0, 0); } } return _framebuffer; }
void UpdateFramebuffer(bool force, VncFramebuffer framebuffer) { if (framebuffer == null) { return; } int w = framebuffer.Width, h = framebuffer.Height; if (_bitmap == null || _bitmap.Width != w || _bitmap.Height != h || force) { _bitmap = new Bitmap(w, h, PixelFormat.Format32bppRgb); VncBitmap.CopyFromFramebuffer(framebuffer, new VncRectangle(0, 0, w, h), _bitmap, 0, 0); ClientSize = new Size(w, h); Invalidate(); } }