private static (VncEncodeAbstract encode, int length) createVncEncodeFromBinarySub(byte[] a_body, int a_basePos, byte a_bytesPerPixel, bool a_isBigendian, ZrleDataReader a_zrleReader)
        {
            UInt16 x          = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 0);
            UInt16 y          = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 2);
            UInt16 w          = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 4);
            UInt16 h          = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 6);
            var    encodeType = (VncEnum.EncodeType)BigEndianBitConverter.ToInt32(a_body, a_basePos + 8);

            int offset;

            switch (encodeType)
            {
            case VncEnum.EncodeType.Raw:
                return(new VncEncodeRaw(x, y, w, h, a_body, a_basePos + 12), 12 + w * h * a_bytesPerPixel);

            case VncEnum.EncodeType.CopyRect:
                UInt16 sx = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 12);
                UInt16 sy = BigEndianBitConverter.ToUInt16(a_body, a_basePos + 14);
                return(new VncEncodeCopyRect(x, y, w, h, sx, sy), 12 + 4);

            case VncEnum.EncodeType.RRE:
                // Read header
                UInt32 numberOfSubrectangles = BigEndianBitConverter.ToUInt32(a_body, a_basePos + 12);
                byte[] backgroundPixelValue  = VncPixelByteGetter.GetPixelByte(a_bytesPerPixel, a_body, a_basePos + 16);

                // Create subrectangles
                int subrectSize   = a_bytesPerPixel + 8;
                var subrectangles = new VncEncodeRreSubrectangle[numberOfSubrectangles];
                for (int i = 0; i < numberOfSubrectangles; ++i)
                {
                    offset = a_basePos + subrectSize * i;
                    byte[] pixel  = VncPixelByteGetter.GetPixelByte(a_bytesPerPixel, a_body, (16 + a_bytesPerPixel) + 0 + offset);
                    UInt16 xpos   = BigEndianBitConverter.ToUInt16(a_body, (16 + a_bytesPerPixel + a_bytesPerPixel) + 0 + offset);
                    UInt16 ypos   = BigEndianBitConverter.ToUInt16(a_body, (16 + a_bytesPerPixel + a_bytesPerPixel) + 2 + offset);
                    UInt16 width  = BigEndianBitConverter.ToUInt16(a_body, (16 + a_bytesPerPixel + a_bytesPerPixel) + 4 + offset);
                    UInt16 height = BigEndianBitConverter.ToUInt16(a_body, (16 + a_bytesPerPixel + a_bytesPerPixel) + 6 + offset);
                    subrectangles[i] = new VncEncodeRreSubrectangle(pixel, xpos, ypos, width, height);
                }

                int len = 12 + (4 + a_bytesPerPixel) + (a_bytesPerPixel + 2 + 2 + 2 + 2) * (int)numberOfSubrectangles;
                return(new VncEncodeRre(x, y, w, h, backgroundPixelValue, subrectangles), len);

            case VncEnum.EncodeType.Hextile:
                int xTileCount = (int)Math.Ceiling(w / 16.0);
                int yTileCount = (int)Math.Ceiling(h / 16.0);
                var hextiles   = new IVncEncodeHextileTile[xTileCount * yTileCount];

                // Loop for each tile
                offset = a_basePos + 12;
                int    index           = 0;
                byte[] backgroundPixel = null;
                byte[] foregroundPixel = null;
                for (int ytile = 0; ytile < yTileCount; ++ytile)
                {
                    int tileHeight = ((ytile == yTileCount - 1) && ((h % 16) != 0)) ? h % 16 : 16;
                    for (int xtile = 0; xtile < xTileCount; ++xtile, ++index)
                    {
                        int tileWidth = ((xtile == xTileCount - 1) && ((w % 16) != 0)) ? w % 16 : 16;

                        // Read header
                        var subencodingMask = new VncEncodeHextileSubencodingMask(a_body[offset]);
                        ++offset;

                        if (subencodingMask.Raw)
                        {
                            // Raw pixel data
                            hextiles[index] = new VncEncodeHextileTileRaw(a_body, offset);
                            offset         += tileWidth * tileHeight * a_bytesPerPixel;
                        }
                        else
                        {
                            // Read BackgroundSpecified if needed
                            if (subencodingMask.BackgroundSpecified)
                            {
                                backgroundPixel = VncPixelByteGetter.GetPixelByte(a_bytesPerPixel, a_body, offset);
                                offset         += a_bytesPerPixel;
                            }

                            // Read ForegroundSpecified if needed
                            if (subencodingMask.ForegroundSpecified)
                            {
                                foregroundPixel = VncPixelByteGetter.GetPixelByte(a_bytesPerPixel, a_body, offset);
                                offset         += a_bytesPerPixel;
                            }

                            // Subrects
                            VncEncodeHextileSubrect[] hextileSubrect;
                            if (subencodingMask.AnySubrects)
                            {
                                // Read number-of-subrectangles
                                byte numberOfSubrectanglesHextile = a_body[offset];
                                ++offset;

                                // Read subrectangle
                                hextileSubrect = new VncEncodeHextileSubrect[numberOfSubrectanglesHextile];
                                if (subencodingMask.SubrectsColored)
                                {
                                    for (int i = 0; i < numberOfSubrectanglesHextile; ++i)
                                    {
                                        hextileSubrect[i] = new VncEncodeHextileSubrect(VncPixelByteGetter.GetPixelByte(a_bytesPerPixel, a_body, offset),
                                                                                        a_body[offset + a_bytesPerPixel],
                                                                                        a_body[offset + a_bytesPerPixel + 1]);
                                        offset += a_bytesPerPixel + 2;
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < numberOfSubrectanglesHextile; ++i)
                                    {
                                        hextileSubrect[i] = new VncEncodeHextileSubrect(foregroundPixel, a_body[offset + 0], a_body[offset + 1]);
                                        offset           += 2;
                                    }
                                }
                            }
                            else
                            {
                                // Set empty subrects
                                hextileSubrect = new VncEncodeHextileSubrect[0];
                            }

                            hextiles[index] = new VncEncodeHextileTileRre(backgroundPixel, hextileSubrect);
                        }
                    }
                }

                return(new VncEncodeHextile(x, y, w, h, hextiles), offset - a_basePos);

            case VncEnum.EncodeType.ZRLE:
                int zrleLength = BigEndianBitConverter.ToInt32(a_body, a_basePos + 12);
                return(new VncEncodeZrle(x, y, w, h, a_body, a_basePos + 16, zrleLength, a_zrleReader), 12 + 4 + zrleLength);

            case VncEnum.EncodeType.Cursor:
            case VncEnum.EncodeType.DesktopSize:
            default:
                throw new NotSupportedException($"Encode type ({encodeType}) is Not supported.");
            }
        }
        private static List <byte[]> createVncEncodeBinaryFromStreamSub(Stream a_stream, byte a_bytesPerPixel, bool a_isBigendian)
        {
            // Add the read data to this list.
            var readDataList = new List <byte[]>();

            // Local function for Reading and Storing
            void readAndStore(byte[] a_buffer, int a_offset, int a_count)
            {
                a_stream.ReadAll(a_buffer, a_offset, a_count);
                readDataList.Add(a_buffer);
            };

            byte[] header = new byte[12];
            readAndStore(header, 0, header.Length);

            UInt16 x          = BigEndianBitConverter.ToUInt16(header, 0);
            UInt16 y          = BigEndianBitConverter.ToUInt16(header, 2);
            UInt16 w          = BigEndianBitConverter.ToUInt16(header, 4);
            UInt16 h          = BigEndianBitConverter.ToUInt16(header, 6);
            var    encodeType = (VncEnum.EncodeType)BigEndianBitConverter.ToInt32(header, 8);

            switch (encodeType)
            {
            case VncEnum.EncodeType.Raw:
                byte[] rawPixel = new byte[w * h * a_bytesPerPixel];
                readAndStore(rawPixel, 0, rawPixel.Length);
                break;

            case VncEnum.EncodeType.CopyRect:
                byte[] copyRectPixel = new byte[4];
                readAndStore(copyRectPixel, 0, copyRectPixel.Length);
                break;

            case VncEnum.EncodeType.RRE:
                // Read header
                byte[] rreHeader = new byte[4 + a_bytesPerPixel];
                readAndStore(rreHeader, 0, rreHeader.Length);

                UInt32 numberOfSubrectangles = BigEndianBitConverter.ToUInt32(rreHeader, 0);

                // Read subrectangles
                int    subrectSize      = a_bytesPerPixel + 8;
                byte[] rreSubrectangles = new byte[subrectSize * numberOfSubrectangles];
                readAndStore(rreSubrectangles, 0, rreSubrectangles.Length);
                break;

            case VncEnum.EncodeType.Hextile:
                int xTileCount = (int)Math.Ceiling(w / 16.0);
                int yTileCount = (int)Math.Ceiling(h / 16.0);

                // Loop for each tile
                int index = 0;
                for (int ytile = 0; ytile < yTileCount; ++ytile)
                {
                    int tileHeight = ((ytile == yTileCount - 1) && ((h % 16) != 0)) ? h % 16 : 16;
                    for (int xtile = 0; xtile < xTileCount; ++xtile, ++index)
                    {
                        int tileWidth = ((xtile == xTileCount - 1) && ((w % 16) != 0)) ? w % 16 : 16;

                        // Read header
                        byte[] subencodingMaskBuffer = new byte[1];
                        readAndStore(subencodingMaskBuffer, 0, subencodingMaskBuffer.Length);
                        var subencodingMask = new VncEncodeHextileSubencodingMask(subencodingMaskBuffer[0]);

                        if (subencodingMask.Raw)
                        {
                            // Read raw pixel data
                            byte[] tilesRawPixel = new byte[tileWidth * tileHeight * a_bytesPerPixel];
                            readAndStore(tilesRawPixel, 0, tilesRawPixel.Length);
                        }
                        else
                        {
                            // Read BackgroundSpecified if needed
                            if (subencodingMask.BackgroundSpecified)
                            {
                                byte[] backgroundPixelBuffer = new byte[a_bytesPerPixel];
                                readAndStore(backgroundPixelBuffer, 0, backgroundPixelBuffer.Length);
                            }

                            // Read ForegroundSpecified if needed
                            if (subencodingMask.ForegroundSpecified)
                            {
                                byte[] foregroundPixelBuffer = new byte[a_bytesPerPixel];
                                readAndStore(foregroundPixelBuffer, 0, foregroundPixelBuffer.Length);
                            }

                            // Subrects
                            if (subencodingMask.AnySubrects)
                            {
                                // Read number-of-subrectangles
                                byte[] numberOfSubrectanglesHextileBuffer = new byte[1];
                                readAndStore(numberOfSubrectanglesHextileBuffer, 0, numberOfSubrectanglesHextileBuffer.Length);
                                byte numberOfSubrectanglesHextile = numberOfSubrectanglesHextileBuffer[0];

                                // Read subrectangle
                                if (subencodingMask.SubrectsColored)
                                {
                                    for (int i = 0; i < numberOfSubrectanglesHextile; ++i)
                                    {
                                        byte[] hextileSubrectBuffer = new byte[a_bytesPerPixel + 2];
                                        readAndStore(hextileSubrectBuffer, 0, hextileSubrectBuffer.Length);
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < numberOfSubrectanglesHextile; ++i)
                                    {
                                        byte[] hextileSubrectBuffer = new byte[2];
                                        readAndStore(hextileSubrectBuffer, 0, hextileSubrectBuffer.Length);
                                    }
                                }
                            }
                        }
                    }
                }

                break;

            case VncEnum.EncodeType.ZRLE:
                // Read length
                byte[] zrleLengthBuffer = new byte[4];
                readAndStore(zrleLengthBuffer, 0, zrleLengthBuffer.Length);
                UInt32 zrleLength = BigEndianBitConverter.ToUInt32(zrleLengthBuffer, 0);

                // Read zlib data
                byte[] zrleZlibData = new byte[zrleLength];
                readAndStore(zrleZlibData, 0, zrleZlibData.Length);

                break;

            case VncEnum.EncodeType.Cursor:
            case VncEnum.EncodeType.DesktopSize:
            default:
                throw new NotSupportedException($"Encode type ({encodeType}) is Not supported.");
            }

            return(readDataList);
        }