
.NET Core Image Processing - jamessouth
https://blogs.msdn.microsoft.com/dotnet/2017/01/19/net-core-image-processing/
======
skrebbel
This might sound like a small thing but the .NET image processing stuff has
traditionally depended a _lot_ on Windows builtins. Mono shipped an entire
mediocre rewrite of GDI (the graphics layer that's been Windows since the
early nineties) just to support the .NET Framework image processing stuff.
Note: not for image _display_ (which is what GDI is mainly for) - even for
headless image processing.

In practice this meant that if you were cropping an image server-side in C#
code on a Linux server, a C-rewrite of a Windows UI layer would kick in and do
the work for you. Amazing work from the Mono team, because it worked, but also
pretty nuts.

If there's one place I remember having stuff that "just worked" on Windows and
had weird subtle quirks on Mono, it's image processing (I'm talking a few
years ago). So IMO it's pretty awesome that they're replacing all that legacy
with a decent 100% .NET image processing library.

(Sidenote: this was also the _only_ real problem we faced developing a C#
backend with a team on Windows, Linux _and_ OSX computers, and running it all
on Mono on Docker on Linux - all well before .NET Core. Mono really is/was
that good)

~~~
ygra
Mono shipped a reimplementation of the types in the System.Drawing namespace
which uses GDI+ (note the +) on Windows. This reimplementation is also what
CoreCompat.System.Drawing is based on. To my knowledge Mono _did_ shim a few
Windows APIs, mostly related to window messages so WndProc can be overridden
in a useful manner, but not actually GDI, as far as I know.

~~~
kodfodrasz
And the implementation was buggy as hell. When I needed to resize pictures on
mono + Linux I finally had to resort to manually building libgb, writing a
simple wrapper for the resizing part, and use that, as back then every other
alternative as either incomplete, or pain to use and/or buggy.

Note: libgd is a well designed native library with design emphasis on simple
interop wrappability.

------
jamessouth
Great to see the positive comments here. ImageSharp is my baby and it fills me
with a lot of confidence that it's something that developers both want and
need.

~~~
camus2
Why would you expect negative comment? .NET Core is a solid platform for web
development. It's easy to deploy and relatively fast compared to the usual
Python/Ruby/PHP and co... only matched by Java(controlled by Oracle) and
Go(which is obnoxious). .NET Core is growing at a fast pace, and it deserves
it, C# and F# are phenomenal languages.

~~~
jamessouth
This isn't my first rodeo with Hacker News, I've unfortunately had negative
responses before when sharing my work.

~~~
MichaelGG
Thank you for your work! I used it with a client that had a System.Drawing
impl. Just making thumbnails of uploaded images. It actually was our CPU
bottleneck! And then it started crashing when load was high, making us drop or
reprocess (which added more load and drops...).

With your lib and a few hours of work, all that disappeared and CPU went way
down. Thanks!

On a side note, users should try to send gratitude to open source authors in
general. I know it's hypocritical of me, since I didn't take the time to email
you before this! I've done it a few times in the past and the replies I've
received indicated that I was the only one to ever thank them! That sucks.
I've written some stuff I know more than a few companies built entire products
and services with -- I've received about 2 notes in 6-7 years. It's not much
but just a bit of thanks really provided motivation.

Cheers to you.

~~~
jamessouth
That's great to hear, With future updates and a little help I'm sure we can
improve the performance further and make us the g0-to library.

And thanks for saying thanks, it is rare and always very much appreciated.

------
kodfodrasz
My experience with any ImageMagick and derivateives is terrible. Obscure
install is needed, app is not portable (which is normally a great default
feature of .Net apps), or building it is difficult. Also its security track
(of the native parts) is very bad, so i strongly discourage anybody using
those libraries.

On the other hand ImageSharp is convinient, and the author is a nice helpful,
responsive guy. I totally suggest using his library. When I needed it once for
mono, though then it did not meet my needs, Mr. South was really helpful.
Eventually I had to stick to manually wrapping libgd, but I'm about to revisit
that code and change it to use a new ImageSharp version! (Also the fluent APIs
make working with images using that lib pretty awesome!)

~~~
simooooo
Magiic.net works fine but it occludes the real API so you might struggle to do
certain things

~~~
kodfodrasz
The real api is a bit of brainfuck to me. I'm not sure what psychedelic the
creators of ImageMagick were on, or maybe they thought it is kinda funny, but
for me the GetMagicWand call was also a single sign that I don't want to use
that.

