הצגת תמונות ברשת (מוזיקה) היא דרישה נפוצה עבור גלריות, לוחות מגע, ודיסק. Aspose.Imaging עבור .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
- יצירת Canvas *
Image.Create(new PngOptions(), width, height)
(אוJpegOptions
אם אתה רוצה אובדן, קבצים קטנים יותר).רקע ברור:g.Clear(Color.White)
אוColor.Transparent
• PNG
- יצירת Canvas *
- מיקום כל תמונה *
לחשב את תא ישר עבור (רוח, עמוד).
עבור תוכן: סולם כדי להתאים בתוך התא, ולאחר מכן להדביק (שמאל / מרכז / ימין, העליון / בינוני / התחתון).
עבור Cover: מקור התרבות לנקודת התא, ולאחר מכן למלא את התא לחלוטין.
עבור Stretch: למלא את התא ללא קשר לשיעור היבט.
- להציל *בחר קוד על פי הרחבת היציאה:
.png
→new PngOptions()
.jpg
/.jpeg
→new JpegOptions { Quality = 90 }
שיטות טובות
- ** שקיפות**: עבור רקע שקוף, שימוש
Color.Transparent
ושמור כמו PNG. - רשתות גדולות מאוד: צפו בסכום פיקסל הכולל כדי למנוע OOM; עיבוד בדפים אם יש צורך.
- Mixed DPI/Color Types: תן לאספוס להתמודד עם ההמרה באופן אינסטינקטיבי, או סטנדרטיז מראש אם צינור שלך דורש את זה.
- תגית: אבטחה
Rows * Columns >= images.Count
(או להחליט כיצד להתמודד עם זרימת יתר בחסד). - תוצאות קבועות *: Fix
CellWidth/CellHeight
כדי ליישם צינורות חד-משמעותיים, במיוחד עבור UI טמפרטורות.
- תוצאות קבועות *: Fix