1

I'm in the very beginning of a team-viewer themed project.

Right now I managed to take a screenshot of the current screen as a Bitmap variable and I need to transfer it to a distant through a socket. Such a process obviously requires Serializing the Bitmap variable using json.

I have tried to do so but it seems like the Bitmap variable just isn't serialize-able. As after the serialization the json string var contains the string "system.Drawing.Bitmap". How do I convert it correctly? thanks.

The method that takes the screenshot:

public static Image TakeScreen()
{
    Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);

    Graphics g = Graphics.FromImage(bitmap);

    g.CopyFromScreen(0,0, 0, 0, bitmap.Size);
    Console.WriteLine(bitmap.ToString());

    return bitmap;       
}

The Serialization:

Image image = TakeScreen();

string jsonData = JsonConvert.SerializeObject(image, Formatting.None);
Console.WriteLine(jsonData);
Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
Safta11
  • 23
  • 1
  • 3
  • 2
    Why would you want to send an image as JSON? If you are using HTTP you can send as a byte array. – Johnathan Barclay Nov 18 '19 at 20:56
  • You wouldn't serialize an image to JSON. JSON is for serializing objects not bytes, hence the name Javascript `Object` Notation. For an image, or any file really, you just send the byte stream. – DetectivePikachu Nov 18 '19 at 20:59
  • Don't forget to dispose the `Image image` after you are done with it, ideally by bracketing it in a `using` statement. – dbc Nov 18 '19 at 22:14
  • Take a look at [How do I Serialize object to json using json.net which contains an image property](https://stackoverflow.com/q/44370046/3744182). However performance may be bad because Json.NET will fully materialize the `Base64` image stream into a `string` and later a byte array; see [Json.Net deserialize out of memory issue](https://stackoverflow.com/q/33480477/3744182). – dbc Nov 18 '19 at 22:17

1 Answers1

3
  1. json can serialize only primitives
  2. sending a picture in json is very expensive, such data as an image or sound should be transmitted via UDP streaming data

If you still need to transfer the image to JSON, you first need to extract the byte array and convert it to HEX or BASE64

Below I give a simple example example

public void ImageTest()
    {
        // get image
        Image image = TakeScreen();
        // conver image to bytes
        byte[] img_byte_arr = ImageToBytes(image);
        // creat packet
        ImagePacket packet = new ImagePacket(img_byte_arr);

        // conver object to json there...
        // send json ...
        // receive json ...
        // convert json to object type of ImagePacket ...

        // get bytes from ImagePacket
        byte[] receive_bytes = packet.GetRawData();
        // conver bytes to Image
        Image receive_image = BytesToImage(receive_bytes);

    }

Use this class as a container for serialization in JSON

/// <summary>
    /// Packet with image
    /// </summary>
    public class ImagePacket
    {
        public string hash { get; set; } = string.Empty;
        public int len { get; set; } = 0;
        public string image { get; set; } = string.Empty;
        public ImagePacket() { }
        public ImagePacket(byte[] img_sources)
        {
            hash = StringHash(img_sources);
            len = img_sources.Length;
            image = EncodeBytes(img_sources);
        }
        public byte[] GetRawData()
        {
            byte[] data = DecodeBytes(image);

            if(data.Length != len) throw new Exception("Error data len");
            if(!StringHash(data).Equals(hash)) throw new Exception("Error hash");

            return data;
        }
    }

Use the following methods for working with pictures and data transformations.

/// <summary>
    /// Get original image
    /// </summary>
    /// <returns></returns>
    public static Image TakeScreen()
    {
        Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
        Graphics g = Graphics.FromImage(bitmap);
        g.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
        return bitmap;
    }
    /// <summary>
    /// Conver Image to byte array
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static byte[] ImageToBytes(Image value)
    {
        ImageConverter converter = new ImageConverter();
        byte[] arr = (byte[])converter.ConvertTo(value, typeof(byte[]));
        return arr;
    }
    /// <summary>
    /// Conver byte array to Image
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static Image BytesToImage(byte[] value)
    {
        using(var ms = new MemoryStream(value))
        {
            return Image.FromStream(ms);
        }
    }
    /// <summary>
    /// Convert bytes to base64
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string EncodeBytes(byte[] value) => Convert.ToBase64String(value);
    /// <summary>
    /// convert base64 to bytes
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static byte[] DecodeBytes(string value) => Convert.FromBase64String(value);
    /// <summary>
    /// get MD5 hash from byte array
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string StringHash(byte[] value)
    {
        using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
        {
            byte[] hashBytes = md5.ComputeHash(value);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("X2"));
            }
            return sb.ToString().ToLower();
        }
    }