blob: 666c6835a399ab67e060155082c09acb03ab2fdf [file] [log] [blame] [raw]
// VncSharp - .NET VNC Client Library
// Copyright (C) 2008 David Humphrey
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Drawing;
namespace NVNC
{
/// <summary>
/// Properties of a VNC Framebuffer, and its Pixel Format.
/// </summary>
public class Framebuffer
{
private string name;
private int bpp;
private int depth;
private bool bigEndian;
private bool trueColor;
private int redMax;
private int greenMax;
private int blueMax;
private int redShift;
private int greenShift;
private int blueShift;
private readonly int width;
private readonly int height;
public readonly int[] pixels; // I'm reusing the same pixel buffer for all update rectangles.
// Pixel values will always be 32-bits to match GDI representation
/// <summary>
/// Creates a new Framebuffer with (width x height) pixels.
/// </summary>
/// <param name="width">The width in pixels of the remote desktop.</param>
/// <param name="height">The height in pixels of the remote desktop.</param>
public Framebuffer(int width, int height)
{
this.width = width;
this.height = height;
// Cache the total size of the pixel array and initialize
int pixelCount = width * height;
pixels = new int[pixelCount];
}
/// <summary>
/// An indexer to allow access to the internal pixel buffer.
/// </summary>
public int this[int index]
{
get
{
return pixels[index];
}
set
{
pixels[index] = value;
}
}
/// <summary>
/// The Width of the Framebuffer, measured in Pixels.
/// </summary>
public int Width
{
get
{
return width;
}
}
/// <summary>
/// The Height of the Framebuffer, measured in Pixels.
/// </summary>
public int Height
{
get
{
return height;
}
}
/// <summary>
/// Gets a Rectangle object constructed out of the Width and Height for the Framebuffer. Used as a convenience in other classes.
/// </summary>
public Rectangle Rectangle
{
get
{
return new Rectangle(0, 0, width, height);
}
}
/// <summary>
/// The number of Bits Per Pixel for the Framebuffer--one of 8, 24, or 32.
/// </summary>
public int BitsPerPixel
{
get
{
return bpp;
}
set
{
if(value != 32 && value != 16 && value != 8) {
throw new ArgumentException(String.Format(
"BitsPerPixel value {0} is not supported", value
));
}
bpp = value;
}
}
/// <summary>
/// The Color Depth of the Framebuffer.
/// The default value is 24.
/// </summary>
public int Depth
{
get
{
return depth;
}
set
{
depth = value;
}
}
/// <summary>
/// Indicates whether the remote host uses Big- or Little-Endian order when sending multi-byte values.
/// </summary>
public bool BigEndian
{
get
{
return bigEndian;
}
set
{
bigEndian = value;
}
}
/// <summary>
/// Indicates whether the remote host supports True Color.
/// The default value is true.
/// </summary>
public bool TrueColor
{
get
{
return trueColor;
}
set
{
trueColor = value;
}
}
/// <summary>
/// The maximum value for Red in a pixel's color value.
/// The default value is 0xFF.
/// </summary>
public int RedMax
{
get
{
return redMax;
}
set
{
redMax = value;
}
}
/// <summary>
/// The maximum value for Green in a pixel's color value.
/// The default value is 0xFF.
/// </summary>
public int GreenMax
{
get
{
return greenMax;
}
set
{
greenMax = value;
}
}
/// <summary>
/// The maximum value for Blue in a pixel's color value.
/// The default value is 0xFF.
/// </summary>
public int BlueMax
{
get
{
return blueMax;
}
set
{
blueMax = value;
}
}
/// <summary>
/// The number of bits to shift pixel values in order to obtain Red values.
/// The default value is 16.
/// </summary>
public int RedShift
{
get
{
return redShift;
}
set
{
redShift = value;
}
}
/// <summary>
/// The number of bits to shift pixel values in order to obtain Green values.
/// The default value is 8.
/// </summary>
public int GreenShift
{
get
{
return greenShift;
}
set
{
greenShift = value;
}
}
/// <summary>
/// The number of bits to shift pixel values in order to obtain Blue values.
/// The default value is 0.
/// </summary>
public int BlueShift
{
get
{
return blueShift;
}
set
{
blueShift = value;
}
}
/// <summary>
/// The name of the remote destkop, if any. Must be non-null.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if a null string is used when setting DesktopName.</exception>
public string DesktopName
{
get
{
return name;
}
set
{
if (value == null)
throw new ArgumentNullException("DesktopName");
name = value;
}
}
/// <summary>
/// When communicating with the VNC Server, bytes are used to represent many of the values above. However, internally it is easier to use Integers. This method provides a translation between the two worlds.
/// </summary>
/// <returns>A byte array of 16 bytes containing the properties of the framebuffer in a format ready for transmission to the VNC server.</returns>
public byte[] ToPixelFormat()
{
byte[] b = new byte[16];
b[0] = Convert.ToByte(bpp);
b[1] = Convert.ToByte(depth);
b[2] = Convert.ToByte(bigEndian ? 1 : 0);
b[3] = Convert.ToByte(trueColor ? 1 : 0);
b[4] = Convert.ToByte((redMax >> 8) & 0xff);
b[5] = Convert.ToByte(redMax & 0xff);
b[6] = Convert.ToByte((greenMax >> 8) & 0xff);
b[7] = Convert.ToByte(greenMax & 0xff);
b[8] = Convert.ToByte((blueMax >> 8) & 0xff);
b[9] = Convert.ToByte(blueMax & 0xff);
b[10] = Convert.ToByte(redShift);
b[11] = Convert.ToByte(greenShift);
b[12] = Convert.ToByte(blueShift);
// plus 3 bytes padding = 16 bytes
return b;
}
/// <summary>
/// Given the dimensions and 16-byte PIXEL_FORMAT record from the VNC Host, deserialize this into a Framebuffer object.
/// </summary>
/// <param name="b">The 16-byte PIXEL_FORMAT record.</param>
/// <param name="width">The width in pixels of the remote desktop.</param>
/// <param name="height">The height in pixles of the remote desktop.</param>
/// <returns>Returns a Framebuffer object matching the specification of b[].</returns>
public static Framebuffer FromPixelFormat(byte[] b, int width, int height)
{
if (b.Length != 16)
throw new ArgumentException("Length of b must be 16 bytes.");
Framebuffer buffer = new Framebuffer(width, height);
buffer.BitsPerPixel = Convert.ToInt32(b[0]);
buffer.Depth = Convert.ToInt32(b[1]);
buffer.BigEndian = (b[2] != 0);
buffer.TrueColor = (b[3] != 0);
buffer.RedMax = Convert.ToInt32(b[5] | b[4] << 8);
buffer.GreenMax = Convert.ToInt32(b[7] | b[6] << 8);
buffer.BlueMax = Convert.ToInt32(b[9] | b[8] << 8);
buffer.RedShift = Convert.ToInt32(b[10]);
buffer.GreenShift = Convert.ToInt32(b[11]);
buffer.BlueShift = Convert.ToInt32(b[12]);
// Last 3 bytes are padding, ignore
return buffer;
}
/// <summary>
/// Prints the Framebuffer data to the console.
/// </summary>
public void Print()
{
Console.WriteLine("BitsPerPixel: " + BitsPerPixel);
Console.WriteLine("Depth: " + Depth);
Console.WriteLine("BigEndian: " + BigEndian);
Console.WriteLine("TrueColor: " + TrueColor);
Console.WriteLine("RedMax: " + RedMax);
Console.WriteLine("GreenMax: " + GreenMax);
Console.WriteLine("BlueMax: " + BlueMax);
Console.WriteLine("RedShift: " + RedShift);
Console.WriteLine("GreenShift: " + GreenShift);
Console.WriteLine("BlueShift: " + BlueShift);
}
public int TranslatePixel(int pixel)
{
if (redFix != -1)
{
return
((pixel & redMask) >> redFix << redShift) |
((pixel & greenMask) >> greenFix << greenShift) |
((pixel & blueMask) >> blueFix << blueShift);
}
return pixel;
}
private int redMask = -1, greenMask = -1, blueMask = -1;
private int redFix = -1, greenFix = -1, blueFix = -1;
private static int FixColorModel(int max1, int max2, int mask)
{
int fix = 0;
for (; fix < 8; fix++)
{
if (max1 == max2)
break;
max1 >>= 1;
}
while ((mask & 1) == 0)
{
fix++;
mask >>= 1;
}
return fix;
}
}
}