/// <summary>
        /// Encode a subcodec bitmap area into byte stream
        /// </summary>
        /// <param name="subcodeBmp">The bitmap to be encoded in subcodec layer.</param>
        /// <param name="subcodecRect">The subcodec area relative to bitmap left-top edge.</param>
        /// <param name="subcodecID">The subcodec ID to be chosen.</param>
        /// <param name="subcodec">The subcodec layer encode result.</param>
        public static bool EncodeSubcodec(Bitmap subcodecBmp, ClearCodec_RECT16 subcodecRect, CLEARCODEC_SUBCODEC_ID subcodecID,
                                          ref CLEARCODEC_SUBCODEC subcodec)
        {
            if (subcodecBmp == null)
            {
                return(false);
            }

            subcodec.xStart = subcodecRect.left;
            subcodec.yStart = subcodecRect.top;
            subcodec.width  = (ushort)(subcodecRect.right - subcodecRect.left);
            subcodec.height = (ushort)(subcodecRect.bottom - subcodecRect.top);
            // save subcodecID
            subcodec.bitmapData.subCodecId = subcodecID;
            // get encoded data based on subcodecID
            if (subcodecID == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                // RLEX encoded bitmap data
                if (!RlexEncode(subcodecBmp, ref subcodec.bitmapData.bmpRlex))
                {
                    return(false);
                }
            }
            else
            {
                // raw encoded bitmap data
                if (!RawEncode(subcodecBmp, ref subcodec.bitmapData.bmpPixels))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// It decode a subcodec bitmap byte stream into CLEARCODEC_SUBCODEC structure
        /// </summary>
        /// <param name = "subcodec"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool DecodeSubcodec(ref CLEARCODEC_SUBCODEC subcodec)
        {
            if (!DecodeUShort(ref subcodec.xStart))
            {
                return(false);
            }
            if (!DecodeUShort(ref subcodec.yStart))
            {
                return(false);
            }
            if (!DecodeUShort(ref subcodec.width))
            {
                return(false);
            }
            if (!DecodeUShort(ref subcodec.height))
            {
                return(false);
            }

            if (!DecodeUInt(ref subcodec.bitmapDataByteCount))
            {
                return(false);
            }

            byte scId = 0;

            if (!DecodeByte(ref scId))
            {
                return(false);
            }
            subcodec.bitmapData.subCodecId = (CLEARCODEC_SUBCODEC_ID)scId;

            if (subcodec.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                if (!DecodeRlexData(subcodec.bitmapDataByteCount, ref subcodec.bitmapData.bmpRlex))
                {
                    return(false);
                }
            }
            else if (subcodec.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RAW)
            {
                if (subcodec.bitmapDataByteCount != 3 * subcodec.width * subcodec.height)
                {
                    return(false);
                }
                if (!DecodeRawData(subcodec.bitmapDataByteCount, ref subcodec.bitmapData.bmpPixels))
                {
                    return(false);
                }
            }
            else   // NSCodec data
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// It decode subcodec layer byte stream into CLEARCODEC_SUBCODECS_DATA structure.
        /// </summary>
        /// <param name="subcodecData">The structure that decode result save to.</param>
        /// <returns>true if decode success, otherwise return false.</returns>
        public bool Decode(ref CLEARCODEC_SUBCODEC_DATA subcodecData)
        {
            if (decodeData == null) return false;

            List<CLEARCODEC_SUBCODEC> subcodecList = new List<CLEARCODEC_SUBCODEC>();
            while (offset < decodeData.Count())
            {
                CLEARCODEC_SUBCODEC subcodec = new CLEARCODEC_SUBCODEC();
                if (!DecodeSubcodec(ref subcodec)) return false;
                subcodecList.Add(subcodec);
            }
            subcodecData.subcodecArr = subcodecList.ToArray();
            return true;
        }
        /// <summary>
        /// It decode subcodec layer byte stream into CLEARCODEC_SUBCODECS_DATA structure.
        /// </summary>
        /// <param name="subcodecData">The structure that decode result save to.</param>
        /// <returns>true if decode success, otherwise return false.</returns>
        public bool Decode(ref CLEARCODEC_SUBCODEC_DATA subcodecData)
        {
            if (decodeData == null)
            {
                return(false);
            }

            List <CLEARCODEC_SUBCODEC> subcodecList = new List <CLEARCODEC_SUBCODEC>();

            while (offset < decodeData.Count())
            {
                CLEARCODEC_SUBCODEC subcodec = new CLEARCODEC_SUBCODEC();
                if (!DecodeSubcodec(ref subcodec))
                {
                    return(false);
                }
                subcodecList.Add(subcodec);
            }
            subcodecData.subcodecArr = subcodecList.ToArray();
            return(true);
        }
        /// <summary>
        /// Encode multiple bitmap areas via subcodec into byte stream
        /// </summary>
        /// <param name="bandDict">The structure saves multiple subcodec layer bitmap, subcodecID and position.</param>
        public static CLEARCODEC_SUBCODEC_DATA Encode(Dictionary <ClearCodec_RECT16, BMP_INFO> subcodecDict)
        {
            List <CLEARCODEC_SUBCODEC> subcodecList = new List <CLEARCODEC_SUBCODEC>();

            foreach (KeyValuePair <ClearCodec_RECT16, BMP_INFO> scArea in subcodecDict)
            {
                CLEARCODEC_SUBCODEC scData = new CLEARCODEC_SUBCODEC();
                if (!EncodeSubcodec((Bitmap)(scArea.Value.bmp), scArea.Key, scArea.Value.scID, ref scData))
                {
                    // skip a subcodec layer bitmap if it failed to be encoded.
                    continue;
                }

                subcodecList.Add(scData);
            }

            CLEARCODEC_SUBCODEC_DATA subcodecs = new CLEARCODEC_SUBCODEC_DATA();

            subcodecs.subcodecArr = subcodecList.ToArray();

            return(subcodecs);
        }
        /// <summary>
        /// Convert CLEARCODEC_SUBCODEC structure into byte stream.
        /// </summary>
        /// <param name="scStruct">The encoded CLEARCODEC_SUBCODEC structure.</param>
        public byte[] ToBytes(CLEARCODEC_SUBCODEC scStruct)
        {
            List <byte> bufList = new List <byte>();

            bufList.AddRange(TypeMarshal.ToBytes <ushort>(scStruct.xStart));
            bufList.AddRange(TypeMarshal.ToBytes <ushort>(scStruct.yStart));
            bufList.AddRange(TypeMarshal.ToBytes <ushort>(scStruct.width));
            bufList.AddRange(TypeMarshal.ToBytes <ushort>(scStruct.height));

            byte[] bmpData = null;

            if (scStruct.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RAW)
            {
                bmpData = ToBytes(scStruct.bitmapData.bmpPixels);
            }
            else if (scStruct.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                bmpData = ToBytes(scStruct.bitmapData.bmpRlex);
            }
            else    // NSCodec bitmap data for subcodec layer.
            {
            }

            // Set bitmapData byte length.
            if (bmpData != null)
            {
                scStruct.bitmapDataByteCount = (uint)bmpData.Count();
            }

            bufList.AddRange(TypeMarshal.ToBytes <uint>(scStruct.bitmapDataByteCount));
            bufList.AddRange(TypeMarshal.ToBytes <byte>((byte)scStruct.bitmapData.subCodecId));
            if (bmpData != null)
            {
                bufList.AddRange(bmpData);
            }

            return(bufList.ToArray());
        }
        /// <summary>
        /// It decode a subcodec bitmap byte stream into CLEARCODEC_SUBCODEC structure
        /// </summary>
        /// <param name = "subcodec"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool DecodeSubcodec(ref CLEARCODEC_SUBCODEC subcodec)
        {
            if (!DecodeUShort(ref subcodec.xStart)) return false;
            if (!DecodeUShort(ref subcodec.yStart)) return false;
            if (!DecodeUShort(ref subcodec.width)) return false;
            if (!DecodeUShort(ref subcodec.height)) return false;

            if (!DecodeUInt(ref subcodec.bitmapDataByteCount)) return false;

            byte scId = 0;
            if (!DecodeByte(ref scId)) return false;
            subcodec.bitmapData.subCodecId = (CLEARCODEC_SUBCODEC_ID)scId;

            if (subcodec.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                if (!DecodeRlexData(subcodec.bitmapDataByteCount, ref subcodec.bitmapData.bmpRlex)) return false;
            }
            else if (subcodec.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RAW)
            {
                if (subcodec.bitmapDataByteCount != 3 * subcodec.width * subcodec.height)
                    return false;
                if (!DecodeRawData(subcodec.bitmapDataByteCount, ref subcodec.bitmapData.bmpPixels)) return false;
            }
            else   // NSCodec data
            {
                return false;
            }

            return true;
        }
        /// <summary>
        /// Encode a subcodec bitmap area into byte stream
        /// </summary>
        /// <param name="subcodeBmp">The bitmap to be encoded in subcodec layer.</param>
        /// <param name="subcodecRect">The subcodec area relative to bitmap left-top edge.</param>
        /// <param name="subcodecID">The subcodec ID to be chosen.</param>
        /// <param name="subcodec">The subcodec layer encode result.</param>
        public static bool EncodeSubcodec(Bitmap subcodecBmp, ClearCodec_RECT16 subcodecRect, CLEARCODEC_SUBCODEC_ID subcodecID, 
            ref CLEARCODEC_SUBCODEC subcodec)
        {
            if (subcodecBmp == null) return false;

            subcodec.xStart = subcodecRect.left;
            subcodec.yStart = subcodecRect.top;
            subcodec.width = (ushort)(subcodecRect.right - subcodecRect.left);
            subcodec.height = (ushort)(subcodecRect.bottom - subcodecRect.top);
            // save subcodecID
            subcodec.bitmapData.subCodecId = subcodecID;
            // get encoded data based on subcodecID
            if (subcodecID == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                // RLEX encoded bitmap data
                if( !RlexEncode(subcodecBmp, ref subcodec.bitmapData.bmpRlex)) return false;

            }
            else
            {
                // raw encoded bitmap data
                if (!RawEncode(subcodecBmp, ref subcodec.bitmapData.bmpPixels)) return false;
            }

            return true;
        }
        /// <summary>
        /// Encode multiple bitmap areas via subcodec into byte stream
        /// </summary>
        /// <param name="bandDict">The structure saves multiple subcodec layer bitmap, subcodecID and position.</param>
        public static CLEARCODEC_SUBCODEC_DATA Encode(Dictionary<ClearCodec_RECT16, BMP_INFO> subcodecDict)
        {
            List<CLEARCODEC_SUBCODEC> subcodecList = new List<CLEARCODEC_SUBCODEC>();

            foreach (KeyValuePair<ClearCodec_RECT16, BMP_INFO> scArea in subcodecDict)
            {
                CLEARCODEC_SUBCODEC scData = new CLEARCODEC_SUBCODEC();
                if (!EncodeSubcodec((Bitmap)(scArea.Value.bmp), scArea.Key, scArea.Value.scID, ref scData))
                {
                    // skip a subcodec layer bitmap if it failed to be encoded.
                    continue;
                }

                subcodecList.Add(scData);
            }

            CLEARCODEC_SUBCODEC_DATA subcodecs = new CLEARCODEC_SUBCODEC_DATA();
            subcodecs.subcodecArr = subcodecList.ToArray();

            return subcodecs;
        }
        /// <summary>
        /// Convert CLEARCODEC_SUBCODEC structure into byte stream.
        /// </summary>
        /// <param name="scStruct">The encoded CLEARCODEC_SUBCODEC structure.</param>
        public byte[] ToBytes(CLEARCODEC_SUBCODEC scStruct)
        {
            List<byte> bufList = new List<byte>();

            bufList.AddRange(TypeMarshal.ToBytes<ushort>(scStruct.xStart));
            bufList.AddRange(TypeMarshal.ToBytes<ushort>(scStruct.yStart));
            bufList.AddRange(TypeMarshal.ToBytes<ushort>(scStruct.width));
            bufList.AddRange(TypeMarshal.ToBytes<ushort>(scStruct.height));

            byte[] bmpData = null;

            if (scStruct.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RAW)
            {
                bmpData = ToBytes(scStruct.bitmapData.bmpPixels);
            }
            else if (scStruct.bitmapData.subCodecId == CLEARCODEC_SUBCODEC_ID.SUBCODEC_RLEX)
            {
                bmpData = ToBytes(scStruct.bitmapData.bmpRlex);
            }
            else    // NSCodec bitmap data for subcodec layer.
            {

            }

            // Set bitmapData byte length.
            if (bmpData != null)
            {
                scStruct.bitmapDataByteCount = (uint)bmpData.Count();
            }

            bufList.AddRange(TypeMarshal.ToBytes<uint>(scStruct.bitmapDataByteCount));
            bufList.AddRange(TypeMarshal.ToBytes<byte>((byte)scStruct.bitmapData.subCodecId));
            if (bmpData != null)
                bufList.AddRange(bmpData);

            return bufList.ToArray();
        }