Skip to content

Commit 547e363

Browse files
committed
Create UnsafeStreamCodec.cs
1 parent b8101ba commit 547e363

File tree

1 file changed

+378
-0
lines changed

1 file changed

+378
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Drawing.Imaging;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
namespace Server.StreamLibrary
10+
{
11+
public class UnsafeStreamCodec : IDisposable
12+
{
13+
internal Size Resolution { get; private set; }
14+
internal Size CheckBlock { get; private set; }
15+
internal int ImageQuality
16+
{
17+
get { return _imageQuality; }
18+
private set
19+
{
20+
lock (_imageProcessLock)
21+
{
22+
_imageQuality = value;
23+
24+
if (_jpgCompression != null)
25+
{
26+
_jpgCompression.Dispose();
27+
}
28+
29+
_jpgCompression = new JpgCompression(_imageQuality);
30+
}
31+
}
32+
}
33+
34+
private int _imageQuality;
35+
private byte[] _encodeBuffer;
36+
private Bitmap _decodedBitmap;
37+
private PixelFormat _encodedFormat;
38+
private int _encodedWidth;
39+
private int _encodedHeight;
40+
private readonly object _imageProcessLock = new object();
41+
private JpgCompression _jpgCompression;
42+
43+
/// <summary>
44+
/// Initialize a new instance of UnsafeStreamCodec class.
45+
/// </summary>
46+
/// <param name="imageQuality">The quality to use between 0-100.</param>
47+
/// <param name="monitor">The monitor used for the images.</param>
48+
/// <param name="resolution">The resolution of the monitor.</param>
49+
internal UnsafeStreamCodec(int imageQuality)
50+
{
51+
this.ImageQuality = imageQuality;
52+
this.CheckBlock = new Size(50, 1);
53+
}
54+
55+
public void Dispose()
56+
{
57+
Dispose(true);
58+
59+
// Tell the Garbage Collector to not waste time finalizing this object
60+
// since we took care of it.
61+
GC.SuppressFinalize(this);
62+
}
63+
64+
protected virtual void Dispose(bool disposing)
65+
{
66+
if (disposing)
67+
{
68+
if (_decodedBitmap != null)
69+
{
70+
_decodedBitmap.Dispose();
71+
}
72+
73+
if (_jpgCompression != null)
74+
{
75+
_jpgCompression.Dispose();
76+
}
77+
}
78+
}
79+
80+
internal unsafe void CodeImage(IntPtr scan0, Rectangle scanArea, Size imageSize, PixelFormat format,
81+
Stream outStream)
82+
{
83+
lock (_imageProcessLock)
84+
{
85+
byte* pScan0;
86+
if (IntPtr.Size == 8)
87+
{
88+
// 64 bit process
89+
pScan0 = (byte*)scan0.ToInt64();
90+
}
91+
else
92+
{
93+
// 32 bit process
94+
pScan0 = (byte*)scan0.ToInt32();
95+
}
96+
97+
if (!outStream.CanWrite)
98+
{
99+
throw new Exception("Must have access to Write in the Stream");
100+
}
101+
102+
int stride = 0;
103+
int rawLength = 0;
104+
int pixelSize = 0;
105+
106+
switch (format)
107+
{
108+
case PixelFormat.Format24bppRgb:
109+
case PixelFormat.Format32bppRgb:
110+
pixelSize = 3;
111+
break;
112+
case PixelFormat.Format32bppArgb:
113+
case PixelFormat.Format32bppPArgb:
114+
pixelSize = 4;
115+
break;
116+
default:
117+
throw new NotSupportedException(format.ToString());
118+
}
119+
120+
stride = imageSize.Width * pixelSize;
121+
rawLength = stride * imageSize.Height;
122+
123+
if (_encodeBuffer == null)
124+
{
125+
this._encodedFormat = format;
126+
this._encodedWidth = imageSize.Width;
127+
this._encodedHeight = imageSize.Height;
128+
this._encodeBuffer = new byte[rawLength];
129+
130+
fixed (byte* ptr = _encodeBuffer)
131+
{
132+
byte[] temp = null;
133+
using (Bitmap tmpBmp = new Bitmap(imageSize.Width, imageSize.Height, stride, format, scan0))
134+
{
135+
temp = _jpgCompression.Compress(tmpBmp);
136+
}
137+
138+
outStream.Write(BitConverter.GetBytes(temp.Length), 0, 4);
139+
outStream.Write(temp, 0, temp.Length);
140+
NativeMethods.memcpy(new IntPtr(ptr), scan0, (uint)rawLength);
141+
}
142+
return;
143+
}
144+
145+
if (this._encodedFormat != format)
146+
{
147+
throw new Exception("PixelFormat is not equal to previous Bitmap");
148+
}
149+
else if (this._encodedWidth != imageSize.Width || this._encodedHeight != imageSize.Height)
150+
{
151+
throw new Exception("Bitmap width/height are not equal to previous bitmap");
152+
}
153+
154+
long oldPos = outStream.Position;
155+
outStream.Write(new byte[4], 0, 4);
156+
long totalDataLength = 0;
157+
158+
List<Rectangle> blocks = new List<Rectangle>();
159+
160+
Size s = new Size(scanArea.Width, CheckBlock.Height);
161+
Size lastSize = new Size(scanArea.Width % CheckBlock.Width, scanArea.Height % CheckBlock.Height);
162+
163+
int lasty = scanArea.Height - lastSize.Height;
164+
int lastx = scanArea.Width - lastSize.Width;
165+
166+
Rectangle cBlock = new Rectangle();
167+
List<Rectangle> finalUpdates = new List<Rectangle>();
168+
169+
s = new Size(scanArea.Width, s.Height);
170+
171+
fixed (byte* encBuffer = _encodeBuffer)
172+
{
173+
var index = 0;
174+
175+
for (int y = scanArea.Y; y != scanArea.Height; y += s.Height)
176+
{
177+
if (y == lasty)
178+
{
179+
s = new Size(scanArea.Width, lastSize.Height);
180+
}
181+
182+
cBlock = new Rectangle(scanArea.X, y, scanArea.Width, s.Height);
183+
184+
int offset = (y * stride) + (scanArea.X * pixelSize);
185+
186+
if (NativeMethods.memcmp(encBuffer + offset, pScan0 + offset, (uint)stride) != 0)
187+
{
188+
index = blocks.Count - 1;
189+
190+
if (blocks.Count != 0 && (blocks[index].Y + blocks[index].Height) == cBlock.Y)
191+
{
192+
cBlock = new Rectangle(blocks[index].X, blocks[index].Y, blocks[index].Width,
193+
blocks[index].Height + cBlock.Height);
194+
blocks[index] = cBlock;
195+
}
196+
else
197+
{
198+
blocks.Add(cBlock);
199+
}
200+
}
201+
}
202+
203+
for (int i = 0; i < blocks.Count; i++)
204+
{
205+
s = new Size(CheckBlock.Width, blocks[i].Height);
206+
207+
for (int x = scanArea.X; x != scanArea.Width; x += s.Width)
208+
{
209+
if (x == lastx)
210+
{
211+
s = new Size(lastSize.Width, blocks[i].Height);
212+
}
213+
214+
cBlock = new Rectangle(x, blocks[i].Y, s.Width, blocks[i].Height);
215+
bool foundChanges = false;
216+
uint blockStride = (uint)(pixelSize * cBlock.Width);
217+
218+
for (int j = 0; j < cBlock.Height; j++)
219+
{
220+
int blockOffset = (stride * (cBlock.Y + j)) + (pixelSize * cBlock.X);
221+
222+
if (NativeMethods.memcmp(encBuffer + blockOffset, pScan0 + blockOffset, blockStride) != 0)
223+
{
224+
foundChanges = true;
225+
}
226+
227+
NativeMethods.memcpy(encBuffer + blockOffset, pScan0 + blockOffset, blockStride);
228+
//copy-changes
229+
}
230+
231+
if (foundChanges)
232+
{
233+
index = finalUpdates.Count - 1;
234+
235+
if (finalUpdates.Count > 0 &&
236+
(finalUpdates[index].X + finalUpdates[index].Width) == cBlock.X)
237+
{
238+
Rectangle rect = finalUpdates[index];
239+
int newWidth = cBlock.Width + rect.Width;
240+
cBlock = new Rectangle(rect.X, rect.Y, newWidth, rect.Height);
241+
finalUpdates[index] = cBlock;
242+
}
243+
else
244+
{
245+
finalUpdates.Add(cBlock);
246+
}
247+
}
248+
}
249+
}
250+
}
251+
252+
for (int i = 0; i < finalUpdates.Count; i++)
253+
{
254+
Rectangle rect = finalUpdates[i];
255+
int blockStride = pixelSize * rect.Width;
256+
257+
Bitmap tmpBmp = null;
258+
BitmapData tmpData = null;
259+
long length;
260+
261+
try
262+
{
263+
tmpBmp = new Bitmap(rect.Width, rect.Height, format);
264+
tmpData = tmpBmp.LockBits(new Rectangle(0, 0, tmpBmp.Width, tmpBmp.Height),
265+
ImageLockMode.ReadWrite, tmpBmp.PixelFormat);
266+
267+
for (int j = 0, offset = 0; j < rect.Height; j++)
268+
{
269+
int blockOffset = (stride * (rect.Y + j)) + (pixelSize * rect.X);
270+
NativeMethods.memcpy((byte*)tmpData.Scan0.ToPointer() + offset, pScan0 + blockOffset, (uint)blockStride);
271+
//copy-changes
272+
offset += blockStride;
273+
}
274+
275+
outStream.Write(BitConverter.GetBytes(rect.X), 0, 4);
276+
outStream.Write(BitConverter.GetBytes(rect.Y), 0, 4);
277+
outStream.Write(BitConverter.GetBytes(rect.Width), 0, 4);
278+
outStream.Write(BitConverter.GetBytes(rect.Height), 0, 4);
279+
outStream.Write(new byte[4], 0, 4);
280+
281+
length = outStream.Length;
282+
long old = outStream.Position;
283+
284+
_jpgCompression.Compress(tmpBmp, ref outStream);
285+
286+
length = outStream.Position - length;
287+
288+
outStream.Position = old - 4;
289+
outStream.Write(BitConverter.GetBytes(length), 0, 4);
290+
outStream.Position += length;
291+
}
292+
finally
293+
{
294+
tmpBmp.UnlockBits(tmpData);
295+
tmpBmp.Dispose();
296+
}
297+
298+
totalDataLength += length + (4 * 5);
299+
}
300+
301+
outStream.Position = oldPos;
302+
outStream.Write(BitConverter.GetBytes(totalDataLength), 0, 4);
303+
}
304+
}
305+
306+
internal unsafe Bitmap DecodeData(IntPtr codecBuffer, uint length)
307+
{
308+
if (length < 4)
309+
{
310+
return _decodedBitmap;
311+
}
312+
313+
int dataSize = *(int*)(codecBuffer);
314+
315+
if (_decodedBitmap == null)
316+
{
317+
byte[] temp = new byte[dataSize];
318+
319+
fixed (byte* tempPtr = temp)
320+
{
321+
NativeMethods.memcpy(new IntPtr(tempPtr), new IntPtr(codecBuffer.ToInt32() + 4), (uint)dataSize);
322+
}
323+
324+
this._decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
325+
326+
return _decodedBitmap;
327+
}
328+
else
329+
{
330+
return _decodedBitmap;
331+
}
332+
}
333+
334+
internal Bitmap DecodeData(Stream inStream)
335+
{
336+
byte[] temp = new byte[4];
337+
inStream.Read(temp, 0, 4);
338+
int dataSize = BitConverter.ToInt32(temp, 0);
339+
340+
if (_decodedBitmap == null)
341+
{
342+
temp = new byte[dataSize];
343+
inStream.Read(temp, 0, temp.Length);
344+
this._decodedBitmap = (Bitmap)Bitmap.FromStream(new MemoryStream(temp));
345+
346+
return _decodedBitmap;
347+
}
348+
349+
using (Graphics g = Graphics.FromImage(_decodedBitmap))
350+
{
351+
while (dataSize > 0)
352+
{
353+
byte[] tempData = new byte[4 * 5];
354+
inStream.Read(tempData, 0, tempData.Length);
355+
356+
Rectangle rect = new Rectangle(BitConverter.ToInt32(tempData, 0), BitConverter.ToInt32(tempData, 4),
357+
BitConverter.ToInt32(tempData, 8), BitConverter.ToInt32(tempData, 12));
358+
int updateLen = BitConverter.ToInt32(tempData, 16);
359+
360+
byte[] buffer = new byte[updateLen];
361+
inStream.Read(buffer, 0, buffer.Length);
362+
363+
using (MemoryStream m = new MemoryStream(buffer))
364+
{
365+
using (Bitmap tmp = (Bitmap)Image.FromStream(m))
366+
{
367+
g.DrawImage(tmp, rect.Location);
368+
}
369+
}
370+
371+
dataSize -= updateLen + (4 * 5);
372+
}
373+
}
374+
Resolution = _decodedBitmap.Size;
375+
return _decodedBitmap;
376+
}
377+
}
378+
}

0 commit comments

Comments
 (0)