/// <summary>
        /// It decode byte stream into CLEARCODEC_SUBCODEC_RLEX_SEGMENT structure
        /// </summary>
        /// <param name = "stopIdxBitNum"> the bit number of stopIndex field </param>
        /// <param name = "relSeg"> the structure that decode result save to </param>
        /// <return> > 0 if decode success, otherwise return 0 </return>
        public byte DecodeRlexSeg(byte stopIdxBitNum, ref CLEARCODEC_SUBCODEC_RLEX_SEGMENT relSeg)
        {
            byte stopIdx_suiteDepth = 0;
            byte decodedCount       = 0;

            if (!DecodeByte(ref stopIdx_suiteDepth))
            {
                return(0);
            }
            decodedCount++;
            byte stopIdxMask = (byte)((1 << stopIdxBitNum) - 1);

            relSeg.stopIndex  = (byte)(stopIdx_suiteDepth & stopIdxMask);
            relSeg.suiteDepth = (byte)(stopIdx_suiteDepth >> stopIdxBitNum);

            if (!DecodeRulLengthFactor(ref relSeg.runLengthFactor))
            {
                return(0);
            }
            if (relSeg.runLengthFactor < 0xff)
            {
                decodedCount++;
            }
            else if (relSeg.runLengthFactor < 0xffff)
            {
                decodedCount += 3;
            }
            else
            {
                decodedCount += 7;
            }

            return(decodedCount);
        }
        /// <summary>
        /// It decode rlexByteCount bytes data into CLEARCODEC_SUBCODEC_RLEX structure
        /// </summary>
        /// <param name = "rlexByteCount"> the number of bytes to be decoded into CLEARCODEC_SUBCODEC_RLEX structure </param>
        /// <param name = "rlex"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool DecodeRlexData(uint rlexByteCount, ref CLEARCODEC_SUBCODEC_RLEX rlex)
        {
            if (!DecodeByte(ref rlex.paletteCount)) return false;
            rlexByteCount--;

            // calculate bitNum of stopIndex in rlex segment
            byte bitNum = 0;
            byte count = rlex.paletteCount;
            // calculate bit number for stopIndex
            while (count > 0)
            {
                bitNum++;
                count >>= 1;
            }

            // decode pletteEntries
            List<RLEX_RGB_TRIPLET> pletList = new List<RLEX_RGB_TRIPLET>();
            for (int i = 0; i < rlex.paletteCount; i++)
            {
                RLEX_RGB_TRIPLET plet = new RLEX_RGB_TRIPLET();
                if (!DecodeByte(ref plet.B)) return false;
                if (!DecodeByte(ref plet.G)) return false;
                if (!DecodeByte(ref plet.R)) return false;
                rlexByteCount -= 3;
                pletList.Add(plet);
            }
            rlex.paletteEntries = pletList.ToArray();

            // decode rlex segments
            List<CLEARCODEC_SUBCODEC_RLEX_SEGMENT> segList = new List<CLEARCODEC_SUBCODEC_RLEX_SEGMENT>();
            while (rlexByteCount > 0)
            {
                CLEARCODEC_SUBCODEC_RLEX_SEGMENT rlex_seg = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();
                byte decodedBytes = DecodeRlexSeg(bitNum, ref rlex_seg);
                if (decodedBytes == 0) return false;
                rlexByteCount -= decodedBytes;
                segList.Add(rlex_seg);
            }

            if (rlexByteCount < 0) return false;
            rlex.segments = segList.ToArray();
            return true;
        }
        /// <summary>
        /// It decode byte stream into CLEARCODEC_SUBCODEC_RLEX_SEGMENT structure
        /// </summary>
        /// <param name = "stopIdxBitNum"> the bit number of stopIndex field </param>
        /// <param name = "relSeg"> the structure that decode result save to </param>
        /// <return> > 0 if decode success, otherwise return 0 </return>
        public byte DecodeRlexSeg(byte stopIdxBitNum, ref CLEARCODEC_SUBCODEC_RLEX_SEGMENT relSeg)
        {
            byte stopIdx_suiteDepth = 0;
            byte decodedCount = 0;
            if (!DecodeByte(ref stopIdx_suiteDepth)) return 0;
            decodedCount++;
            byte stopIdxMask =  (byte)((1 << stopIdxBitNum) - 1);
            relSeg.stopIndex = (byte)(stopIdx_suiteDepth & stopIdxMask);
            relSeg.suiteDepth = (byte)(stopIdx_suiteDepth >> stopIdxBitNum);

            if (!DecodeRulLengthFactor(ref relSeg.runLengthFactor)) return 0;
            if (relSeg.runLengthFactor < 0xff)
                decodedCount++;
            else if (relSeg.runLengthFactor < 0xffff)
                decodedCount += 3;
            else
                decodedCount += 7;

            return decodedCount;
        }
        /// <summary>
        /// Encode a bitmap with RLEX method
        /// </summary>
        /// <param name="subcodeBmp">The bitmap to be encoded in subcodec layer.</param>
        /// <return> > 0 if encode success, otherwise return 0 </return>
        public static bool RlexEncode(Bitmap subcodecBmp, ref CLEARCODEC_SUBCODEC_RLEX rlex)
        {
            if (subcodecBmp == null) return false;

            Dictionary<RLEX_RGB_TRIPLET, byte> pletteDict = GetTripletDict(subcodecBmp);

            // if the bitmap color number is bigger than 255, RLEX subcodec encoding can't be applied.
            if (pletteDict.Count() > 0xff)
                return false;

            rlex.paletteCount = (byte)pletteDict.Count();
            rlex.paletteEntries = new RLEX_RGB_TRIPLET[rlex.paletteCount];
            int index=0;
            foreach (KeyValuePair<RLEX_RGB_TRIPLET, byte> triPlette in pletteDict)
            {
                rlex.paletteEntries[index] = triPlette.Key;
                index++;
            }

            List<CLEARCODEC_SUBCODEC_RLEX_SEGMENT> rlexSegList = new List<CLEARCODEC_SUBCODEC_RLEX_SEGMENT>();
            CLEARCODEC_SUBCODEC_RLEX_SEGMENT rlex_seg = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();

            rlex_seg.suiteDepth = 0; // we always set suite depth is 0 due to only 1 color in a suite
            rlex_seg.stopIndex = ColorToPletIdx(subcodecBmp.GetPixel(0, 0), pletteDict);
            rlex_seg.runLengthFactor = 0;   // the first pixel in blow loop is at (0, 0), rlfactor is init as 0 here.

            for (int y = 0; y < subcodecBmp.Height; y++)
            {
                for (int x = 0; x < subcodecBmp.Width; x++)
                {
                    if (x == 0 && y == 0) continue; // skip the pixel (0, 0)
                    Color pixelColor = subcodecBmp.GetPixel(x, y);
                    byte pletIdx = ColorToPletIdx(pixelColor, pletteDict);

                    if (rlex_seg.stopIndex == pletIdx)  // same color as previous one
                    {
                        rlex_seg.runLengthFactor++;
                    }
                    else
                    {
                        // add old structure into list
                        rlexSegList.Add(rlex_seg);
                        // create a new structure for the pixel
                        rlex_seg = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();
                        rlex_seg.suiteDepth = 0;
                        rlex_seg.stopIndex = pletIdx;
                        rlex_seg.runLengthFactor = 0;
                    }
                }

            }
            // add the final structure into list
            rlexSegList.Add(rlex_seg);

            rlex.segments = rlexSegList.ToArray();

            return true;
        }
        /// <summary>
        /// It decode rlexByteCount bytes data into CLEARCODEC_SUBCODEC_RLEX structure
        /// </summary>
        /// <param name = "rlexByteCount"> the number of bytes to be decoded into CLEARCODEC_SUBCODEC_RLEX structure </param>
        /// <param name = "rlex"> the structure that decode result save to </param>
        /// <return> true if decode success, otherwise return false </return>
        public bool DecodeRlexData(uint rlexByteCount, ref CLEARCODEC_SUBCODEC_RLEX rlex)
        {
            if (!DecodeByte(ref rlex.paletteCount))
            {
                return(false);
            }
            rlexByteCount--;

            // calculate bitNum of stopIndex in rlex segment
            byte bitNum = 0;
            byte count  = rlex.paletteCount;

            // calculate bit number for stopIndex
            while (count > 0)
            {
                bitNum++;
                count >>= 1;
            }

            // decode pletteEntries
            List <RLEX_RGB_TRIPLET> pletList = new List <RLEX_RGB_TRIPLET>();

            for (int i = 0; i < rlex.paletteCount; i++)
            {
                RLEX_RGB_TRIPLET plet = new RLEX_RGB_TRIPLET();
                if (!DecodeByte(ref plet.B))
                {
                    return(false);
                }
                if (!DecodeByte(ref plet.G))
                {
                    return(false);
                }
                if (!DecodeByte(ref plet.R))
                {
                    return(false);
                }
                rlexByteCount -= 3;
                pletList.Add(plet);
            }
            rlex.paletteEntries = pletList.ToArray();

            // decode rlex segments
            List <CLEARCODEC_SUBCODEC_RLEX_SEGMENT> segList = new List <CLEARCODEC_SUBCODEC_RLEX_SEGMENT>();

            while (rlexByteCount > 0)
            {
                CLEARCODEC_SUBCODEC_RLEX_SEGMENT rlex_seg = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();
                byte decodedBytes = DecodeRlexSeg(bitNum, ref rlex_seg);
                if (decodedBytes == 0)
                {
                    return(false);
                }
                rlexByteCount -= decodedBytes;
                segList.Add(rlex_seg);
            }

            if (rlexByteCount < 0)
            {
                return(false);
            }
            rlex.segments = segList.ToArray();
            return(true);
        }
        /// <summary>
        /// Encode a bitmap with RLEX method
        /// </summary>
        /// <param name="subcodeBmp">The bitmap to be encoded in subcodec layer.</param>
        /// <return> > 0 if encode success, otherwise return 0 </return>
        public static bool RlexEncode(Bitmap subcodecBmp, ref CLEARCODEC_SUBCODEC_RLEX rlex)
        {
            if (subcodecBmp == null)
            {
                return(false);
            }

            Dictionary <RLEX_RGB_TRIPLET, byte> pletteDict = GetTripletDict(subcodecBmp);

            // if the bitmap color number is bigger than 255, RLEX subcodec encoding can't be applied.
            if (pletteDict.Count() > 0xff)
            {
                return(false);
            }

            rlex.paletteCount   = (byte)pletteDict.Count();
            rlex.paletteEntries = new RLEX_RGB_TRIPLET[rlex.paletteCount];
            int index = 0;

            foreach (KeyValuePair <RLEX_RGB_TRIPLET, byte> triPlette in pletteDict)
            {
                rlex.paletteEntries[index] = triPlette.Key;
                index++;
            }

            List <CLEARCODEC_SUBCODEC_RLEX_SEGMENT> rlexSegList = new List <CLEARCODEC_SUBCODEC_RLEX_SEGMENT>();
            CLEARCODEC_SUBCODEC_RLEX_SEGMENT        rlex_seg    = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();

            rlex_seg.suiteDepth      = 0; // we always set suite depth is 0 due to only 1 color in a suite
            rlex_seg.stopIndex       = ColorToPletIdx(subcodecBmp.GetPixel(0, 0), pletteDict);
            rlex_seg.runLengthFactor = 0; // the first pixel in blow loop is at (0, 0), rlfactor is init as 0 here.

            for (int y = 0; y < subcodecBmp.Height; y++)
            {
                for (int x = 0; x < subcodecBmp.Width; x++)
                {
                    if (x == 0 && y == 0)
                    {
                        continue;                   // skip the pixel (0, 0)
                    }
                    Color pixelColor = subcodecBmp.GetPixel(x, y);
                    byte  pletIdx    = ColorToPletIdx(pixelColor, pletteDict);

                    if (rlex_seg.stopIndex == pletIdx)  // same color as previous one
                    {
                        rlex_seg.runLengthFactor++;
                    }
                    else
                    {
                        // add old structure into list
                        rlexSegList.Add(rlex_seg);
                        // create a new structure for the pixel
                        rlex_seg                 = new CLEARCODEC_SUBCODEC_RLEX_SEGMENT();
                        rlex_seg.suiteDepth      = 0;
                        rlex_seg.stopIndex       = pletIdx;
                        rlex_seg.runLengthFactor = 0;
                    }
                }
            }
            // add the final structure into list
            rlexSegList.Add(rlex_seg);

            rlex.segments = rlexSegList.ToArray();

            return(true);
        }