Alternatives to System.Drawing for Use with ASP.NET

Alternatives to System.Drawing for use with ASP.NET?

There is an excellent blog post including C# code about using the ImageMagick graphics library through Interop over at TopTen Software Blog. This post deals specifically with running ASP.net on linux under mono; however, the C# code should be perfectly copy-paste-able, the only thing you'll need to change is the Interop attributes if you are running under windows referencing a window binary (DLL).

ImageMagick® is a software suite to create, edit, compose, or convert
bitmap images. It can read and write images in a variety of formats
(over 100) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD,
PNG, Postscript, SVG, and TIFF. Use ImageMagick to resize, flip,
mirror, rotate, distort, shear and transform images, adjust image
colors, apply various special effects, or draw text, lines, polygons,
ellipses and Bézier curves.

There is also an ImageMagick .Net development project on codeplex that wraps up everything for you. But it doesn't show active development since 2009, so it may be lagging behind the current ImageMagick library version. For a small trivial resizing routine, I'd probably stick with the interop. You just need to watch your implementation carefully for your own memory leak or unreleased resources (the library itself is well tested and vetted by the community).

The library is free and open source. The Apache 2 license appears to be compatible with both personal and commercial purposes. See ImageMagick License Page.

The library is totally cross platform and implements many powerful image handling and transformation routines that are not found in GDI+ (or not implemented under mono) and has a good reputation as an alternative for ASP.net image processing.

Update: Looks like there is an updated version of a .NET wrapper here: http://magick.codeplex.com/

Image manipulation in asp.net/c# without System.Drawing/GDI+

I don't know of any fully-managed 2D drawing libraries that are either free or open-source (there appears to be a few commercially available, but OSS is the way to go). However, you might look into the Mono bindings to Cairo.

Cairo is a platform independent 2D drawing API. You can find more information about it at the Cairo homepage. The Cairo Wikipedia page also has some good info.

Cairo is also used fairly widely in the Open Source world, which to me says something about its robustness. Mozilla, Webkit, and Mono all use it, among others. Ironically, Mono actually uses it to back their System.Drawing implementation... go figure.

There might also be a way to use Mono's System.Drawing implementation as a drop-in replacement for the Microsoft implementation, though I'm not sure how or if that would even work. I would probably start by replacing the System.Drawing.dll reference with Mono's version, and then try to deal with any errors.

.NET Core and System.Drawing

System.Drawing is not a good option with ASP.NET

If you want graphics manipulation i suggest to use ImageSharp (https://github.com/JimBobSquarePants/ImageSharp) on .Net Core or ImageProcessor (http://imageprocessor.org/) / ImageResizer (https://imageresizing.net/) on .Net Framework

Also, if you really need to use System.Drawing change frameworks in your project.json to netstandard1.6 and add in dependencies "NETStandard.Library": "1.6.1"

System.Drawing in Windows or ASP.NET services

To clear up any confusion, System.Drawing does work under ASP.NET and Services, it's just not supported. There can be issues with high load (running out of unmanaged resources), memory or resource leaks (badly implemented or called dispose patterns) and/or dialogs being popped when there's no desktop to show them on.

Testing will take care of the latter, and monitoring will alert you to the former. But, if/when you have a problem, don't expect to be able to call PSS and ask for a fix.

So, what are you options? Well, if you don't need a completely supported route, and you don't expect extreme load - a lot of folks have disregarded the MSDN caveat and used System.Drawing with success. A few of them have been bitten, but there's alot more success than failure stories.

If you want something supported, then you need to know if you're running interactively or not. Personally, I'd probably just leave it up to the hosting app to set a non-interactive flag somewhere or other. After all, the app is in the best position to determine if they're in a hosted environment and/or want to risk the GDI+ issues.

But, if you want to automagically detect your environment, I suppose there's worse answers than are offered right here on SO for a service. To summarize, you can either check the EntryAssembly to see if it inherits from ServiceBase, or try to access System.Console. For ASP.NET, along the same lines, detecting HttpContext.Current should be sufficient.

I'd think there'd be a managed or p/invoke way to look for a desktop (which is really the defining factor in all this, I think) and/or something off the AppDomain which would clue you in. But I'm not sure what it is, and MSDN is less than enlightening on it.

Edit: Trolling MSDN, I recalled that it's actually a Window Station (which hosts a desktop) that's the important bit here. With that info, I was able to find GetProcessWindowStation() which returns a handle to the current window station. Passing that handle to GetUserObjectInformation() will get you a USEROBJECTFLAGS struct with should have a dwFlags with WSF_VISIBLE if you have a visible desktop.

Alternatively, EnumWindowsStations will give you a list of stations which you could check - WinSta0 is the interactive one.

But, yeah, I still think just having the app set a property or something is the much easier route....

Edit again: 7 years later, I get clued into Environment.UserInteractive where MS does the exact GetProcessWindowStation dance I described above for you....I'd still recommend delegating to the hosting app (they may well want the faster, but slightly riskier System.Drawing path), but UserInteractive seems a good default to have without having it pinvoke it yourself.

Graphics generation in csharp with Graphics.DrawString renders different, depending on platform. (GDI)

Don't use System.Drawing. Microsoft itself warns against this in the documentation. It exists in .NET Core only for compatibility

In .NET 6 and later versions, the System.Drawing.Common package, which includes this type, is only supported on Windows operating systems. Use of this type in cross-platform apps causes compile-time warnings and run-time exceptions. For more information, see System.Drawing.Common only supported on Windows.

The linked article explains what's wrong and offers several cross-platform alternatives like ImageSharp and SkiaSharp.

System.Drawing's primary job is to draw the UI on the screen anyway, not manipulate images. On Windows it's just a very thin wrapper over GDI+. The equivalent cross-platform technology is MAUI, which hasn't been released yet.

The equivalent code in ImageSharp could be:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.Fonts;
...
//Load the fonts
FontCollection fonts = new FontCollection();
var boldPath = Path.Combine(_hostingEnvironment.WebRootPath, "fonts/bold.ttf");
var lightPath = Path.Combine(_hostingEnvironment.WebRootPath, "fonts/light.ttf");
var boldFont = fonts.Install(boldPath);
var lightFont = fonts.Install(lightPath);

//Load the image
var image = await Image.LoadAsync(stream);

//Draw the text
string yourText = $"{summary?.UniqueColsInYear.Number()}";

Font font = boldFont.CreateFont(58, FontStyle.Bold);

DrawingOptions options = new DrawingOptions()
{
TextOptions = new TextOptions
{
WrapTextWidth = yearValuesRightBorder,
HorizontalAlignment = HorizontalAlignment.Right
}
};

var point = PointF(0, startHeightYear);
image.Mutate(x => x.DrawText(options, yourText, font, Color.Black, point));

//Save as PNG to a buffer
using var ms = new MemoryStream();
await image.SaveAsPngAsync(ms);
return ms.ToArray();

You can check the Getting Started section in the docs. SaveAsPngAsync is a convenience extension method. Drawing Text shows how to draw text on the image and the Fonts section shows how to handle fonts.



Related Topics



Leave a reply



Submit