Example #1
0
		/// <summary>
        /// Analyzes image colors and creates color map.
		/// </summary>
		private void AnalyzePixels() 
		{
            if (this.firstFrame)
            {
                // HEY YOU - THIS IS IMPORTANT!
                //
                // Unlike the code this project is built on, we generate a palette only once, using the data from the
                // first frame. This speeds up encoding (building the palette is slow) and makes it so that subsequent
                // frames use the same colors and look more consistent from frame to frame, but has an undesirable
                // side-effect of getting confused when radically different colors show up in later frames. This wasn't
                // a problem with Infinifactory, but if your game uses a deliberately reduced color palette you might
                // want to switch back to using per-frame palettes. 
                //
                // This is, of course, left as an exercise for the reader.

                // initialize quantizer and create reduced palette
                this.nq = new NeuQuant(this.pixels, this.pixels.Length, this.sample);
                this.colorTab = nq.Process();
                
                // create the buffer for the displayed pixel data:
                this.visiblePixels = new byte[this.pixels.Length];
            }

			int nPix = this.pixels.Length / 3;
			this.indexedPixels = new byte[nPix];
			// map image pixels to new palette
			for (int i = 0; i < nPix; i++) 
			{
                int r = i * 3 + 0;
                int g = r + 1;
                int b = g + 1;
                
                // HEY YOU - THIS IS IMPORTANT!
                //
                // As you may know, animated GIFs aren't exactly the most efficient way to encode video; notably,
                // they lack the interframe compression found in real video formats. However, we can do something
                // similar by taking advantage of the GIF format's ability to "build on" a previous frame by
                // specifying pixels as transparent and allowing the previous frame's image to show through in those
                // locations. If a pixel doesn't change much from a previous pixel it will be replaced with the
                // transparent color, and if enough of those pixels are used in a frame it will compress much better
                // than if you had all the original color data for the frame. 
                // 
                // In a game like Infinifactory, where the recording camera is locked and only a small portion of
                // the scene is animated, this reduced the size of GIFs to about 1/3 of their original size.

                const int ChangeDelta = 3;
                bool pixelRequired = this.firstFrame ||
                    Math.Abs(this.pixels[r] - this.visiblePixels[r]) > ChangeDelta ||
                    Math.Abs(this.pixels[g] - this.visiblePixels[g]) > ChangeDelta ||
                    Math.Abs(this.pixels[b] - this.visiblePixels[b]) > ChangeDelta;

                int index;
                if (pixelRequired)
                {
                    this.visiblePixels[r] = this.pixels[r];
                    this.visiblePixels[g] = this.pixels[g];
                    this.visiblePixels[b] = this.pixels[b];
                    index = this.nq.Map(this.pixels[r], this.pixels[g], this.pixels[b]);
                }
                else
                {
                    index = NeuQuant.PaletteSize;
                }

                this.usedEntry[index] = true;
                this.indexedPixels[i] = (byte)index;
			}
            this.colorDepth = (int)Math.Log(NeuQuant.PaletteSize + 1, 2);
            this.palSize = this.colorDepth - 1;
		}
Example #2
0
 /**
  * Analyzes image colors and creates color map.
  */
 protected void AnalyzePixels()
 {
     int len = pixels.Length;
     int nPix = len / 3;
     indexedPixels = new byte[nPix];
     NeuQuant nq = new NeuQuant(pixels, len, sample);
     // initialize quantizer
     colorTab = nq.Process(); // create reduced palette
     // convert map from BGR to RGB
     //			for (int i = 0; i < colorTab.Length; i += 3)
     //			{
     //				byte temp = colorTab[i];
     //				colorTab[i] = colorTab[i + 2];
     //				colorTab[i + 2] = temp;
     //				usedEntry[i / 3] = false;
     //			}
     // map image pixels to new palette
     int k = 0;
     for (int i = 0; i < nPix; i++)
     {
         int index =
             nq.Map(pixels[k++] & 0xff,
             pixels[k++] & 0xff,
             pixels[k++] & 0xff);
         usedEntry[index] = true;
         indexedPixels[i] = (byte) index;
     }
     pixels = null;
     colorDepth = 8;
     palSize = 7;
     // get closest match to transparent color if specified
     if (transparent != Color.Empty )
     {
         transIndex = FindClosest(transparent);
     }
 }