How rebuild a image and change only different pixels?

FLASHCODER 21 Reputation points
2021-12-15T10:53:02.127+00:00

I have a client > Server application (sender and receiver respectively). The sender is a Java android application and receptor is a Windows Forms Application C#. Then i'm trying send to server only parts of screenshot (compressed as PNG) that are different. Until now seems that my Java code is right because i'm receiving only these differences of image, and the result is like it:

6Vovf.png

But like you can see on image above, i not able to reproduce the full image on server. What i'm missing ?

Below follow relevant code.

Java (where second is current screenshot and compare is the difference sent)

private static int pixelDiff(int argb1, int argb2) {
        int a1 = (argb1 >> 24) & 0xff;
        int r1 = (argb1 >> 16) & 0xff;
        int g1 = (argb1 >> 8) & 0xff;
        int b1 = argb1 & 0xff;
        int a2 = (argb2 >> 24) & 0xff;
        int r2 = (argb2 >> 16) & 0xff;
        int g2 = (argb2 >> 8) & 0xff;
        int b2 = argb2 & 0xff;
        return Math.abs(a1 - a2) + Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);
    }

public static void compareBitmap(Bitmap first, Bitmap second, Bitmap compare) {

        int width = first.getWidth();
        int height = first.getHeight();
        int width2 = second.getWidth();
        int height2 = second.getHeight();
        int width3 = compare.getWidth();
        int height3 = compare.getHeight();
        long pxdiff = 0;

        if (first == null || second == null || compare == null || width != width2 || height != height2 || width != width3 || height != height3)
            return;

        ByteBuffer buffer1 = ByteBuffer.allocate(height * first.getRowBytes());
        first.copyPixelsToBuffer(buffer1);

        ByteBuffer buffer2 = ByteBuffer.allocate(height2 * second.getRowBytes());
        second.copyPixelsToBuffer(buffer2);

        ByteBuffer buffer3 = ByteBuffer.allocate(height3 * compare.getRowBytes());

        byte[] array1 = buffer1.array();
        byte[] array2 = buffer2.array();
        byte[] array3 = buffer3.array();

        int len = array1.length; 

        String zero = "0";
        Charset charset = StandardCharsets.UTF_8;
        byte[] arr = charset.encode(zero).array();

        for (int i = 0; i < len; i++) {

            int alphaValue = Color.alpha(array1[i]);
            int redValue = Color.red(array1[i]);
            int greenValue = Color.green(array1[i]);
            int blueValue = Color.blue(array1[i]);

            int alphaValue2 = Color.alpha(array2[i]);
            int redValue2 = Color.red(array2[i]);
            int greenValue2 = Color.green(array2[i]);
            int blueValue2 = Color.blue(array2[i]);

            int argb1 = Color.argb(alphaValue, redValue, greenValue, blueValue);
            int argb2 = Color.argb(alphaValue2, redValue2, greenValue2, blueValue2);

            pxdiff = pixelDiff(argb1, argb2);

            if (pxdiff == 0)
                array3[i] = arr[0];
            else
                array3[i] = array2[i];
        }

        ByteBuffer compareBuf = ByteBuffer.wrap(array3);
        compare.copyPixelsFromBuffer(compareBuf);

        ByteBuffer firstBuf = ByteBuffer.wrap(array2);
        first.copyPixelsFromBuffer(firstBuf);
    }

C# (where changes are made on _second and is rendered on PictureBox)

public unsafe void CompareBitmaps(Bitmap bmp, Bitmap bmp2, Bitmap bmp3)
    {
        if (bmp.Width != bmp2.Width || bmp.Height != bmp2.Height)
            throw new Exception("Images (or portions of images) must be of same size");

        BitmapData bmData1 = null;
        BitmapData bmData2 = null;
        BitmapData bmData3 = null;

        bmData1 = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
        bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadWrite, bmp2.PixelFormat);
        bmData3 = bmp3.LockBits(new Rectangle(0, 0, bmp3.Width, bmp3.Height), ImageLockMode.ReadOnly, bmp3.PixelFormat);

        IntPtr Scan01 = bmData1.Scan0;
        IntPtr Scan02 = bmData2.Scan0;
        IntPtr Scan03 = bmData3.Scan0;

        byte* p1 = (byte*)(void*)Scan01;
        byte* p2 = (byte*)(void*)Scan02;
        byte* p3 = (byte*)(void*)Scan03;

        int bytes = bmp.Width * bmp.Height * (Image.GetPixelFormatSize(bmp.PixelFormat) / 8);

        byte[] zero = Encoding.UTF8.GetBytes("0");

        for (int i = 0; i < bytes; i++)
        {
            if (p3[i] == zero[0])
                p2[i] = p1[i];
            else
                p2[i] = p3[i];
        }

        bmp.UnlockBits(bmData1);
        bmp2.UnlockBits(bmData2);
        bmp3.UnlockBits(bmData3);
    }

    private Bitmap _buffer, _first, _second;

    private void serverReceivedImage(Client client, byte[] image)
        {
            try
            {
                byte[] newImage = new byte[image.Length - 6];

                Array.Copy(image, 6, newImage, 0, newImage.Length);

                using (var stream = new MemoryStream(newImage))
                {
                    stream.Seek(2, SeekOrigin.Begin);

                    using (var msInner = new MemoryStream())
                    {
                        using (DeflateStream z = new DeflateStream(stream, CompressionMode.Decompress))
                        {
                            z.CopyTo(msInner);
                        }

                        msInner.Seek(0, SeekOrigin.Begin);

                        var bitmap = new Bitmap(msInner);

                        if (_first == null && _second == null)
                        {
                            _first = new Bitmap(bitmap);
                            _second = new Bitmap(bitmap.Width, bitmap.Height);
                            Invoke(new ImageCompleteDelegate(ImageComplete), new object[] { _first });
                        }
                        else
                        {
                            CompareBitmaps(_first, _second, bitmap);
                            Invoke(new ImageCompleteDelegate(ImageComplete), new object[] { _second });
                            _first = new Bitmap(_second);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }

        private delegate void ImageCompleteDelegate(Bitmap bitmap);
        private void ImageComplete(Bitmap bitmap)
        {
            if (_buffer != null)
                _buffer.Dispose();

            _buffer = new Bitmap(bitmap);
            pictureBox1.Size = _buffer.Size;
            pictureBox1.Invalidate();
        }
Developer technologies | C#
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Stephen Foy 1 Reputation point
    2021-12-15T12:49:52.567+00:00

    I assume you are trying to build some sort of screen sharing program? With all the enhancements of video streaming these days it would be better to implement a video stream as opposed to differencing images over and over manually.

    However for your problem it might be better to use Magick.NET/ImageMagick which has built in functions to compare images and get the differences and then composite/merge them together.

    https://github.com/dlemstra/Magick.NET

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.