/// <summary>
    /// Set GIF data
    /// </summary>
    /// <param name="gifBytes">GIF byte data</param>
    /// <param name="gifData">ref GIF data</param>
    /// <param name="debugLog">Debug log flag</param>
    /// <returns>Result</returns>
    private static bool SetGifData(byte[] gifBytes, ref GifData gifData, bool debugLog)
    {
        if (debugLog)
        {
            Debug.Log("SetGifData Start.");
        }

        if (gifBytes == null || gifBytes.Length <= 0)
        {
            Debug.LogError("bytes is nothing.");
            return(false);
        }

        int byteIndex = 0;

        if (SetGifHeader(gifBytes, ref byteIndex, ref gifData) == false)
        {
            Debug.LogError("GIF header set error.");
            return(false);
        }

        if (SetGifBlock(gifBytes, ref byteIndex, ref gifData) == false)
        {
            Debug.LogError("GIF block set error.");
            return(false);
        }

        if (debugLog)
        {
            gifData.Dump();
            Debug.Log("SetGifData Finish.");
        }
        return(true);
    }
Exemple #2
0
 internal GifData GetGifData(byte[] data)
 {
     if ((data[0] == 71) || (data[1] == 73) || (data[2] == 70))
     {
         GifData g = new GifData();
         g.BackgroundColor = data[11];
         int ii = 10;
         g.HasGCTF = ((data[ii] & 0x80) > 0);
         if (g.HasGCTF == true)
         {
             // if we have a GCTF
             g.GCTFColors = (int)Math.Pow(2, (data[ii] & 0x07) + 1);
             g.GCTFSize   = 3 * g.GCTFColors;
             g.Palette    = new Color[g.GCTFColors];
             ii          += 3;
             for (int c = 0; c < g.GCTFColors; c++)
             {
                 g.Palette[c] = new Color(data[ii], data[ii + 1], data[ii + 2]);
                 ii          += 3;
             }
         }
         // should have application block here now
         if (data[ii] == 0x21 && data[ii + 1] == 0xff)
         {
             ii += 19;
             if (data[ii] == 0x21 && data[ii + 1] == 0xf9)
             {
                 g.TransparencyIndex = data[ii + 6];
             }
         }
         return(g);
     }
     return(null);
 }
    /// <summary>
    /// Get GIF texture list (This is a possibility of lock up)
    /// </summary>
    /// <param name="bytes">GIF file byte data</param>
    /// <param name="loopCount">out Animation loop count</param>
    /// <param name="width">out GIF image width (px)</param>
    /// <param name="height">out GIF image height (px)</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <param name="debugLog">Debug Log Flag</param>
    /// <returns>GIF texture list</returns>
    public static List<GifTexture> GetTextureList (byte[] bytes, out int loopCount, out int width, out int height,
        FilterMode filterMode = FilterMode.Bilinear, TextureWrapMode wrapMode = TextureWrapMode.Clamp, bool debugLog = false)
    {
        loopCount = -1;
        width = 0;
        height = 0;

        // Set GIF data
        var gifData = new GifData ();
        if (SetGifData (bytes, ref gifData, debugLog) == false) {
            Debug.LogError ("GIF file data set error.");
            return null;
        }

        // Decode to textures from GIF data
        var gifTexList = new List<GifTexture> ();
        if (DecodeTexture (gifData, gifTexList, filterMode, wrapMode) == false) {
            Debug.LogError ("GIF texture decode error.");
            return null;
        }

        loopCount = gifData.appEx.loopCount;
        width = gifData.logicalScreenWidth;
        height = gifData.logicalScreenHeight;
        return gifTexList;
    }
    /// <summary>
    /// Create Texture2D object and initial settings
    /// </summary>
    private static Texture2D CreateTexture2D(GifData gifData, List <GifTexture> gifTexList, int imgBlockIndex, ushort disposalMethod, FilterMode filterMode, TextureWrapMode wrapMode, ref bool useBeforeTex)
    {
        // Create texture
        Texture2D tex = new Texture2D(gifData.logicalScreenWidth, gifData.logicalScreenHeight, TextureFormat.ARGB32, false);

        tex.filterMode = filterMode;
        tex.wrapMode   = wrapMode;

        // Check dispose
        useBeforeTex = false;
        int beforeIndex = -1;

        if (imgBlockIndex > 0 && disposalMethod == 0 || disposalMethod == 1)
        {
            // before 1
            beforeIndex = imgBlockIndex - 1;
        }
        else if (imgBlockIndex > 1 && disposalMethod == 3)
        {
            // before 2
            beforeIndex = imgBlockIndex - 2;
        }
        if (beforeIndex >= 0)
        {
            // Do not dispose
            useBeforeTex = true;
            Color32[] pix = gifTexList[beforeIndex].texture2d.GetPixels32();
            tex.SetPixels32(pix);
            tex.Apply();
        }

        return(tex);
    }
Exemple #5
0
    public async static Task <Texture2D> GetTextureAsync
    (
        byte[] bytes,
        FilterMode filterMode    = FilterMode.Bilinear,
        TextureWrapMode wrapMode = TextureWrapMode.Clamp,
        bool debugLog            = false
    )
    {
        // Set GIF data
        var gifData = new GifData();

        if (!SetGifData(bytes, ref gifData, debugLog))
        {
            Debug.LogError("GIF file data set error.");
            await Task.Delay(1);
        }

        // Decode to textures from GIF data
        Texture2D texture = await DecodeTextureAsync(gifData, filterMode, wrapMode);

        if (texture == null)
        {
            Debug.LogError("GIF texture decode error.");
            await Task.Delay(1);
        }

        int loopCount = gifData.m_appEx.loopCount;
        int width     = gifData.m_logicalScreenWidth;
        int height    = gifData.m_logicalScreenHeight;

        return(texture);
    }
    static void CalculColors(GifData gifData, int index)
    {
        Color[] previousFrame = gifData.previousFrame;
        if (previousFrame == null)
        {
            previousFrame = new Color[gifData.canvasWidth * gifData.canvasHeight];
        }
        Color[] currentFrame = gifData.currentFrame;
        if (currentFrame == null)
        {
            currentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight];
        }
        Color[] transparentFrame = gifData.transparentFrame;
        if (transparentFrame == null)
        {
            transparentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight];
        }

        GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[index];
        GifImageDescriptor          imageDescriptor    = graphicsControlExt.imageDescriptor;
        GifImageData imageData      = imageDescriptor.imageData;
        int          top            = imageDescriptor.imageTop;
        int          left           = imageDescriptor.imageLeft;
        int          disposalMethod = graphicsControlExt.disposalMethod;

        int transparencyIndex = graphicsControlExt.transparentColorFlag ? graphicsControlExt.transparentColorIndex : -1;

        Color[] colorTabel = imageData.imageDescriptor.localColorTableFlag ? imageData.imageDescriptor.localColorTable : gifData.globalColorTable;

        for (int j = 0; j < imageDescriptor.imageWidth; j++)
        {
            for (int k = 0; k < imageDescriptor.imageHeight; k++)
            {
                int x           = left + j;
                int y           = (gifData.canvasHeight - 1) - (top + k);
                int colorIndex  = imageData.colorIndices[j + k * imageDescriptor.imageWidth];
                int pixelOffset = x + y * gifData.canvasWidth;

                if (colorIndex != transparencyIndex)
                {
                    currentFrame[pixelOffset] = colorTabel[colorIndex];
                }
            }
        }

        currentFrame.CopyTo(previousFrame, 0);
        if (disposalMethod == 0 || disposalMethod == 2)
        {
            currentFrame     = new Color[currentFrame.Length];
            imageData.colors = currentFrame;
        }
        else
        {
            imageData.colors = new Color[currentFrame.Length];
            currentFrame.CopyTo(imageData.colors, 0);
        }
        gifData.previousFrame    = previousFrame;
        gifData.currentFrame     = currentFrame;
        gifData.transparentFrame = transparentFrame;
    }
