Сжатие и восстановление картинки, чтобы мог передать одним пакетом по протоколу UDP? - C#
Формулировка задачи:
У меня есть 2 клиента,первый отправляет онлайн трансляцию своего экрана на другого клиента.
Мне нужен такой алгоритм сжатия, чтобы я мог отослать одним пакетом по UDP.
когда устанавливаю значения 40L и меньше, то полученная картинка вмещается в UDP пакет. Но я хочу восстановить в оригинальное качество,подскажите как сделать?или какой-нибудь другой алгоритм, заранее спасибо)
private:
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 40L);
myEncoderParameters.Param[0] = myEncoderParameter;
private ImageCodecInfo GetEncoder(ImageFormat jpeg)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == jpeg.Guid)
{
return codec;
}
}
return null;
}
private byte[] CompressFrame(Bitmap bitmap, ImageFormat format)
{
bitmap.Save(stream, GetEncoder(format), myEncoderParameters);
return stream.ToArray();
}
byte[] message = CompressFrame((Bitmap)frame.Clone(),ImageFormat.Jpeg); // тут получаю сжатую картинку(40L)Решение задачи: «Сжатие и восстановление картинки, чтобы мог передать одним пакетом по протоколу UDP?»
textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication345
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//создаем Image для отображения скриншота и Graphics для него
var image = new Bitmap(1300, 1300);
var gr = Graphics.FromImage(image);
//создаем PictureBox для отображения скриншотов
var pb = new PictureBox { Parent = this, Dock = DockStyle.Fill, SizeMode = PictureBoxSizeMode.Zoom, Image = image };
//создаем поток для клиента (на самом деле это должно запускаться на машине клиента, но для теста, клиент запускается здесь)
ThreadPool.QueueUserWorkItem(delegate { new Client().Start(); });
//создаем поток для сервера
ThreadPool.QueueUserWorkItem(
delegate
{
//получаем в цикле скриншоты с клиента
foreach (var chunk in new Server().GetScreenshots())
{
//заносим скриншот в PictureBox
gr.DrawImage(chunk.Image, chunk.Position);
pb.Invalidate();
}
});
}
}
/// <summary>
/// Сервер
/// </summary>
class Server
{
public IEnumerable<Chunk> GetScreenshots(int port = 24432)
{
using (var udp = new UdpClient(port))
while (true)//делаем бесконечно
{
//принимаем массив
IPEndPoint ip = null;
var arr = udp.Receive(ref ip);
//читаем координаты
var x = arr[0] * Client.CHUNK_SIZE;
var y = arr[1] * Client.CHUNK_SIZE;
using (var ms = new MemoryStream(arr, 2, arr.Length - 2))//создаем временный поток для сжатого изображения
{
//создаем изображение
var bmp = Bitmap.FromStream(ms);
//возвращаем
yield return new Chunk {Position = new Point(x, y), Image = bmp};
}
}
}
public class Chunk
{
public Point Position;
public Image Image;
}
}
/// <summary>
/// Клиент
/// </summary>
class Client
{
public const int CHUNK_SIZE = 128;
public void Start(string host = "localhost", int port = 24432)
{
//размеры экрана
var rect = Screen.PrimaryScreen.Bounds;
var chunkHash = new Dictionary<Point, int>();
//конкетимся к серверу, получаем поток
using (var udp = new UdpClient(host, port)) //создаем TcpClient
using (var screenshot = new Bitmap(rect.Width, rect.Height)) //создаем битмап для отправки
using (var gr = Graphics.FromImage(screenshot)) //создаем канву скриншота
while (true) //делаем бесконечно
{
//захватываем изображение экрана
gr.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(rect.Width + CHUNK_SIZE, rect.Height + CHUNK_SIZE));
//перебираем кусочки
for (int x = 0; x < rect.Width; x += CHUNK_SIZE)
for (int y = 0; y < rect.Height; y += CHUNK_SIZE)
//вырезаем кусочек
using (var bmp = screenshot.Clone(new Rectangle(x, y, CHUNK_SIZE, CHUNK_SIZE), screenshot.PixelFormat))
using (var ms = new MemoryStream()) //создаем временный поток для сжатого изображения
{
//отправляем координаты кусочка
ms.WriteByte((byte)(x/CHUNK_SIZE));
ms.WriteByte((byte)(y/CHUNK_SIZE));
//конвертируем изображение в массив в формат jpeg
bmp.Save(ms, ImageFormat.Jpeg);
//получаем массив байт
var arr = ms.ToArray();
//отправляем датаграмму (только изменившиеся кусочки)
var p = new Point(x, y);
if (!chunkHash.ContainsKey(p) || chunkHash[p] != arr.Length)//хеш кусочка изменился?
{
udp.Send(arr, arr.Length);//отправляем
chunkHash[p] = arr.Length;//сохраняем новый хеш
Thread.Sleep(10);//если убрать эту задержку, то не все UDP пакеты приходит, почему - хз
}
}
}
}
}
}