// Copyright © 2018 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using CefSharp.Structs; namespace CefSharp.OffScreen { /// /// BitmapBuffer contains a byte[] used to store the Bitmap generated from /// and associated methods for updating that buffer and creating a from the actaual Buffer /// public class BitmapBuffer { private const int BytesPerPixel = 4; private const PixelFormat Format = PixelFormat.Format32bppPArgb; private byte[] buffer; /// /// Number of bytes /// public int NumberOfBytes { get; private set; } /// /// Width /// public int Width { get; private set; } /// /// Height /// public int Height { get; private set; } /// /// Dirty Rect - unified region containing th /// public Rect DirtyRect { get; private set; } /// /// Locking object used to syncronise access to the underlying buffer /// public object BitmapLock { get; private set; } /// /// Create a new instance of BitmapBuffer /// /// Reference to the bitmapLock, a shared lock object is expected public BitmapBuffer(object bitmapLock) { BitmapLock = bitmapLock; } /// /// Get the byte[] array that represents the Bitmap /// public byte[] Buffer { get { return buffer; } } //TODO: May need to Pin the buffer in memory using GCHandle.Alloc(this.buffer, GCHandleType.Pinned); private void ResizeBuffer(int width, int height) { if (buffer == null || width != Width || height != Height) { //No of Pixels (width * height) * BytesPerPixel NumberOfBytes = width * height * BytesPerPixel; buffer = new byte[NumberOfBytes]; Width = width; Height = height; } } /// /// Copy data from the unmanaged buffer (IntPtr) into our managed buffer. /// Locks BitmapLock before performing any update /// /// width /// height /// pointer to unmanaged buffer (void*) /// rectangle to be updated public void UpdateBuffer(int width, int height, IntPtr buffer, Rect dirtyRect) { lock (BitmapLock) { DirtyRect = dirtyRect; ResizeBuffer(width, height); Marshal.Copy(buffer, this.buffer, 0, NumberOfBytes); } } /// /// Creates a new Bitmap given with the current Width/Height and /// then copies the buffer that represents the bitmap. /// Locks before creating the /// /// A new bitmap public Bitmap CreateBitmap() { lock (BitmapLock) { if (Width == 0 || Height == 0 || buffer.Length == 0) { return null; } var bitmap = new Bitmap(Width, Height, Format); var bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, Format); Marshal.Copy(Buffer, 0, bitmapData.Scan0, NumberOfBytes); bitmap.UnlockBits(bitmapData); return bitmap; } } } }