Exemple #7
0
        /// <summary>
        ///     Get color table and set background color (local or global)
        /// </summary>
        private static List <byte[]> GetColorTableAndSetBgColor(GifData gifData, ImageBlock imgBlock,
                                                                int transparentIndex, out Color32 bgColor)
        {
            var colorTable = imgBlock.m_localColorTableFlag ? imgBlock.m_localColorTable :
                             gifData.m_globalColorTableFlag ? gifData.m_globalColorTable : null;

            if (colorTable != null)
            {
                // Set background color from color table
                var bgRgb = colorTable[gifData.m_bgColorIndex];
                bgColor = new Color32(bgRgb[0], bgRgb[1], bgRgb[2], 1);

                // After inspecting over hours this implementation I have determined that this part is incorrect.
                // Because this is comparting transparentIndex that comes from the local color table, while the background color index comes from the upper scope (the global one).

                // (byte)(transparentIndex == gifData.m_bgColorIndex ? 0 : 255));

                // El bgColor puede que sea opaco porque se está comparando el transparentIndex (que viene dado por el GraphicControlExtension)
                // cuando el bgColorIndex que se está comparando viene del "Background Color Index" que es independiente a cada GraphicControlExtension (es global y anexo al GifData)
            }
            else
            {
                bgColor = Color.black;
            }

            return(colorTable);
        }
    /// <summary>
    /// Set GIF data
    /// </summary>
    /// <param name="gifBytes">GIF byte data</param>
    /// <param name="gifData">ref GIF data</param>
    /// <param name="debugLog">Debug log flag</param>
    /// <returns>Result</returns>
    static bool SetGifData (byte[] gifBytes, ref GifData gifData, bool debugLog)
    {
        if (debugLog) {
            Debug.Log ("SetGifData Start.");
        }

        if (gifBytes == null || gifBytes.Length <= 0) {
            Debug.LogError ("bytes is nothing.");
            return false;
        }

        int byteIndex = 0;

        if (SetGifHeader (gifBytes, ref byteIndex, ref gifData) == false) {
            Debug.LogError ("GIF header set error.");
            return false;
        }

        if (SetGifBlock (gifBytes, ref byteIndex, ref gifData) == false) {
            Debug.LogError ("GIF block set error.");
            return false;
        }

        if (debugLog) {
            gifData.Dump ();
            Debug.Log ("SetGifData Finish.");
        }
        return true;
    }
Exemple #9
0
    /// <summary>
    /// Get GIF texture list (This is a possibility of lock up)
    /// </summary>
    /// <param name="bytes">GIF file byte data</param>
    /// <param name="loopCount">out Animation loop count</param>
    /// <param name="width">out GIF image width (px)</param>
    /// <param name="height">out GIF image height (px)</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <param name="debugLog">Debug Log Flag</param>
    /// <returns>GIF texture list</returns>
    public static List <GifTexture> GetTextureList(byte[] bytes, out int loopCount, out int width, out int height,
                                                   FilterMode filterMode = FilterMode.Bilinear, TextureWrapMode wrapMode = TextureWrapMode.Clamp, bool debugLog = false)
    {
        loopCount = -1;
        width     = 0;
        height    = 0;

        // Set GIF data
        var gifData = new GifData();

        if (SetGifData(bytes, ref gifData, debugLog) == false)
        {
            Debug.LogError("GIF file data set error.");
            return(null);
        }

        // Decode to textures from GIF data
        var gifTexList = new List <GifTexture>();

        if (DecodeTexture(gifData, gifTexList, filterMode, wrapMode) == false)
        {
            Debug.LogError("GIF texture decode error.");
            return(null);
        }

        loopCount = gifData.appEx.loopCount;
        width     = gifData.logicalScreenWidth;
        height    = gifData.logicalScreenHeight;
        return(gifTexList);
    }
    private GifImageData readImageData(GifData gifData, byte[] bytes, int offset)
    {
        GifImageData imgData        = new GifImageData(gifData);
        int          subblockOffset = offset + 1;
        int          subblockCount  = 0;

        imgData.lzwMinimumCodeSize = bytes[offset];

        // Read subblock data
        while (true)
        {
            int subblockSize = bytes[subblockOffset];

            if (subblockSize == 0)
            {
                break;
            }
            else
            {
                for (int i = 0; i < subblockSize; i++)
                {
                    imgData.blockBytes.Add(bytes[subblockOffset + 1 + i]);
                }

                subblockOffset += subblockSize + 1;
                subblockCount++;
            }
        }
        imgData.endingOffset = subblockOffset;

        //Debug.Log("Number of subblocks read: " + subblockCount);

        return(imgData);
    }
Exemple #11
0
    /*
     * public Coroutine Init(GifData gif)
     * {
     * Coroutine lc;
     * playing = true;
     * lc= StartCoroutine(play(gif));
     * return lc;
     * }
     *
     *
     *
     * private void Start()
     * {
     *   Init(_g);
     * }
     *
     * public void ChangeGif(GifData gd) {
     *  playing = false;
     *  StopCoroutine(lastCoroutine);
     *  lastCoroutine = Init(gd);
     * }
     */

    public override void Initialize(GifData gif)

    {
        playing = true;
        StopAllCoroutines();
        StartCoroutine(Play(gif));
    }
Exemple #12
0
    /// <summary>
    /// 加载gif
    /// </summary>
    public void LoadGif()
    {
        string fullName = FilePath.picPath + "暗中观察.gif";

        GifData data = LoadLocalImage.LoadImage(fullName);

        _imagePlayer.SetImage(data);
    }
Exemple #13
0
    /// <summary>
    /// 加载png
    /// </summary>
    public void LoadPng()
    {
        string fullName = FilePath.picPath + "magic.png";

        GifData data = LoadLocalImage.LoadImage(fullName);

        _imagePlayer.SetImage(data);
    }
Exemple #14
0
    /// <summary>
    /// 路径错误的情况
    /// </summary>
    public void LoadFalse()
    {
        string fullName = FilePath.picPath + "这张图不存在的";

        GifData data = LoadLocalImage.LoadImage(fullName);

        _imagePlayer.SetImage(data);
    }
    void OneFrame(GifData gif)
    {
        _imageComponent.sprite = gif.frames[0].sprite;

        AdjustmentHeightAndWidth(gif);

        Stop();
    }
