/// <summary>
        /// Encode a bitmap with Run-length format
        /// </summary>
        /// <param name="resBmp">The bitmap to be encoded in residual layer.</param>
        public static CLEARCODEC_RESIDUAL_DATA Encode(Bitmap resBmp)
        {
            CLEARCODEC_RESIDUAL_DATA          resData      = new CLEARCODEC_RESIDUAL_DATA();
            List <CLEARCODEC_RGB_RUN_SEGMENT> resRLSegList = new List <CLEARCODEC_RGB_RUN_SEGMENT>();
            Color compColor = resBmp.GetPixel(0, 0);

            uint count = 0;

            for (ushort y = 0; y < resBmp.Height; y++)
            {
                for (ushort x = 0; x < resBmp.Width; x++)
                {
                    Color pixelColor = resBmp.GetPixel(x, y);
                    if (compColor.Equals(pixelColor))
                    {
                        count++;
                    }
                    else
                    {
                        // add old compared color with repeate count into list
                        addPixelToRLSegList(resRLSegList, compColor, count);

                        // reset to new compare color and count.
                        compColor = pixelColor;
                        count     = 1;
                    }
                }
            }

            // add the last color RL seg here
            addPixelToRLSegList(resRLSegList, compColor, count);
            resData.resRLSegArr = resRLSegList.ToArray();

            return(resData);
        }
        /// <summary>
        /// It decode byte stream into CLEARCODEC_RESIDUAL_DATA structure
        /// </summary>
        /// <param name = "residualSegs"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool Decode(ref CLEARCODEC_RESIDUAL_DATA residualSegs)
        {
            if (decodeData == null) return false;

            List<CLEARCODEC_RGB_RUN_SEGMENT> segList = new List<CLEARCODEC_RGB_RUN_SEGMENT>();

            while (offset < decodeData.Count())
            {
                CLEARCODEC_RGB_RUN_SEGMENT runSeg = new CLEARCODEC_RGB_RUN_SEGMENT();
                if (!DecodeByte(ref runSeg.buleValue)) return false;
                if (!DecodeByte(ref runSeg.greenValue)) return false;
                if (!DecodeByte(ref runSeg.redValue)) return false;
                // decode rlfactor
                if (!DecodeRulLengthFactor(ref runSeg.rlFactor)) return false;

                segList.Add(runSeg);
            }

            residualSegs.resRLSegArr = segList.ToArray();
            return true;
        }
        /// <summary>
        /// It decode byte stream into CLEARCODEC_RESIDUAL_DATA structure
        /// </summary>
        /// <param name = "residualSegs"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool Decode(ref CLEARCODEC_RESIDUAL_DATA residualSegs)
        {
            if (decodeData == null)
            {
                return(false);
            }

            List <CLEARCODEC_RGB_RUN_SEGMENT> segList = new List <CLEARCODEC_RGB_RUN_SEGMENT>();

            while (offset < decodeData.Count())
            {
                CLEARCODEC_RGB_RUN_SEGMENT runSeg = new CLEARCODEC_RGB_RUN_SEGMENT();
                if (!DecodeByte(ref runSeg.buleValue))
                {
                    return(false);
                }
                if (!DecodeByte(ref runSeg.greenValue))
                {
                    return(false);
                }
                if (!DecodeByte(ref runSeg.redValue))
                {
                    return(false);
                }
                // decode rlfactor
                if (!DecodeRulLengthFactor(ref runSeg.rlFactor))
                {
                    return(false);
                }

                segList.Add(runSeg);
            }

            residualSegs.resRLSegArr = segList.ToArray();
            return(true);
        }
        /// <summary>
        /// Convert encoded residual layer structure into byte stream.
        /// </summary>
        /// <param name = "resData">The structure data to be converted into byte stream.</param>
        public byte[] ToBytes(CLEARCODEC_RESIDUAL_DATA resData)
        {
            if (resData.resRLSegArr == null) return null;
            List<byte> bufList = new List<byte>();

            for (int i = 0; i < resData.resRLSegArr.Count(); i++)
            {
                CLEARCODEC_RGB_RUN_SEGMENT seg = resData.resRLSegArr[i];

                bufList.AddRange(TypeMarshal.ToBytes<byte>(seg.buleValue));
                bufList.AddRange(TypeMarshal.ToBytes<byte>(seg.greenValue));
                bufList.AddRange(TypeMarshal.ToBytes<byte>(seg.redValue));

                if (ccTestType == RdpegfxNegativeTypes.ClearCodec_Residual_ZeroRunLengthFactor)
                {
                    bufList.AddRange(TypeMarshal.ToBytes<byte>(0x00));
                    break;
                }

                if (seg.rlFactor < 255) // RLF1 exists, RLF2 & 3 doesn't exit.
                {
                    bufList.AddRange(TypeMarshal.ToBytes<byte>((byte)seg.rlFactor));
                }
                else if (seg.rlFactor < 65535)  // RLF1 is 0xff, RLF2 exists, RLF3 doesn't exit.
                {
                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<byte>(0xff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<byte>(0xf0));
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_AbsentRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<ushort>((ushort)seg.rlFactor));
                    }
                }
                else  // RLF1 is 0xff, RLF2 is 0xffff, RLF3 exists.
                {
                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<byte>(0xff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<byte>(0xf0));
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor3)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<ushort>(0xffff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<ushort>(0xf0f0));
                        // Change RLF3 highest byte to avoid RLF3 is parsed into a color(3 bytes) plus RLF1=0
                        // when RLF1 is zero, all the left area will be filled by the color, no error triggers.
                        seg.rlFactor |= 0xf0000000;
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_AbsentRunLengthFactor3)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes<uint>((uint)seg.rlFactor));
                    }
                }
            }
            return bufList.ToArray();
        }
        /// <summary>
        /// Encode a bitmap with Run-length format
        /// </summary>
        /// <param name="resBmp">The bitmap to be encoded in residual layer.</param>
        public static CLEARCODEC_RESIDUAL_DATA Encode(Bitmap resBmp)
        {
            CLEARCODEC_RESIDUAL_DATA resData = new CLEARCODEC_RESIDUAL_DATA();
            List<CLEARCODEC_RGB_RUN_SEGMENT> resRLSegList = new List<CLEARCODEC_RGB_RUN_SEGMENT>();
            Color compColor = resBmp.GetPixel(0, 0);

            uint count = 0;
            for (ushort y = 0; y < resBmp.Height; y++)
            {
                for (ushort x = 0; x < resBmp.Width; x++)
                {
                    Color pixelColor = resBmp.GetPixel(x, y);
                    if (compColor.Equals(pixelColor))
                    {
                        count++;
                    }
                    else
                    {
                        // add old compared color with repeate count into list
                        addPixelToRLSegList(resRLSegList, compColor, count);

                        // reset to new compare color and count.
                        compColor = pixelColor;
                        count = 1;
                    }
                }
            }

            // add the last color RL seg here
            addPixelToRLSegList(resRLSegList, compColor, count);
            resData.resRLSegArr = resRLSegList.ToArray();

            return resData;
        }
        /// <summary>
        /// Encode the residual, band, and subcodec layer images into a bytestream.
        /// </summary>
        public byte[] EncodeCompositePayload()
        {
            List <byte> buf = new List <byte>();

            if (resBmp != null)
            {
                CLEARCODEC_RESIDUAL_DATA resData = ClearCodecResidualEncoder.Encode(resBmp);
                compPayload.residualData = ToBytes(resData);
                if (compPayload.residualData == null)
                {
                    return(null);
                }
                compPayload.residualByteCount = (uint)compPayload.residualData.Count();
            }
            else
            {
                compPayload.residualByteCount = 0;
                compPayload.residualData      = null;
            }

            if (bandDict.Count() != 0)  // Band image are loaded before.
            {
                ClearCodecBandEncoder bandencoder = ClearCodecBandEncoder.GetInstance();
                if ((this.flags & ClearCodec_BitmapStream.CLEARCODEC_FLAG_CACHE_RESET) != 0)
                {
                    bandencoder.ResetVBarStorage();
                }
                CLEARCODEC_BAND_DATA bandsData = bandencoder.Encode(bandDict);
                compPayload.bandData = ToBytes(bandsData);
                if (compPayload.bandData == null)
                {
                    return(null);
                }
                compPayload.bandByteCount = (uint)compPayload.bandData.Count();
            }
            else
            {
                compPayload.bandByteCount = 0;
                compPayload.bandData      = null;
            }

            if (subcodecDict.Count() != 0)  // Subcodec image are loaded before.
            {
                CLEARCODEC_SUBCODEC_DATA subcodecs = ClearCodecSubCodecEncoder.Encode(subcodecDict);
                compPayload.subcodecData = ToBytes(subcodecs);
                if (compPayload.subcodecData == null)
                {
                    return(null);
                }
                compPayload.subcodecByteCount = (uint)compPayload.subcodecData.Count();
            }
            else
            {
                compPayload.subcodecByteCount = 0;
                compPayload.subcodecData      = null;
            }

            buf.AddRange(TypeMarshal.ToBytes <uint>(compPayload.residualByteCount));
            buf.AddRange(TypeMarshal.ToBytes <uint>(compPayload.bandByteCount));
            buf.AddRange(TypeMarshal.ToBytes <uint>(compPayload.subcodecByteCount));

            if (compPayload.residualByteCount > 0)
            {
                buf.AddRange(compPayload.residualData);
            }

            if (compPayload.bandByteCount > 0)
            {
                buf.AddRange(compPayload.bandData);
            }

            if (compPayload.subcodecByteCount > 0)
            {
                buf.AddRange(compPayload.subcodecData);
            }

            return(buf.ToArray());
        }
        /// <summary>
        /// Convert encoded residual layer structure into byte stream.
        /// </summary>
        /// <param name = "resData">The structure data to be converted into byte stream.</param>
        public byte[] ToBytes(CLEARCODEC_RESIDUAL_DATA resData)
        {
            if (resData.resRLSegArr == null)
            {
                return(null);
            }
            List <byte> bufList = new List <byte>();

            for (int i = 0; i < resData.resRLSegArr.Count(); i++)
            {
                CLEARCODEC_RGB_RUN_SEGMENT seg = resData.resRLSegArr[i];

                bufList.AddRange(TypeMarshal.ToBytes <byte>(seg.buleValue));
                bufList.AddRange(TypeMarshal.ToBytes <byte>(seg.greenValue));
                bufList.AddRange(TypeMarshal.ToBytes <byte>(seg.redValue));

                if (ccTestType == RdpegfxNegativeTypes.ClearCodec_Residual_ZeroRunLengthFactor)
                {
                    bufList.AddRange(TypeMarshal.ToBytes <byte>(0x00));
                    break;
                }

                if (seg.rlFactor < 255) // RLF1 exists, RLF2 & 3 doesn't exit.
                {
                    bufList.AddRange(TypeMarshal.ToBytes <byte>((byte)seg.rlFactor));
                }
                else if (seg.rlFactor < 65535)  // RLF1 is 0xff, RLF2 exists, RLF3 doesn't exit.
                {
                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <byte>(0xff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <byte>(0xf0));
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_AbsentRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <ushort>((ushort)seg.rlFactor));
                    }
                }
                else  // RLF1 is 0xff, RLF2 is 0xffff, RLF3 exists.
                {
                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor2)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <byte>(0xff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <byte>(0xf0));
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_RedundantRunLengthFactor3)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <ushort>(0xffff));
                    }
                    else
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <ushort>(0xf0f0));
                        // Change RLF3 highest byte to avoid RLF3 is parsed into a color(3 bytes) plus RLF1=0
                        // when RLF1 is zero, all the left area will be filled by the color, no error triggers.
                        seg.rlFactor |= 0xf0000000;
                    }

                    if (ccTestType != RdpegfxNegativeTypes.ClearCodec_Residual_AbsentRunLengthFactor3)
                    {
                        bufList.AddRange(TypeMarshal.ToBytes <uint>((uint)seg.rlFactor));
                    }
                }
            }
            return(bufList.ToArray());
        }