네트워크 (모사이크)에서 이미지를 표시하는 것은 갤러리, 접촉 잎 및 데스크 보드에 대한 일반적인 요구 사항입니다. Aspose.Imaging for .NET는 이미지가 충전되어야 할 모든 것을 제공하고, 캔버스에 구성되어 최종 컴포지트를 저장합니다.

이 가이드는 ** 라인/열**, 외부 패딩을 사용하여 재사용 가능한 네트워크 컴포더를 구축하는 방법을 보여줍니다. 세포 간 스파킹과 ** 배경 색상 ( 투명 포함)** 및 ** 적합 모드** (콘테인 / 커버 / 스트레치) 플러스 각 세포 내부의 조정.

완전하고 자기소개된 예제

using System;
using System.Collections.Generic;
using System.IO;
using Aspose.Imaging;
using Aspose.Imaging.ImageOptions;

namespace ImagingGridDemo
{
    public enum FitMode { Contain, Cover, Stretch }
    public enum HAlign { Left, Center, Right }
    public enum VAlign { Top, Middle, Bottom }

    public sealed class GridOptions
    {
        // Required layout
        public int Rows { get; init; }
        public int Columns { get; init; }

        // Optional cell size. If null, computed from max source dimensions.
        public int? CellWidth { get; init; }
        public int? CellHeight { get; init; }

        // Spacing/padding
        public int Spacing { get; init; } = 8;     // space between cells
        public int Padding { get; init; } = 16;    // outer canvas padding

        // Drawing behavior
        public FitMode Fit { get; init; } = FitMode.Contain;
        public HAlign AlignX { get; init; } = HAlign.Center;
        public VAlign AlignY { get; init; } = VAlign.Middle;

        // Background
        public Color Background { get; init; } = Color.White;

        // Output
        public string OutputPath { get; init; } = "grid.png"; // encoder inferred by extension

