/// <summary>
        /// Packs a collection of images into a single image.
        /// </summary>
        /// <param name="imageFiles">The list of Textures of the images to be combined.</param>
        /// <param name="requirePowerOfTwo">Whether or not the output image must have a power of two size.</param>
        /// <param name="requireSquareImage">Whether or not the output image must be a square.</param>
        /// <param name="fastImagePacker">Accept the first successfull image packing.</param>
        /// <param name="TextureWidth">The maximum width of the output image.</param>
        /// <param name="TextureHeight">The maximum height of the output image.</param>
        /// <param name="imagePadding">The amount of blank space to insert in between individual images.</param>
        /// <param name="generateMap">Whether or not to generate the map dictionary.</param>
        /// <param name="outputImage">The resulting output image.</param>
        /// <param name="outputMap">The resulting output map of placement rectangles for the images.</param>
        /// <returns>0 if the packing was successful, error code otherwise.</returns>
        public int PackImage(
            IEnumerable <Texture> imageFiles,
            Atlas.State requirePowerOfTwo,
            Atlas.State requireSquareImage,
            bool fastImagePacker,
            int TextureWidth,
            int TextureHeight,
            int imagePadding,
            bool generateMap,
            out Bitmap outputImage,
            out Dictionary <string, Rectangle> outputMap)
        {
            outputImage = null;
            outputMap   = null;

            List <Texture> files = new List <Texture>();

            // make sure our dictionaries are cleared before starting
            imageSizes.Clear();
            imagePlacement.Clear();

            int  NewHeight;
            bool isTrimAtlas = false;

            // int Result = 0;

            // Rect[] TakePlace = new Rect[imageFiles.Count()];
            // TakePlace = new Rectangle[imageFiles.Count()];
            // TakePlace = new TakePlace[imageFiles.Count()];
            TakePlace = new Texture[imageFiles.Count()];


            ArrayImage = imageFiles.ToArray();
            try
            {
                TakePlace[0] = ArrayImage[0];
                // outputMap.Add(ArrayImage[0].name, Rectangle.FromLTRB(ArrayImage[0].x, ArrayImage[0].y, ArrayImage[0].width + ArrayImage[0].x, ArrayImage[0].height + ArrayImage[0].y));
                // TakePlace[0].Rect = Rectangle.FromLTRB(ArrayImage[0].x, ArrayImage[0].y, ArrayImage[0].width + ArrayImage[0].x, ArrayImage[0].height + ArrayImage[0].y);
                // TakePlace[0].Name = ArrayImage[0].name;
                // TakePlace[0].AtlasImage = ArrayImage[0].AtlasImage;
                // TakePlace[0] = new Rect(ArrayImage[0].x, ArrayImage[0].y, ArrayImage[0].width + ArrayImage[0].x, ArrayImage[0].height + ArrayImage[0].y);
                len = 1;
                for (I = 1; I < ArrayImage.Count(); I++)
                {
                    J        = 0;
                    CurrentY = TextureHeight;
                    FindFreePlace(TextureWidth, TextureHeight);
                    if (ArrayImage[I].height > TextureHeight)
                    {
                        Logging.Manager("ImpossiblePlace");
                        return((int)FailCode.FailedToPackImage);
                    }
                    J = len - 1;
                    while ((J >= 0) && (TakePlace[J].Rect.Bottom > ArrayImage[I].y + ArrayImage[I].height))
                    {
                        J--;
                    }
                    K = J;
                    while ((K >= 0) && (TakePlace[K].Rect.Bottom == ArrayImage[I].y + ArrayImage[I].height))
                    {
                        if ((ArrayImage[I].x == TakePlace[K].Rect.Right + 1) && (ArrayImage[I].y == TakePlace[K].Rect.Top))
                        {
                            // TakePlace[K].Right = ArrayImage[I].rX;
                            TakePlace[K].Rect.X = ArrayImage[I].x;
                            len--;
                            K = -1;
                            J = -10;
                        }
                        else
                        {
                            K--;
                        }
                    }
                    if (J != -10)
                    {
                        J++;
                        for (K = len; len > J; K--)         //     ?????? ggf. J + 1 ???
                        {
                            TakePlace[K] = TakePlace[K - 1];
                        }
                        TakePlace[J] = ArrayImage[I];
                        // TakePlace[J] = ArrayImage[I].Rct;
                        // TakePlace[J].Rect = Rectangle.FromLTRB(ArrayImage[I].x, ArrayImage[I].y, ArrayImage[I].width + ArrayImage[I].x, ArrayImage[I].height + ArrayImage[I].y);
                        // TakePlace[J].Name = ArrayImage[I].name;
                        // TakePlace[J].AtlasImage = ArrayImage[I].AtlasImage;
                    }
                    len++;
                }
                if (isTrimAtlas)
                {
                    NewHeight = 0;
                    for (I = 0; I < len; I++)
                    {
                        if (NewHeight < TakePlace[I].Rect.Bottom)
                        {
                            NewHeight = TakePlace[I].Rect.Bottom;
                        }
                    }
                    if (NewHeight > 0)
                    {
                        // https://stackoverflow.com/questions/5383050/how-can-i-calculate-divide-and-modulo-for-integers
                        // if (NewHeight mod 4 == 0)
                        if (NewHeight % 4 == 0)
                        {
                            TextureHeight = NewHeight;
                        }
                        else
                        {
                            // TextureHeight = (NewHeight div 4 + 1) * 4;
                            TextureHeight = (NewHeight / 4 + 1) * 4;
                        }
                    }
                }
                // Result = len;
            }
            catch (Exception ex)
            {
                Utils.ExceptionLog("ImagePackerV2", "PackImage", ex);
            }

            // List<Texture> files = null;
            foreach (var iF in TakePlace)
            {
                imagePlacement.Add(iF, iF.Rect);
                files.Add(iF);
            }
            // List<Texture> files = new List<Texture>(imageFiles);


            // make our output image
            // outputImage = CreateOutputImage();
            outputImage = CreateOutputImage.generateImage(files, imagePlacement, TextureWidth, TextureHeight);
            if (outputImage == null)
            {
                return((int)FailCode.FailedToSaveImage);
            }

            Installer.args.ChildProcessed++;
            Installer.ReportProgressToInstallWorker(0);

            if (generateMap)
            {
                // get the sizes of all the images
                int i = 0;
                foreach (var image in ArrayImage)
                {
                    imageSizes.Add(image, image.AtlasImage.Size);
                    i++;
                }
                outputMap = CreateOutputMapData.generateMapData(imagePlacement, imageSizes);
            }

            Installer.ReportProgressToInstallWorker(0);

            // clear our dictionaries just to free up some memory
            imageSizes.Clear();
            imagePlacement.Clear();

            return(0);
        }
