<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pt-BR">
	<id>https://www.tibiawiki.com.br/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AOmggif.js</id>
	<title>MediaWiki:Omggif.js - Histórico de revisão</title>
	<link rel="self" type="application/atom+xml" href="https://www.tibiawiki.com.br/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AOmggif.js"/>
	<link rel="alternate" type="text/html" href="https://www.tibiawiki.com.br/index.php?title=MediaWiki:Omggif.js&amp;action=history"/>
	<updated>2026-04-21T22:16:50Z</updated>
	<subtitle>Histórico de revisões para esta página neste wiki</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://www.tibiawiki.com.br/index.php?title=MediaWiki:Omggif.js&amp;diff=367195&amp;oldid=prev</id>
		<title>Master Player: Criou página com '// (c) Dean McNamee &lt;dean@gmail.com&gt;, 2013. // // https://github.com/deanm/omggif // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this...'</title>
		<link rel="alternate" type="text/html" href="https://www.tibiawiki.com.br/index.php?title=MediaWiki:Omggif.js&amp;diff=367195&amp;oldid=prev"/>
		<updated>2022-08-02T01:11:21Z</updated>

		<summary type="html">&lt;p&gt;Criou página com &amp;#039;// (c) Dean McNamee &amp;lt;dean@gmail.com&amp;gt;, 2013. // // https://github.com/deanm/omggif // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this...&amp;#039;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Página nova&lt;/b&gt;&lt;/p&gt;&lt;div&gt;// (c) Dean McNamee &amp;lt;dean@gmail.com&amp;gt;, 2013.&lt;br /&gt;