        public void Validate()
        {
            if (Rows <= 0 || Columns <= 0)
                throw new ArgumentException("Rows and Columns must be positive.");
            if (Spacing < 0 || Padding < 0)
                throw new ArgumentException("Spacing and Padding cannot be negative.");
            if (!OutputPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
                !OutputPath.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
                !OutputPath.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase))
                throw new ArgumentException("OutputPath must end with .png or .jpg/.jpeg.");
        }
    }

    public static class ImageGridComposer
    {
        /// <summary>
        /// Builds a grid/mosaic from the given image file paths.
        /// </summary>
        public static void Compose(IReadOnlyList<string> imagePaths, GridOptions options)
        {
            if (imagePaths is null || imagePaths.Count == 0)
                throw new ArgumentException("No input images provided.");
            options.Validate();

            // 1) Load the images
            var images = new List<Image>(imagePaths.Count);
            try
            {
                foreach (var path in imagePaths)
                    images.Add(Image.Load(path));

                // 2) Determine cell size (if not supplied) from the max width/height of sources
                int cellW = options.CellWidth ?? GetMaxWidth(images);
                int cellH = options.CellHeight ?? GetMaxHeight(images);

                // 3) Compute canvas size
                int w = options.Padding * 2
                        + (options.Columns * cellW)
                        + ((options.Columns - 1) * options.Spacing);
                int h = options.Padding * 2
                        + (options.Rows * cellH)
                        + ((options.Rows - 1) * options.Spacing);

                // 4) Create canvas. Use PNG by default (lossless & supports transparency).
                ImageOptionsBase canvasOptions = options.OutputPath.EndsWith(".png", StringComparison.OrdinalIgnoreCase)
                    ? new PngOptions()
                    : new JpegOptions { Quality = 90 };

                using var canvas = Image.Create(canvasOptions, w, h);

                // If you want transparent background, set Background = Color.Transparent and save as PNG
                using var g = new Graphics(canvas);
                g.Clear(options.Background);

                // 5) Draw each image into its cell
                int idx = 0;
                for (int r = 0; r < options.Rows; r++)
                {
                    for (int c = 0; c < options.Columns; c++)
                    {
                        if (idx >= images.Count) break;

                        var img = images[idx++];
                        var cellRect = CellRect(r, c, cellW, cellH, options);

                        // Determine source and destination rectangles according to FitMode
                        GetDrawRects(img.Width, img.Height, cellRect, options, out Rectangle srcRect, out Rectangle dstRect);

                        // Draw scaled/cropped as needed
                        g.DrawImage(img, dstRect, srcRect);

                        // (Optional) draw cell borders for debugging:
                        // g.DrawRectangle(new Pen(Color.LightGray), cellRect);
                    }
                }

                // 6) Save by extension
                SaveByExtension(canvas, options.OutputPath);
            }
            finally
            {
                foreach (var img in images)
                    img.Dispose();
            }
        }

        private static int GetMaxWidth(List<Image> imgs)
        {
            int m = 1;
            foreach (var i in imgs) m = Math.Max(m, i.Width);
            return m;
        }

        private static int GetMaxHeight(List<Image> imgs)
        {
            int m = 1;
            foreach (var i in imgs) m = Math.Max(m, i.Height);
            return m;
        }

        private static Rectangle CellRect(int row, int col, int cellW, int cellH, GridOptions opt)
        {
            int x = opt.Padding + col * (cellW + opt.Spacing);
            int y = opt.Padding + row * (cellH + opt.Spacing);
            return new Rectangle(x, y, cellW, cellH);
        }

        /// <summary>
        /// Computes source and destination rectangles for DrawImage based on fit & alignment.
        /// </summary>
        private static void GetDrawRects(
            int srcW, int srcH, Rectangle cell, GridOptions opt,
            out Rectangle srcRect, out Rectangle dstRect)
        {
            srcRect = new Rectangle(0, 0, srcW, srcH);

            if (opt.Fit == FitMode.Stretch)
            {
                // Stretch to fill the entire cell.
                dstRect = cell;
                return;
            }

            // Aspect ratios
            double imgAR = (double)srcW / srcH;
            double cellAR = (double)cell.Width / cell.Height;

            if (opt.Fit == FitMode.Contain)
            {
                // Scale down so the whole image fits inside the cell (letterboxing possible).
                double scale = (imgAR > cellAR)
                    ? (double)cell.Width / srcW
                    : (double)cell.Height / srcH;

                int drawW = (int)Math.Round(srcW * scale);
                int drawH = (int)Math.Round(srcH * scale);

                int dx = AlignX(cell.X, cell.Width, drawW, opt.AlignX);
                int dy = AlignY(cell.Y, cell.Height, drawH, opt.AlignY);

                dstRect = new Rectangle(dx, dy, drawW, drawH);
                return;
            }

            // FitMode.Cover:
            // Crop source to match cell aspect, then scale to fill cell completely.
            if (opt.Fit == FitMode.Cover)
            {
                if (imgAR > cellAR)
                {
                    // Image too wide; crop left/right
                    int newSrcW = (int)Math.Round(srcH * cellAR);
                    int sx = (srcW - newSrcW) / 2;
                    srcRect = new Rectangle(sx, 0, newSrcW, srcH);
                }
                else
                {
                    // Image too tall; crop top/bottom
                    int newSrcH = (int)Math.Round(srcW / cellAR);
                    int sy = (srcH - newSrcH) / 2;
                    srcRect = new Rectangle(0, sy, srcW, newSrcH);
                }

                dstRect = cell; // fill the cell exactly
                return;
            }

            // Default fallback (shouldn't hit)
            dstRect = cell;
        }

        private static int AlignX(int cellX, int cellW, int drawW, HAlign ax)
        {
            return ax switch
            {
                HAlign.Left   => cellX,
                HAlign.Center => cellX + (cellW - drawW) / 2,
                HAlign.Right  => cellX + (cellW - drawW),
                _             => cellX
            };
        }

        private static int AlignY(int cellY, int cellH, int drawH, VAlign ay)
        {
            return ay switch
            {
                VAlign.Top    => cellY,
                VAlign.Middle => cellY + (cellH - drawH) / 2,
                VAlign.Bottom => cellY + (cellH - drawH),
                _             => cellY
            };
        }

        private static void SaveByExtension(Image image, string outputPath)
        {
            var ext = Path.GetExtension(outputPath).ToLowerInvariant();
            ImageOptionsBase opts = ext switch
            {
                ".jpg" or ".jpeg" => new JpegOptions { Quality = 90 },
                ".png"            => new PngOptions(),
                _                 => new PngOptions()
            };
            image.Save(outputPath, opts);
        }
    }

    // Demo usage
    public static class Program
    {
        public static void Main()
        {
            var inputs = new List<string>
            {
                "img1.jpg", "img2.png", "img3.jpg",
                "img4.jpg", "img5.png", "img6.jpg"
            };

            var opts = new GridOptions
            {
                Rows = 2,
                Columns = 3,
                // Leave CellWidth/CellHeight null to auto-fit to largest source,
                // or set fixed cell size (e.g., 640x480):
                // CellWidth = 640, CellHeight = 480,

                Spacing = 10,
                Padding = 20,
                Fit = FitMode.Contain,         // Contain | Cover | Stretch
                AlignX = HAlign.Center,        // used by Contain
                AlignY = VAlign.Middle,        // used by Contain
                Background = Color.White,      // use Color.Transparent with PNG for transparent canvas
                OutputPath = "grid.png"
            };

            ImageGridComposer.Compose(inputs, opts);
            Console.WriteLine("Grid created: " + opts.OutputPath);
        }
    }
}