Example #2
0
        /// <summary>
        /// Packs a collection of images into a single image.
        /// </summary>
        /// <param name="imageFiles">The list of Textures of the images to be combined.</param>
        /// <param name="requirePowerOfTwo">Whether or not the output image must have a power of two size.</param>
        /// <param name="requireSquareImage">Whether or not the output image must be a square.</param>
        /// <param name="fastImagePacker">Accept the first successfull image packing.</param>
        /// <param name="maximumWidth">The maximum width of the output image.</param>
        /// <param name="maximumHeight">The maximum height of the output image.</param>
        /// <param name="imagePadding">The amount of blank space to insert in between individual images.</param>
        /// <param name="generateMap">Whether or not to generate the map dictionary.</param>
        /// <param name="outputImage">The resulting output image.</param>
        /// <param name="outputMap">The resulting output map of placement rectangles for the images.</param>
        /// <returns>0 if the packing was successful, error code otherwise.</returns>
        public int PackImage(
            IEnumerable <Texture> imageFiles,
            Atlas.State requirePowerOfTwo,
            Atlas.State requireSquareImage,
            bool fastImagePacker,
            int maximumWidth,
            int maximumHeight,
            int imagePadding,
            bool generateMap,
            out Bitmap outputImage,
            out Dictionary <string, Rectangle> outputMap)
        {
            files           = new List <Texture>(imageFiles);
            requirePow2     = requirePowerOfTwo == Atlas.State.True;
            requireSquare   = requireSquareImage == Atlas.State.True;
            acceptFirstPass = fastImagePacker;
            outputWidth     = maximumWidth;
            outputHeight    = maximumHeight;
            padding         = imagePadding;

            outputImage = null;
            outputMap   = null;

            // make sure our dictionaries are cleared before starting
            imageSizes.Clear();
            imagePlacement.Clear();

            // get the sizes of all the images
            int i = 0;

            foreach (var image in files)
            {
                imageSizes.Add(image, image.AtlasImage.Size);
                i++;
            }

            // sort our files by file size so we place large sprites first
            files.Sort(
                (f1, f2) =>
            {
                Size b1 = imageSizes[f1];
                Size b2 = imageSizes[f2];

                //check surface size first
                int c = -(b1.Width * b1.Height).CompareTo(b2.Width * b2.Height);
                if (c != 0)
                {
                    return(c);
                }

                //check sizes first
                c = -b1.Width.CompareTo(b2.Width);
                if (c != 0)
                {
                    return(c);
                }

                c = -b1.Height.CompareTo(b2.Height);
                if (c != 0)
                {
                    return(c);
                }

                //same size? go alphabetical i guess
                return(f1.name.CompareTo(f2.name));
            });

            // try to pack the images
            if (!PackImageRectangles())
            {
                return((int)FailCode.FailedToPackImage);
            }

            Installer.args.ChildProcessed++;
            Installer.ReportProgressToInstallWorker(0);

            // make our output image
            outputImage = CreateOutputImage.generateImage(files, imagePlacement, outputWidth, outputHeight);
            if (outputImage == null)
            {
                return((int)FailCode.FailedToSaveImage);
            }

            Installer.args.ChildProcessed++;
            Installer.ReportProgressToInstallWorker(0);

            if (generateMap)
            {
                outputMap = CreateOutputMapData.generateMapData(imagePlacement, imageSizes);
            }


            Installer.ReportProgressToInstallWorker(0);

            // clear our dictionaries just to free up some memory
            imageSizes.Clear();
            imagePlacement.Clear();

            return(0);
        }