//&lt;br /&gt;
// https://github.com/deanm/omggif&lt;br /&gt;
//&lt;br /&gt;
// Permission is hereby granted, free of charge, to any person obtaining a copy&lt;br /&gt;
// of this software and associated documentation files (the &amp;quot;Software&amp;quot;), to&lt;br /&gt;
// deal in the Software without restriction, including without limitation the&lt;br /&gt;
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or&lt;br /&gt;
// sell copies of the Software, and to permit persons to whom the Software is&lt;br /&gt;
// furnished to do so, subject to the following conditions:&lt;br /&gt;
//&lt;br /&gt;
// The above copyright notice and this permission notice shall be included in&lt;br /&gt;
// all copies or substantial portions of the Software.&lt;br /&gt;
//&lt;br /&gt;
// THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&lt;br /&gt;
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&lt;br /&gt;
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&lt;br /&gt;
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&lt;br /&gt;
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING&lt;br /&gt;
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS&lt;br /&gt;
// IN THE SOFTWARE.&lt;br /&gt;
//&lt;br /&gt;
// omggif is a JavaScript implementation of a GIF 89a encoder and decoder,&lt;br /&gt;
// including animation and compression.  It does not rely on any specific&lt;br /&gt;
// underlying system, so should run in the browser, Node, or Plask.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
function GifWriter(buf, width, height, gopts) {&lt;br /&gt;
  var p = 0;&lt;br /&gt;
&lt;br /&gt;
  var gopts = gopts === undefined ? { } : gopts;&lt;br /&gt;
  var loop_count = gopts.loop === undefined ? null : gopts.loop;&lt;br /&gt;
  var global_palette = gopts.palette === undefined ? null : gopts.palette;&lt;br /&gt;
&lt;br /&gt;
  if (width &amp;lt;= 0 || height &amp;lt;= 0 || width &amp;gt; 65535 || height &amp;gt; 65535)&lt;br /&gt;
    throw new Error(&amp;quot;Width/Height invalid.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  function check_palette_and_num_colors(palette) {&lt;br /&gt;
    var num_colors = palette.length;&lt;br /&gt;
    if (num_colors &amp;lt; 2 || num_colors &amp;gt; 256 ||  num_colors &amp;amp; (num_colors-1)) {&lt;br /&gt;
      throw new Error(&lt;br /&gt;
        &amp;quot;Invalid code/color length, must be power of 2 and 2 .. 256.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    return num_colors;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // - Header.&lt;br /&gt;
  buf[p++] = 0x47; buf[p++] = 0x49; buf[p++] = 0x46;  // GIF&lt;br /&gt;
  buf[p++] = 0x38; buf[p++] = 0x39; buf[p++] = 0x61;  // 89a&lt;br /&gt;
&lt;br /&gt;
  // Handling of Global Color Table (palette) and background index.&lt;br /&gt;
  var gp_num_colors_pow2 = 0;&lt;br /&gt;
  var background = 0;&lt;br /&gt;
  if (global_palette !== null) {&lt;br /&gt;
    var gp_num_colors = check_palette_and_num_colors(global_palette);&lt;br /&gt;
    while (gp_num_colors &amp;gt;&amp;gt;= 1) ++gp_num_colors_pow2;&lt;br /&gt;
    gp_num_colors = 1 &amp;lt;&amp;lt; gp_num_colors_pow2;&lt;br /&gt;
    --gp_num_colors_pow2;&lt;br /&gt;
    if (gopts.background !== undefined) {&lt;br /&gt;
      background = gopts.background;&lt;br /&gt;
      if (background &amp;gt;= gp_num_colors)&lt;br /&gt;
        throw new Error(&amp;quot;Background index out of range.&amp;quot;);&lt;br /&gt;
      // The GIF spec states that a background index of 0 should be ignored, so&lt;br /&gt;
      // this is probably a mistake and you really want to set it to another&lt;br /&gt;
      // slot in the palette.  But actually in the end most browsers, etc end&lt;br /&gt;
      // up ignoring this almost completely (including for dispose background).&lt;br /&gt;
      if (background === 0)&lt;br /&gt;
        throw new Error(&amp;quot;Background index explicitly passed as 0.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // - Logical Screen Descriptor.&lt;br /&gt;
  // NOTE(deanm): w/h apparently ignored by implementations, but set anyway.&lt;br /&gt;
  buf[p++] = width &amp;amp; 0xff; buf[p++] = width &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
  buf[p++] = height &amp;amp; 0xff; buf[p++] = height &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
  // NOTE: Indicates 0-bpp original color resolution (unused?).&lt;br /&gt;
  buf[p++] = (global_palette !== null ? 0x80 : 0) |  // Global Color Table Flag.&lt;br /&gt;
    gp_num_colors_pow2;  // NOTE: No sort flag (unused?).&lt;br /&gt;
  buf[p++] = background;  // Background Color Index.&lt;br /&gt;
  buf[p++] = 0;  // Pixel aspect ratio (unused?).&lt;br /&gt;
&lt;br /&gt;
  // - Global Color Table&lt;br /&gt;
  if (global_palette !== null) {&lt;br /&gt;
    for (var i = 0, il = global_palette.length; i &amp;lt; il; ++i) {&lt;br /&gt;
      var rgb = global_palette[i];&lt;br /&gt;
      buf[p++] = rgb &amp;gt;&amp;gt; 16 &amp;amp; 0xff;&lt;br /&gt;
      buf[p++] = rgb &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
      buf[p++] = rgb &amp;amp; 0xff;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (loop_count !== null) {  // Netscape block for looping.&lt;br /&gt;
    if (loop_count &amp;lt; 0 || loop_count &amp;gt; 65535)&lt;br /&gt;
      throw new Error(&amp;quot;Loop count invalid.&amp;quot;);&lt;br /&gt;
    // Extension code, label, and length.&lt;br /&gt;
    buf[p++] = 0x21; buf[p++] = 0xff; buf[p++] = 0x0b;&lt;br /&gt;
    // NETSCAPE2.0&lt;br /&gt;
    buf[p++] = 0x4e; buf[p++] = 0x45; buf[p++] = 0x54; buf[p++] = 0x53;&lt;br /&gt;
    buf[p++] = 0x43; buf[p++] = 0x41; buf[p++] = 0x50; buf[p++] = 0x45;&lt;br /&gt;
    buf[p++] = 0x32; buf[p++] = 0x2e; buf[p++] = 0x30;&lt;br /&gt;
    // Sub-block&lt;br /&gt;
    buf[p++] = 0x03; buf[p++] = 0x01;&lt;br /&gt;
    buf[p++] = loop_count &amp;amp; 0xff; buf[p++] = loop_count &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
    buf[p++] = 0x00;  // Terminator.&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  var ended = false;&lt;br /&gt;
&lt;br /&gt;
  this.addFrame = function(x, y, w, h, indexed_pixels, opts) {&lt;br /&gt;
    if (ended === true) { --p; ended = false; }  // Un-end.&lt;br /&gt;
&lt;br /&gt;
    opts = opts === undefined ? { } : opts;&lt;br /&gt;
&lt;br /&gt;
    // TODO(deanm): Bounds check x, y.  Do they need to be within the virtual&lt;br /&gt;
    // canvas width/height, I imagine?&lt;br /&gt;
    if (x &amp;lt; 0 || y &amp;lt; 0 || x &amp;gt; 65535 || y &amp;gt; 65535)&lt;br /&gt;
      throw new Error(&amp;quot;x/y invalid.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (w &amp;lt;= 0 || h &amp;lt;= 0 || w &amp;gt; 65535 || h &amp;gt; 65535)&lt;br /&gt;
      throw new Error(&amp;quot;Width/Height invalid.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (indexed_pixels.length &amp;lt; w * h)&lt;br /&gt;
      throw new Error(&amp;quot;Not enough pixels for the frame size.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    var using_local_palette = true;&lt;br /&gt;
    var palette = opts.palette;&lt;br /&gt;
    if (palette === undefined || palette === null) {&lt;br /&gt;
      using_local_palette = false;&lt;br /&gt;
      palette = global_palette;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (palette === undefined || palette === null)&lt;br /&gt;
      throw new Error(&amp;quot;Must supply either a local or global palette.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    var num_colors = check_palette_and_num_colors(palette);&lt;br /&gt;
&lt;br /&gt;
    // Compute the min_code_size (power of 2), destroying num_colors.&lt;br /&gt;
    var min_code_size = 0;&lt;br /&gt;
    while (num_colors &amp;gt;&amp;gt;= 1) ++min_code_size;&lt;br /&gt;
    num_colors = 1 &amp;lt;&amp;lt; min_code_size;  // Now we can easily get it back.&lt;br /&gt;
&lt;br /&gt;
    var delay = opts.delay === undefined ? 0 : opts.delay;&lt;br /&gt;
&lt;br /&gt;
    // From the spec:&lt;br /&gt;
    //     0 -   No disposal specified. The decoder is&lt;br /&gt;
    //           not required to take any action.&lt;br /&gt;
    //     1 -   Do not dispose. The graphic is to be left&lt;br /&gt;
    //           in place.&lt;br /&gt;
    //     2 -   Restore to background color. The area used by the&lt;br /&gt;
    //           graphic must be restored to the background color.&lt;br /&gt;
    //     3 -   Restore to previous. The decoder is required to&lt;br /&gt;
    //           restore the area overwritten by the graphic with&lt;br /&gt;
    //           what was there prior to rendering the graphic.&lt;br /&gt;
    //  4-7 -    To be defined.&lt;br /&gt;
    // NOTE(deanm): Dispose background doesn't really work, apparently most&lt;br /&gt;
    // browsers ignore the background palette index and clear to transparency.&lt;br /&gt;
    var disposal = opts.disposal === undefined ? 0 : opts.disposal;&lt;br /&gt;
    if (disposal &amp;lt; 0 || disposal &amp;gt; 3)  // 4-7 is reserved.&lt;br /&gt;
      throw new Error(&amp;quot;Disposal out of range.&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    var use_transparency = false;&lt;br /&gt;
    var transparent_index = 0;&lt;br /&gt;
    if (opts.transparent !== undefined &amp;amp;&amp;amp; opts.transparent !== null) {&lt;br /&gt;
      use_transparency = true;&lt;br /&gt;
      transparent_index = opts.transparent;&lt;br /&gt;
      if (transparent_index &amp;lt; 0 || transparent_index &amp;gt;= num_colors)&lt;br /&gt;
        throw new Error(&amp;quot;Transparent color index.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (disposal !== 0 || use_transparency || delay !== 0) {&lt;br /&gt;
      // - Graphics Control Extension&lt;br /&gt;
      buf[p++] = 0x21; buf[p++] = 0xf9;  // Extension / Label.&lt;br /&gt;
      buf[p++] = 4;  // Byte size.&lt;br /&gt;
&lt;br /&gt;
      buf[p++] = disposal &amp;lt;&amp;lt; 2 | (use_transparency === true ? 1 : 0);&lt;br /&gt;
      buf[p++] = delay &amp;amp; 0xff; buf[p++] = delay &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
      buf[p++] = transparent_index;  // Transparent color index.&lt;br /&gt;
      buf[p++] = 0;  // Block Terminator.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // - Image Descriptor&lt;br /&gt;
    buf[p++] = 0x2c;  // Image Seperator.&lt;br /&gt;
    buf[p++] = x &amp;amp; 0xff; buf[p++] = x &amp;gt;&amp;gt; 8 &amp;amp; 0xff;  // Left.&lt;br /&gt;
    buf[p++] = y &amp;amp; 0xff; buf[p++] = y &amp;gt;&amp;gt; 8 &amp;amp; 0xff;  // Top.&lt;br /&gt;
    buf[p++] = w &amp;amp; 0xff; buf[p++] = w &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
    buf[p++] = h &amp;amp; 0xff; buf[p++] = h &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
    // NOTE: No sort flag (unused?).&lt;br /&gt;
    // TODO(deanm): Support interlace.&lt;br /&gt;
    buf[p++] = using_local_palette === true ? (0x80 | (min_code_size-1)) : 0;&lt;br /&gt;
&lt;br /&gt;
    // - Local Color Table&lt;br /&gt;
    if (using_local_palette === true) {&lt;br /&gt;
      for (var i = 0, il = palette.length; i &amp;lt; il; ++i) {&lt;br /&gt;
        var rgb = palette[i];&lt;br /&gt;
        buf[p++] = rgb &amp;gt;&amp;gt; 16 &amp;amp; 0xff;&lt;br /&gt;
        buf[p++] = rgb &amp;gt;&amp;gt; 8 &amp;amp; 0xff;&lt;br /&gt;
        buf[p++] = rgb &amp;amp; 0xff;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    p = GifWriterOutputLZWCodeStream(&lt;br /&gt;
      buf, p, min_code_size &amp;lt; 2 ? 2 : min_code_size, indexed_pixels);&lt;br /&gt;
&lt;br /&gt;
    return p;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  this.end = function() {&lt;br /&gt;
    if (ended === false) {&lt;br /&gt;
      buf[p++] = 0x3b;  // Trailer.&lt;br /&gt;
      ended = true;&lt;br /&gt;
    }&lt;br /&gt;
    return p;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  this.getOutputBuffer = function() { return buf; };&lt;br /&gt;
  this.setOutputBuffer = function(v) { buf = v; };&lt;br /&gt;
  this.getOutputBufferPosition = function() { return p; };&lt;br /&gt;
  this.setOutputBufferPosition = function(v) { p = v; };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Main compression routine, palette indexes -&amp;gt; LZW code stream.&lt;br /&gt;
// |index_stream| must have at least one entry.&lt;br /&gt;
function GifWriterOutputLZWCodeStream(buf, p, min_code_size, index_stream) {&lt;br /&gt;
  buf[p++] = min_code_size;&lt;br /&gt;
  var cur_subblock = p++;  // Pointing at the length field.&lt;br /&gt;
&lt;br /&gt;
  var clear_code = 1 &amp;lt;&amp;lt; min_code_size;&lt;br /&gt;
  var code_mask = clear_code - 1;&lt;br /&gt;
  var eoi_code = clear_code + 1;&lt;br /&gt;
  var next_code = eoi_code + 1;&lt;br /&gt;
&lt;br /&gt;
  var cur_code_size = min_code_size + 1;  // Number of bits per code.&lt;br /&gt;
  var cur_shift = 0;&lt;br /&gt;
  // We have at most 12-bit codes, so we should have to hold a max of 19&lt;br /&gt;
  // bits here (and then we would write out).&lt;br /&gt;
  var cur = 0;&lt;br /&gt;
&lt;br /&gt;
  function emit_bytes_to_buffer(bit_block_size) {&lt;br /&gt;
    while (cur_shift &amp;gt;= bit_block_size) {&lt;br /&gt;
      buf[p++] = cur &amp;amp; 0xff;&lt;br /&gt;
      cur &amp;gt;&amp;gt;= 8; cur_shift -= 8;&lt;br /&gt;
      if (p === cur_subblock + 256) {  // Finished a subblock.&lt;br /&gt;
        buf[cur_subblock] = 255;&lt;br /&gt;
        cur_subblock = p++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function emit_code(c) {&lt;br /&gt;
    cur |= c &amp;lt;&amp;lt; cur_shift;&lt;br /&gt;
    cur_shift += cur_code_size;&lt;br /&gt;
    emit_bytes_to_buffer(8);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // I am not an expert on the topic, and I don't want to write a thesis.&lt;br /&gt;
  // However, it is good to outline here the basic algorithm and the few data&lt;br /&gt;
  // structures and optimizations here that make this implementation fast.&lt;br /&gt;
  // The basic idea behind LZW is to build a table of previously seen runs&lt;br /&gt;
  // addressed by a short id (herein called output code).  All data is&lt;br /&gt;
  // referenced by a code, which represents one or more values from the&lt;br /&gt;
  // original input stream.  All input bytes can be referenced as the same&lt;br /&gt;
  // value as an output code.  So if you didn't want any compression, you&lt;br /&gt;
  // could more or less just output the original bytes as codes (there are&lt;br /&gt;
  // some details to this, but it is the idea).  In order to achieve&lt;br /&gt;
  // compression, values greater then the input range (codes can be up to&lt;br /&gt;
  // 12-bit while input only 8-bit) represent a sequence of previously seen&lt;br /&gt;
  // inputs.  The decompressor is able to build the same mapping while&lt;br /&gt;
  // decoding, so there is always a shared common knowledge between the&lt;br /&gt;
  // encoding and decoder, which is also important for &amp;quot;timing&amp;quot; aspects like&lt;br /&gt;
  // how to handle variable bit width code encoding.&lt;br /&gt;
  //&lt;br /&gt;
  // One obvious but very important consequence of the table system is there&lt;br /&gt;
  // is always a unique id (at most 12-bits) to map the runs.  'A' might be&lt;br /&gt;
  // 4, then 'AA' might be 10, 'AAA' 11, 'AAAA' 12, etc.  This relationship&lt;br /&gt;
  // can be used for an effecient lookup strategy for the code mapping.  We&lt;br /&gt;
  // need to know if a run has been seen before, and be able to map that run&lt;br /&gt;
  // to the output code.  Since we start with known unique ids (input bytes),&lt;br /&gt;
  // and then from those build more unique ids (table entries), we can&lt;br /&gt;
  // continue this chain (almost like a linked list) to always have small&lt;br /&gt;
  // integer values that represent the current byte chains in the encoder.&lt;br /&gt;
  // This means instead of tracking the input bytes (AAAABCD) to know our&lt;br /&gt;
  // current state, we can track the table entry for AAAABC (it is guaranteed&lt;br /&gt;
  // to exist by the nature of the algorithm) and the next character D.&lt;br /&gt;
  // Therefor the tuple of (table_entry, byte) is guaranteed to also be&lt;br /&gt;
  // unique.  This allows us to create a simple lookup key for mapping input&lt;br /&gt;
  // sequences to codes (table indices) without having to store or search&lt;br /&gt;
  // any of the code sequences.  So if 'AAAA' has a table entry of 12, the&lt;br /&gt;
  // tuple of ('AAAA', K) for any input byte K will be unique, and can be our&lt;br /&gt;
  // key.  This leads to a integer value at most 20-bits, which can always&lt;br /&gt;
  // fit in an SMI value and be used as a fast sparse array / object key.&lt;br /&gt;
&lt;br /&gt;
  // Output code for the current contents of the index buffer.&lt;br /&gt;
  var ib_code = index_stream[0] &amp;amp; code_mask;  // Load first input index.&lt;br /&gt;
  var code_table = { };  // Key'd on our 20-bit &amp;quot;tuple&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
  emit_code(clear_code);  // Spec says first code should be a clear code.&lt;br /&gt;
&lt;br /&gt;
  // First index already loaded, process the rest of the stream.&lt;br /&gt;
  for (var i = 1, il = index_stream.length; i &amp;lt; il; ++i) {&lt;br /&gt;
    var k = index_stream[i] &amp;amp; code_mask;&lt;br /&gt;
    var cur_key = ib_code &amp;lt;&amp;lt; 8 | k;  // (prev, k) unique tuple.&lt;br /&gt;
    var cur_code = code_table[cur_key];  // buffer + k.&lt;br /&gt;
&lt;br /&gt;
    // Check if we have to create a new code table entry.&lt;br /&gt;
    if (cur_code === undefined) {  // We don't have buffer + k.&lt;br /&gt;
      // Emit index buffer (without k).&lt;br /&gt;
      // This is an inline version of emit_code, because this is the core&lt;br /&gt;
      // writing routine of the compressor (and V8 cannot inline emit_code&lt;br /&gt;
      // because it is a closure here in a different context).  Additionally&lt;br /&gt;
      // we can call emit_byte_to_buffer less often, because we can have&lt;br /&gt;
      // 30-bits (from our 31-bit signed SMI), and we know our codes will only&lt;br /&gt;
      // be 12-bits, so can safely have 18-bits there without overflow.&lt;br /&gt;
      // emit_code(ib_code);&lt;br /&gt;
      cur |= ib_code &amp;lt;&amp;lt; cur_shift;&lt;br /&gt;
      cur_shift += cur_code_size;&lt;br /&gt;
      while (cur_shift &amp;gt;= 8) {&lt;br /&gt;
        buf[p++] = cur &amp;amp; 0xff;&lt;br /&gt;
        cur &amp;gt;&amp;gt;= 8; cur_shift -= 8;&lt;br /&gt;
        if (p === cur_subblock + 256) {  // Finished a subblock.&lt;br /&gt;
          buf[cur_subblock] = 255;&lt;br /&gt;
          cur_subblock = p++;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (next_code === 4096) {  // Table full, need a clear.&lt;br /&gt;
        emit_code(clear_code);&lt;br /&gt;
        next_code = eoi_code + 1;&lt;br /&gt;
        cur_code_size = min_code_size + 1;&lt;br /&gt;
        code_table = { };&lt;br /&gt;
      } else {  // Table not full, insert a new entry.&lt;br /&gt;
        // Increase our variable bit code sizes if necessary.  This is a bit&lt;br /&gt;
        // tricky as it is based on &amp;quot;timing&amp;quot; between the encoding and&lt;br /&gt;
        // decoder.  From the encoders perspective this should happen after&lt;br /&gt;
        // we've already emitted the index buffer and are about to create the&lt;br /&gt;
        // first table entry that would overflow our current code bit size.&lt;br /&gt;
        if (next_code &amp;gt;= (1 &amp;lt;&amp;lt; cur_code_size)) ++cur_code_size;&lt;br /&gt;
        code_table[cur_key] = next_code++;  // Insert into code table.&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      ib_code = k;  // Index buffer to single input k.&lt;br /&gt;
    } else {&lt;br /&gt;
      ib_code = cur_code;  // Index buffer to sequence in code table.&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  emit_code(ib_code);  // There will still be something in the index buffer.&lt;br /&gt;
  emit_code(eoi_code);  // End Of Information.&lt;br /&gt;
&lt;br /&gt;
  // Flush / finalize the sub-blocks stream to the buffer.&lt;br /&gt;
  emit_bytes_to_buffer(1);&lt;br /&gt;
&lt;br /&gt;
  // Finish the sub-blocks, writing out any unfinished lengths and&lt;br /&gt;
  // terminating with a sub-block of length 0.  If we have already started&lt;br /&gt;
  // but not yet used a sub-block it can just become the terminator.&lt;br /&gt;
  if (cur_subblock + 1 === p) {  // Started but unused.&lt;br /&gt;
    buf[cur_subblock] = 0;&lt;br /&gt;
  } else {  // Started and used, write length and additional terminator block.&lt;br /&gt;
    buf[cur_subblock] = p - cur_subblock - 1;&lt;br /&gt;
    buf[p++] = 0;&lt;br /&gt;
  }&lt;br /&gt;
  return p;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function GifReader(buf) {&lt;br /&gt;
  var p = 0;&lt;br /&gt;
&lt;br /&gt;
  // - Header (GIF87a or GIF89a).&lt;br /&gt;
  if (buf[p++] !== 0x47 ||            buf[p++] !== 0x49 || buf[p++] !== 0x46 ||&lt;br /&gt;
    buf[p++] !== 0x38 || (buf[p++]+1 &amp;amp; 0xfd) !== 0x38 || buf[p++] !== 0x61) {&lt;br /&gt;
    throw new Error(&amp;quot;Invalid GIF 87a/89a header.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // - Logical Screen Descriptor.&lt;br /&gt;
  var width = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
  var height = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
  var pf0 = buf[p++];  // &amp;lt;Packed Fields&amp;gt;.&lt;br /&gt;
  var global_palette_flag = pf0 &amp;gt;&amp;gt; 7;&lt;br /&gt;
  var num_global_colors_pow2 = pf0 &amp;amp; 0x7;&lt;br /&gt;
  var num_global_colors = 1 &amp;lt;&amp;lt; (num_global_colors_pow2 + 1);&lt;br /&gt;
  var background = buf[p++];&lt;br /&gt;
  buf[p++];  // Pixel aspect ratio (unused?).&lt;br /&gt;
&lt;br /&gt;
  var global_palette_offset = null;&lt;br /&gt;
  var global_palette_size   = null;&lt;br /&gt;
&lt;br /&gt;
  if (global_palette_flag) {&lt;br /&gt;
    global_palette_offset = p;&lt;br /&gt;
    global_palette_size = num_global_colors;&lt;br /&gt;
    p += num_global_colors * 3;  // Seek past palette.&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var no_eof = true;&lt;br /&gt;
&lt;br /&gt;
  var frames = [ ];&lt;br /&gt;
&lt;br /&gt;
  var delay = 0;&lt;br /&gt;
  var transparent_index = null;&lt;br /&gt;
  var disposal = 0;  // 0 - No disposal specified.&lt;br /&gt;
  var loop_count = null;&lt;br /&gt;
&lt;br /&gt;
  this.width = width;&lt;br /&gt;
  this.height = height;&lt;br /&gt;
&lt;br /&gt;
  while (no_eof &amp;amp;&amp;amp; p &amp;lt; buf.length) {&lt;br /&gt;
    switch (buf[p++]) {&lt;br /&gt;
      case 0x21:  // Graphics Control Extension Block&lt;br /&gt;
        switch (buf[p++]) {&lt;br /&gt;
          case 0xff:  // Application specific block&lt;br /&gt;
                      // Try if it's a Netscape block (with animation loop counter).&lt;br /&gt;
            if (buf[p   ] !== 0x0b ||  // 21 FF already read, check block size.&lt;br /&gt;
              // NETSCAPE2.0&lt;br /&gt;
              buf[p+1 ] == 0x4e &amp;amp;&amp;amp; buf[p+2 ] == 0x45 &amp;amp;&amp;amp; buf[p+3 ] == 0x54 &amp;amp;&amp;amp;&lt;br /&gt;
              buf[p+4 ] == 0x53 &amp;amp;&amp;amp; buf[p+5 ] == 0x43 &amp;amp;&amp;amp; buf[p+6 ] == 0x41 &amp;amp;&amp;amp;&lt;br /&gt;
              buf[p+7 ] == 0x50 &amp;amp;&amp;amp; buf[p+8 ] == 0x45 &amp;amp;&amp;amp; buf[p+9 ] == 0x32 &amp;amp;&amp;amp;&lt;br /&gt;
              buf[p+10] == 0x2e &amp;amp;&amp;amp; buf[p+11] == 0x30 &amp;amp;&amp;amp;&lt;br /&gt;
              // Sub-block&lt;br /&gt;
              buf[p+12] == 0x03 &amp;amp;&amp;amp; buf[p+13] == 0x01 &amp;amp;&amp;amp; buf[p+16] == 0) {&lt;br /&gt;
              p += 14;&lt;br /&gt;
              loop_count = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
              p++;  // Skip terminator.&lt;br /&gt;
            } else {  // We don't know what it is, just try to get past it.&lt;br /&gt;
              p += 12;&lt;br /&gt;
              while (true) {  // Seek through subblocks.&lt;br /&gt;
                var block_size = buf[p++];&lt;br /&gt;
                // Bad block size (ex: undefined from an out of bounds read).&lt;br /&gt;
                if (!(block_size &amp;gt;= 0)) throw Error(&amp;quot;Invalid block size&amp;quot;);&lt;br /&gt;
                if (block_size === 0) break;  // 0 size is terminator&lt;br /&gt;
                p += block_size;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
            break;&lt;br /&gt;
&lt;br /&gt;
          case 0xf9:  // Graphics Control Extension&lt;br /&gt;
            if (buf[p++] !== 0x4 || buf[p+4] !== 0)&lt;br /&gt;
              throw new Error(&amp;quot;Invalid graphics extension block.&amp;quot;);&lt;br /&gt;
            var pf1 = buf[p++];&lt;br /&gt;
            delay = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
            transparent_index = buf[p++];&lt;br /&gt;
            if ((pf1 &amp;amp; 1) === 0) transparent_index = null;&lt;br /&gt;
            disposal = pf1 &amp;gt;&amp;gt; 2 &amp;amp; 0x7;&lt;br /&gt;
            p++;  // Skip terminator.&lt;br /&gt;
            break;&lt;br /&gt;
&lt;br /&gt;
          // Plain Text Extension could be present and we just want to be able&lt;br /&gt;
          // to parse past it.  It follows the block structure of the comment&lt;br /&gt;
          // extension enough to reuse the path to skip through the blocks.&lt;br /&gt;
          case 0x01:  // Plain Text Extension (fallthrough to Comment Extension)&lt;br /&gt;
          case 0xfe:  // Comment Extension.&lt;br /&gt;
            while (true) {  // Seek through subblocks.&lt;br /&gt;
              var block_size = buf[p++];&lt;br /&gt;
              // Bad block size (ex: undefined from an out of bounds read).&lt;br /&gt;
              if (!(block_size &amp;gt;= 0)) throw Error(&amp;quot;Invalid block size&amp;quot;);&lt;br /&gt;
              if (block_size === 0) break;  // 0 size is terminator&lt;br /&gt;
              // console.log(buf.slice(p, p+block_size).toString('ascii'));&lt;br /&gt;
              p += block_size;&lt;br /&gt;
            }&lt;br /&gt;
            break;&lt;br /&gt;
&lt;br /&gt;
          default:&lt;br /&gt;
            throw new Error(&lt;br /&gt;
              &amp;quot;Unknown graphic control label: 0x&amp;quot; + buf[p-1].toString(16));&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case 0x2c:  // Image Descriptor.&lt;br /&gt;
        var x = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
        var y = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
        var w = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
        var h = buf[p++] | buf[p++] &amp;lt;&amp;lt; 8;&lt;br /&gt;
        var pf2 = buf[p++];&lt;br /&gt;
        var local_palette_flag = pf2 &amp;gt;&amp;gt; 7;&lt;br /&gt;
        var interlace_flag = pf2 &amp;gt;&amp;gt; 6 &amp;amp; 1;&lt;br /&gt;
        var num_local_colors_pow2 = pf2 &amp;amp; 0x7;&lt;br /&gt;
        var num_local_colors = 1 &amp;lt;&amp;lt; (num_local_colors_pow2 + 1);&lt;br /&gt;
        var palette_offset = global_palette_offset;&lt;br /&gt;
        var palette_size = global_palette_size;&lt;br /&gt;
        var has_local_palette = false;&lt;br /&gt;
        if (local_palette_flag) {&lt;br /&gt;
          var has_local_palette = true;&lt;br /&gt;
          palette_offset = p;  // Override with local palette.&lt;br /&gt;
          palette_size = num_local_colors;&lt;br /&gt;
          p += num_local_colors * 3;  // Seek past palette.&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var data_offset = p;&lt;br /&gt;
&lt;br /&gt;
        p++;  // codesize&lt;br /&gt;
        while (true) {&lt;br /&gt;
          var block_size = buf[p++];&lt;br /&gt;
          // Bad block size (ex: undefined from an out of bounds read).&lt;br /&gt;
          if (!(block_size &amp;gt;= 0)) throw Error(&amp;quot;Invalid block size&amp;quot;);&lt;br /&gt;
          if (block_size === 0) break;  // 0 size is terminator&lt;br /&gt;
          p += block_size;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        frames.push({x: x, y: y, width: w, height: h,&lt;br /&gt;
          has_local_palette: has_local_palette,&lt;br /&gt;
          palette_offset: palette_offset,&lt;br /&gt;
          palette_size: palette_size,&lt;br /&gt;
          data_offset: data_offset,&lt;br /&gt;
          data_length: p - data_offset,&lt;br /&gt;
          transparent_index: transparent_index,&lt;br /&gt;
          interlaced: !!interlace_flag,&lt;br /&gt;
          delay: delay,&lt;br /&gt;
          disposal: disposal});&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case 0x3b:  // Trailer Marker (end of file).&lt;br /&gt;
        no_eof = false;&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      default:&lt;br /&gt;
        throw new Error(&amp;quot;Unknown gif block: 0x&amp;quot; + buf[p-1].toString(16));&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  this.numFrames = function() {&lt;br /&gt;
    return frames.length;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  this.loopCount = function() {&lt;br /&gt;
    return loop_count;&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  this.frameInfo = function(frame_num) {&lt;br /&gt;
    if (frame_num &amp;lt; 0 || frame_num &amp;gt;= frames.length)&lt;br /&gt;
      throw new Error(&amp;quot;Frame index out of range.&amp;quot;);&lt;br /&gt;
    return frames[frame_num];&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  this.decodeAndBlitFrameBGRA = function(frame_num, pixels) {&lt;br /&gt;
    var frame = this.frameInfo(frame_num);&lt;br /&gt;
    var num_pixels = frame.width * frame.height;&lt;br /&gt;
    var index_stream = new Uint8Array(num_pixels);  // At most 8-bit indices.&lt;br /&gt;
    GifReaderLZWOutputIndexStream(&lt;br /&gt;
      buf, frame.data_offset, index_stream, num_pixels);&lt;br /&gt;
    var palette_offset = frame.palette_offset;&lt;br /&gt;
&lt;br /&gt;
    // NOTE(deanm): It seems to be much faster to compare index to 256 than&lt;br /&gt;
    // to === null.  Not sure why, but CompareStub_EQ_STRICT shows up high in&lt;br /&gt;
    // the profile, not sure if it's related to using a Uint8Array.&lt;br /&gt;
    var trans = frame.transparent_index;&lt;br /&gt;
    if (trans === null) trans = 256;&lt;br /&gt;
&lt;br /&gt;
    // We are possibly just blitting to a portion of the entire frame.&lt;br /&gt;
    // That is a subrect within the framerect, so the additional pixels&lt;br /&gt;
    // must be skipped over after we finished a scanline.&lt;br /&gt;
    var framewidth  = frame.width;&lt;br /&gt;
    var framestride = width - framewidth;&lt;br /&gt;
    var xleft       = framewidth;  // Number of subrect pixels left in scanline.&lt;br /&gt;
&lt;br /&gt;
    // Output index of the top left corner of the subrect.&lt;br /&gt;
    var opbeg = ((frame.y * width) + frame.x) * 4;&lt;br /&gt;
    // Output index of what would be the left edge of the subrect, one row&lt;br /&gt;
    // below it, i.e. the index at which an interlace pass should wrap.&lt;br /&gt;
    var opend = ((frame.y + frame.height) * width + frame.x) * 4;&lt;br /&gt;
    var op    = opbeg;&lt;br /&gt;
&lt;br /&gt;
    var scanstride = framestride * 4;&lt;br /&gt;
&lt;br /&gt;
    // Use scanstride to skip past the rows when interlacing.  This is skipping&lt;br /&gt;
    // 7 rows for the first two passes, then 3 then 1.&lt;br /&gt;
    if (frame.interlaced === true) {&lt;br /&gt;
      scanstride += width * 4 * 7;  // Pass 1.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var interlaceskip = 8;  // Tracking the row interval in the current pass.&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0, il = index_stream.length; i &amp;lt; il; ++i) {&lt;br /&gt;
      var index = index_stream[i];&lt;br /&gt;
&lt;br /&gt;
      if (xleft === 0) {  // Beginning of new scan line&lt;br /&gt;
        op += scanstride;&lt;br /&gt;
        xleft = framewidth;&lt;br /&gt;
        if (op &amp;gt;= opend) { // Catch the wrap to switch passes when interlacing.&lt;br /&gt;
          scanstride = framestride * 4 + width * 4 * (interlaceskip-1);&lt;br /&gt;
          // interlaceskip / 2 * 4 is interlaceskip &amp;lt;&amp;lt; 1.&lt;br /&gt;
          op = opbeg + (framewidth + framestride) * (interlaceskip &amp;lt;&amp;lt; 1);&lt;br /&gt;
          interlaceskip &amp;gt;&amp;gt;= 1;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (index === trans) {&lt;br /&gt;
        op += 4;&lt;br /&gt;
      } else {&lt;br /&gt;
        var r = buf[palette_offset + index * 3];&lt;br /&gt;
        var g = buf[palette_offset + index * 3 + 1];&lt;br /&gt;
        var b = buf[palette_offset + index * 3 + 2];&lt;br /&gt;
        pixels[op++] = b;&lt;br /&gt;
        pixels[op++] = g;&lt;br /&gt;
        pixels[op++] = r;&lt;br /&gt;
        pixels[op++] = 255;&lt;br /&gt;
      }&lt;br /&gt;
      --xleft;&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // I will go to copy and paste hell one day...&lt;br /&gt;
  this.decodeAndBlitFrameRGBA = function(frame_num, pixels) {&lt;br /&gt;
    var frame = this.frameInfo(frame_num);&lt;br /&gt;
    var num_pixels = frame.width * frame.height;&lt;br /&gt;
    var index_stream = new Uint8Array(num_pixels);  // At most 8-bit indices.&lt;br /&gt;
    GifReaderLZWOutputIndexStream(&lt;br /&gt;
      buf, frame.data_offset, index_stream, num_pixels);&lt;br /&gt;
    var palette_offset = frame.palette_offset;&lt;br /&gt;
&lt;br /&gt;
    // NOTE(deanm): It seems to be much faster to compare index to 256 than&lt;br /&gt;
    // to === null.  Not sure why, but CompareStub_EQ_STRICT shows up high in&lt;br /&gt;
    // the profile, not sure if it's related to using a Uint8Array.&lt;br /&gt;
    var trans = frame.transparent_index;&lt;br /&gt;
    if (trans === null) trans = 256;&lt;br /&gt;
&lt;br /&gt;
    // We are possibly just blitting to a portion of the entire frame.&lt;br /&gt;
    // That is a subrect within the framerect, so the additional pixels&lt;br /&gt;
    // must be skipped over after we finished a scanline.&lt;br /&gt;
    var framewidth  = frame.width;&lt;br /&gt;
    var framestride = width - framewidth;&lt;br /&gt;
    var xleft       = framewidth;  // Number of subrect pixels left in scanline.&lt;br /&gt;
&lt;br /&gt;
    // Output index of the top left corner of the subrect.&lt;br /&gt;
    var opbeg = ((frame.y * width) + frame.x) * 4;&lt;br /&gt;
    // Output index of what would be the left edge of the subrect, one row&lt;br /&gt;
    // below it, i.e. the index at which an interlace pass should wrap.&lt;br /&gt;
    var opend = ((frame.y + frame.height) * width + frame.x) * 4;&lt;br /&gt;
    var op    = opbeg;&lt;br /&gt;
&lt;br /&gt;
    var scanstride = framestride * 4;&lt;br /&gt;
&lt;br /&gt;
    // Use scanstride to skip past the rows when interlacing.  This is skipping&lt;br /&gt;
    // 7 rows for the first two passes, then 3 then 1.&lt;br /&gt;
    if (frame.interlaced === true) {&lt;br /&gt;
      scanstride += width * 4 * 7;  // Pass 1.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var interlaceskip = 8;  // Tracking the row interval in the current pass.&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0, il = index_stream.length; i &amp;lt; il; ++i) {&lt;br /&gt;
      var index = index_stream[i];&lt;br /&gt;
&lt;br /&gt;
      if (xleft === 0) {  // Beginning of new scan line&lt;br /&gt;
        op += scanstride;&lt;br /&gt;
        xleft = framewidth;&lt;br /&gt;
        if (op &amp;gt;= opend) { // Catch the wrap to switch passes when interlacing.&lt;br /&gt;
          scanstride = framestride * 4 + width * 4 * (interlaceskip-1);&lt;br /&gt;
          // interlaceskip / 2 * 4 is interlaceskip &amp;lt;&amp;lt; 1.&lt;br /&gt;
          op = opbeg + (framewidth + framestride) * (interlaceskip &amp;lt;&amp;lt; 1);&lt;br /&gt;
          interlaceskip &amp;gt;&amp;gt;= 1;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (index === trans) {&lt;br /&gt;
        op += 4;&lt;br /&gt;
      } else {&lt;br /&gt;
        var r = buf[palette_offset + index * 3];&lt;br /&gt;
        var g = buf[palette_offset + index * 3 + 1];&lt;br /&gt;
        var b = buf[palette_offset + index * 3 + 2];&lt;br /&gt;
        pixels[op++] = r;&lt;br /&gt;
        pixels[op++] = g;&lt;br /&gt;
        pixels[op++] = b;&lt;br /&gt;
        pixels[op++] = 255;&lt;br /&gt;
      }&lt;br /&gt;
      --xleft;&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function GifReaderLZWOutputIndexStream(code_stream, p, output, output_length) {&lt;br /&gt;
  var min_code_size = code_stream[p++];&lt;br /&gt;
&lt;br /&gt;
  var clear_code = 1 &amp;lt;&amp;lt; min_code_size;&lt;br /&gt;
  var eoi_code = clear_code + 1;&lt;br /&gt;
  var next_code = eoi_code + 1;&lt;br /&gt;
&lt;br /&gt;
  var cur_code_size = min_code_size + 1;  // Number of bits per code.&lt;br /&gt;
  // NOTE: This shares the same name as the encoder, but has a different&lt;br /&gt;
  // meaning here.  Here this masks each code coming from the code stream.&lt;br /&gt;
  var code_mask = (1 &amp;lt;&amp;lt; cur_code_size) - 1;&lt;br /&gt;
  var cur_shift = 0;&lt;br /&gt;
  var cur = 0;&lt;br /&gt;
&lt;br /&gt;
  var op = 0;  // Output pointer.&lt;br /&gt;
&lt;br /&gt;
  var subblock_size = code_stream[p++];&lt;br /&gt;
&lt;br /&gt;
  // TODO(deanm): Would using a TypedArray be any faster?  At least it would&lt;br /&gt;
  // solve the fast mode / backing store uncertainty.&lt;br /&gt;
  // var code_table = Array(4096);&lt;br /&gt;
  var code_table = new Int32Array(4096);  // Can be signed, we only use 20 bits.&lt;br /&gt;
&lt;br /&gt;
  var prev_code = null;  // Track code-1.&lt;br /&gt;
&lt;br /&gt;
  while (true) {&lt;br /&gt;
    // Read up to two bytes, making sure we always 12-bits for max sized code.&lt;br /&gt;
    while (cur_shift &amp;lt; 16) {&lt;br /&gt;
      if (subblock_size === 0) break;  // No more data to be read.&lt;br /&gt;
&lt;br /&gt;
      cur |= code_stream[p++] &amp;lt;&amp;lt; cur_shift;&lt;br /&gt;
      cur_shift += 8;&lt;br /&gt;
&lt;br /&gt;
      if (subblock_size === 1) {  // Never let it get to 0 to hold logic above.&lt;br /&gt;
        subblock_size = code_stream[p++];  // Next subblock.&lt;br /&gt;
      } else {&lt;br /&gt;
        --subblock_size;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // TODO(deanm): We should never really get here, we should have received&lt;br /&gt;
    // and EOI.&lt;br /&gt;
    if (cur_shift &amp;lt; cur_code_size)&lt;br /&gt;
      break;&lt;br /&gt;
&lt;br /&gt;
    var code = cur &amp;amp; code_mask;&lt;br /&gt;
    cur &amp;gt;&amp;gt;= cur_code_size;&lt;br /&gt;
    cur_shift -= cur_code_size;&lt;br /&gt;
&lt;br /&gt;
    // TODO(deanm): Maybe should check that the first code was a clear code,&lt;br /&gt;
    // at least this is what you're supposed to do.  But actually our encoder&lt;br /&gt;
    // now doesn't emit a clear code first anyway.&lt;br /&gt;
    if (code === clear_code) {&lt;br /&gt;
      // We don't actually have to clear the table.  This could be a good idea&lt;br /&gt;
      // for greater error checking, but we don't really do any anyway.  We&lt;br /&gt;
      // will just track it with next_code and overwrite old entries.&lt;br /&gt;
&lt;br /&gt;
      next_code = eoi_code + 1;&lt;br /&gt;
      cur_code_size = min_code_size + 1;&lt;br /&gt;
      code_mask = (1 &amp;lt;&amp;lt; cur_code_size) - 1;&lt;br /&gt;
&lt;br /&gt;
      // Don't update prev_code ?&lt;br /&gt;
      prev_code = null;&lt;br /&gt;
      continue;&lt;br /&gt;
    } else if (code === eoi_code) {&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // We have a similar situation as the decoder, where we want to store&lt;br /&gt;
    // variable length entries (code table entries), but we want to do in a&lt;br /&gt;
    // faster manner than an array of arrays.  The code below stores sort of a&lt;br /&gt;
    // linked list within the code table, and then &amp;quot;chases&amp;quot; through it to&lt;br /&gt;
    // construct the dictionary entries.  When a new entry is created, just the&lt;br /&gt;
    // last byte is stored, and the rest (prefix) of the entry is only&lt;br /&gt;
    // referenced by its table entry.  Then the code chases through the&lt;br /&gt;
    // prefixes until it reaches a single byte code.  We have to chase twice,&lt;br /&gt;
    // first to compute the length, and then to actually copy the data to the&lt;br /&gt;
    // output (backwards, since we know the length).  The alternative would be&lt;br /&gt;
    // storing something in an intermediate stack, but that doesn't make any&lt;br /&gt;
    // more sense.  I implemented an approach where it also stored the length&lt;br /&gt;
    // in the code table, although it's a bit tricky because you run out of&lt;br /&gt;
    // bits (12 + 12 + 8), but I didn't measure much improvements (the table&lt;br /&gt;
    // entries are generally not the long).  Even when I created benchmarks for&lt;br /&gt;
    // very long table entries the complexity did not seem worth it.&lt;br /&gt;
    // The code table stores the prefix entry in 12 bits and then the suffix&lt;br /&gt;
    // byte in 8 bits, so each entry is 20 bits.&lt;br /&gt;
&lt;br /&gt;
    var chase_code = code &amp;lt; next_code ? code : prev_code;&lt;br /&gt;
&lt;br /&gt;
    // Chase what we will output, either {CODE} or {CODE-1}.&lt;br /&gt;
    var chase_length = 0;&lt;br /&gt;
    var chase = chase_code;&lt;br /&gt;
    while (chase &amp;gt; clear_code) {&lt;br /&gt;
      chase = code_table[chase] &amp;gt;&amp;gt; 8;&lt;br /&gt;
      ++chase_length;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var k = chase;&lt;br /&gt;
&lt;br /&gt;
    var op_end = op + chase_length + (chase_code !== code ? 1 : 0);&lt;br /&gt;
    if (op_end &amp;gt; output_length) {&lt;br /&gt;
      console.log(&amp;quot;Warning, gif stream longer than expected.&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Already have the first byte from the chase, might as well write it fast.&lt;br /&gt;
    output[op++] = k;&lt;br /&gt;
&lt;br /&gt;
    op += chase_length;&lt;br /&gt;
    var b = op;  // Track pointer, writing backwards.&lt;br /&gt;
&lt;br /&gt;
    if (chase_code !== code)  // The case of emitting {CODE-1} + k.&lt;br /&gt;
      output[op++] = k;&lt;br /&gt;
&lt;br /&gt;
    chase = chase_code;&lt;br /&gt;
    while (chase_length--) {&lt;br /&gt;
      chase = code_table[chase];&lt;br /&gt;
      output[--b] = chase &amp;amp; 0xff;  // Write backwards.&lt;br /&gt;
      chase &amp;gt;&amp;gt;= 8;  // Pull down to the prefix code.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (prev_code !== null &amp;amp;&amp;amp; next_code &amp;lt; 4096) {&lt;br /&gt;
      code_table[next_code++] = prev_code &amp;lt;&amp;lt; 8 | k;&lt;br /&gt;
      // TODO(deanm): Figure out this clearing vs code growth logic better.  I&lt;br /&gt;
      // have an feeling that it should just happen somewhere else, for now it&lt;br /&gt;
      // is awkward between when we grow past the max and then hit a clear code.&lt;br /&gt;
      // For now just check if we hit the max 12-bits (then a clear code should&lt;br /&gt;
      // follow, also of course encoded in 12-bits).&lt;br /&gt;
      if (next_code &amp;gt;= code_mask+1 &amp;amp;&amp;amp; cur_code_size &amp;lt; 12) {&lt;br /&gt;
        ++cur_code_size;&lt;br /&gt;
        code_mask = code_mask &amp;lt;&amp;lt; 1 | 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    prev_code = code;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (op !== output_length) {&lt;br /&gt;
    console.log(&amp;quot;Warning, gif stream shorter than expected.&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return output;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// CommonJS.&lt;br /&gt;
try { exports.GifWriter = GifWriter; exports.GifReader = GifReader } catch(e) {}&lt;/div&gt;</summary>
		<author><name>Master Player</name></author>
	</entry>
</feed>