Сжатие и восстановление картинки, чтобы мог передать одним пакетом по протоколу UDP? - C#

Узнай цену своей работы

Формулировка задачи:

У меня есть 2 клиента,первый отправляет онлайн трансляцию своего экрана на другого клиента. Мне нужен такой алгоритм сжатия, чтобы я мог отослать одним пакетом по 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)
когда устанавливаю значения 40L и меньше, то полученная картинка вмещается в UDP пакет. Но я хочу восстановить в оригинальное качество,подскажите как сделать?или какой-нибудь другой алгоритм, заранее спасибо)

Решение задачи: «Сжатие и восстановление картинки, чтобы мог передать одним пакетом по протоколу 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 пакеты приходит, почему - хз
                    }
                }
            }
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 4 из 5
Похожие ответы