So what I mean by this: in my opinion occluding the real API is probably a
feature of Magiic.net. Still I do not like if a library needs systemwide
install and config files, etc, as ImageMagick/GraphicsMagic does. Maybe the
creators of these libs have solved the portability problems created by this,
but I'm disgusted by these native libraries, and I avoid them. (Back then the
one wrapper I tried needed a systemwide install of imagemagick. A click
through wizard needing administrative rights, instead of dropping a dll into
the PATH or the program directory... Also it has config files. Config files..
for a library. IMHO this is insane! It is a good approach to configure apps by
config files. Libraries should be configured by API calls, or build time
constants.)

Having custom build scripts for 3rdparty code is a huge work to keep up to
date which will always lag behind, thus the security will also lag behind. On
the other hand this is needed to solve the portability issues of the native
parts. I find this approach unproductive, but wish the maintainers the best.

------
jamessouth
Amazed this is trending. If anyone has any interest in image processing of
performance in general please get in touch and give me a hand. Any help will
be appreciated.

------
jsingleton
Nice post. Looks like I'll need to update the compatibility list:
[https://github.com/jpsingleton/ANCLAFS#image-
manipulation](https://github.com/jpsingleton/ANCLAFS#image-manipulation)

NB: You shouldn't use System.Drawing in a web app. It can lead to memory leaks
and lots of pain. Even the newer WPF equivalents are not safe for use on a web
server.

~~~
koyote
What would you recommend instead of System.Drawing in a web app?

Any of the ones listed in the article?

~~~
jsingleton
Unless you have a good reason to then I would recommend against rolling your
own (with any library). Use an existing cloud service that specializes in it.

~~~
gjjrfcbugxbhf
Most b2b saas products have a specific reason to not use a third party for
everything - their customers don't want their data sprayed everywhere. Add to
that anyone with a government contact.

------
gthtjtkt
What are the best resources for someone who wants to move from .NET desktop
development to .NET web development? All the popular sites like Udacity and
FreeCodeBootcamp rarely (if ever) touch the MS stack.

I know this isn't exactly the right place to ask, but I've had no luck
anywhere else...

~~~
phhlho
If you are already familiar with .NET, you might find some courses on
Microsoft Virtual Academy a good starting point. There is a web development
category: [https://mva.microsoft.com/training-topics/web-
development#!i...](https://mva.microsoft.com/training-topics/web-
development#!index=6&lang=1033)

Looking at the courses available, I would probably start with:
[https://mva.microsoft.com/en-US/training-courses/getting-
sta...](https://mva.microsoft.com/en-US/training-courses/getting-started-with-
web-technologies-15937)

then look into either ASP.NET MVC: [https://mva.microsoft.com/en-US/training-
courses/introductio...](https://mva.microsoft.com/en-US/training-
courses/introduction-to-aspnet-mvc-8322)

or ASP.NET Core: [https://mva.microsoft.com/en-US/training-
courses/intermediat...](https://mva.microsoft.com/en-US/training-
courses/intermediate-aspnet-core-10-16964?l=Kvl35KmJD_4306218965)

This is coming from someone that hasn't actually used these, so take my
recommendations with a grain of salt.

------
benmorris
I have a ton of code that relies on System.Drawing so I've been watching this
closely. These are projects that go back over 10 years now. I have code in
both web server and client side versions. System.Drawing offers some features
that other image processing libraries don't. My use case probably isn't
typical but when you are trying to go back and forth from vector to raster
data you need access to the point data (along with manipulation) that is going
to be drawn. System.Drawing provides this flexibility through the GraphicsPath
object. It is good to see some official word on this though.

~~~
jamessouth
Chat to us on github. Our path drawing public API's are very similar to
System.Drawing so we may well be able to provide you with the same
functionality.

~~~
benmorris
I'll check it out James. I keep up with you on twitter, wish I had more time
to contribute. I have a lot of respect for your hard work though.

~~~
jamessouth
Thanks!

------
okreallywtf
Also take into account that rely on the GDI API won't work in Azure App
Services (which is where most new azure based web apps reside) [1]. It would
be nice if this reduced some of the issues with 3rd party libraries (pdf
generation etc) running inside of app services. We've had some issues having
to keep old web/worker roles around for this exact reason and it costs us more
money.

>Components rely on GDI API may not work on Azure Websites. The workaround is
moving to Azure Web Role. (If you are using the ReportViewer control, we have
enabled PDF generation for most applications.)

[1] [https://social.msdn.microsoft.com/Forums/en-
US/6ed5c738-390a...](https://social.msdn.microsoft.com/Forums/en-
US/6ed5c738-390a-4ca7-81d0-370124a4fc88/azure-websites-
faq?forum=windowsazurewebsitespreview)

------
alexc05
Is it a pipe dream to hope they go for DirectX in dotnetcore one day?

I'm so happy to read that they've gotten the image processing piece in place.

A while ago, on a bit of a lark and to see if I could, I started trying to
port a copy of selenium webdriver to DNC and was initially surprised bow how
successful I was in getting it to compile and build.

For the most part it was just re-pointing namespaces to their new locations.

When I got to the piece about image processing I hit a wall.

Maybe I'll take that on again sometime.

~~~
rubber_duck
>Is it a pipe dream to hope they go for DirectX in dotnetcore one day?

What do you mean ? DX is Windows specific, .NET core is cross platform. And DX
doesn't even have official .NET bindings on full .NET AFAIK.

OTOH I'm sure SharpDX and the likes could be ported (if it already isn't -
this :
[https://github.com/sharpdx/SharpDX/issues/520](https://github.com/sharpdx/SharpDX/issues/520)
suggest it should work but I haven't tried it)

~~~
mellinoe
Yes, SharpDX does work on .NET Core. Although it's not "official", it is
essentially the de-facto library for DirectX bindings.

------
romanovcode
Offtopic:

I am the only one who absolutely hates charts like [0]these? Like what are
those numbers on top, why it has no legend? Is it CPU utilization,
miliseconds, seconds (maybe it was done over 1000 images or so)?

[0] -
[https://msdnshared.blob.core.windows.net/media/2017/01/Resiz...](https://msdnshared.blob.core.windows.net/media/2017/01/ResizeWin.png)

~~~
endorphone
In this case does it matter though? The purpose of the chart is relative
performance, which it conveys minus a legend. Though I would agree that if
they aren't including the legend, they should remove the axis and standard
range labels entirely.

~~~
lanaius
It matters at a quick glance - is performance measured in images per
millisecond or milliseconds per image? The answer to that question is
obviously important to how you interpret the relative performance. Both
metrics (units per time and time per unit) are used widely in computing.

I was initially confused by the chart and yes the text (and following table)
make the units clear, but the chart should be standalone.

------
morrbo
Great to know, and good article. Can't help but feel that the author should
have put in the full compressed images so we can view them. From the table at
the bottom, Skia looks like it has quality issues, but it is kind of hard to
say without seeing the full-sized compressed images. The uncompressed ones are
on github, unless i've missed something, the compressed ones aren't.

~~~
bleroy
What do you mean? The test is doing resize and JPEG compression. If you're
interested in isolating the compression part, the code on GH should be super
easy to modify to your particular requirements.

------
aphextron
This seems like a really great use case for dotnetcore. I can see it being
perfect for an image manipulation microservice.

------
wolfspider
Why wasn't Pixman/Cairo tested but Skia was tested? I'm sure it has to do with
the natural availability of these things on .NET but I just checked and Cairo
still has binding pre and post Mono. I would consider this option strongly
there is way more support for Cairo in just about everything than Skia.

~~~
bleroy
Because it's not Skia that is tested, but SkiaSharp, which is a .NET / Mono
wrapper for Skia. It was included because the work to make it compatible with
.NET Core is close to completion and because it's promising work. I hope this
clarifies. If there were Pixman/Cairo .NET Core wrappers in existence or close
to completion, I'd be happy to update the post with them.

~~~
wolfspider
[https://github.com/zwcloud/CairoSharp](https://github.com/zwcloud/CairoSharp)

~~~
bleroy
Thanks, I'll check it out.

------
replete
Google's library destroys in benchmarks, but quality and filesize is lower
which suggests to me it wasn't a fair test.

The quality settings should have been standardised to human-perceived image
quality, given that's the purpose of an image.

~~~
bleroy
Unfortunately that's not possible. Each library makes choices and tradeoffs on
their defaults. Each time, I set whatever quality dials existed to the highest
available, and I standardized on 75 JPEG compression. There is no way to get
consistent quality across all libraries, which is why I included the results
for the 12 images used in the test in the blog post, so everyone can handle
this the way they want.

------
manigandham
There is also [https://imageresizing.net/](https://imageresizing.net/) with a
new ImageFlow library for cross-platform

~~~
bleroy
Yes, but that doesn't have a .NET Core library, and as such wasn't included in
the post.

------
pmalynin
Does anyone know when .NET Core will get a decent linear algebra library?

I've heard MathNet.Numerics has a plan to add it, but so far there seems to
not have been much progress.

------
jononor
5-10 megapixels input images might be more representative, as many phones
produce such sizes.

~~~
bleroy
It doesn't make a difference in the relative performance of the libraries on
the metrics in the post, it only makes the benchmarks slower to run. This
being said, the code is available, so this is easy for anyone to check. If I
ever get to do a memory benchmark, that would probably be a different story,
however.

------
thomasz
If you need something right now, consider imagemagick or graphicsmagick.