Exemple #16
0
    public GifImageData(GifData gifData)
    {
        _gifData = gifData;

        codeTable    = new List <int[]>(4096);
        colorIndices = new List <int>(256);
        blockBytes   = new List <byte>(255);
    }
 /// <summary>
 /// Get GraphicControlExtension from GifData
 /// </summary>
 private static GraphicControlExtension?GetGraphicCtrlExt(GifData gifData, int imgBlockIndex)
 {
     if (gifData.graphicCtrlExList != null && gifData.graphicCtrlExList.Count > imgBlockIndex)
     {
         return(gifData.graphicCtrlExList[imgBlockIndex]);
     }
     return(null);
 }
Exemple #18
0
        /// <summary>
        ///     Get GIF texture list Coroutine
        /// </summary>
        /// <param name="bytes">GIF file byte data</param>
        /// <param name="callback">
        ///     Callback method(param is GIF texture list, Animation loop count, GIF image width (px), GIF image
        ///     height (px))
        /// </param>
        /// <param name="thisReference">The this reference.</param>
        /// <param name="mono">The mono.</param>
        /// <param name="filterMode">Textures filter mode</param>
        /// <param name="wrapMode">Textures wrap mode</param>
        /// <param name="debugLog">Debug Log Flag</param>
        /// <returns>
        ///     IEnumerator
        /// </returns>
        /// <exception cref="ArgumentNullException">mono</exception>
        public static IEnumerator GetTextureListCoroutine(
            byte[] bytes,
            Action <List <GifTexture>, int, int, int> callback,
            object thisReference,
            MonoBehaviour mono,
            FilterMode filterMode    = FilterMode.Bilinear,
            TextureWrapMode wrapMode = TextureWrapMode.Clamp,
            bool debugLog            = false)
        {
            var isEditor = thisReference != null;

            if (mono == null)
            {
                throw new ArgumentNullException(nameof(mono));
            }

            var loopCount = -1;

            var width  = 0;
            var height = 0;

            // Set GIF data
            var gifData = new GifData();

            if (!SetGifData(bytes, ref gifData, debugLog))
            {
                Debug.LogError("GIF file data set error.");
                callback?.Invoke(null, loopCount, width, height);

                yield break;
            }

            // Decode to textures from GIF data
            List <GifTexture> gifTexList = null;

            yield return(gifData.DecodeTextureCoroutine(result => gifTexList = result, filterMode, wrapMode, isEditor)
                         .CreateSmartCorotine(thisReference, mono));

            if (gifTexList == null || gifTexList.Count <= 0)
            {
                Debug.LogError(
                    $"GIF texture decode error. Count: {gifTexList.PrintListLength()} || Byte Count: {bytes?.Length}");
                callback?.Invoke(null, loopCount, width, height);

                yield break;
            }

            if (gifData.IsNull())
            {
                throw new NullReferenceException();
            }

            loopCount = gifData.m_appEx.loopCount;
            width     = gifData.m_logicalScreenWidth;
            height    = gifData.m_logicalScreenHeight;

            callback?.Invoke(gifTexList, loopCount, width, height);
        }
        /// <summary>
        /// Create Texture2D object and initial settings
        /// </summary>
        private static Texture2D CreateTexture2D(GifData gifData, List <GifTexture> gifTexList, int imgIndex, List <ushort> disposalMethodList, Color32 bgColor, FilterMode filterMode, TextureWrapMode wrapMode, out bool filledTexture)
        {
            filledTexture = false;

            // Create texture
            Texture2D tex = new Texture2D(gifData.m_logicalScreenWidth, gifData.m_logicalScreenHeight, TextureFormat.ARGB32, false);

            tex.filterMode = filterMode;
            tex.wrapMode   = wrapMode;

            // Check dispose
            ushort disposalMethod = imgIndex > 0 ? disposalMethodList[imgIndex - 1] : (ushort)2;
            int    useBeforeIndex = -1;

            if (disposalMethod == 0)
            {
                // 0 (No disposal specified)
            }
            else if (disposalMethod == 1)
            {
                // 1 (Do not dispose)
                useBeforeIndex = imgIndex - 1;
            }
            else if (disposalMethod == 2)
            {
                // 2 (Restore to background color)
                filledTexture = true;
                Color32[] pix = new Color32[tex.width * tex.height];
                for (int i = 0; i < pix.Length; i++)
                {
                    pix[i] = bgColor;
                }
                tex.SetPixels32(pix);
                tex.Apply();
            }
            else if (disposalMethod == 3)
            {
                // 3 (Restore to previous)
                for (int i = imgIndex - 1; i >= 0; i--)
                {
                    if (disposalMethodList[i] == 0 || disposalMethodList[i] == 1)
                    {
                        useBeforeIndex = i;
                        break;
                    }
                }
            }

            if (useBeforeIndex >= 0)
            {
                filledTexture = true;
                Color32[] pix = gifTexList[useBeforeIndex].m_texture2d.GetPixels32();
                tex.SetPixels32(pix);
                tex.Apply();
            }

            return(tex);
        }
        /// <summary>
        /// Decode to textures from GIF data
        /// </summary>
        /// <param name="gifData">GIF data</param>
        /// <param name="callback">Callback method(param is GIF texture list)</param>
        /// <param name="filterMode">Textures filter mode</param>
        /// <param name="wrapMode">Textures wrap mode</param>
        /// <returns>IEnumerator</returns>
        private static IEnumerator DecodeTextureCoroutine(GifData gifData, Action <List <GifTexture> > callback, FilterMode filterMode, TextureWrapMode wrapMode)
        {
            if (gifData.m_imageBlockList == null || gifData.m_imageBlockList.Count < 1)
            {
                yield break;
            }

            List <GifTexture> gifTexList         = new List <GifTexture>(gifData.m_imageBlockList.Count);
            List <ushort>     disposalMethodList = new List <ushort>(gifData.m_imageBlockList.Count);

            int imgIndex = 0;

            for (int i = 0; i < gifData.m_imageBlockList.Count; i++)
            {
                byte[] decodedData = GetDecodedData(gifData.m_imageBlockList[i]);

                GraphicControlExtension?graphicCtrlEx = GetGraphicCtrlExt(gifData, imgIndex);

                int transparentIndex = GetTransparentIndex(graphicCtrlEx);

                disposalMethodList.Add(GetDisposalMethod(graphicCtrlEx));

                Color32       bgColor;
                List <byte[]> colorTable = GetColorTableAndSetBgColor(gifData, gifData.m_imageBlockList[i], transparentIndex, out bgColor);

                yield return(0);

                bool      filledTexture;
                Texture2D tex = CreateTexture2D(gifData, gifTexList, imgIndex, disposalMethodList, bgColor, filterMode, wrapMode, out filledTexture);

                yield return(0);

                // Set pixel data
                int dataIndex = 0;
                // Reverse set pixels. because GIF data starts from the top left.
                for (int y = tex.height - 1; y >= 0; y--)
                {
                    SetTexturePixelRow(tex, y, gifData.m_imageBlockList[i], decodedData, ref dataIndex, colorTable, bgColor, transparentIndex, filledTexture);
                }
                tex.Apply();

                yield return(0);

                float delaySec = GetDelaySec(graphicCtrlEx);

                // Add to GIF texture list
                gifTexList.Add(new GifTexture(tex, delaySec));

                imgIndex++;
            }

            if (callback != null)
            {
                callback(gifTexList);
            }

            yield break;
        }
    /// <summary>
    /// Decode to textures from GIF data
    /// </summary>
    /// <param name="gifData">GIF data</param>
    /// <param name="gifTexList">GIF texture list</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <returns>IEnumerator</returns>
    static IEnumerator DecodeTextureCoroutine(GifData gifData, List<GifTexture> gifTexList, FilterMode filterMode, TextureWrapMode wrapMode)
    {
        if (gifData.imageBlockList == null || gifData.imageBlockList.Count < 1) {
            yield break;
        }

        Color32? bgColor = GetGlobalBgColor (gifData);

        // Disposal Method
        // 0 (No disposal specified)
        // 1 (Do not dispose)
        // 2 (Restore to background color)
        // 3 (Restore to previous)
        ushort disposalMethod = 0;

        int imgBlockIndex = 0;
        foreach (var imgBlock in gifData.imageBlockList) {
            var decodedData = GetDecodedData (imgBlock);

            var colorTable = GetColorTable (gifData, imgBlock, ref bgColor);

            var graphicCtrlEx = GetGraphicCtrlExt (gifData, imgBlockIndex);

            int transparentIndex = GetTransparentIndex (graphicCtrlEx);

            // avoid lock up
            yield return 0;

            bool useBeforeTex = false;
            var tex = CreateTexture2D (gifData, gifTexList, imgBlockIndex, disposalMethod, filterMode, wrapMode, ref useBeforeTex);

            // Set pixel data
            int dataIndex = 0;
            // Reverse set pixels. because GIF data starts from the top left.
            for (int y = tex.height - 1; y >= 0; y--) {
                SetTexturePixelRow (tex, y, imgBlock, decodedData, ref dataIndex, colorTable, bgColor, transparentIndex, useBeforeTex);

                // avoid lock up
                //if (y % 10 == 0) {
                //    yield return 0;
                //}
            }
            tex.Apply ();

            float delaySec = GetDelaySec (graphicCtrlEx);

            // Add to GIF texture list
            gifTexList.Add (new GifTexture (tex, delaySec));

            disposalMethod = GetDisposalMethod (graphicCtrlEx);

            imgBlockIndex++;

            // avoid lock up
            yield return 0;
        }
    }
