แสดงภาพในเครือข่าย (โมเสค) เป็นข้อกําหนดทั่วไปสําหรับแกลเลอรี่ แผ่นติดต่อและ dashboards. Aspose.Imaging สําหรับ .NET ให้ทุกสิ่งที่คุณต้องการเพื่อโหลดภาพประกอบไว้บนแถบและบันทึกคอมโพสิตสุดท้าย - อย่างบริสุทธิ์และ cross-platform
คู่มือนี้แสดงให้เห็นถึงวิธีการสร้างคอมโพสิตเครือข่ายที่สามารถใช้ใหม่ได้ด้วย สาย / ตาราง, การวางภายนอก การวางภายในเซลล์** สีพื้นหลัง (รวมถึงโปร่งใส)** และ โหมดที่เหมาะสม (คอนเทนเนอร์ / ฝาครอบ / สกรู) รวมถึงการสอดคล้องภายใน клетแต่ละ
ตัวอย่างที่สมบูรณ์แบบด้วยตนเอง
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 ความกว้าง / ความสูงระหว่างแหล่งข้อมูลหรือบังคับให้ขนาดเซลล์ที่เฉพาะเจาะจงสําหรับเครือข่ายเดียว
*ขนาด Canvas *
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**: กรอกเซลล์โดยไม่คํานึงถึงความสัมพันธ์ด้าน
*บันทึก *เลือก encoder โดย extension output:
.png
→new PngOptions()
.jpg
/.jpeg
→new JpegOptions { Quality = 90 }
แนวทางที่ดีที่สุด
- ความโปร่งใส: สําหรับพื้นหลังที่ชัดเจนการใช้งาน
Color.Transparent
และบันทึกเป็น PNG - เครือข่ายขนาดใหญ่มาก: ตรวจสอบปริมาณ pixel ทั้งหมดเพื่อหลีกเลี่ยง OOM; การประมวลผลในหน้าถ้าจําเป็น
- ประเภท DPI / สีผสม: ปล่อยให้ Aspose จัดการการแปลงโดยอัจฉริยะหรือมาตรฐานก่อนหน้านี้หากท่อของคุณต้องการ
- การยืนยัน: รับประกัน
Rows * Columns >= images.Count
(หรือตัดสินใจวิธีการจัดการการไหลเวียนด้วยความสุข) - ผลลัพธ์ที่กําหนด: Fix
CellWidth/CellHeight
การบังคับใช้กระเบื้องแบบสม่ําเสมอโดยเฉพาะอย่างยิ่งสําหรับ UI thumbnails
More in this category
- การเพิ่มประสิทธิภาพของ GIF ของ animated ใน .NET โดยใช้ Aspose.Imaging
- Optimize Multi-Page TIFFs for Archival in .NET ด้วย Aspose
- HEIC ไปยัง JPEG / PNG แปลงด้วย Aspose.Imaging สําหรับ .NET
- การเคลื่อนไหวที่ขับเคลื่อนข้อมูลใน .NET ด้วย Aspose.Imaging
- การบีบอัดภาพที่มีคุณภาพและไม่มีการสูญเสียใน .NET ด้วย Aspose.Imaging