단계별 가이드

    • 충전 입력*Image.Load(path) 각 파일을 위해 그들을 기억할 때까지 복합물이 저장되고 그 후에 분해됩니다.
    • 세포 크기*
  • 제공되지 않으면, 계산 cellWidth 그리고 cellHeight *max 폭 / 높이를 각 출처에 따라.

  • 또는 유니폼 네트워크에 대한 특정 셀 크기를 강요합니다.

    • 크기 변경*
width  = 2*Padding + Columns*cellW + (Columns-1)*Spacing
height = 2*Padding + Rows*cellH    + (Rows-1)*Spacing
    • 캔버스 만들기*Image.Create(new PngOptions(), width, height) (또는 JpegOptions 손실을 원한다면, 작은 파일).명확한 배경 : g.Clear(Color.White) 또는 Color.Transparent 그리고 PNG.
    • 각각의 사진을 대체하십시오*
  • 세포 직경을 계산하십시오 (로, 열).

  • ** 컨테이너**: 셀 내에 맞게 스케일, 그 후에 일치 (왼쪽/중앙/오른쪽, 상단/평균/바닥).

  • Cover : 세포 측면에 곡물 출처, 그 후에 세트를 완전히 채우십시오.

  • Stretch : 측면 비율에 상관없이 세포를 채우십시오.

    • 구원*출력 확장에 따라 코더를 선택하십시오 :
  • .pngnew PngOptions()

  • .jpg/.jpegnew JpegOptions { Quality = 90 }

모범 사례

  • ** 투명성** : 투표 배경을 위해, 사용 Color.Transparent 그리고 PNG로 저장합니다.
  • Very Large Grids: OOM을 피하기 위해 전체 픽셀 계산을 지켜보십시오; 필요한 경우 페이지로 처리합니다.
  • Mixed DPI/Color Types: Aspose가 변환을 지시적으로 처리하거나 파이프 라인이 요구하는 경우 사전에 표준화하십시오.
    • 유효성* : 보장 Rows * Columns >= images.Count (또는 과도한 흐름을 은혜롭게 처리하는 방법을 결정하십시오.)
  • ** 결정적 출력** : 고정 CellWidth/CellHeight 유일한 타일을 적용하기 위해, 특히 UI 튜브를 위해.

More in this category