/// <summary>
 /// Check if a given index in the scope of this surface
 /// </summary>
 /// <param name="index">Specified</param>
 /// <param name="bRgb">If true, check if Rgb data exist for specified frame; otherwise, check if Dwt data exist.</param>
 /// <returns></returns>
 public bool IsIndexInScope(TileIndex index, bool bRgb)
 {
     if (bRgb) return rgbTileDic.ContainsKey(index);
     else return dwtQDic.ContainsKey(index);
 }
 /// <summary>
 /// Update the coefficients after DWT and Quantization of specified tile.
 /// </summary>
 /// <param name="index">The index of the tile.</param>
 /// <param name="dwtQ">The DwtQ coefficients.</param>
 public void UpdateTileDwtQ(TileIndex index, DwtTile dwtQ)
 {
     if (index.X * RdpegfxTileUtils.TileSize >= this.Width || index.Y * RdpegfxTileUtils.TileSize >= this.Height) return;
     lock (dwtQDic)
     {
         if (dwtQDic.ContainsKey(index))
         {
             dwtQDic[index] = dwtQ;
         }
         else
         {
             dwtQDic.Add(index, dwtQ);
         }
     }
 }
 public RgbTile GetRgbTile(TileIndex index)
 {
     if (rgbTileDic.ContainsKey(index))
     {
         return rgbTileDic[index];
     }
     else
     {
         return null;
     }
 }
 public DwtTile GetTriState(TileIndex index)
 {
     if (this.triStateDic.ContainsKey(index))
     {
         return triStateDic[index];
     }
     else
     {
         return null;
     }
 }
        /// <summary>
        /// Constructor, create RFX_PROGRESSIVE_TILE_UPGRADE block 
        /// </summary>
        /// <param name="quantIdx">This is used to indicate index in TS_RFX_CODEC_AUANT array of region block</param>
        /// <param name="tileIdx">This is used to indicate tile position([x, y]).</param>
        /// <param name="tileData">This is used to indicate encoded tile data which is related to quantIdx</param>
        public RFX_PROGRESSIVE_TILE_UPGRADE(byte quantIdx, TileIndex tileIdx, EncodedTile tileData)
        {
            this.blockType = RFXProgCodecBlockType.WBT_TILE_PROGRESSIVE_UPGRADE;
            this.blockLen = 6;  // Common part 6 bytes.

            this.quantIdxY = quantIdx;
            this.quantIdxCb = quantIdx;
            this.quantIdxCr = quantIdx;

            this.xIdx = tileIdx.X;
            this.yIdx = tileIdx.Y;

            this.progressiveQuality = tileData.ProgCodecQuant.quality;
            this.blockLen += 8;

            // Srl data.
            this.ySrlLen = (tileData.YEncodedData == null) ? (ushort)0 : (ushort)tileData.YEncodedData.Count();
            this.ySrlData = tileData.YEncodedData;

            this.cbSrlLen = (tileData.CbEncodedData == null) ? (ushort)0 : (ushort)tileData.CbEncodedData.Count();
            this.cbSrlData = tileData.CbEncodedData;
            this.crSrlLen = (tileData.CrEncodedData == null) ? (ushort)0 : (ushort)tileData.CrEncodedData.Count();
            this.crSrlData = tileData.CrEncodedData;
            this.blockLen += (uint)(6 + this.ySrlLen + this.cbSrlLen + this.crSrlLen);

            // Raw data.
            this.yRawLen = (tileData.YRawData == null) ? (ushort)0 : (ushort)tileData.YRawData.Count();
            this.yRawData = tileData.YRawData;
            this.cbRawLen = (tileData.CbRawData == null) ? (ushort)0 : (ushort)tileData.CbRawData.Count();
            this.cbRawData = tileData.CbRawData;
            this.crRawLen = (tileData.CrRawData == null) ? (ushort)0 : (ushort)tileData.CrRawData.Count();
            this.crRawData = tileData.CrRawData;
            this.blockLen += (uint)(6 + this.yRawLen + this.cbRawLen + this.crRawLen);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="newFrame">The current frame contains this tile</param>
 /// <param name="index">The index of this tile in surface</param>
 public TileState(SurfaceFrame newFrame, TileIndex index)
 {
     NewFrame = newFrame;
     Index = index;
 }
        /// <summary>
        /// Generate a surface from a bitmap
        /// </summary>
        /// <param name="sId">The surface Id</param>
        /// <param name="bm">The original bitmap</param>
        /// <returns>A surface instance</returns>
        public static SurfaceFrame GetFromImage(ushort sId, Bitmap bitmap)
        {
            SurfaceFrame surf = new SurfaceFrame(sId, (ushort)bitmap.Width, (ushort)bitmap.Height);
            for (int xIndex = 0; xIndex * RdpegfxTileUtils.TileSize < bitmap.Width; xIndex++)
            {
                for (int yIndex = 0; yIndex * RdpegfxTileUtils.TileSize < bitmap.Height; yIndex++)
                {
                    TileIndex tIndex = new TileIndex((ushort)xIndex, (ushort)yIndex, bitmap.Width, bitmap.Height);

                    RgbTile rgbTl = RgbTile.GetFromImage(bitmap, xIndex * RdpegfxTileUtils.TileSize, yIndex * RdpegfxTileUtils.TileSize);
                    surf.rgbTileDic.Add(tIndex, rgbTl);
                }
            }
            return surf;
        }
        /// <summary>
        /// Get all the tile indexes in this surface
        /// </summary>
        /// <returns>TileIndex array.</returns>
        public TileIndex[] GetAllIndexes()
        {
            List<TileIndex> indexList = new List<TileIndex>();
            for (int xIndex = 0; xIndex * RdpegfxTileUtils.TileSize < this.Width; xIndex++)
            {
                for (int yIndex = 0; yIndex * RdpegfxTileUtils.TileSize < this.Height; yIndex++)
                {
                    TileIndex tIndex = new TileIndex((ushort)xIndex, (ushort)yIndex, this.Width, this.Height);

                    indexList.Add(tIndex);
                }
            }
            return indexList.ToArray();
        }
 /// <summary>
 /// Get the bitmap of a tile
 /// </summary>
 /// <param name="ti">Tile index</param>
 /// <returns>Tile bitmap</returns>
 public Bitmap GetTileBitmap(TileIndex ti)
 {
     RgbTile tl = CurrentFrame.GetRgbTile(ti);
     if (tl != null)
     {
         return tl.ToImage();
     }
     return null;
 }
 /// <summary>
 /// Check if a given index in the scope of this surface
 /// </summary>
 /// <param name="index">Specified</param>
 /// <returns></returns>
 public bool IsIndexInScope(TileIndex index)
 {
     return (index.X * RdpegfxTileUtils.TileSize < this.Width) && (index.Y * RdpegfxTileUtils.TileSize < this.Height);
 }
 /// <summary>
 /// Get the specified RgbTile
 /// </summary>
 /// <param name="index">The index of tile in this surface</param>
 /// <returns>A RgbTile</returns>
 public RgbTile GetRgbTile(TileIndex index)
 {
     return CurrentFrame.GetRgbTile(index);
 }
        /// <summary>
        /// Get the tile indexes which covers the specified area
        /// </summary>
        /// <param name="rect">The rect area</param>
        /// <returns>The tile indexes cover the specified area</returns>
        public TileIndex[] GetIndexesInRect(Rectangle[] rects)
        {
            List<TileIndex> indexList = new List<TileIndex>();
            foreach (Rectangle rect in rects)
            {
                int leftXIndex = rect.X / RdpegfxTileUtils.TileSize;
                int topYIndex = rect.Y / RdpegfxTileUtils.TileSize;
                int rightXIndex = (rect.X + rect.Width) / RdpegfxTileUtils.TileSize;
                int bottomYIndex = (rect.Y + rect.Height) / RdpegfxTileUtils.TileSize;

                for (int x = leftXIndex; x <= rightXIndex; x++)
                {
                    for (int y = topYIndex; y <= bottomYIndex; y++)
                    {
                        TileIndex index = new TileIndex((ushort)x, (ushort)y, (rect.X + rect.Width), (rect.Y + rect.Height));
                        if (!indexList.Contains(index) && IsIndexInScope(index))
                        {
                            indexList.Add(index);
                        }
                    }
                }
            }
            return indexList.ToArray();
        }
        /// <summary>
        /// Get the different tiles of this surface
        /// </summary>
        /// <param name="bRgb">If true, check if Rgb data exist for specified frame; otherwise, check if Dwt data exist.</param>
        /// <returns>The array of different tiles.</returns>
        public TileIndex[] GetDiffIndexes(bool bRgb)
        {
            if (this.pendingUpdateIndexs != null && this.pendingUpdateIndexs.Length <= RdpegfxTileUtils.TileDiffMinCount)
            {
                return this.pendingUpdateIndexs;
            }

            if (CurrentFrame == null) return null;
            if (LastFrame == null) return this.pendingUpdateIndexs;
            List<TileIndex> diffIndexList = new List<TileIndex>();
            for (int xIndex = 0; xIndex * RdpegfxTileUtils.TileSize < this.Width; xIndex++)
            {
                for (int yIndex = 0; yIndex * RdpegfxTileUtils.TileSize < this.Height; yIndex++)
                {
                    TileIndex tIndex = new TileIndex((ushort)xIndex, (ushort)yIndex, this.Width, this.Height);
                    if(CurrentFrame.IsIndexInScope(tIndex, bRgb))
                    {
                        //diffIndexList.Add(tIndex);
                        if (LastFrame != null && LastFrame.IsIndexInScope(tIndex, bRgb))
                        {
                            if (bRgb)
                            {
                                RgbTile prvRgb = LastFrame.GetRgbTile(tIndex);
                                RgbTile curRgb = CurrentFrame.GetRgbTile(tIndex);
                                if (!curRgb.EqualsWith(prvRgb)) diffIndexList.Add(tIndex);
                            }
                            else
                            {
                                DwtTile prvDwt = LastFrame.GetDwt(tIndex);
                                DwtTile curDwt = CurrentFrame.GetDwt(tIndex);
                                if (!curDwt.EqualsWith(prvDwt)) diffIndexList.Add(tIndex);
                            }
                        }
                        else
                        {
                            diffIndexList.Add(tIndex);
                        }
                    }
                }
            }
            return diffIndexList.ToArray();
        }
 /// <summary>
 /// Update the RGB data of the specified tile.
 /// </summary>
 /// <param name="index">The index of the tile.</param>
 /// <param name="dwtQ">The RGB data.</param>
 public void UpdateTileRgb(TileIndex index, RgbTile rgbT)
 {
     if (index.X * RdpegfxTileUtils.TileSize >= this.Width || index.Y * RdpegfxTileUtils.TileSize >= this.Height) return;
     lock (rgbTileDic)
     {
         if (rgbTileDic.ContainsKey(index))
         {
             rgbTileDic[index] = rgbT;
         }
         else
         {
             rgbTileDic.Add(index, rgbT);
         }
     }
 }
        /// <summary>
        /// Generate a surface from a bitmap, only update the specified tiles
        /// </summary>
        /// <param name="sId">The surface Id</param>
        /// <param name="bm">The original bitmap</param>
        /// <param name="changedTileIndexs">The indexes of the changed tiles</param>
        /// <returns>A surface instance</returns>
        public static SurfaceFrame GetFromImage(ushort sId, Bitmap bitmap, TileIndex[] changedTileIndexs)
        {
            SurfaceFrame surf = new SurfaceFrame(sId, (ushort)bitmap.Width, (ushort)bitmap.Height);

            foreach (TileIndex tIndex in changedTileIndexs)
            {
                RgbTile rgbTl = RgbTile.GetFromImage(bitmap, tIndex.X * RdpegfxTileUtils.TileSize, tIndex.Y * RdpegfxTileUtils.TileSize);
                surf.rgbTileDic.Add(tIndex, rgbTl);
            }
            return surf;
        }
 /// <summary>
 /// Update the tri-state of a tile
 /// </summary>
 /// <param name="index">The tile index</param>
 /// <param name="stat">The tri-state of the specified tile</param>
 public void UpdateTriState(TileIndex index, DwtTile stat)
 {
     if (index.X * RdpegfxTileUtils.TileSize >= this.Width || index.Y * RdpegfxTileUtils.TileSize >= this.Height) return;
     lock (triStateDic)
     {
         if (triStateDic.ContainsKey(index))
         {
             triStateDic[index] = stat;
         }
         else
         {
             triStateDic.Add(index, stat);
         }
     }
 }
        /// <summary>
        /// Get all the tile indexes in this surface
        /// </summary>
        /// <returns>TileIndex array.</returns>
        public TileIndex[] GetAllIndexes()
        {
            List<TileIndex> indexList = new List<TileIndex>();
            for (int xIndex = 0; xIndex * RdpegfxTileUtils.TileSize < this.Width; xIndex++)
            {
                for (int yIndex = 0; yIndex * RdpegfxTileUtils.TileSize < this.Height; yIndex++)
                {
                    TileIndex tIndex = new TileIndex((ushort)xIndex, (ushort)yIndex, this.Width, this.Height);

                    //  set tile width and height
                    if ((xIndex + 1) * RdpegfxTileUtils.TileSize > this.Width)
                        tIndex.WidthInSurface = (byte)(this.Width - xIndex * RdpegfxTileUtils.TileSize);
                    else
                        tIndex.WidthInSurface = RdpegfxTileUtils.TileSize;

                    if ((yIndex + 1) * RdpegfxTileUtils.TileSize > this.Height)
                        tIndex.HeightInSurface = (byte)(this.Height - yIndex * RdpegfxTileUtils.TileSize);
                    else
                        tIndex.HeightInSurface = RdpegfxTileUtils.TileSize;
                    indexList.Add(tIndex);
                }
            }
            return indexList.ToArray();
        }
        /// <summary>
        /// constructor, create RFX_Progressive_TILE_SIMPLE block 
        /// </summary>
        /// <param name="quantIdx">This is used to indicate index in TS_RFX_CODEC_AUANT array of region block</param>
        /// <param name="tileIdx">This is used to indicate tile position([x, y]).</param>
        /// <param name="tileData">This is used to indicate encoded tile data</param>
        public RFX_Progressive_TILE_SIMPLE(byte quantIdx, TileIndex tileIdx, EncodedTile tileData)
        {
            this.blockType = RFXProgCodecBlockType.WBT_TILE_SIMPLE;
            this.blockLen = 6;  // common part 6 bytes

            this.quantIdxY = quantIdx;
            this.quantIdxCb = quantIdx;
            this.quantIdxCr = quantIdx;

            this.xIdx = tileIdx.X;
            this.yIdx = tileIdx.Y;

            this.flags = tileData.IsDifferenceTile;
            this.blockLen += 8;

            this.yLen = (tileData.YEncodedData == null) ? (ushort)0 : (ushort)tileData.YEncodedData.Count();
            this.yData = tileData.YEncodedData;
            this.blockLen += (uint)(2 + this.yLen);

            this.cbLen = (tileData.CbEncodedData == null) ? (ushort)0 : (ushort)tileData.CbEncodedData.Count();
            this.cbData = tileData.CbEncodedData;
            this.blockLen += (uint)(2 + this.cbLen);

            this.crLen = (tileData.CrEncodedData == null) ? (ushort)0 : (ushort)tileData.CrEncodedData.Count();
            this.crData = tileData.CrEncodedData;
            this.blockLen += (uint)(2 + this.crLen);

            //this.tailLen = 8;
            //this.tailData = new byte[8]{0x4C, 0x41, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x10};
            this.tailLen = 0;
            this.tailData = null;
            this.blockLen += (uint)(2 + this.tailLen);
        }
 /// <summary>
 /// Get the coefficients for the same tile of last frame after DWT and Quantization.
 /// </summary>
 /// <param name="index">The index of the tile.</param>
 public DwtTile GetDwt(TileIndex index)
 {
     if (dwtQDic.ContainsKey(index))
     {
         return dwtQDic[index];
     }
     else
     {
         return null;
     }
 }
        /// <summary>
        /// Build tile data blocks(tile simple or tile first or tile upgrade).
        /// </summary>
        /// <param name="quantIdx">This is used to indicate index in TS_RFX_CODEC_QUANT array of region block</param>
        /// <param name="tileIdx">This is used to indicate the tile index.</param>
        /// <param name="tileData">This is used to indicate the encoded tile data.</param>
        /// <param name="tileBlockType">This is used to indicate the tile data block type(simple, first, or upgrade).</param>
        public RFX_Progressive_DataBlock BuildTileDataBlock(byte quantIdx, TileIndex tileIdx, EncodedTile tileData, RFXProgCodecBlockType tileBlockType)
        {
            RFX_Progressive_DataBlock tile_block;

            if (tileBlockType == RFXProgCodecBlockType.WBT_TILE_PROGRESSIVE_FIRST)
            {
                tile_block = new RFX_Progressive_TILE_FIRST(quantIdx, tileIdx, tileData);
            }
            else if (tileBlockType == RFXProgCodecBlockType.WBT_TILE_PROGRESSIVE_UPGRADE)
            {
                tile_block = new RFX_PROGRESSIVE_TILE_UPGRADE(quantIdx, tileIdx, tileData);
            }
            else
            {
                tile_block = new RFX_Progressive_TILE_SIMPLE(quantIdx, tileIdx, tileData);
            }

            return tile_block;
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="surface">The surface contains this tile</param>
 /// <param name="index">The index of this tile in surface</param>
 public TileState(Surface surface, TileIndex index)
 {
     NewFrame = surface.CurrentFrame;
     LastFrame = surface.LastFrame;
     Index = index;
 }