How to take a catalog of images and render a grid of images in one image

Someone recently asked me if there was a way to make a program that could output a single image containing a grid of images from the source directory, with a custom number of columns that should determine the number of rows.

I dropped that concept at first as you could do it on many free photo editing platforms in the wild, but after explaining the situation in great detail I figured it might be worth the 30 minutes it would take to write this just for their own mind and time savings.

+3


source to share


1 answer


First, you need a way to read images:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grimager.ImageProcessing
{
    public class ImageReader
    {
        protected string[] Files { get; set; }

        public ImageReader(string path)
        {
            Files = Directory.GetFiles(path);
        }

        public IEnumerable<Image> GetImages()
        {
            foreach (var f in Files.OrderBy(x => x))
            {
                yield return Image.FromFile(f);
            }
        }
    }
}

      

Next, image processing. Given the number of columns, the spacing between images, and a numeric field, to tell which image index is the layout can be calculated quite simply:



using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grimager.ImageProcessing
{
    public class ImageProcessor
    {
        protected int Columns { get; set; }

        public ImageProcessor(int columns)
        {
            Columns = columns;
        }

        public string[] ProcessTo(string sourceDirectory, string outputFile)
        {
            var reader = new ImageReader(sourceDirectory);
            int idx = 1;
            var cfg = Settings.Get();
            var images = new List<Image>();
            foreach (var original in reader.GetImages())
            {
                var img = ResizeImage(original, cfg.Width, cfg.Height);
                using (var graphic = Graphics.FromImage(img))
                {
                    graphic.FillRectangle(Brushes.White, new Rectangle(0, 0, cfg.LetterBoxSize, cfg.LetterBoxSize));
                    using (var font = new Font("Arial", cfg.LetterBoxSize - 1))
                    {
                        graphic.DrawString(idx.ToString(), font, Brushes.Red, new PointF(0,0));
                    }
                }
                images.Add(img);
                idx++;
            }

            var totalImages = images.Count();
            var totalRows = (int) Math.Ceiling(totalImages/(double)Columns);
            var totalWidth = Columns*cfg.Width + ((Columns - 1) * cfg.Spacing);
            var totalHeight = totalRows * cfg.Height + ((totalRows-1) * cfg.Spacing);
            var output = new Bitmap(totalWidth, totalHeight);
            var row = 0;
            using (var graphic = Graphics.FromImage(output))
            {
                for (var i = 0; i < totalImages; i++)
                {
                    if (i> 0 && i%Columns == 0)
                        row++;

                    var column = i%Columns;

                    var x = column*cfg.Width;
                    if (column > 0)
                    {
                        x += cfg.Spacing*column;
                    }
                    var y = row*cfg.Height;

                    if (row > 0)
                    {
                        y += cfg.Spacing*row;
                    }

                    graphic.DrawImage(images[i], new Rectangle(new Point(x,y), new Size(cfg.Width, cfg.Height)));
                }
            }

            output.Save(outputFile, ImageFormat.Jpeg);

            return new string[0];
        }

        protected Image ResizeImage(Image image, int width, int height)
        {
            var destRect = new Rectangle(0, 0, width, height);
            var destImage = new Bitmap(width, height);

            destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            using (var graphics = Graphics.FromImage(destImage))
            {
                graphics.CompositingMode = CompositingMode.SourceCopy;
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

                using (var wrapMode = new ImageAttributes())
                {
                    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                    graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
                }
            }

            return destImage;
        }
    }
}

      

Not really the best of the "hows" on stack overflow, but figured since I was asked to write it, I would share and maybe save another poor soul there for a while.

The full source is available in the public domain on GitHub at: The Grimager

+3


source







All Articles