void BuildPackedImage() { _packedImage = null; _outputPreview.Invalidate(); // Remove any duplicates from the character set. string characterSet = GetCharacterSetUnion(); CharacterInfo[] infos = new CharacterInfo[ characterSet.Length ]; Brush whiteBrush = new SolidBrush( Color.White ); Brush blackBrush = new SolidBrush( Color.Black ); // Get all the bitmap data and extents for the characters. using ( Bitmap tempBitmap = new Bitmap( 512, 512, PixelFormat.Format32bppArgb ) ) { using ( Graphics g = Graphics.FromImage( tempBitmap ) ) { // Initialize it to black to start. g.Clear( Color.Black ); // Initialize each CharacterInfo. for ( int i=0; i < characterSet.Length; i++ ) { CharacterInfo c = new CharacterInfo(); infos[i] = c; c.Character = characterSet[i]; // Draw this character into tempBitmap. _currentFont.DrawString( g, c.Character.ToString(), whiteBrush, new Point( 0, 0 ) ); // Scan to find the extents. Rectangle? startingExtentsNullable = GetMaximumCharacterExtents( g, _currentFont, c.Character ); if ( !startingExtentsNullable.HasValue ) return; // Make sure we're not accessing outside the bitmap itself. If this letter is larger than 512x512, // then we've got bigger problems elsewhere! Rectangle startingExtents = startingExtentsNullable.Value; startingExtents.Width = Math.Min( startingExtents.Width, tempBitmap.Width ); startingExtents.Height = Math.Min( startingExtents.Height, tempBitmap.Height ); Rectangle extents; ExtractImageData( tempBitmap, startingExtents, out c.Image, out extents ); c.XOffset = extents.X; c.YOffset = extents.Y; c.PackedWidth = extents.Width; c.PackedHeight = extents.Height; // Clear out the previous space used by it. g.FillRectangle( blackBrush, new Rectangle( 0, 0, extents.X + extents.Width + 20, extents.Y + extents.Height + 20 ) ); } } } int maxImageDimension = 1024; // Now, pack all the characters in the output. // First, sort by height. CharacterInfo[] sorted = infos.OrderBy( x => -x.PackedHeight ).ToArray(); _finalCharacterSet = sorted; // Now we can write the final index of each character. for ( int i=0; i < _finalCharacterSet.Length; i++ ) _finalCharacterSet[i].SudoFontIndex = i; int atomicPixels = ReadAtomicPixelsControl(); int packedWidth = 16; int packedHeight = 0; while ( packedWidth < maxImageDimension ) { // We started out with a tiny width, so the height was super likely to be larger than the width. // If we finally get it where the width and height are equal, or where width is just one power of // two larger, then we're happy. packedHeight = PackCharacters( sorted, packedWidth, atomicPixels ); if ( NextPowerOfTwo( packedWidth ) >= packedHeight ) break; packedWidth <<= 1; } // Now render the final bitmap. _packedImage = new Bitmap( packedWidth, NextPowerOfTwo( packedHeight ) ); RenderPackedImage( _packedImage, infos, _alphaOnlyControl.Checked ); }