Exemple #22
0
    public GifImageData(GifData gifData)
    {
        _gifData = gifData;
        _colors  = new Dictionary <int, GifColor>(256);

        codeTable    = new Dictionary <int, int[]>(4096);
        colorIndices = new List <int>(256);
        blockBytes   = new List <byte>(255);
    }
    public GifImageData(GifData gifData)
    {
        _gifData = gifData;
        _colors = new Dictionary<int, GifColor>(256);

        codeTable = new Dictionary<int, int[]>(4096);
        colorIndices = new List<int>(256);
        blockBytes = new List<byte>(255);
    }
    /// <summary>
    /// Decode to textures from GIF data
    /// </summary>
    /// <param name="gifData">GIF data</param>
    /// <param name="gifTexList">GIF texture list</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <returns>Result</returns>
    private static bool DecodeTexture(GifData gifData, List <GifTexture> gifTexList, FilterMode filterMode, TextureWrapMode wrapMode)
    {
        if (gifData.imageBlockList == null || gifData.imageBlockList.Count < 1)
        {
            return(false);
        }

        Color32?bgColor = GetGlobalBgColor(gifData);

        // Disposal Method
        // 0 (No disposal specified)
        // 1 (Do not dispose)
        // 2 (Restore to background color)
        // 3 (Restore to previous)
        ushort disposalMethod = 0;

        int imgBlockIndex = 0;

        foreach (var imgBlock in gifData.imageBlockList)
        {
            var decodedData = GetDecodedData(imgBlock);

            var colorTable = GetColorTable(gifData, imgBlock, ref bgColor);

            var graphicCtrlEx = GetGraphicCtrlExt(gifData, imgBlockIndex);

            int transparentIndex = GetTransparentIndex(graphicCtrlEx);

            bool useBeforeTex = false;
            var  tex          = CreateTexture2D(gifData, gifTexList, imgBlockIndex, disposalMethod, filterMode, wrapMode, ref useBeforeTex);

            // Set pixel data
            int dataIndex = 0;
            // Reverse set pixels. because GIF data starts from the top left.
            for (int y = tex.height - 1; y >= 0; y--)
            {
                SetTexturePixelRow(tex, y, imgBlock, decodedData, ref dataIndex, colorTable, bgColor, transparentIndex, useBeforeTex);
            }
            tex.Apply();

            float delaySec = GetDelaySec(graphicCtrlEx);

            // Add to GIF texture list
            if (gifTexList == null)
            {
                gifTexList = new List <GifTexture>();
            }
            gifTexList.Add(new GifTexture(tex, delaySec));

            disposalMethod = GetDisposalMethod(graphicCtrlEx);

            imgBlockIndex++;
        }

        return(true);
    }
    void MultipleFrames(GifData gif)
    {
        _gifData = gif;

        AdjustmentHeightAndWidth(gif);

        ComputeNextFrameTimeArray(gif);

        PlayFromBeginning();
    }
    /*
     * 假设Image是正方形,有四种情况
     *  1.图片是扁的、适应大小    ->  保持宽度
     *  2.图片是扁的、填充        ->  保持高度
     *  3.图片是高的、适应大小    ->  保持高度
     *  4.图片是高的、填充        ->  保持宽度
     *
     * 假设Image不是正方形,宽度 / 高度 = WH
     *  1.图片WH > 显示WH、适应    ->  保持宽度
     *  2.图片WH > 显示WH、填充    ->  保持高度
     *  3.图片WH < 显示WH、适应    ->  保持高度
     *  4.图片WH < 显示WH、填充    ->  保持宽度
     *
     * 需要先求出适应和填充,之后插值,则
     *  1.图片WH > 显示WH、适应    ->  保持宽度
     *  2.图片WH < 显示WH、适应    ->  保持高度
     *  3.图片WH > 显示WH、填充    ->  保持高度
     *  4.图片WH < 显示WH、填充    ->  保持宽度
     */
    void AdjustmentHeightAndWidth(GifData imageData)
    {
        Vector2 imageSize = new Vector2(imageData.frames[0].sprite.texture.width, imageData.frames[0].sprite.texture.height);
        //如果用 imageData.frames[0].sprite.textureRect.size 就能直接获取到宽高,但不知道为什么有时候宽高会获取错误,只能这样分两次获取了

        Vector2 adaptableSize = GetAdaptableSizeDelta(imageSize);
        Vector2 fillSize      = GetFillSizeDelta(imageSize);

        _rectTransform.sizeDelta = Vector2.Lerp(adaptableSize, fillSize, _AdaptableToFill);
    }
    private GifGraphicsControlExtension readGraphicsControlExtension(GifData gifData, byte[] bytes, int offset)
    {
        GifGraphicsControlExtension gce = new GifGraphicsControlExtension(gifData);

        gce.disposalMethod        = BitHelper.getIntFromPackedByte(bytes[offset + 3], 3, 6);
        gce.transparentColorFlag  = BitHelper.getIntFromPackedByte(bytes[offset + 3], 7, 8) == 1;
        gce.delayTime             = BitHelper.getInt16FromBytes(bytes, offset + 4);
        gce.transparentColorIndex = bytes[offset + 6];

        return(gce);
    }
