/// <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>
 /// Load a residual layer bitmap into clearcode encoder.
 /// </summary>
 /// <param name = "bandBitmap"> specifies a band layer image </param>
 /// <param name = "pos"> specifies position of band layer image, relative to residual layer image </param>
 public void LoadBandBitmap(Bitmap bandBitmap, RDPGFX_POINT16 pos)
 {
     if (bandBitmap != null)
     {
         ClearCodec_RECT16 bRect = new ClearCodec_RECT16();
         bRect.left   = pos.x;
         bRect.top    = pos.y;
         bRect.right  = (ushort)(pos.x + bandBitmap.Width);
         bRect.bottom = (ushort)(pos.y + bandBitmap.Height);
         this.bandDict.Add(bRect, bandBitmap);
     }
 }
 /// <summary>
 /// Load a residual layer bitmap into clearcode encoder.
 /// </summary>
 /// <param name = "subcodecBitmap"> specifies a subcodec layer image </param>
 /// <param name = "pos"> specifies position of subcodec layer image, relative to residual layer image </param>
 /// <param name = "sbcID"> specifies subcodec ID to encoding subcodec layer image </param>
 public void LoadSubcodecBitmap(Bitmap subcodecBitmap, RDPGFX_POINT16 pos, CLEARCODEC_SUBCODEC_ID sbcID)
 {
     if (subcodecBitmap != null)
     {
         ClearCodec_RECT16 scRect = new ClearCodec_RECT16();
         scRect.left   = pos.x;
         scRect.top    = pos.y;
         scRect.right  = (ushort)(pos.x + subcodecBitmap.Width);
         scRect.bottom = (ushort)(pos.x + subcodecBitmap.Height);
         BMP_INFO bmp_info = new BMP_INFO();
         bmp_info.bmp  = subcodecBitmap;
         bmp_info.scID = sbcID;
         this.subcodecDict.Add(scRect, bmp_info);
     }
 }
        /// <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 a band bitmap into byte stream
        /// </summary>
        /// <param name="bandBmp">The bitmap to be encoded in band layer.</param>
        /// <param name="bandRect">The band position relative to bitmap left-top edge.</param>
        public CLEARCODEC_BAND EncodeBand(Bitmap bandBmp, ClearCodec_RECT16 bandRect)
        {
            CLEARCODEC_BAND bandData = new CLEARCODEC_BAND();

            Color bgColor = bandBmp.GetPixel(0, 0);

            bandData.xStart = bandRect.left;
            bandData.xEnd   = (ushort)(bandRect.right - 1);
            bandData.yStart = bandRect.top;
            bandData.yEnd   = (ushort)(bandRect.bottom - 1);

            bandData.blueBkg  = bgColor.B;
            bandData.greenBkg = bgColor.G;
            bandData.redBkg   = bgColor.R;

            List <CLEARCODEC_VBAR> vBarList = new List <CLEARCODEC_VBAR>();

            // use short vbar cache miss method
            for (ushort x = 0; x < bandBmp.Width; x++)
            {
                byte shortVBarYOn  = 0; // relative to top of V-Bar, won't excceed 52
                byte shortVBarYOff = 0; // relative to top of V-Bar, won't excceed 52

                // find shortVBarYOn from top
                byte y;  // bandBmp.Height can't exceed 52 pixels
                for (y = 0; y < bandBmp.Height; y++)
                {
                    Color pixelColor = bandBmp.GetPixel(x, y);
                    if (!bgColor.Equals(pixelColor))
                    {
                        shortVBarYOn = (byte)y;
                        break;
                    }
                }

                // the whole vbar use bgColor
                if (y == (ushort)bandBmp.Height)
                {
                    shortVBarYOn  = (byte)y;
                    shortVBarYOff = (byte)y;
                }

                // find shortVBarYOff from bottem, which is the first position for left bgcolor
                for (y = (byte)(bandBmp.Height - 1); y > shortVBarYOn; y--)
                {
                    Color pixelColor = bandBmp.GetPixel(x, y);
                    if (!bgColor.Equals(pixelColor))
                    {
                        shortVBarYOff = (byte)(y + 1);
                        break;
                    }
                }

                // only one point in shortVBar is different from bgColor
                if (y == shortVBarYOn)
                {
                    shortVBarYOff = (byte)(shortVBarYOn + 1);
                }

                // construct short Vbar Pixels

                List <Color_RGB> shortVBarPixelList = new List <Color_RGB>();
                for (y = shortVBarYOn; y < shortVBarYOff; y++)
                {
                    Color     pixelColor = bandBmp.GetPixel(x, y);
                    Color_RGB svbarColor = new Color_RGB();
                    svbarColor.B = pixelColor.B;
                    svbarColor.G = pixelColor.G;
                    svbarColor.R = pixelColor.R;

                    shortVBarPixelList.Add(svbarColor);
                }

                // construct vbar pixels
                List <Color_RGB> vBarPixelList = new List <Color_RGB>();
                for (int k = 0; k < bandBmp.Height; k++)
                {
                    Color     pixelColor = bandBmp.GetPixel(x, k);
                    Color_RGB vbarColor  = new Color_RGB();
                    vbarColor.B = pixelColor.B;
                    vbarColor.G = pixelColor.G;
                    vbarColor.R = pixelColor.R;
                    vBarPixelList.Add(vbarColor);
                }

                // check if vbar or short vbar cache matched
                ushort vbarIdx = GetVbarIndex(vBarPixelList);
                if (vbarIdx != 0xffff)
                {
                    // use cache index
                    CLEARCODEC_VBAR vBar = new CLEARCODEC_VBAR();
                    vBar.type                   = VBAR_TYPE.VBAR_CACHE_HIT;
                    vBar.vbarCacheHit.x         = 0x1;
                    vBar.vbarCacheHit.vBarIndex = vbarIdx;

                    vBarList.Add(vBar);

                    continue;
                }
                else
                {
                    vBarDict.Add(vBarPixelList, vBarCursor);
                    vBarCursor = (ushort)((vBarCursor + 1) % CLEARCODEC_CONST.CLEARCODEC_BAND_MAX_VBAR_CACHE_SLOT);
                }

                // cechk short vbar cache
                ushort shortvbarIdx = GetShortVbarIndex(shortVBarPixelList);
                if (shortvbarIdx != 0xffff)
                {
                    // use short vbar cache index
                    CLEARCODEC_VBAR svBar = new CLEARCODEC_VBAR();
                    svBar.type = VBAR_TYPE.SHORT_VBAR_CACHE_HIT;
                    svBar.shortVbarCacheHit.x = 0x1;
                    svBar.shortVbarCacheHit.shortVBarIndex = shortvbarIdx;
                    svBar.shortVbarCacheHit.shortVBarYOn   = shortVBarYOn;

                    vBarList.Add(svBar);
                    continue;
                }
                else
                {
                    // add short vbar into cache dictionary and send the short vbar vbar in SHORT_VBAR_CACHE_MISS structure later.
                    shortvBarDict.Add(shortVBarPixelList, shortvBarCursor);
                    shortvBarCursor = (ushort)((shortvBarCursor + 1) % CLEARCODEC_CONST.CLEARCODEC_BAND_MAX_SHORT_VBAR_CACHE_SLOT);
                }


                // get to here mean no vbar or short vbar cache hit
                CLEARCODEC_VBAR vBarUncache = new CLEARCODEC_VBAR();
                vBarUncache.type = VBAR_TYPE.SHORT_VBAR_CACHE_MISS;
                vBarUncache.shortVbarCacheMiss.x = 0x0;

                // pack data into vBar.shortVbarCacheMiss
                vBarUncache.shortVbarCacheMiss.shortVBarYOn  = shortVBarYOn;
                vBarUncache.shortVbarCacheMiss.shortVBarYOff = shortVBarYOff;
                if (shortVBarYOff > shortVBarYOn)
                {
                    vBarUncache.shortVbarCacheMiss.shortVBarPixels = shortVBarPixelList.ToArray();
                }

                vBarList.Add(vBarUncache);
            }

            bandData.vBars = vBarList.ToArray();

            return(bandData);
        }
 /// <summary>
 /// Load a residual layer bitmap into clearcode encoder.   
 /// </summary>
 /// <param name = "subcodecBitmap"> specifies a subcodec layer image </param>
 /// <param name = "pos"> specifies position of subcodec layer image, relative to residual layer image </param>
 /// <param name = "sbcID"> specifies subcodec ID to encoding subcodec layer image </param>
 public void LoadSubcodecBitmap(Bitmap subcodecBitmap, RDPGFX_POINT16 pos, CLEARCODEC_SUBCODEC_ID sbcID)
 {
     if (subcodecBitmap != null)
     {
         ClearCodec_RECT16 scRect = new ClearCodec_RECT16();
         scRect.left = pos.x;
         scRect.top = pos.y;
         scRect.right = (ushort)(pos.x + subcodecBitmap.Width);
         scRect.bottom = (ushort)(pos.x + subcodecBitmap.Height);
         BMP_INFO bmp_info = new BMP_INFO();
         bmp_info.bmp = subcodecBitmap;
         bmp_info.scID = sbcID;
         this.subcodecDict.Add(scRect, bmp_info);
     }
 }
 /// <summary>
 /// Load a residual layer bitmap into clearcode encoder.   
 /// </summary>
 /// <param name = "bandBitmap"> specifies a band layer image </param>
 /// <param name = "pos"> specifies position of band layer image, relative to residual layer image </param>
 public void LoadBandBitmap(Bitmap bandBitmap, RDPGFX_POINT16 pos)
 {
     if (bandBitmap != null)
     {
         ClearCodec_RECT16 bRect = new ClearCodec_RECT16();
         bRect.left = pos.x;
         bRect.top = pos.y;
         bRect.right = (ushort)(pos.x + bandBitmap.Width);
         bRect.bottom = (ushort)(pos.y + bandBitmap.Height);
         this.bandDict.Add(bRect, bandBitmap);
     }
 }
        /// <summary>
        /// Encode a band bitmap into byte stream
        /// </summary>
        /// <param name="bandBmp">The bitmap to be encoded in band layer.</param>
        /// <param name="bandRect">The band position relative to bitmap left-top edge.</param>
        public CLEARCODEC_BAND EncodeBand(Bitmap bandBmp, ClearCodec_RECT16 bandRect)
        {
            CLEARCODEC_BAND bandData = new CLEARCODEC_BAND();

            Color bgColor = bandBmp.GetPixel(0, 0);

            bandData.xStart = bandRect.left;
            bandData.xEnd = (ushort)(bandRect.right-1);
            bandData.yStart = bandRect.top;
            bandData.yEnd = (ushort)(bandRect.bottom-1);

            bandData.blueBkg = bgColor.B;
            bandData.greenBkg = bgColor.G;
            bandData.redBkg = bgColor.R;

            List<CLEARCODEC_VBAR> vBarList = new List<CLEARCODEC_VBAR>();

            // use short vbar cache miss method
            for (ushort x = 0; x < bandBmp.Width; x++)
            {
                byte shortVBarYOn = 0;  // relative to top of V-Bar, won't excceed 52
                byte shortVBarYOff = 0; // relative to top of V-Bar, won't excceed 52

                // find shortVBarYOn from top
                byte y;  // bandBmp.Height can't exceed 52 pixels
                for ( y = 0; y < bandBmp.Height; y++)
                {
                    Color pixelColor = bandBmp.GetPixel(x, y);
                    if (!bgColor.Equals(pixelColor))
                    {
                        shortVBarYOn = (byte)y;
                        break;
                    }
                }

                // the whole vbar use bgColor
                if (y == (ushort)bandBmp.Height)
                {
                    shortVBarYOn = (byte)y;
                    shortVBarYOff = (byte)y;
                }

                // find shortVBarYOff from bottem, which is the first position for left bgcolor
                for (y = (byte)(bandBmp.Height - 1); y > shortVBarYOn; y--)
                {
                    Color pixelColor = bandBmp.GetPixel(x, y);
                    if (!bgColor.Equals(pixelColor))
                    {
                        shortVBarYOff = (byte)(y + 1);
                        break;
                    }
                }

                // only one point in shortVBar is different from bgColor
                if (y == shortVBarYOn)
                {
                    shortVBarYOff = (byte)(shortVBarYOn + 1);
                }

                // construct short Vbar Pixels

                List<Color_RGB> shortVBarPixelList = new List<Color_RGB>();
                for (y = shortVBarYOn; y < shortVBarYOff; y++)
                {
                    Color pixelColor = bandBmp.GetPixel(x, y);
                    Color_RGB svbarColor = new Color_RGB();
                    svbarColor.B = pixelColor.B;
                    svbarColor.G = pixelColor.G;
                    svbarColor.R = pixelColor.R;

                    shortVBarPixelList.Add(svbarColor);
                }

                // construct vbar pixels
                List<Color_RGB> vBarPixelList = new List<Color_RGB>();
                for (int k = 0; k < bandBmp.Height; k++)
                {
                    Color pixelColor = bandBmp.GetPixel(x, k);
                    Color_RGB vbarColor = new Color_RGB();
                    vbarColor.B = pixelColor.B;
                    vbarColor.G = pixelColor.G;
                    vbarColor.R = pixelColor.R;
                    vBarPixelList.Add(vbarColor);
                }

                // check if vbar or short vbar cache matched
                ushort vbarIdx = GetVbarIndex(vBarPixelList);
                if (vbarIdx != 0xffff)
                {
                    // use cache index
                    CLEARCODEC_VBAR vBar = new CLEARCODEC_VBAR();
                    vBar.type = VBAR_TYPE.VBAR_CACHE_HIT;
                    vBar.vbarCacheHit.x = 0x1;
                    vBar.vbarCacheHit.vBarIndex = vbarIdx;

                    vBarList.Add(vBar);

                    continue;
                }
                else
                {
                    vBarDict.Add(vBarPixelList, vBarCursor);
                    vBarCursor = (ushort)((vBarCursor + 1) % CLEARCODEC_CONST.CLEARCODEC_BAND_MAX_VBAR_CACHE_SLOT);
                }

                // cechk short vbar cache
                ushort shortvbarIdx = GetShortVbarIndex(shortVBarPixelList);
                if (shortvbarIdx != 0xffff)
                {
                    // use short vbar cache index
                    CLEARCODEC_VBAR svBar = new CLEARCODEC_VBAR();
                    svBar.type = VBAR_TYPE.SHORT_VBAR_CACHE_HIT;
                    svBar.shortVbarCacheHit.x = 0x1;
                    svBar.shortVbarCacheHit.shortVBarIndex = shortvbarIdx;
                    svBar.shortVbarCacheHit.shortVBarYOn = shortVBarYOn;

                    vBarList.Add(svBar);
                    continue;
                }
                else
                {
                    // add short vbar into cache dictionary and send the short vbar vbar in SHORT_VBAR_CACHE_MISS structure later.
                    shortvBarDict.Add(shortVBarPixelList, shortvBarCursor);
                    shortvBarCursor = (ushort)((shortvBarCursor + 1) % CLEARCODEC_CONST.CLEARCODEC_BAND_MAX_SHORT_VBAR_CACHE_SLOT);
                }

                // get to here mean no vbar or short vbar cache hit
                CLEARCODEC_VBAR vBarUncache = new CLEARCODEC_VBAR();
                vBarUncache.type = VBAR_TYPE.SHORT_VBAR_CACHE_MISS;
                vBarUncache.shortVbarCacheMiss.x = 0x0;

                // pack data into vBar.shortVbarCacheMiss
                vBarUncache.shortVbarCacheMiss.shortVBarYOn = shortVBarYOn;
                vBarUncache.shortVbarCacheMiss.shortVBarYOff = shortVBarYOff;
                if (shortVBarYOff > shortVBarYOn )
                {
                    vBarUncache.shortVbarCacheMiss.shortVBarPixels = shortVBarPixelList.ToArray();
                }

                vBarList.Add(vBarUncache);
            }

            bandData.vBars = vBarList.ToArray();

            return bandData;
        }