ASP.Net Core MVC跨平台绘图需求:矩形、直线、椭圆实现方案咨询
Hey there! Let's walk through the most reliable, cross-platform-friendly way to build your drawing app (rectangles, lines, ellipses) with ASP.NET Core MVC. First, let's address the System.Drawing.Common elephant in the room, then dive into a sustainable solution.
The Problem with System.Drawing.Common
Heads up:
System.Drawing.Commonis marked as obsolete for non-Windows platforms in .NET 6 and later. While you can enable it via project configuration and install native dependencies (likelibgdipluson Linux), this isn't a long-term solution—it's likely to be removed in future .NET versions. For true cross-platform support, we need a better alternative.
Recommended Solution: SkiaSharp
SkiaSharp is Google's open-source cross-platform graphics library, built for .NET. It works seamlessly on Windows, Linux, macOS, and even mobile, making it perfect for your use case. It's lightweight, performant, and integrates smoothly with ASP.NET Core MVC.
Step 1: Install Dependencies
First, add the required NuGet packages to your project:
Install-Package SkiaSharp Install-Package SkiaSharp.Views.AspNetCore
Step 2: Define Shape Models
Create a set of model classes to represent your drawing objects, with properties for position, dimensions, color, and a method to handle drawing logic. This keeps your code clean and follows MVC's separation of concerns.
public abstract class Shape { public int X { get; set; } public int Y { get; set; } public string Color { get; set; } = "#000000"; public abstract void Draw(SKCanvas canvas); } public class RectangleShape : Shape { public int Width { get; set; } public int Height { get; set; } public override void Draw(SKCanvas canvas) { using var paint = new SKPaint { Color = SKColor.Parse(Color), Style = SKPaintStyle.Stroke, StrokeWidth = 2 }; canvas.DrawRect(X, Y, Width, Height, paint); } } public class LineShape : Shape { public int EndX { get; set; } public int EndY { get; set; } public override void Draw(SKCanvas canvas) { using var paint = new SKPaint { Color = SKColor.Parse(Color), StrokeWidth = 2 }; canvas.DrawLine(X, Y, EndX, EndY, paint); } } public class EllipseShape : Shape { public int Width { get; set; } public int Height { get; set; } public override void Draw(SKCanvas canvas) { using var paint = new SKPaint { Color = SKColor.Parse(Color), Style = SKPaintStyle.Stroke, StrokeWidth = 2 }; // DrawOval uses center coordinates, so we adjust from top-left X/Y canvas.DrawOval(X + Width/2, Y + Height/2, Width/2, Height/2, paint); } }
Step 3: Controller Implementation (Two Options)
You have two solid paths here—choose based on whether you want to render server-side images or let the browser handle drawing via Canvas.
Option 1: Server-Side Image Generation
Use this if you need to return a static image file (great for APIs or simple displays):
public class DrawingController : Controller { public IActionResult GenerateImage() { // Populate your shapes (could come from a database, user input, etc.) var shapes = new List<Shape> { new RectangleShape { X = 50, Y = 50, Width = 100, Height = 80, Color = "#FF0000" }, new LineShape { X = 200, Y = 50, EndX = 300, EndY = 130, Color = "#00FF00" }, new EllipseShape { X = 150, Y = 200, Width = 120, Height = 80, Color = "#0000FF" } }; // Create a bitmap and canvas to draw on using var bitmap = new SKBitmap(400, 300); using var canvas = new SKCanvas(bitmap); canvas.Clear(SKColors.White); // Set background to white // Draw all shapes foreach (var shape in shapes) { shape.Draw(canvas); } // Encode the bitmap to a PNG and return as a file using var image = SKImage.FromBitmap(bitmap); using var data = image.Encode(SKEncodedImageFormat.Png, 100); return File(data.ToArray(), "image/png"); } }
Option 2: Pass Shape Data to Razor View for Frontend Rendering
Use this if you want interactive drawing, dynamic updates, or lighter server load:
Controller:
public IActionResult DrawShapes() { var shapes = new List<Shape> { new RectangleShape { X = 50, Y = 50, Width = 100, Height = 80, Color = "#FF0000" }, new LineShape { X = 200, Y = 50, EndX = 300, EndY = 130, Color = "#00FF00" }, new EllipseShape { X = 150, Y = 200, Width = 120, Height = 80, Color = "#0000FF" } }; return View(shapes); }
Razor View (DrawShapes.cshtml):
@model List<Shape> <h1>Your Drawing</h1> <canvas id="drawingCanvas" width="400" height="300" style="border: 1px solid #ccc;"></canvas> @section Scripts { <script> const canvas = document.getElementById('drawingCanvas'); const ctx = canvas.getContext('2d'); // Set white background ctx.fillStyle = '#FFFFFF'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Get shape data from model (serialized to JSON) const shapes = @Json.Serialize(Model); // Draw each shape on the canvas shapes.forEach(shape => { ctx.strokeStyle = shape.color; ctx.lineWidth = 2; // Determine shape type and draw accordingly const shapeType = shape.$type.split('.').pop(); switch (shapeType) { case 'RectangleShape': ctx.strokeRect(shape.x, shape.y, shape.width, shape.height); break; case 'LineShape': ctx.beginPath(); ctx.moveTo(shape.x, shape.y); ctx.lineTo(shape.endX, shape.endY); ctx.stroke(); break; case 'EllipseShape': ctx.beginPath(); // Canvas ellipse uses center coordinates, so adjust from top-left const centerX = shape.x + shape.width / 2; const centerY = shape.y + shape.height / 2; ctx.ellipse(centerX, centerY, shape.width/2, shape.height/2, 0, 0, 2 * Math.PI); ctx.stroke(); break; } }); </script> }
Why This Works
- True Cross-Platform: SkiaSharp runs everywhere ASP.NET Core does, no native dependency hacks required.
- MVC-Friendly: Models hold shape state and drawing logic, controllers handle data flow, views handle presentation (either server-side or client-side).
- Scalable: You can easily add more shapes, persist shape data to a database, or add user input for dynamic drawing later.
内容的提问来源于stack exchange,提问作者Sjoerd Alaerds