Exemple #28
0
    public void ChangeGif(GifData gd)
    {
        lastPlayed = _g;
        playing    = false;

        //StopCoroutine(play(_g));
        if (lastPlayed.name != gd.name)
        {
            Initialize(gd);
        }
    }
    static async Task <Texture2D> DecodeTextureAsync
    (
        GifData gifData,
        FilterMode filterMode,
        TextureWrapMode wrapMode
    )
    {
        if (gifData.m_imageBlockList == null || gifData.m_imageBlockList.Count < 1)
        {
            await Task.Delay(1);
        }

        List <ushort> disposalMethodList = new List <ushort>(gifData.m_imageBlockList.Count);

        int imgIndex = 0;
        int i        = 0;

        byte[] decodedData = GetDecodedData(gifData.m_imageBlockList[i]);

        GraphicControlExtension?graphicCtrlEx = GetGraphicCtrlExt(gifData, imgIndex);

        int transparentIndex = GetTransparentIndex(graphicCtrlEx);

        disposalMethodList.Add(GetDisposalMethod(graphicCtrlEx));

        Color32       bgColor;
        List <byte[]> colorTable = GetColorTableAndSetBgColor(gifData, gifData.m_imageBlockList[i], transparentIndex, out bgColor);

        await Task.Delay(1);

        bool      filledTexture;
        Texture2D texture = CreateTexture2D(gifData, imgIndex, disposalMethodList, bgColor, filterMode, wrapMode, out filledTexture);

        await Task.Delay(1);

        // Set pixel data
        int dataIndex = 0;

        // Reverse set pixels. because GIF data starts from the top left.
        for (int y = texture.height - 1; y >= 0; y--)
        {
            SetTexturePixelRow(texture, y, gifData.m_imageBlockList[i], decodedData, ref dataIndex, colorTable, bgColor, transparentIndex, filledTexture);
        }
        texture.Apply();

        await Task.Delay(1);

        float delaySec = GetDelaySec(graphicCtrlEx);


        imgIndex++;

        return(texture);
    }
    public GifImageData(GifData gifData, int curOffset)
    {
        _curOffset = curOffset;
        _gifData   = gifData;
        _colors    = new Dictionary <int, GifColor>(256);
        _indices   = new HashSet <int>();

        codeTable    = new Dictionary <int, int[]>(4096);
        colorIndices = new List <int>(256);
        blockBytes   = new List <byte>(255);
    }
Exemple #31
0
    private void Start()
    {
        var sw = Stopwatch.StartNew();

        _gifData = parseGifData(gif.bytes);

        createAnimator(_gifData);

        sw.Stop();
        Debug.Log($"Gif readed in {sw.ElapsedMilliseconds} ms!");
        Debug.Log(_gifData.ToString());
    }
Exemple #32
0
 IEnumerator play(GifData gif)
 {
     while (playing)
     {
         for (int j = 0; j < gif.frames.Length; j++)
         {
             spritey.sprite = Sprite.Create(gif.frames[j], new Rect(0, 0, gif.frames[j].width, gif.frames[j].height), new Vector2(0.5f, 0.5f));
             yield return(new WaitForSeconds(gif.delay));
         }
     }
     playing = false;
 }
    /// <summary>
    /// Get background color from global color table
    /// </summary>
    private static Color32?GetGlobalBgColor(GifData gifData)
    {
        Color32?bgColor = null;

        if (gifData.globalColorTableFlag)
        {
            // Set background color from global color table
            byte[] bgRgb = gifData.globalColorTable[gifData.bgColorIndex];
            bgColor = new Color32(bgRgb[0], bgRgb[1], bgRgb[2], 255);
        }
        return(bgColor);
    }
Exemple #34
0
 IEnumerator play(GifData gif)
 {
     while (playing)
     {
         for (int j = 0; j < gif.frames.Length; j++)
         {
             img.texture = gif.frames[j];
             yield return(new WaitForSeconds(gif.delay));
         }
     }
     playing = false;
 }
