Draw Images in ASP.NET Core 5
System.Drawing package is added back to .NET 5. It provides common GDI+ graphics to draw images: System.Drawing.Bitmap, System.Drawing.BitmapData, System.Drawing.Brush, System.Drawing.Font, System.Drawing.Graphics, System.Drawing.Icon and etc. Previously we have to use third-party libraries to draw images in .NET Core 2.x/3.x as article Graphics Programming and Image Processing in .NET Core 2.x shows. This article provides detailed steps to implement the same in ASP.NET 5 applications.
Prerequisites
.NET 5 SDK is required to create projects through command line. Refer to page .NET 5 is Officially Released for more details about .NET.
Create sample ASP.NET project
Use the following commands to create a sample project:
mkdir dotnet5-drawing cd dotnet5-drawing dotnet new webapp
The project structure looks like the following screenshot:
Add package reference
The package required is available here NuGet Gallery | System.Drawing.Common 5.0.1.
Use the following command to add reference to the package:
dotnet add package System.Drawing.Common --version 5.0.1
After this, the project file will be updated accordingly:
<ItemGroup> <PackageReference Include="System.Drawing.Common" Version="5.0.1" /> </ItemGroup>
Add a controller
Let's add a controller class to draw images. Follow these steps:
1) Add package reference
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
Or upgrade it already exists:
dotnet tool update --global dotnet-aspnet-codegenerator
2) Add a controller class
Generate a controller class using template:
dotnet aspnet-codegenerator --project . controller -name CaptchaController
A new class file named CaptchaController.cs will be generated.
Update controller
Update the controller implementation to draw a captcha image in the response.
Replace the content with the following:
using System; using System.Drawing; using System.IO; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace dotnet5_drawing { [Route("/api/[controller]")] public class CaptchaController : Controller { // Background color private readonly Color bgColor = Color.FromArgb(0xe9, 0xec, 0xef); // Code color private readonly Color codeColor = Color.FromArgb(0x00, 0x69, 0xd9); // Obstruction color private readonly Color obsColor = Color.FromArgb(0x28, 0xa7, 0x45); [HttpGet] [AllowAnonymous] public async Task IndexAsync() { var (content, contentType) = GenerateCaptchaImage(); HttpContext.Response.ContentType = contentType; await HttpContext.Response.BodyWriter.WriteAsync(content); } private (byte[] content, string contentType) GenerateCaptchaImage() { // Setup output format var contentType = "image/png"; // Image width const int imageWidth = 150; // Image height const int imageHeight = 50; // Captcha code length const int captchaCodeLength = 4; // Captcha code string, all the possible chars that can appear in the image. const string captchaCodeString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; Random random = new Random(); // Generate random characters StringBuilder s = new StringBuilder(); using var ms = new MemoryStream(); // Create the image using Bitmap bitmap = new Bitmap(imageWidth, imageHeight); // Create the graphics using Graphics graphics = Graphics.FromImage(bitmap); // Write bg color graphics.FillRectangle(new SolidBrush(bgColor), 0, 0, imageWidth, imageHeight); // Add obstructions using (Pen pen = new Pen(new SolidBrush(obsColor), 2)) { for (int i = 0; i < 10; i++) { graphics.DrawLine(pen, new Point(random.Next(0, imageWidth - 1), random.Next(0, imageHeight - 1)), new Point(random.Next(0, imageWidth - 1), random.Next(0, imageHeight - 1))); } } for (int i = 0; i < 100; i++) { bitmap.SetPixel(random.Next(imageWidth), random.Next(imageHeight), Color.FromArgb(random.Next())); } // Font using (Font font = new Font(FontFamily.GenericMonospace, 32, FontStyle.Bold | FontStyle.Italic, GraphicsUnit.Pixel)) { for (int i = 0; i < captchaCodeLength; i++) { s.Append(captchaCodeString.Substring(random.Next(0, captchaCodeString.Length - 1), 1)); // Write char to the graphic graphics.DrawString(s[s.Length - 1].ToString(), font, new SolidBrush(codeColor), i * 32, random.Next(0, 24)); } } // Save image, image format type is consistent with response content type. bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); return (ms.ToArray(), contentType); } } }
The controller will be exposed via route /api/captcha.
The most important logic is implemented in function GenerateCaptchaImage. This function does the following:
- Use namespace System.Drawing.
- Instantiate a Bitmap object which is then used to instantiate Graphics object.
- The Graphics object is used to draw lines, dots and characters. The characters are randomly selected from a predefined string. The color and formats of these drawings are defined by the pens/brushes. The position of the characters are randomly decided too.
- At last the bitmap binary content is save to a memory stream which is eventually output to the HTTP response stream.
Update Startup.cs
We need to update Startup.cs file to ensure controller routes are mapped and exposed:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //... app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); }); }
Build and run the application
Now we can build and run the application using the following command:
dotnet build dotnet run
The output of the last command looks something like the following:
Building... info: Microsoft.Hosting.Lifetime[0] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: F:\Projects\dotnet5-drawing
The image can be viewed via opening the following URL in your browser:
https://localhost:5001/api/captcha
The captcha image looks like the following screenshot:
Add image to Razor pages
You can also add the image in other pages. For example, the following code snippet displays the image in Index page:
@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Welcome</h1> <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> <p><img src="/api/captcha" /></p> </div>
Summarize
It's very easy to use System.Drawing.Common package to draw images in ASP.NET Core or .NET core. For more information about GDI+, refer to GDI+ - Win32 apps | Microsoft Docs.