├── .gitignore ├── Assets ├── GifDecoder.meta ├── GifDecoder │ ├── BitHelper.cs │ ├── BitHelper.cs.meta │ ├── GifAnimatorScript.cs │ ├── GifAnimatorScript.cs.meta │ ├── GifColor.cs │ ├── GifColor.cs.meta │ ├── GifData.cs │ ├── GifData.cs.meta │ ├── GifGraphicsControlExtension.cs │ ├── GifGraphicsControlExtension.cs.meta │ ├── GifImageData.cs │ ├── GifImageData.cs.meta │ ├── GifImageDescriptor.cs │ ├── GifImageDescriptor.cs.meta │ ├── GifParserScript.cs │ └── GifParserScript.cs.meta ├── gif.bytes ├── gif.bytes.meta ├── scene.unity └── scene.unity.meta ├── ProjectSettings ├── AudioManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshLayers.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── ProjectSettings.asset ├── QualitySettings.asset ├── TagManager.asset └── TimeManager.asset └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # =============== # 2 | # Unity generated # 3 | # =============== # 4 | Temp/ 5 | Obj/ 6 | UnityGenerated/ 7 | Library/ 8 | bin/ 9 | 10 | # ===================================== # 11 | # Visual Studio / MonoDevelop generated # 12 | # ===================================== # 13 | ExportedObj/ 14 | *.svd 15 | *.userprefs 16 | *.csproj 17 | *.pidb 18 | *.suo 19 | *.sln 20 | *.user 21 | *.unityproj 22 | *.booproj 23 | 24 | # ============ # 25 | # OS generated # 26 | # ============ # 27 | .DS_Store 28 | .DS_Store? 29 | ._* 30 | .Spotlight-V100 31 | .Trashes 32 | Icon? 33 | ehthumbs.db 34 | Thumbs.db -------------------------------------------------------------------------------- /Assets/GifDecoder.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9825b5a67e09e7c439ce7a92b94a0098 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | -------------------------------------------------------------------------------- /Assets/GifDecoder/BitHelper.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using System; 14 | 15 | public class BitHelper 16 | { 17 | public static int getIntFromPackedByte(byte input, int start, int end) 18 | { 19 | int size = end - start; 20 | int shiftAmount = 8 - end; 21 | int mask = (1 << size) - 1; 22 | int result = (input >> shiftAmount) & mask; 23 | 24 | //Debug.Log("size: " + size + ", shiftAmount: " + shiftAmount + ", mask: " + mask + ", result: " + result); 25 | 26 | return result; 27 | } 28 | 29 | public static int getInt16FromBytes(byte[] bytes, int offset) 30 | { 31 | return BitConverter.ToInt16(new byte[] { bytes[offset], bytes[offset + 1] }, 0); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Assets/GifDecoder/BitHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: abdb6385752c4b0418dbf1bba64b5275 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifAnimatorScript.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System.Collections.Generic; 15 | using System.Diagnostics; 16 | 17 | public class GifAnimatorScript : MonoBehaviour 18 | { 19 | private SpriteRenderer _spriteRenderer; 20 | private int _frameCounter = 0; 21 | private float _timePerFrame = 1 / 15f; 22 | private float _timeAccumulator; 23 | private Stopwatch _stopwatch; 24 | 25 | public List sprites; 26 | 27 | private void createRenderer() 28 | { 29 | _spriteRenderer = gameObject.AddComponent(); 30 | _spriteRenderer.sprite = sprites[0]; 31 | _frameCounter = 0; 32 | } 33 | 34 | private void startStopwatch() 35 | { 36 | _stopwatch.Reset(); 37 | _stopwatch.Start(); 38 | } 39 | 40 | private void endStopwatch() 41 | { 42 | _stopwatch.Stop(); 43 | } 44 | 45 | private void updateFrame() 46 | { 47 | _timeAccumulator += (float)_stopwatch.Elapsed.Milliseconds * 0.001f; 48 | 49 | if (_timeAccumulator >= _timePerFrame) 50 | { 51 | _frameCounter = (_frameCounter + 1) % sprites.Count; 52 | _timeAccumulator -= _timePerFrame; 53 | } 54 | _spriteRenderer.sprite = sprites[_frameCounter]; 55 | } 56 | 57 | void Update() 58 | { 59 | endStopwatch(); 60 | updateFrame(); 61 | startStopwatch(); 62 | } 63 | 64 | void Start() 65 | { 66 | _stopwatch = new Stopwatch(); 67 | 68 | createRenderer(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifAnimatorScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97f39d617acc6054abdb014ef8c7efd0 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifColor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | public struct GifColor 14 | { 15 | public int r; 16 | public int g; 17 | public int b; 18 | public int a; 19 | 20 | public GifColor(int r, int g, int b, int a) 21 | { 22 | this.r = r; 23 | this.g = g; 24 | this.b = b; 25 | this.a = a; 26 | } 27 | 28 | public override string ToString() 29 | { 30 | return "R: " + r + " G: " + g + " B: " + b + " A: " + a; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifColor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5e8681076a146446abf27ec3ddfb3bd 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifData.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System.Collections.Generic; 15 | 16 | public class GifData 17 | { 18 | public string header; 19 | public int canvasWidth; 20 | public int canvasHeight; 21 | public bool globalColorTableFlag; 22 | public int bitsPerPixel; 23 | public bool sortFlag; 24 | public int globalColorTableSize; 25 | public int backgroundColorIndex; 26 | public int pixelAspectRatio; 27 | public GifColor[] globalColorTable; 28 | 29 | public List graphicsControlExtensions; 30 | public List imageDescriptors; 31 | public List imageDatas; 32 | 33 | public GifData() 34 | { 35 | graphicsControlExtensions = new List(); 36 | imageDescriptors = new List(); 37 | imageDatas = new List(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1429ef370fab6974ebbba10d7192fbc1 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifGraphicsControlExtension.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System.Collections; 15 | 16 | public class GifGraphicsControlExtension 17 | { 18 | private GifData _gifData; 19 | 20 | public int disposalMethod; 21 | public bool transparentColorFlag; 22 | public int delayTime; 23 | public int transparentColorIndex; 24 | public GifImageDescriptor imageDescriptor; 25 | public GifImageData imageData; 26 | 27 | public GifGraphicsControlExtension(GifData gifData) 28 | { 29 | _gifData = gifData; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifGraphicsControlExtension.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0939a838cabac194eb879d5b5f4c1d0a 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifImageData.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System; 15 | using System.Collections; 16 | using System.Collections.Generic; 17 | 18 | public class GifImageData 19 | { 20 | private GifData _gifData; 21 | private BitArray _blockBits; 22 | private int _currentCodeSize; 23 | private Dictionary _colors; 24 | 25 | public int lzwMinimumCodeSize; 26 | public int endingOffset; 27 | public List blockBytes; 28 | public Dictionary codeTable; 29 | public List colorIndices; 30 | public GifGraphicsControlExtension graphicsControlExt; 31 | public GifImageDescriptor imageDescriptor; 32 | 33 | public GifImageData(GifData gifData) 34 | { 35 | _gifData = gifData; 36 | _colors = new Dictionary(256); 37 | 38 | codeTable = new Dictionary(4096); 39 | colorIndices = new List(256); 40 | blockBytes = new List(255); 41 | } 42 | 43 | public void decode() 44 | { 45 | // Convert bytes to bits 46 | _blockBits = new BitArray(blockBytes.ToArray()); 47 | //Debug.Log("Converted " + blockBytes.Count + " bytes into " + _blockBits.Length + " bits."); 48 | 49 | // Translate block 50 | translateBlock(); 51 | 52 | // Prepare colors 53 | prepareColors(); 54 | } 55 | 56 | private void translateBlock() 57 | { 58 | _currentCodeSize = lzwMinimumCodeSize + 1; 59 | int currentCode; 60 | int previousCode; 61 | int bitOffset = _currentCodeSize; 62 | int iteration = 0; 63 | int cc = 1 << lzwMinimumCodeSize; 64 | int eoi = cc + 1; 65 | 66 | //Debug.Log("Starting to translate block. Current code size: " + _currentCodeSize +", CC: " + cc + ", EOI: " + eoi); 67 | 68 | initializeCodeTable(); 69 | currentCode = getCode(_blockBits, bitOffset, _currentCodeSize); 70 | addToColorIndices(getCodeValues(currentCode)); 71 | previousCode = currentCode; 72 | bitOffset += _currentCodeSize; 73 | 74 | while (true) 75 | { 76 | currentCode = getCode(_blockBits, bitOffset, _currentCodeSize); 77 | bitOffset += _currentCodeSize; 78 | 79 | // Handle special codes 80 | if (currentCode == cc) 81 | { 82 | //Debug.Log("Encountered CC. Reinitializing code table..."); 83 | _currentCodeSize = lzwMinimumCodeSize + 1; 84 | initializeCodeTable(); 85 | currentCode = getCode(_blockBits, bitOffset, _currentCodeSize); 86 | addToColorIndices(getCodeValues(currentCode)); 87 | previousCode = currentCode; 88 | bitOffset += _currentCodeSize; 89 | continue; 90 | } 91 | else if (currentCode == eoi) 92 | { 93 | break; 94 | } 95 | 96 | // Does code table contain the current code 97 | if (codeTable.ContainsKey(currentCode)) 98 | { 99 | int[] newEntry; 100 | int[] previousValues; 101 | int[] currentValues; 102 | 103 | addToColorIndices(getCodeValues(currentCode)); 104 | previousValues = getCodeValues(previousCode); 105 | currentValues = getCodeValues(currentCode); 106 | newEntry = new int[previousValues.Length + 1]; 107 | 108 | for (int i = 0; i < previousValues.Length; i++) 109 | { 110 | newEntry[i] = previousValues[i]; 111 | } 112 | newEntry[newEntry.Length - 1] = currentValues[0]; 113 | 114 | addToCodeTable(newEntry); 115 | previousCode = currentCode; 116 | } 117 | else 118 | { 119 | int[] previousValues = getCodeValues(previousCode); 120 | int[] indices = new int[previousValues.Length + 1]; 121 | 122 | for (int i = 0; i < previousValues.Length; i++) 123 | { 124 | indices[i] = previousValues[i]; 125 | } 126 | indices[indices.Length - 1] = previousValues[0]; 127 | 128 | addToCodeTable(indices); 129 | addToColorIndices(indices); 130 | previousCode = currentCode; 131 | } 132 | 133 | iteration++; 134 | 135 | // Infinite loop exit check 136 | if (iteration > 999999) 137 | { 138 | throw new Exception("Too many iterations. Infinite loop."); 139 | } 140 | } 141 | } 142 | 143 | private void addToCodeTable(int[] entry) 144 | { 145 | string indices = ""; 146 | 147 | for (int i = 0; i < entry.Length; i++) 148 | { 149 | indices += entry[i]; 150 | indices += (i < entry.Length - 1) ? ", " : ""; 151 | } 152 | 153 | //Debug.Log("Adding code " + codeTable.Count + " to code table with values: " + indices); 154 | 155 | if (codeTable.Count == (1 << _currentCodeSize) - 1) 156 | { 157 | _currentCodeSize++; 158 | //Debug.Log("Increasing current code size to: " + _currentCodeSize); 159 | 160 | if (_currentCodeSize > 12) 161 | { 162 | throw new NotImplementedException("Code size larger than max (12). Figure out how to handle this."); 163 | } 164 | } 165 | 166 | if (codeTable.Count >= 4096) 167 | { 168 | throw new Exception("Exceeded max number of entries in code table."); 169 | } 170 | 171 | codeTable.Add(codeTable.Count, entry); 172 | } 173 | 174 | private void addToColorIndices(int[] indices) 175 | { 176 | for (int i = 0; i < indices.Length; i++) 177 | { 178 | colorIndices.Add(indices[i]); 179 | } 180 | } 181 | 182 | private bool isMaxCodeValue(int currentCode, int currentCodeSize) 183 | { 184 | return currentCode == (1 << currentCodeSize) - 1; 185 | } 186 | 187 | private void initializeCodeTable() 188 | { 189 | int initialCodeTableSize = (1 << lzwMinimumCodeSize) + 1; 190 | 191 | codeTable.Clear(); 192 | for (int i = 0; i <= initialCodeTableSize; i++) 193 | { 194 | codeTable.Add(i, new int[] { i }); 195 | } 196 | 197 | //Debug.Log("Initialized code table. Highest index: " + (codeTable.Count - 1)); 198 | } 199 | 200 | private int getCode(BitArray bits, int bitOffset, int currentCodeSize) 201 | { 202 | int value = 0; 203 | string debugValue = ""; 204 | 205 | // Max code size check 206 | if (currentCodeSize > 12) 207 | { 208 | throw new ArgumentOutOfRangeException("currentCodeSize", "Max code size is 12"); 209 | } 210 | 211 | // Calculate value 212 | for (int i = 0; i < currentCodeSize; i++) 213 | { 214 | int index = bitOffset + i; 215 | 216 | if (bits[index]) 217 | { 218 | value += (1 << i); 219 | debugValue += "1"; 220 | } 221 | else 222 | { 223 | debugValue += "0"; 224 | } 225 | } 226 | 227 | //Debug.Log("Read code [" + value + "(" + debugValue + ")] at bit offset [" + bitOffset + "] using code size [" + currentCodeSize + "]"); 228 | 229 | return value; 230 | } 231 | 232 | private int[] getCodeValues(int code) 233 | { 234 | if (codeTable.ContainsKey(code)) 235 | { 236 | return codeTable[code]; 237 | } 238 | else 239 | { 240 | throw new Exception("Code " + code + " does not exist. Code table size: " + codeTable.Count + ". Aborting..."); 241 | } 242 | } 243 | 244 | private void prepareColors() 245 | { 246 | GifColor[] colorTable = imageDescriptor.localColorTableFlag ? imageDescriptor.localColorTable : _gifData.globalColorTable; 247 | 248 | foreach (int index in colorIndices) 249 | { 250 | if (!_colors.ContainsKey(index)) 251 | { 252 | _colors.Add(index, colorTable[index]); 253 | } 254 | } 255 | } 256 | 257 | public GifColor getColor(int index) 258 | { 259 | return _colors[index]; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifImageData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 499a257c766539c43aa01cef02d43169 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifImageDescriptor.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System.Collections; 15 | 16 | public class GifImageDescriptor 17 | { 18 | private GifData _gifData; 19 | 20 | public int imageLeft; 21 | public int imageTop; 22 | public int imageWidth; 23 | public int imageHeight; 24 | public bool localColorTableFlag; 25 | public bool interlaceFlag; 26 | public bool sortFlag; 27 | public int localColorTableSize; 28 | public GifGraphicsControlExtension graphicsControlExt; 29 | public GifImageData imageData; 30 | public GifColor[] localColorTable; 31 | 32 | public GifImageDescriptor(GifData gifData) 33 | { 34 | _gifData = gifData; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifImageDescriptor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e0f61453a58d6543b3445a20b189c7b 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifParserScript.cs: -------------------------------------------------------------------------------- 1 | /* Copyright © 2016 Graeme Collins. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 12 | 13 | using UnityEngine; 14 | using System; 15 | using System.Text; 16 | using System.Collections.Generic; 17 | 18 | public class GifParserScript : MonoBehaviour 19 | { 20 | private GifData _gifData; 21 | 22 | public TextAsset gif; 23 | 24 | private GifData parseGifData(byte[] bytes) 25 | { 26 | GifData gifData = new GifData(); 27 | 28 | gifData.header = Encoding.UTF8.GetString(bytes, 0, 6); 29 | gifData.canvasWidth = BitHelper.getInt16FromBytes(bytes, 6); 30 | gifData.canvasHeight = BitHelper.getInt16FromBytes(bytes, 8); 31 | gifData.globalColorTableFlag = BitHelper.getIntFromPackedByte(bytes[10], 0, 1) == 1; 32 | gifData.bitsPerPixel = BitHelper.getIntFromPackedByte(bytes[10], 1, 4) + 1; 33 | gifData.sortFlag = BitHelper.getIntFromPackedByte(bytes[10], 4, 5) == 1; 34 | gifData.globalColorTableSize = BitHelper.getIntFromPackedByte(bytes[10], 5, 8); 35 | gifData.backgroundColorIndex = bytes[11]; 36 | gifData.pixelAspectRatio = bytes[12]; 37 | 38 | if (gifData.globalColorTableFlag) 39 | { 40 | gifData.globalColorTable = readColorTable(bytes, 13, 1 << (gifData.globalColorTableSize + 1)); 41 | } 42 | readBlocks(gifData, bytes); 43 | 44 | return gifData; 45 | } 46 | 47 | private GifColor[] readColorTable(byte[] bytes, int offset, int size) 48 | { 49 | GifColor[] colorTable = new GifColor[size]; 50 | 51 | for (int i = 0; i < size; i++) 52 | { 53 | int startIndex = offset + i * 3; 54 | GifColor color = new GifColor(bytes[startIndex], bytes[startIndex + 1], bytes[startIndex + 2], 1); 55 | 56 | colorTable[i] = color; 57 | } 58 | 59 | return colorTable; 60 | } 61 | 62 | private void readBlocks(GifData gifData, byte[] bytes) 63 | { 64 | int currentOffset = 13; 65 | 66 | while (true) 67 | { 68 | // Stop at last byte 69 | if (currentOffset == bytes.Length - 1) 70 | { 71 | break; 72 | } 73 | 74 | // Search for graphics control extensions 75 | if (bytes[currentOffset] == 0x21 && bytes[currentOffset + 1] == 0xF9 && bytes[currentOffset + 7] == 0x00) 76 | { 77 | GifGraphicsControlExtension graphicsControlExt; 78 | GifImageDescriptor imageDescriptor; 79 | GifImageData imageData; 80 | 81 | // Graphics control extension 82 | graphicsControlExt = readGraphicsControlExtension(gifData, bytes, currentOffset); 83 | gifData.graphicsControlExtensions.Add(graphicsControlExt); 84 | currentOffset += 8; 85 | 86 | // Image descriptor 87 | imageDescriptor = readImageDescriptor(gifData, bytes, currentOffset); 88 | gifData.imageDescriptors.Add(imageDescriptor); 89 | currentOffset += 10; 90 | 91 | // Local color table 92 | if (imageDescriptor.localColorTableFlag) 93 | { 94 | int colorTableSize = 1 << (imageDescriptor.localColorTableSize + 1); 95 | 96 | imageDescriptor.localColorTable = readColorTable(bytes, currentOffset, colorTableSize); 97 | currentOffset += 3 * colorTableSize; 98 | } 99 | 100 | // Image data 101 | imageData = readImageData(gifData, bytes, currentOffset); 102 | gifData.imageDatas.Add(imageData); 103 | 104 | // Connect graphics control extension, image descriptor, and image data 105 | graphicsControlExt.imageData = imageData; 106 | graphicsControlExt.imageDescriptor = imageDescriptor; 107 | imageData.graphicsControlExt = graphicsControlExt; 108 | imageData.imageDescriptor = imageDescriptor; 109 | imageDescriptor.graphicsControlExt = graphicsControlExt; 110 | imageDescriptor.imageData = imageData; 111 | 112 | // Decode image data 113 | imageData.decode(); 114 | 115 | // Advance 116 | currentOffset = imageData.endingOffset; 117 | } 118 | else 119 | { 120 | currentOffset++; 121 | } 122 | } 123 | } 124 | 125 | private GifGraphicsControlExtension readGraphicsControlExtension(GifData gifData, byte[] bytes, int offset) 126 | { 127 | GifGraphicsControlExtension gce = new GifGraphicsControlExtension(gifData); 128 | 129 | gce.disposalMethod = BitHelper.getIntFromPackedByte(bytes[offset + 3], 3, 6); 130 | gce.transparentColorFlag = BitHelper.getIntFromPackedByte(bytes[offset + 3], 7, 8) == 1; 131 | gce.delayTime = BitHelper.getInt16FromBytes(bytes, offset + 4); 132 | gce.transparentColorIndex = bytes[offset + 6]; 133 | 134 | return gce; 135 | } 136 | 137 | private GifImageDescriptor readImageDescriptor(GifData gifData, byte[] bytes, int offset) 138 | { 139 | GifImageDescriptor id = new GifImageDescriptor(gifData); 140 | 141 | id.imageLeft = BitHelper.getInt16FromBytes(bytes, offset + 1); 142 | id.imageTop = BitHelper.getInt16FromBytes(bytes, offset + 3); 143 | id.imageWidth = BitHelper.getInt16FromBytes(bytes, offset + 5); 144 | id.imageHeight = BitHelper.getInt16FromBytes(bytes, offset + 7); 145 | id.localColorTableFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 0, 1) == 1; 146 | id.interlaceFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 1, 2) == 1; 147 | id.sortFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 2, 3) == 1; 148 | id.localColorTableSize = BitHelper.getIntFromPackedByte(bytes[offset + 9], 5, 8); 149 | 150 | // Interlace flag 151 | if (id.interlaceFlag) 152 | { 153 | throw new NotImplementedException("Use of interlace flag not implemented."); 154 | } 155 | 156 | return id; 157 | } 158 | 159 | private GifImageData readImageData(GifData gifData, byte[] bytes, int offset) 160 | { 161 | GifImageData imgData = new GifImageData(gifData); 162 | int subblockOffset = offset + 1; 163 | int subblockCount = 0; 164 | 165 | imgData.lzwMinimumCodeSize = bytes[offset]; 166 | 167 | // Read subblock data 168 | while (true) 169 | { 170 | int subblockSize = bytes[subblockOffset]; 171 | 172 | if (subblockSize == 0) 173 | { 174 | break; 175 | } 176 | else 177 | { 178 | for (int i = 0; i < subblockSize; i++) 179 | { 180 | imgData.blockBytes.Add(bytes[subblockOffset + 1 + i]); 181 | } 182 | 183 | subblockOffset += subblockSize + 1; 184 | subblockCount++; 185 | } 186 | } 187 | imgData.endingOffset = subblockOffset; 188 | 189 | //Debug.Log("Number of subblocks read: " + subblockCount); 190 | 191 | return imgData; 192 | } 193 | 194 | private void createAnimator(GifData gifData) 195 | { 196 | List sprites = new List(); 197 | GifAnimatorScript animatorScript = gameObject.AddComponent(); 198 | Color[] previousFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; 199 | Color[] currentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; 200 | Color[] transparentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; 201 | 202 | // Create sprites 203 | for (int i = 0; i < gifData.graphicsControlExtensions.Count; i++) 204 | { 205 | GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[i]; 206 | GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; 207 | GifImageData imageData = imageDescriptor.imageData; 208 | int top = imageDescriptor.imageTop; 209 | int left = imageDescriptor.imageLeft; 210 | int disposalMethod = graphicsControlExt.disposalMethod; 211 | Texture2D texture = new Texture2D(gifData.canvasWidth, gifData.canvasHeight); 212 | int transparencyIndex = graphicsControlExt.transparentColorFlag ? graphicsControlExt.transparentColorIndex : -1; 213 | 214 | // Determine base pixels 215 | if (i == 0) 216 | { 217 | texture.SetPixels(transparentFrame); 218 | } 219 | else 220 | { 221 | if (disposalMethod == 1) 222 | { 223 | texture.SetPixels(previousFrame); 224 | } 225 | else if (disposalMethod == 2) 226 | { 227 | texture.SetPixels(transparentFrame); 228 | } 229 | else if (disposalMethod == 3) 230 | { 231 | throw new NotImplementedException("Disposal method 3 is not implemented."); 232 | } 233 | } 234 | 235 | // Set pixels from image data 236 | for (int j = 0; j < imageDescriptor.imageWidth; j++) 237 | { 238 | for (int k = 0; k < imageDescriptor.imageHeight; k++) 239 | { 240 | int x = left + j; 241 | int y = (gifData.canvasHeight - 1) - (top + k); 242 | int colorIndex = imageData.colorIndices[j + k * imageDescriptor.imageWidth]; 243 | int pixelOffset = x + y * gifData.canvasWidth; 244 | 245 | if (colorIndex != transparencyIndex) 246 | { 247 | GifColor gifColor = imageData.getColor(colorIndex); 248 | 249 | currentFrame[pixelOffset] = new Color(gifColor.r / 255f, gifColor.g / 255f, gifColor.b / 255f); 250 | } 251 | } 252 | } 253 | 254 | // Set texture pixels and create sprite 255 | texture.SetPixels(currentFrame); 256 | texture.Apply(); 257 | texture.filterMode = FilterMode.Point; 258 | sprites.Add(Sprite.Create(texture, new Rect(0f, 0f, gifData.canvasWidth, gifData.canvasHeight), new Vector2(1f, 1f))); 259 | 260 | // Store current frame as previous before continuing, and reset current frame 261 | currentFrame.CopyTo(previousFrame, 0); 262 | if (disposalMethod == 0 || disposalMethod == 2) 263 | { 264 | currentFrame = new Color[currentFrame.Length]; 265 | } 266 | } 267 | 268 | // Setup animator script 269 | animatorScript.sprites = sprites; 270 | } 271 | 272 | void Start() 273 | { 274 | _gifData = parseGifData(gif.bytes); 275 | 276 | createAnimator(_gifData); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /Assets/GifDecoder/GifParserScript.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2f0c1f5301494c940bcec2464d08d9bd 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | -------------------------------------------------------------------------------- /Assets/gif.bytes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/Assets/gif.bytes -------------------------------------------------------------------------------- /Assets/gif.bytes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f41b82ed8bf6b014a9311a9aa2c7d1c3 3 | TextScriptImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /Assets/scene.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/Assets/scene.unity -------------------------------------------------------------------------------- /Assets/scene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39dc60bc3b47716458e329423a1a0ff0 3 | DefaultImporter: 4 | userData: 5 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshLayers.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/NavMeshLayers.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutch/UnityGifDecoder/0c293494bdec9ef5a213bc81e757ebccf2672953/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnityGifDecoder 2 | Experimental GIF decoder for use in Unity projects. 3 | This is my first attempt at a GIF decoder, so what you see is what you get. 4 | Feel free to post issues if you have questions/suggestions, but keep in mind this project was never used because of performance problems (especially on mobile devices). 5 | 6 | ## License 7 | Copyright © 2016 Graeme Collins. All Rights Reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 14 | 15 | 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY GRAEME COLLINS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | ## References 20 | * "What's in a GIF": http://www.matthewflickinger.com/lab/whatsinagif/ --------------------------------------------------------------------------------