public void XAreaEqualToYAreaAndXLongestDimensionLessThanY()
 {
     Sprite x = new Sprite("X", new Bitmap(15, 20), 0, false);
     Sprite y = new Sprite("Y", new Bitmap(10, 30), 0, false);
     SpriteSizeComparer comparer = new SpriteSizeComparer();
     int expected = -1;
     int actual = comparer.Compare(x, y);
     Assert.AreEqual(expected, actual);
 }
 public void XAreaLessThanYArea()
 {
     Sprite x = new Sprite("X", new Bitmap(10, 20), 0, false);
     Sprite y = new Sprite("Y", new Bitmap(20, 30), 0, false);
     SpriteSizeComparer comparer = new SpriteSizeComparer();
     int expected = -1;
     int actual = comparer.Compare(x, y);
     Assert.AreEqual(expected, actual);
 }
        /// <summary>
        /// Uses all images found in the specified source folder to build a compacted sprite sheet.
        /// Images used maintain their original orientation, but may be cropped to remove transparency
        /// if the <paramref name="cropTransparency"/> parameter is true.
        /// </summary>
        /// <param name="sourceFolder">Folder containing images to use in the sprite sheet.
        /// All images in the folder will be used.</param>
        /// <param name="outputName">Name to use for the sprite sheet output image file and XML definition file.</param>
        /// <param name="cropTransparency">True if transparent pixels should be removed when determining
        /// the source area of the image, or false if not.</param>
        public void BuildSheet(string sourceFolder, string outputName, bool cropTransparency, bool roundUpPower2Size)
        {
            if (!Directory.Exists(sourceFolder))
            {
                throw new ArgumentException(string.Format("Source folder '{0}' does not exist", sourceFolder), "sourceFolder");
            }

            if (string.IsNullOrWhiteSpace(outputName))
            {
                throw new ArgumentNullException("outputName");
            }

            DirectoryInfo dirInfo = new DirectoryInfo(sourceFolder);
            FileInfo[] files = dirInfo.GetFiles("*.png");
            if ((files == null) || (files.Length == 0))
            {
                // Not finding image files means nothing can be built, but this should not
                // be treated as an exception
                return;
            }

            // Replace spaces in the name with underscores to help with compatibility
            // with other tools or across platforms.
            outputName = outputName.Replace(' ', '_');
            string sheetName = Path.Combine(sourceFolder, outputName + ".png");
            string xmlName = Path.Combine(sourceFolder, outputName + ".xml");
            if (File.Exists(sheetName))
            {
                File.Delete(sheetName);
            }
            if (File.Exists(xmlName))
            {
                File.Delete(xmlName);
            }

            // Calculate the total area of all images and find the widest.
            // Then create a list of images, sorted from smallest to largest.
            int totalArea = 0;
            int maxWidth = 0;
            List<Sprite> sprites = new List<Sprite>();
            foreach (FileInfo file in files)
            {
                if (file.FullName != sheetName)
                {
                    Bitmap image = new Bitmap(file.FullName);
                    Sprite sprite = new Sprite(Path.GetFileNameWithoutExtension(file.FullName).Replace(' ', '_'), image, HorizontalPadding, VerticalPadding, cropTransparency);
                    sprites.Add(sprite);

                    totalArea += sprite.Width * sprite.Height;
                    maxWidth = (sprite.Width > maxWidth) ? sprite.Width : maxWidth;
                }
            }
            sprites.Sort(new SpriteSizeComparer());
            sprites.Reverse();

            // Target width of the output sprite sheet is the larger of either the square root
            // of the total area of all images, rounded up, or the width of the widest image.
            int targetWidth = Math.Max((int)Math.Ceiling(Math.Sqrt(totalArea)), maxWidth);
            if (roundUpPower2Size)
            {
                targetWidth = MathHelper.LeastPower2GreaterThanX(targetWidth);
            }
            int remainingWidth = targetWidth;
            int nextX = 0;
            int nextY = 0;
            int maxHeightInRow = 0;
            for (int i = 0; i < sprites.Count; ++i)
            {
                // If the next image being added is wider than the remaining allowed
                // width of the current row of images, start a new row
                if (remainingWidth - sprites[i].Width <= 0)
                {
                    remainingWidth = targetWidth;
                    nextX = 0;
                    nextY += maxHeightInRow;
                    maxHeightInRow = 0;
                }
                sprites[i].SheetPosition = new Point(nextX, nextY);
                remainingWidth -= sprites[i].Width;
                nextX += sprites[i].Width;
                if (sprites[i].Height > maxHeightInRow)
                {
                    maxHeightInRow = sprites[i].Height;
                }
            }
            int targetHeight = nextY + maxHeightInRow;
            if (roundUpPower2Size)
            {
                targetHeight = MathHelper.LeastPower2GreaterThanX(targetHeight);
            }
            Size size = new Size(targetWidth, targetHeight);
            WriteOutput(outputName, sheetName, xmlName, size, sprites);
        }