Exemple #35
0
    /// <summary>
    /// Get GIF texture list Coroutine (Avoid lock up but more slow)
    /// </summary>
    /// <param name="mb">MonoBehaviour to start the coroutine</param>
    /// <param name="bytes">GIF file byte data</param>
    /// <param name="cb">Callback method(param is GIF texture list, Animation loop count, GIF image width (px), GIF image height (px))</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <param name="debugLog">Debug Log Flag</param>
    /// <returns>IEnumerator</returns>
    public static IEnumerator GetTextureListCoroutine (MonoBehaviour mb, byte[] bytes, Action<List<GifTexture>, int, int, int> cb,
        FilterMode filterMode = FilterMode.Bilinear, TextureWrapMode wrapMode = TextureWrapMode.Clamp, bool debugLog = false)
    {
        int loopCount = -1;
        int width = 0;
        int height = 0;

        // Set GIF data
        var gifData = new GifData ();
        if (SetGifData (bytes, ref gifData, debugLog) == false) {
            Debug.LogError ("GIF file data set error.");
            if (cb != null) {
                cb (null, loopCount, width, height);
            }
            yield break;
        }

        // avoid lock up
        yield return 0;

        // Decode to textures from GIF data
        List<GifTexture> gifTexList = null;
        yield return mb.StartCoroutine (UniGif.DecodeTextureCoroutine (gifData, gtList => {
            gifTexList = gtList;
        }, filterMode, wrapMode));

        if (gifTexList == null) {
            Debug.LogError ("GIF texture decode error.");
            if (cb != null) {
                cb (null, loopCount, width, height);
            }
            yield break;
        }

        loopCount = gifData.appEx.loopCount;
        width = gifData.logicalScreenWidth;
        height = gifData.logicalScreenHeight;

        if (cb != null) {
            cb (gifTexList, loopCount, width, height);
        }
    }
    static void SetGraphicControlExtension (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        GraphicControlExtension gcEx = new GraphicControlExtension ();

        // Extension Introducer(1 Byte)
        // 0x21
        gcEx.extensionIntroducer = gifBytes[byteIndex];
        byteIndex++;

        // Graphic Control Label(1 Byte)
        // 0xf9
        gcEx.graphicControlLabel = gifBytes[byteIndex];
        byteIndex++;

        // Block Size(1 Byte)
        // 0x04
        gcEx.blockSize = gifBytes[byteIndex];
        byteIndex++;

        // 1 Byte
        {
            // Reserved(3 Bits)
            // Unused

            // Disposal Mothod(3 Bits)
            // 0 (No disposal specified)
            // 1 (Do not dispose)
            // 2 (Restore to background color)
            // 3 (Restore to previous)
            switch (gifBytes[byteIndex] & 28) { // 0b00011100
                case 4:     // 0b00000100
                    gcEx.disposalMethod = 1;
                    break;
                case 8:     // 0b00001000
                    gcEx.disposalMethod = 2;
                    break;
                case 12:    // 0b00001100
                    gcEx.disposalMethod = 3;
                    break;
                default:
                    gcEx.disposalMethod = 0;
                    break;
            }

            // User Input Flag(1 Bit)
            // Unknown

            // Transparent Color Flag(1 Bit)
            gcEx.transparentColorFlag = (gifBytes[byteIndex] & 1) == 1; // 0b00000001

            byteIndex++;
        }

        // Delay Time(2 Bytes)
        gcEx.delayTime = BitConverter.ToUInt16 (gifBytes, byteIndex);
        byteIndex += 2;

        // Transparent Color Index(1 Byte)
        gcEx.transparentColorIndex = gifBytes[byteIndex];
        byteIndex++;

        // Block Terminator(1 Byte)
        gcEx.blockTerminator = gifBytes[byteIndex];
        byteIndex++;

        if (gifData.graphicCtrlExList == null) {
            gifData.graphicCtrlExList = new List<GraphicControlExtension> ();
        }
        gifData.graphicCtrlExList.Add (gcEx);
    }
    /// <summary>
    /// Get GIF texture list Coroutine (Avoid lock up but more slow)
    /// </summary>
    /// <param name="mb">MonoBehaviour to start the coroutine</param>
    /// <param name="bytes">GIF file byte data</param>
    /// <param name="cb">Callback method(param is GIF texture list, Animation loop count, GIF image width (px), GIF image height (px))</param>
    /// <param name="filterMode">Textures filter mode</param>
    /// <param name="wrapMode">Textures wrap mode</param>
    /// <param name="debugLog">Debug Log Flag</param>
    /// <returns>IEnumerator</returns>
    public static IEnumerator GetTextureListCoroutine (MonoBehaviour mb, byte[] bytes, int instanceId, List<GifTexture> gifTexList,
        Action<List<GifTexture>, int, int, int> cb, FilterMode filterMode = FilterMode.Bilinear, TextureWrapMode wrapMode = TextureWrapMode.Clamp, bool debugLog = false)
    {
        int loopCount = -1;
        int width = 0;
        int height = 0;
        if (gifTexList == null)
        {
            gifTexList = new List<GifTexture>();
        }
        else
        {
            gifTexList = gifDict[instanceId].textureList;
        }

        if (!gifDict.ContainsKey(instanceId))
        {
            // Set GIF data
            var gifData = new GifData();
            if (SetGifData(bytes, ref gifData, debugLog) == false)
            {
                Debug.LogError("GIF file data set error.");
                if (cb != null)
                {
                    cb(null, loopCount, width, height);
                }
                yield break;
            }

            loopCount = gifData.appEx.loopCount;
            width = gifData.logicalScreenWidth;
            height = gifData.logicalScreenHeight;

            Debug.Log("loopCount " + loopCount);

            gifDict.Add(instanceId, new GifAnimation
            {
                loopCount = loopCount,
                width = width,
                height = height,
                textureList = gifTexList,
            });

            // avoid lock up
            yield return 0;

            // Decode to textures from GIF data
            yield return mb.StartCoroutine(UniGif.DecodeTextureCoroutine(gifData, gifTexList, filterMode, wrapMode));
        }

        if (cb != null)
        {
            //Debug.Log(gifDict[instanceId].textureList.Count + " " + gifDict[instanceId].loopCount);
            //if (gifDict[instanceId].textureList.Count == gifDict[instanceId].loopCount)
            //{
                loopCount = gifDict[instanceId].loopCount;
                width = gifDict[instanceId].width;
                height = gifDict[instanceId].height;
                gifTexList = gifDict[instanceId].textureList;

                cb(gifTexList, loopCount, width, height);
            //    yield break;
            //}
            //yield return new WaitForSeconds(0.1f);
        }

    }
 public GifGraphicsControlExtension(GifData gifData)
 {
     _gifData = gifData;
 }
 /// <summary>
 /// Get GraphicControlExtension from GifData
 /// </summary>
 static GraphicControlExtension? GetGraphicCtrlExt (GifData gifData, int imgBlockIndex)
 {
     if (gifData.graphicCtrlExList != null && gifData.graphicCtrlExList.Count > imgBlockIndex) {
         return gifData.graphicCtrlExList[imgBlockIndex];
     }
     return null;
 }
    /// <summary>
    /// Create Texture2D object and initial settings
    /// </summary>
    static Texture2D CreateTexture2D (GifData gifData, List<GifTexture> gifTexList, int imgBlockIndex, ushort disposalMethod, FilterMode filterMode, TextureWrapMode wrapMode, ref bool useBeforeTex)
    {
        // Create texture
        Texture2D tex = new Texture2D (gifData.logicalScreenWidth, gifData.logicalScreenHeight, TextureFormat.ARGB32, false);
        tex.filterMode = filterMode;
        tex.wrapMode = wrapMode;

        // Check dispose
        useBeforeTex = false;
        int beforeIndex = -1;
        if (imgBlockIndex > 0 && disposalMethod == 0 || disposalMethod == 1) {
            // before 1
            beforeIndex = imgBlockIndex - 1;
        } else if (imgBlockIndex > 1 && disposalMethod == 3) {
            // before 2
            beforeIndex = imgBlockIndex - 2;
        }
        if (beforeIndex >= 0) {
            // Do not dispose
            useBeforeTex = true;
            Color32[] pix = gifTexList[beforeIndex].texture2d.GetPixels32 ();
            tex.SetPixels32 (pix);
            tex.Apply ();
        }

        return tex;
    }
 /// <summary>
 /// Get background color from global color table
 /// </summary>
 static Color32? GetGlobalBgColor (GifData gifData)
 {
     Color32? bgColor = null;
     if (gifData.globalColorTableFlag) {
         // Set background color from global color table
         byte[] bgRgb = gifData.globalColorTable[gifData.bgColorIndex];
         bgColor = new Color32 (bgRgb[0], bgRgb[1], bgRgb[2], 255);
     }
     return bgColor;
 }
    /// <summary>
    /// Get color table (local or global)
    /// </summary>
    static List<byte[]> GetColorTable (GifData gifData, ImageBlock imgBlock, ref Color32? bgColor)
    {
        var colorTable = imgBlock.localColorTableFlag ? imgBlock.localColorTable : gifData.globalColorTable;

        if (imgBlock.localColorTableFlag) {
            // Set background color from local color table
            byte[] bgRgb = imgBlock.localColorTable[gifData.bgColorIndex];
            bgColor = new Color32 (bgRgb[0], bgRgb[1], bgRgb[2], 255);
        }

        return colorTable;
    }
    static void SetImageBlock (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        ImageBlock ib = new ImageBlock ();

        // Image Separator(1 Byte)
        // 0x2c
        ib.imageSeparator = gifBytes[byteIndex];
        byteIndex++;

        // Image Left Position(2 Bytes)
        ib.imageLeftPosition = BitConverter.ToUInt16 (gifBytes, byteIndex);
        byteIndex += 2;

        // Image Top Position(2 Bytes)
        ib.imageTopPosition = BitConverter.ToUInt16 (gifBytes, byteIndex);
        byteIndex += 2;

        // Image Width(2 Bytes)
        ib.imageWidth = BitConverter.ToUInt16 (gifBytes, byteIndex);
        byteIndex += 2;

        // Image Height(2 Bytes)
        ib.imageHeight = BitConverter.ToUInt16 (gifBytes, byteIndex);
        byteIndex += 2;

        // 1 Byte
        {
            // Local Color Table Flag(1 Bit)
            ib.localColorTableFlag = (gifBytes[byteIndex] & 128) == 128; // 0b10000000

            // Interlace Flag(1 Bit)
            ib.interlaceFlag = (gifBytes[byteIndex] & 64) == 64; // 0b01000000

            // Sort Flag(1 Bit)
            ib.sortFlag = (gifBytes[byteIndex] & 32) == 32; // 0b00100000

            // Reserved(2 Bits)
            // Unused

            // Size of Local Color Table(3 Bits)
            int val = (gifBytes[byteIndex] & 7) + 1;
            ib.sizeOfLocalColorTable = (int) Math.Pow (2, val);

            byteIndex++;
        }

        if (ib.localColorTableFlag) {
            // Local Color Table(0~255×3 Bytes)
            ib.localColorTable = new List<byte[]> ();
            for (int i = byteIndex; i < byteIndex + (ib.sizeOfLocalColorTable * 3); i += 3) {
                ib.localColorTable.Add (new byte[] { gifBytes[i], gifBytes[i + 1], gifBytes[i + 2] });
            }
            byteIndex = byteIndex + (ib.sizeOfLocalColorTable * 3);
        }

        // LZW Minimum Code Size(1 Byte)
        ib.LzwMinimumCodeSize = gifBytes[byteIndex];
        byteIndex++;

        // Block Size & Image Data List
        while (true) {
            // Block Size(1 Byte)
            byte blockSize = gifBytes[byteIndex];
            byteIndex++;

            if (blockSize == 0x00) {
                // Block Terminator(1 Byte)
                break;
            }

            var imageDataBlock = new ImageBlock.ImageDataBlock ();
            imageDataBlock.blockSize = blockSize;

            // Image Data(? Bytes)
            imageDataBlock.imageData = new byte[imageDataBlock.blockSize];
            for (int i = 0; i < imageDataBlock.imageData.Length; i++) {
                imageDataBlock.imageData[i] = gifBytes[byteIndex];
                byteIndex++;
            }

            if (ib.imageDataList == null) {
                ib.imageDataList = new List<ImageBlock.ImageDataBlock> ();
            }
            ib.imageDataList.Add (imageDataBlock);
        }

        if (gifData.imageBlockList == null) {
            gifData.imageBlockList = new List<ImageBlock> ();
        }
        gifData.imageBlockList.Add (ib);
    }
    static bool SetGifBlock (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        try {
            int lastIndex = 0;
            while (true) {
                int nowIndex = byteIndex;

                if (gifBytes[nowIndex] == 0x2c) {
                    // Image Block(0x2c)
                    SetImageBlock (gifBytes, ref byteIndex, ref gifData);

                } else if (gifBytes[nowIndex] == 0x21) {
                    // Extension
                    switch (gifBytes[nowIndex + 1]) {
                        case 0xf9:
                            // Graphic Control Extension(0x21 0xf9)
                            SetGraphicControlExtension (gifBytes, ref byteIndex, ref gifData);
                            break;
                        case 0xfe:
                            // Comment Extension(0x21 0xfe)
                            SetCommentExtension (gifBytes, ref byteIndex, ref gifData);
                            break;
                        case 0x01:
                            // Plain Text Extension(0x21 0x01)
                            SetPlainTextExtension (gifBytes, ref byteIndex, ref gifData);
                            break;
                        case 0xff:
                            // Application Extension(0x21 0xff)
                            SetApplicationExtension (gifBytes, ref byteIndex, ref gifData);
                            break;
                        default:
                            break;
                    }
                } else if (gifBytes[nowIndex] == 0x3b) {
                    // Trailer(1 Byte)
                    gifData.trailer = gifBytes[byteIndex];
                    byteIndex++;
                    break;
                }

                if (lastIndex == nowIndex) {
                    Debug.LogError ("Infinite loop error.");
                    return false;
                }

                lastIndex = nowIndex;
            }
        } catch (Exception ex) {
            Debug.LogError (ex.Message);
            return false;
        }

        return true;
    }
    static bool SetGifHeader (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        // Signature(3 Bytes)
        // 0x47 0x49 0x46 (GIF)
        if (gifBytes[0] != 'G' || gifBytes[1] != 'I' || gifBytes[2] != 'F') {
            Debug.LogError ("This is not GIF image.");
            return false;
        }
        gifData.sig0 = gifBytes[0];
        gifData.sig1 = gifBytes[1];
        gifData.sig2 = gifBytes[2];

        // Version(3 Bytes)
        // 0x38 0x37 0x61 (87a) or 0x38 0x39 0x61 (89a)
        if ((gifBytes[3] != '8' || gifBytes[4] != '7' || gifBytes[5] != 'a') &&
            (gifBytes[3] != '8' || gifBytes[4] != '9' || gifBytes[5] != 'a')) {
            Debug.LogError ("GIF version error.\nSupported only GIF87a or GIF89a.");
            return false;
        }
        gifData.ver0 = gifBytes[3];
        gifData.ver1 = gifBytes[4];
        gifData.ver2 = gifBytes[5];

        // Logical Screen Width(2 Bytes)
        gifData.logicalScreenWidth = BitConverter.ToUInt16 (gifBytes, 6);

        // Logical Screen Height(2 Bytes)
        gifData.logicalScreenHeight = BitConverter.ToUInt16 (gifBytes, 8);

        // 1 Byte
        {
            // Global Color Table Flag(1 Bit)
            gifData.globalColorTableFlag = (gifBytes[10] & 128) == 128; // 0b10000000

            // Color Resolution(3 Bits)
            switch (gifBytes[10] & 112) {
                case 112: // 0b01110000
                    gifData.colorResolution = 8;
                    break;
                case 96: // 0b01100000
                    gifData.colorResolution = 7;
                    break;
                case 80: // 0b01010000
                    gifData.colorResolution = 6;
                    break;
                case 64: // 0b01000000
                    gifData.colorResolution = 5;
                    break;
                case 48: // 0b00110000
                    gifData.colorResolution = 4;
                    break;
                case 32: // 0b00100000
                    gifData.colorResolution = 3;
                    break;
                case 16: // 0b00010000
                    gifData.colorResolution = 2;
                    break;
                default:
                    gifData.colorResolution = 1;
                    break;
            }

            // Sort Flag(1 Bit)
            gifData.sortFlag = (gifBytes[10] & 8) == 8; // 0b00001000

            // Size of Global Color Table(3 Bits)
            int val = (gifBytes[10] & 7) + 1;
            gifData.sizeOfGlobalColorTable = (int) Math.Pow (2, val);
        }

        // Background Color Index(1 Byte)
        gifData.bgColorIndex = gifBytes[11];

        // Pixel Aspect Ratio(1 Byte)
        gifData.pixelAspectRatio = gifBytes[12];

        byteIndex = 13;
        if (gifData.globalColorTableFlag) {
            // Global Color Table(0~255×3 Bytes)
            gifData.globalColorTable = new List<byte[]> ();
            for (int i = byteIndex; i < byteIndex + (gifData.sizeOfGlobalColorTable * 3); i += 3) {
                gifData.globalColorTable.Add (new byte[] { gifBytes[i], gifBytes[i + 1], gifBytes[i + 2] });
            }
            byteIndex = byteIndex + (gifData.sizeOfGlobalColorTable * 3);
        }

        return true;
    }
    static void SetApplicationExtension (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        // Extension Introducer(1 Byte)
        // 0x21
        gifData.appEx.extensionIntroducer = gifBytes[byteIndex];
        byteIndex++;

        // Extension Label(1 Byte)
        // 0xff
        gifData.appEx.extensionLabel = gifBytes[byteIndex];
        byteIndex++;

        // Block Size(1 Byte)
        // 0x0b
        gifData.appEx.blockSize = gifBytes[byteIndex];
        byteIndex++;

        // Application Identifier(8 Bytes)
        gifData.appEx.appId1 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId2 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId3 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId4 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId5 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId6 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId7 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appId8 = gifBytes[byteIndex];
        byteIndex++;

        // Application Authentication Code(3 Bytes)
        gifData.appEx.appAuthCode1 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appAuthCode2 = gifBytes[byteIndex];
        byteIndex++;
        gifData.appEx.appAuthCode3 = gifBytes[byteIndex];
        byteIndex++;

        // Block Size & Application Data List
        while (true) {
            // Block Size (1 Byte)
            byte blockSize = gifBytes[byteIndex];
            byteIndex++;

            if (blockSize == 0x00) {
                // Block Terminator(1 Byte)
                break;
            }

            var appDataBlock = new ApplicationExtension.ApplicationDataBlock ();
            appDataBlock.blockSize = blockSize;

            // Application Data(n Byte)
            appDataBlock.applicationData = new byte[appDataBlock.blockSize];
            for (int i = 0; i < appDataBlock.applicationData.Length; i++) {
                appDataBlock.applicationData[i] = gifBytes[byteIndex];
                byteIndex++;
            }

            if (gifData.appEx.appDataList == null) {
                gifData.appEx.appDataList = new List<ApplicationExtension.ApplicationDataBlock> ();
            }
            gifData.appEx.appDataList.Add (appDataBlock);
        }
    }
    static void SetPlainTextExtension (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        PlainTextExtension plainTxtEx = new PlainTextExtension ();

        // Extension Introducer(1 Byte)
        // 0x21
        plainTxtEx.extensionIntroducer = gifBytes[byteIndex];
        byteIndex++;

        // Plain Text Label(1 Byte)
        // 0x01
        plainTxtEx.plainTextLabel = gifBytes[byteIndex];
        byteIndex++;

        // Block Size(1 Byte)
        // 0x0c
        plainTxtEx.blockSize = gifBytes[byteIndex];
        byteIndex++;

        // Text Grid Left Position(2 Bytes)
        // Not supported
        byteIndex += 2;

        // Text Grid Top Position(2 Bytes)
        // Not supported
        byteIndex += 2;

        // Text Grid Width(2 Bytes)
        // Not supported
        byteIndex += 2;

        // Text Grid Height(2 Bytes)
        // Not supported
        byteIndex += 2;

        // Character Cell Width(1 Bytes)
        // Not supported
        byteIndex++;

        // Character Cell Height(1 Bytes)
        // Not supported
        byteIndex++;

        // Text Foreground Color Index(1 Bytes)
        // Not supported
        byteIndex++;

        // Text Background Color Index(1 Bytes)
        // Not supported
        byteIndex++;

        // Block Size & Plain Text Data List
        while (true) {
            // Block Size(1 Byte)
            byte blockSize = gifBytes[byteIndex];
            byteIndex++;

            if (blockSize == 0x00) {
                // Block Terminator(1 Byte)
                break;
            }

            var plainTextDataBlock = new PlainTextExtension.PlainTextDataBlock ();
            plainTextDataBlock.blockSize = blockSize;

            // Plain Text Data(n Byte)
            plainTextDataBlock.plainTextData = new byte[plainTextDataBlock.blockSize];
            for (int i = 0; i < plainTextDataBlock.plainTextData.Length; i++) {
                plainTextDataBlock.plainTextData[i] = gifBytes[byteIndex];
                byteIndex++;
            }

            if (plainTxtEx.plainTextDataList == null) {
                plainTxtEx.plainTextDataList = new List<PlainTextExtension.PlainTextDataBlock> ();
            }
            plainTxtEx.plainTextDataList.Add (plainTextDataBlock);
        }

        if (gifData.plainTextExList == null) {
            gifData.plainTextExList = new List<PlainTextExtension> ();
        }
        gifData.plainTextExList.Add (plainTxtEx);
    }
    static void SetCommentExtension (byte[] gifBytes, ref int byteIndex, ref GifData gifData)
    {
        CommentExtension commentEx = new CommentExtension ();

        // Extension Introducer(1 Byte)
        // 0x21
        commentEx.extensionIntroducer = gifBytes[byteIndex];
        byteIndex++;

        // Comment Label(1 Byte)
        // 0xfe
        commentEx.commentLabel = gifBytes[byteIndex];
        byteIndex++;

        // Block Size & Comment Data List
        while (true) {
            // Block Size(1 Byte)
            byte blockSize = gifBytes[byteIndex];
            byteIndex++;

            if (blockSize == 0x00) {
                // Block Terminator(1 Byte)
                break;
            }

            var commentDataBlock = new CommentExtension.CommentDataBlock ();
            commentDataBlock.blockSize = blockSize;

            // Comment Data(n Byte)
            commentDataBlock.commentData = new byte[commentDataBlock.blockSize];
            for (int i = 0; i < commentDataBlock.commentData.Length; i++) {
                commentDataBlock.commentData[i] = gifBytes[byteIndex];
                byteIndex++;
            }

            if (commentEx.commentDataList == null) {
                commentEx.commentDataList = new List<CommentExtension.CommentDataBlock> ();
            }
            commentEx.commentDataList.Add (commentDataBlock);
        }

        if (gifData.commentExList == null) {
            gifData.commentExList = new List<CommentExtension> ();
        }
        gifData.commentExList.Add (commentEx);
    }
 public GifImageDescriptor(GifData gifData)
 {
     _gifData = gifData;
 }