<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="http://jamessouth.me/blog/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>James Jackson-South</title>
    <link>http://jamessouth.me/blog/</link>
    <description>Microsoft MVP, Creator of ImageSharp, ImageProcessor and ResponsiveBP, Web developer, Lifter of heavy weights, and all round nice guy.</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <item>
      <guid isPermaLink="false">1135</guid>
      <link>http://jamessouth.me/archive/imagesharpweb-my-continued-plans-for-world-image-dominance/</link>
      <category>System.String[]</category>
      <title>ImageSharp.Web  (My continued plans for world image dominance)</title>
      <description>&lt;h1&gt;I better build this before someone else does!&lt;/h1&gt;
&lt;p&gt;I recently read a series of blog posts by &lt;a href="https://andrewlock.net/using-imagesharp-to-resize-images-in-asp-net-core-a-comparison-with-corecompat-system-drawing/"&gt;Andrew Lock&lt;/a&gt; comparing &lt;strong&gt;ImageSharp&lt;/strong&gt; to &lt;strong&gt;CoreCompat.System.Drawing&lt;/strong&gt; in which he creates a simple ASP.NET Core &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware"&gt;Middleware&lt;/a&gt; for resizing image via a URI API. They're really, really great and I suggest you read them. &lt;/p&gt;
&lt;p&gt;These posts got me thinking though... I knew I was always going to build a URI API, I just didn't know when I was going to get around to it. I mean... I spend every spare waking hour plus ones I should be sleeping just now building &lt;a href="https://github.com/JimBobSquarePants/ImageSharp"&gt;ImageSharp&lt;/a&gt; (Big HINT &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/issues?q=is:issue%20is:open%20label:%22help%20needed%22"&gt;help me finish the bloody thing&lt;/a&gt;, it's been TWO YEARS!)&lt;/p&gt;
&lt;p&gt;It had to happen sooner rather than later as people are getting twitchy and &lt;strong&gt;ImageSharp&lt;/strong&gt; is getting very close to a beta release, so inspired by Andrew's brilliant writing I got busy...&lt;/p&gt;
&lt;h2&gt;Introducing ImageSharp.Web&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;ImageSharp.Web&lt;/strong&gt; is everything I wished &lt;a href="http://imageprocessor.org/imageprocessor-web/"&gt;ImageProcessor.Web&lt;/a&gt; was and I've only been writing the code for two days. I'm that happy with it. :)&lt;/p&gt;
&lt;p&gt;It runs on ASP.NET Core Middleware, is super extensible, and, should be able to support all your web-based imaging needs once finished. &lt;/p&gt;
&lt;p&gt;You can see the codebase as of time of writing &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/tree/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So how does it work?&lt;/p&gt;
&lt;h2&gt;The Pipeline&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The hip bone's connected to the...&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The Middleware intercepts the current request, an &lt;code&gt;IUriParser&lt;/code&gt; parses the request looking for commands and creates a dictionary of results.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;IImageService&lt;/code&gt; is assigned to the request. This will grab the image if required. &lt;/li&gt;
&lt;li&gt;An &lt;code&gt;IImageCache&lt;/code&gt; checks the cache for any previously processed results, if one found, we return the correct response (304, 200) and exit.&lt;/li&gt;
&lt;li&gt;Non cached? We process the file using a collection of &lt;code&gt;IImageWebProcessor&lt;/code&gt; instances using our collected commands via a &lt;code&gt;CommandParser&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The resultant image is cached using the &lt;code&gt;IImageCache&lt;/code&gt; and we return the result with the correct headers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Simples!&lt;/p&gt;
&lt;p&gt;If all goes well you get something like the following. &lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1055/is-web-output.png" alt="Output example for ImageSharp.Web" /&gt;&lt;/p&gt;
&lt;p&gt;So lets examine some of the interfaces I just mentioned. &lt;/p&gt;
&lt;h2&gt;Behind the Curtain&lt;/h2&gt;
&lt;p&gt;All the interfaces described in the pipeline are injected via the &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection"&gt;ASP.NET Core Dependency Injection&lt;/a&gt; container so you can replace them at will.&lt;/p&gt;
&lt;h2&gt;IUriParser&lt;/h2&gt;
&lt;p&gt;This is a neat little interface inspired by some feedback from Andrew that allows you to choose how commands are parsed from the URI. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface IUriParser
{
    IDictionary&amp;lt;string, string&amp;gt; ParseUriCommands(HttpContext context);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By default &lt;strong&gt;ImageSharp.Web&lt;/strong&gt; will parse &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/blob/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web/Commands/QueryCollectionUriParser.cs"&gt;querystring parameters&lt;/a&gt; but there's nothing to stop you from replacing that with something else. Maybe you want to parse something like &lt;code&gt;/resize/{width}/{height}/{path}&lt;/code&gt; who knows?!&lt;/p&gt;
&lt;h2&gt;IImageService&lt;/h2&gt;
&lt;p&gt;This interface is very similar to the ones found in &lt;a href="http://imageprocessor.org/imageprocessor-web/extending/#iimageservice"&gt;ImageProcessor.Web&lt;/a&gt; except it's a bit simpler&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface IImageService
{
    string Key { get; set; }

    IDictionary&amp;lt;string, string&amp;gt; Settings { get; set; }

    Task&amp;lt;bool&amp;gt; IsValidRequestAsync(HttpContext context, ILogger logger, string path);

    Task&amp;lt;byte[]&amp;gt; ResolveImageAsync(HttpContext context, ILogger logger, string path);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;key&lt;/code&gt; property there indicates an identifier in the URI that we use to choose which service to implement e.g &lt;code&gt;http://mysite.com/remote/http://remote-image.jpg?width=200&lt;/code&gt; would resolve to a &lt;code&gt;RemoteImageService&lt;/code&gt; (not built yet) as it uses the &lt;code&gt;remote&lt;/code&gt; prefix. Any implementations without a prefix match all requests.&lt;/p&gt;
&lt;p&gt;I've put together one so far, the &lt;code&gt;PhysicalFileImageService&lt;/code&gt;. You can see the code for that &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/blob/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web/Services/PhysicalFileImageService.cs"&gt;here&lt;/a&gt;. It's pretty simple but leverages the DI container to get certain functionality.&lt;/p&gt;
&lt;h2&gt;IImageCache&lt;/h2&gt;
&lt;p&gt;I didn't want to build this at first as I wanted to use the built in primitives like &lt;a href="https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.caching.distributed.idistributedcache"&gt;&lt;code&gt;IDistributedCache&lt;/code&gt;&lt;/a&gt; but the API of those primitives was both more complicated than I needed and also lacked the functionality to check if a cached item existed without retrieving it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface IImageCache
{
    IDictionary&amp;lt;string, string&amp;gt; Settings { get; set; }

    Task&amp;lt;CachedBuffer&amp;gt; GetAsync(string key);

    Task&amp;lt;CachedInfo&amp;gt; IsExpiredAsync(string key, DateTime minDateUtc);

    Task&amp;lt;DateTimeOffset&amp;gt; SetAsync(string key, byte[] value, int length);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It's again pretty simple but contains enough information to create any kind of cache you require. I've written a &lt;code&gt;PhysicalFileSystemCache&lt;/code&gt; &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/blob/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs"&gt;implementation&lt;/a&gt; so far for non-multi-tenant applications but I plan on creating others for Azure etc. (&lt;strong&gt;I will probably charge a small fee for those though as I need to start making some money off the back of my work&lt;/strong&gt; )  
&lt;/p&gt;
&lt;h2&gt;IImageWebProcessor&lt;/h2&gt;
&lt;p&gt;This is how we actually process the image. We pass our commands and process the image accordingly. There's an overload to &lt;code&gt;Image&amp;lt;TPixel&amp;gt;&lt;/code&gt; that loops through available processors. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface IImageWebProcessor
{
    IEnumerable&amp;lt;string&amp;gt; Commands { get; }

    Image&amp;lt;TPixel&amp;gt; Process&amp;lt;TPixel&amp;gt;(Image&amp;lt;TPixel&amp;gt; image, ILogger logger, IDictionary&amp;lt;string, string&amp;gt; commands)
        where TPixel : struct, IPixel&amp;lt;TPixel&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here's the &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/blob/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web/Processors/ResizeWebProcessor.cs"&gt;source code&lt;/a&gt; for the ResizeWebProcessor. This allows you to choose all the available resize options including the size, mode, and sampler. I'll knock up another couple of processors also that ship out-of-the-box too. AutoRotate, Format &amp;amp; BackgroundColor. Any additional ones will require $$ I'm afraid.&lt;/p&gt;
&lt;h2&gt;Commands&lt;/h2&gt;
&lt;p&gt;Parsing input commands is a non-trivial task. The web is a hostile environment and you not only have to deal with potential attacks, you have to deal with developers who are not keen on reading documentation. As such I have had to write a pluggable system of &lt;code&gt;ICommandConverter&lt;/code&gt; &lt;a href="https://github.com/JimBobSquarePants/ImageSharp/tree/eff6fed0eb1676c4e305be2b029255f6eb6fbdfe/src/ImageSharp.Web/Commands"&gt;implementations&lt;/a&gt; that are used by the &lt;code&gt;CommandParser&lt;/code&gt; singleton to deal with common parsing tasks. Again, this is extensible.&lt;/p&gt;
&lt;h2&gt;Rich Returns&lt;/h2&gt;
&lt;p&gt;The Middleware returns the correct response type for processed images (200, 304) and instructs the browser to cache the images for a configurable number of days (we max out by default at 365 days but of course this is configurable)!&lt;/p&gt;
&lt;p&gt;As such you will see a server response like the following.&lt;/p&gt;
&lt;h4&gt;Default Response&lt;/h4&gt;
&lt;p&gt;The result is processed and returned as normal.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1056/is-network.jpg" alt="Raw image processing response shown in the network tab" /&gt;&lt;/p&gt;
&lt;h4&gt;Cached Response&lt;/h4&gt;
&lt;p&gt;The result is cached so no request is made to the server.. Nippy!&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1057/is-network-cached.jpg" alt="Cached image processing response shown in the network tab" /&gt;&lt;/p&gt;
&lt;p&gt;There'll be an event that you can tap into also to add additional headers like Cors headers.&lt;/p&gt;
&lt;h2&gt;Gimme, Gimme, Gimme!&lt;/h2&gt;
&lt;p&gt;So when can you get your hands on this? &lt;/p&gt;
&lt;p&gt;Well... As soon as the main &lt;strong&gt;ImageSharp&lt;/strong&gt; library is ready for primetime I'll release a Nuget package for &lt;strong&gt;ImageSharp.Web&lt;/strong&gt;. By then any issues will be long ironed out and you'll have a great solution to you image processing needs in .NET Core. &lt;/p&gt;
&lt;p&gt;Of course, the sooner you give us a hand, the sooner that can happen ;)&lt;/p&gt;
&lt;p&gt;Please comment below, your feedback is super useful!&lt;/p&gt;
</description>
      <pubDate>Fri, 19 May 2017 06:08:11 Z</pubDate>
      <a10:updated>2017-05-19T06:08:11Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1124</guid>
      <link>http://jamessouth.me/archive/imageprocessor-core/</link>
      <category>System.String[]</category>
      <title>ImageProcessor Core</title>
      <description>&lt;h3&gt;So its been a while...&lt;/h3&gt;
&lt;p&gt;It's been roughly a year since my last &lt;a href="http://www.jamessouth.me/archive/mo-images-mo-processing/"&gt;blog post&lt;/a&gt;. I wrote it about a recent ImageProcessor release and opened the last paragraph with the following.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For me this release marks the last I shall actively work on in this
major version. It might well be the last I do ever depending on what
Microsoft do with graphics with the next .NET releases. I've fallen
out of love with the open source community a little over the years due
to the lack of collaboration I've received on this project and others.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sad eh?... Well it turns out I lied. Not only have I released several updates to the &lt;a href="http://www.nuget.org/packages/ImageProcessor/"&gt;V2 branch&lt;/a&gt; with some &lt;a href="https://github.com/jimbobsquarepants/imageprocessor/issues/49"&gt;great contributions&lt;/a&gt; from the community, but I've been hard at work on something a little special... &lt;strong&gt;&lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/Core"&gt;ImageProcessor Core&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;A Little History&lt;/h3&gt;
&lt;p&gt;In 2014 Microsoft blew everyone's minds by &lt;a href="https://blogs.msdn.microsoft.com/somasegar/2014/11/12/opening-up-visual-studio-and-net-to-every-developer-any-application-net-server-core-open-source-and-cross-platform-visual-studio-community-2013-and-preview-of-visual-studio-2015-and-net-2015/"&gt;announcing&lt;/a&gt; that they were building a new, open source, cross-platform framework containing a subset of the full .NET Framework. Everyone rightfully got very excited but a few people (me included) started to worry about the lack of discussion around a graphics API. Issues were opened up on the Github repo and quite a few people &lt;a href="https://github.com/dotnet/corefx/issues/2020"&gt;pitched in with their two cents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nobody was doing anything though and it was very frustrating for me to watch.&lt;/p&gt;
&lt;p&gt;You see, I have a dream...&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1047/toystory-images-everywhere.jpg" alt="Toy Story meme" /&gt;&lt;/p&gt;
&lt;p&gt;I originally wrote &lt;a href="http://imageprocessor.org"&gt;ImageProcessor&lt;/a&gt; to make it easier for developers to do common tasks with &lt;code&gt;System.Drawing&lt;/code&gt;. I kept seeing blog posts with copy/pasted code examples full of memory leaks and slow code and I wanted to make a difference and give back to a community I learned from.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/Core"&gt;ImageProcessor Core&lt;/a&gt; is an extension of that idea.&lt;/p&gt;
&lt;h3&gt;The Elevator Pitch&lt;/h3&gt;
&lt;p&gt;Common imaging tasks should be accessible to all developers. If you want to resize or crop an image you should be able to use a simple API and do so easily. You shouldn't have to worry about memory leaks and you shouldn't have to worry about  binding to native libraries or deploying in different environments. It should be cross-platform and it should &lt;strong&gt;Just Work &amp;trade;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Oh and of course it needs to be scalable and allow for complex operations and different pixel formats. You know... Simple stuff!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/Core"&gt;ImageProcessor Core&lt;/a&gt; is designed with that in mind.&lt;/p&gt;
&lt;p&gt;So what can it do? As of writing &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/Core"&gt;ImageProcessor Core&lt;/a&gt; is still very much in alpha status but it turns out quite a lot.&lt;/p&gt;
&lt;p&gt;I have....&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Algorithms for common operations. Resize, Crop, Flip, Rotate, Edge Detection and so on.&lt;/li&gt;
&lt;li&gt;Almost complete support for four different codecs. Bmp, Png, Gif, and of course the most complicated but commonplace of all Jpeg.&lt;/li&gt;
&lt;li&gt;Full EXIF read and write capability using a simple API.&lt;/li&gt;
&lt;li&gt;A generic image class that is signature compatible with Microsoft XNA Game Studio and MonoGame.&lt;/li&gt;
&lt;li&gt;A snazzy new logo that I designed myself :)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And much much more..&lt;/p&gt;
&lt;h3&gt;Example Time&lt;/h3&gt;
&lt;p&gt;To demonstrate the API I will show you some code demonstrating some common tasks. Here's how to resize an image using the default bicubic resampler.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using (FileStream input = File.OpenRead(&amp;quot;foo.jpg&amp;quot;))
using (FileStream output = File.OpenWrite(&amp;quot;bar.jpg&amp;quot;))
{
    Image image = new Image(input);
    image.Resize(image.Width / 2, image.Height / 2)
         .Save(output);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Want to use a different resampler? We've got you covered.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using (FileStream input = File.OpenRead(&amp;quot;foo.jpg&amp;quot;))
using (FileStream output = File.OpenWrite(&amp;quot;bar.jpg&amp;quot;))
{
    Image image = new Image(input);
    image.Resize(image.Width / 2, image.Height / 2, new MitchellNetravaliResampler())
         .Save(output);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How about companding the image to resize with &lt;a href="http://www.4p8.com/eric.brasseur/gamma.html"&gt;gamma correction&lt;/a&gt;?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;using (FileStream input = File.OpenRead(&amp;quot;foo.jpg&amp;quot;))
using (FileStream output = File.OpenWrite(&amp;quot;bar.jpg&amp;quot;))
{
    Image image = new Image(input);
    image.Resize(image.Width / 2, image.Height / 2, true)
         .Save(output);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How about setting individual pixel values?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Image image = new Image(400, 400);
using (PixelAccessor&amp;lt;Color, uint&amp;gt; pixels = image.Lock())
{
    pixels[200, 200] = Color.White;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How easy is that?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Image&lt;/code&gt; class is actually an implementation of a generic class &lt;code&gt;Image&amp;lt;TColor, TPacked&amp;gt;&lt;/code&gt; where &lt;code&gt;TColor&lt;/code&gt; implements an interface identical to the Microsoft XNA Game Studio and MonoGame &lt;a href="https://msdn.microsoft.com/en-us/library/bb197661.aspx"&gt;&lt;code&gt;IPackedVector&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;. This allows the library to work well with those frameworks and tightly control memory usage. Underneath the hood it's actually an &lt;code&gt;Image&amp;lt;Color, uint&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Performance&lt;/h3&gt;
&lt;p&gt;A lot of developers say that C# can never be truly fast. A lot of developers are wrong. I've got a long way to go yet but I've been able to get some pretty decent performance going in this early stage.&lt;/p&gt;
&lt;p&gt;Check out this benchmark using the awesome &lt;a href="https://github.com/PerfDotNet/BenchmarkDotNet"&gt;BenchMarkDotNet&lt;/a&gt; comparing a 2000x2000 pixel image downsampled to 400x400 pixels.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Host Process Environment Information:
BenchmarkDotNet-Dev.Core=v0.9.9.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-4712HQ CPU 2.30GHz, ProcessorCount=8
Frequency=2240907 ticks, Resolution=446.2479 ns, Timer=TSC
CLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
GC=Concurrent Workstation
JitModules=clrjit-v4.6.1080.0

Type=Resize  Mode=Throughput
                        Method |     Median |    StdDev | Scaled | Scaled-SD |
         System.Drawing Resize | 66.2606 ms | 1.2463 ms |   1.00 |      0.00 |
     ImageProcessorCore Resize | 56.4141 ms | 1.0673 ms |   0.85 |      0.02 |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Other methods like Crop are much faster and Get/Set pixel is ~94% faster than the &lt;code&gt;System.Drawing&lt;/code&gt; equivalent on my test machine.  I'm very happy with progress so far and I'm sure I can go much faster.&lt;/p&gt;
&lt;h3&gt;So What's The Plan?&lt;/h3&gt;
&lt;p&gt;It's been a very long alpha but I think the API is pretty solid so I shall be moving out of alpha and into beta status soon. Beta releases will be hosted on Nuget as opposed to the current &lt;a href="https://www.myget.org/gallery/imageprocessor"&gt;MyGet&lt;/a&gt; server though you shouldn't use it in production environments until I reach Release Candidate status.&lt;/p&gt;
&lt;p&gt;In beta I shall be concentrating on filling out missing encoder support (&lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/issues/446"&gt;you can help!&lt;/a&gt;) and really cranking up the performance. &lt;/p&gt;
&lt;p&gt;I'd love to get 2D drawing added to the API but that's probably better off in V1.1 as there's a lot of work involved. &lt;/p&gt;
&lt;h3&gt;Want To Help?&lt;/h3&gt;
&lt;p&gt;Please do... Spread the word, contribute algorithms, submit performance improvements, unit tests. Play around with the API and tell me what is missing. &lt;/p&gt;
&lt;p&gt;If you know someone who works in image processing please try to convince them to get involved. &lt;/p&gt;
&lt;p&gt;There's simply no reason why as a community we cannot build an absolute first-class imaging API that can benefit all levels of developer.&lt;/p&gt;
&lt;p&gt;So come on, &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor"&gt;visit the repo&lt;/a&gt; and get mucked in!&lt;/p&gt;
&lt;p&gt;Please let me know what you think in the comments below.&lt;/p&gt;
&lt;h3&gt;Update&lt;/h3&gt;
&lt;p&gt;Shannon below wanted to see the logo so drink it in. Pure design... Take that Instagram!&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1048/imageprocessor-logo-512.png" alt="ImageProcessor Logo" /&gt;&lt;/p&gt;
</description>
      <pubDate>Mon, 05 Sep 2016 09:45:56 Z</pubDate>
      <a10:updated>2016-09-05T09:45:56Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1122</guid>
      <link>http://jamessouth.me/archive/mo-images-mo-processing/</link>
      <category>System.String[]</category>
      <title>Mo Images Mo Processing</title>
      <description>&lt;p&gt;Today marks another big ImageProcessor release, and my first antipodean one - There's a lot going on so here's a run through of new functionality that's been added to &lt;strong&gt;Imageprocessor v2.4&lt;/strong&gt; and &lt;strong&gt;ImageProcessor.Web. v4.4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tl;dr... Upgrade&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;ImageProcessor&lt;/h1&gt;
&lt;h2&gt;New Stuff&lt;/h2&gt;
&lt;h3&gt;Resolution&lt;/h3&gt;
&lt;p&gt;This method allows you to change the resolution of the given image. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public ImageFactory Resolution(int horizontal, int vertical, PropertyTagResolutionUnit unit = PropertyTagResolutionUnit.Inch)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If any EXIF data is to be preserved, the metadata will be updated to match the given resolution.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Resize&lt;/h3&gt;
&lt;p&gt;With this release I've added two new resize modes to the library: &lt;code&gt;ResizeMode.BoxPad&lt;/code&gt; and &lt;code&gt;ResizeMode.Min&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ResizeMode.BoxPad&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;When upscaling an image using this mode the image pixels themselves are not resized, rather the image is padded to fit the given dimensions. When downscaling the image is resized using the rules defined by &lt;code&gt;ResizeMode.Pad&lt;/code&gt;. As with that mode you can recolour the background colour of the padded area for image types without transparency from the default black.&lt;/p&gt;
&lt;p&gt;Here's an example resizing the original to 500x500px:&lt;/p&gt;
&lt;div class="row"&gt;
&lt;div class="col-m-6"&gt;
 &lt;h4&gt;Original Image &lt;/h4&gt;
&lt;img src="http://jamessouth.me/blog/media/1046/car-small.jpg"/&gt;
&lt;/div&gt;
&lt;div class="col-m-6"&gt;
&lt;h4&gt;Padded Image With Hot Pink Background &lt;/h4&gt;
&lt;img src="http://jamessouth.me/blog/media/1046/car-small.jpg?width=500&amp;height=500&amp;mode=boxpad&amp;bgcolor=hotpink"/&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As with &lt;code&gt;ResizeMode.Pad&lt;/code&gt; and &lt;code&gt;ResizeMode.Crop&lt;/code&gt; the position of the image can be anchored to one of nine different anchor points.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ResizeMode.Min&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;This mode looks for the shortest difference in each dimension between the source length and intended length. it will then resize that side to the intended length on the result, the other dimension is resized maintaining the aspect ratio of the original image. Upscaling is disabled in this mode and the original image will be returned if attempted.&lt;/p&gt;
&lt;p&gt;Here's an example downscaling a larger version of the original with target dimensions of  500x500px:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1006/car.jpg?width=500&amp;amp;height=500&amp;amp;mode=min" alt="Image resized using ResizeMode.Min" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;I've managed to reduce the memory usage by up to 25% in some circumstances in this version by rewriting the way I ensure certain methods performs their functionality in the correct colour space. These rewrites have also slightly improved the speed on earlier releases which is a nice bonus.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Bug fixes&lt;/h2&gt;
&lt;p&gt;In this release I've ironed out numerous bugs relating to image resolution. EXIF metadata for any method that changes the dimension of the image are now updated also where previously this was overlooked.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;ImageProcessor.Web&lt;/h1&gt;
&lt;h2&gt;New Stuff&lt;/h2&gt;
&lt;h3&gt;PostProcessing&lt;/h3&gt;
&lt;p&gt;This is a big one and I'm very pleased with it...&lt;/p&gt;
&lt;p&gt;I'm all about keeping the web lean but the default image encoders in .NET are not that efficient and you can sometimes actually end up with a &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/issues/208"&gt;larger image&lt;/a&gt; than what you started with. As such, I've been looking at a way to ensure that anything I output has been optimised as much as possible. For previous versions of &lt;strong&gt;ImageProcessor.Web&lt;/strong&gt; I developed a plugin that post-processed any newly cached images using a variety of tools to reduce the file size as much as possible.  
&lt;/p&gt;
&lt;p&gt;This worked... To a point. Firstly it only worked with the disk cache and not any other cache plugins. Secondly it only acted after the first requests so someone, somewhere would always get an unoptimised image, Thirdly one of the tools I used, optipng was incorrectly detected as malware by Windows Defender.... Not good enough.&lt;/p&gt;
&lt;p&gt;As of this version, &lt;strong&gt;every image that is processed using ImageProcessor.Web is passed through a series of tools that reduce the output size&lt;/strong&gt;. This works with whatever cache implementation is used and can dramatically reduce the weight of your pages. This all happens asynchronously and stays snappy so you shouldn't notice any increased processing time.&lt;/p&gt;
&lt;p&gt;Here's the built in tools I use so you can check them out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gifsicle : http://www.lcdf.org/gifsicle/&lt;/li&gt;
&lt;li&gt;pngout : http://advsys.net/ken/utils.htm#pngout&lt;/li&gt;
&lt;li&gt;pngquant : https://pngquant.org/&lt;/li&gt;
&lt;li&gt;jpegtran : http://jpegclub.org/&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's possible to turn off this behaviour vie the &lt;a href="http://imageprocessor.org/imageprocessor-web/configuration/"&gt;config&lt;/a&gt; but you really shouldn't.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Bug fixes&lt;/h3&gt;
&lt;p&gt;There's been various minor little issues I've found and fixed while building this update, one of note though was an &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/issues/211"&gt;issue&lt;/a&gt; where prefix values were globally replaced within the request url.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;So... What's Next?&lt;/h1&gt;
&lt;p&gt;For me this release marks the last I shall actively work on in this major version.  It might well be the last I do ever depending on what Microsoft do with graphics with the next .NET releases. I've fallen out of love with the open source community a little over the years due to the lack of collaboration I've received on this project and others. &lt;/p&gt;
&lt;p&gt;When I started ImageProcessor I didn't know much about images. I was a front end developer who decided to have a go at solving a problem colleagues were struggling with. I'd only been writing C# for a very short while and I was learning as I went on.... I still am. &lt;/p&gt;
&lt;p&gt;These libraries are now hugely popular with hundreds of thousands of downloads but the number of people who contribute is still minuscule. If I can write this stuff I guarantee there are a very great number of people out there who could do it and do it better. &lt;/p&gt;
&lt;p&gt;I'm very grateful for the work and encouragement of the team at Umbraco for their faith in me and contribution to my code but I feel somewhat that they are alone in doing what they do best in promoting a healthy community around developers.&lt;/p&gt;
&lt;p&gt;I'll still fix bugs but I will not add any more new features nor work on making the library cross-platform for now. It's simply too much work for me to do.&lt;/p&gt;
&lt;h3&gt;Help Me To Help You&lt;/h3&gt;
&lt;p&gt;If you want to see ImageProcessor continue and you know anyone with the chops to help me or think you can spend an hour a week tinkering away, please get in touch. I'd love to build a &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/5c94066bc5e020d9fc34364573c62c049aa5103f"&gt;v3&lt;/a&gt; as part of a community of developers creating something amazing.&lt;/p&gt;
&lt;p&gt;Anyhoo... Enjoy the new releases. As ever you can read about them in the documentation and download them from Nuget.&lt;/p&gt;
</description>
      <pubDate>Sun, 20 Sep 2015 04:16:08 Z</pubDate>
      <a10:updated>2015-09-20T04:16:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1118</guid>
      <link>http://jamessouth.me/archive/announcing-imageprocessorwebpostprocessor/</link>
      <category>System.String[]</category>
      <title>Announcing ImageProcessor.Web.PostProcessor</title>
      <description>&lt;h2&gt;The Nourishing Fruits of Boredom&lt;/h2&gt;
&lt;p&gt;So last night I got a little bored watching the old haunted fishtank and my mind, as it often does, drifted to code.&lt;/p&gt;
&lt;p&gt;I started thinking about a &lt;a href="http://stream.umbraco.org/video/9950321/the-future-of-aspnet-web-tooling"&gt;talk&lt;/a&gt; that &lt;a href="https://twitter.com/mkristensen"&gt;Mads Kristensen&lt;/a&gt; gave at CodeGarden this year that featured a tool he had written with &lt;a href="https://twitter.com/sayedihashimi"&gt;Sayed I. Hashimi&lt;/a&gt; called Azure Image Optimizer which wraps various tools like Jpegtran and Gifsicle in an Azure Job to optimize your file based images. He writes about it &lt;a href="http://madskristensen.net/post/automatic-optimization-of-images-css-and-javascript"&gt;here&lt;/a&gt; and the source can be found &lt;a href="https://github.com/ligershark/AzureJobs"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I thought it was really nifty and since they've kindly released it under the wonderfully permissive Apache 2.0 license I decided to see if I could grab some of the goodies from the code and add something to &lt;a href="http://imageprocessor.org/imageprocessor-web/"&gt;ImageProcessor.Web&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Three hours later &lt;a href="https://www.nuget.org/packages/ImageProcessor.Web.PostProcessor/"&gt;ImageProcessor.Web.PostProcessor&lt;/a&gt; was born...&lt;/p&gt;
&lt;h2&gt;How It Works&lt;/h2&gt;
&lt;p&gt;ImageProcessor.Web fires an event once an image has been processed and saved to the cache that can be wired up to asynchronously to further manipulate that file. Tapping into it is  fairly simple.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ImageProcessingModule.OnPostProcessing += YOUR_POST_PROCESSING_METHOD_ASYNC;

private static async void YOUR_POST_PROCESSING_METHOD_ASYNC(object sender, PostProcessingEventArgs e)
{
     // Do your thang...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Where &lt;code&gt;PostProcessingEventArgs&lt;/code&gt; contains a single property &lt;code&gt;CachedImagePath&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In ImageProcessor.Web.PostProcessor I have embedded copies of the various image compressing tools: &lt;a href="http://www.lcdf.org/gifsicle/"&gt;Gifsicle&lt;/a&gt;, &lt;a href="http://jpegclub.org/jpegtran/"&gt;Jpegtran&lt;/a&gt;, &lt;a href="http://optipng.sourceforge.net/"&gt;Optipng&lt;/a&gt;, and &lt;a href="http://advsys.net/ken/utils.htm"&gt;Pngout&lt;/a&gt; which are extracted into the running web applications folder and are used to further compress the cached images whenever the event is fired. &lt;/p&gt;
&lt;p&gt;If a saving can be found then the cached file is replaced with the newly optimized image and voila your fancy-dancy website is now even leaner and you can celebrate by having a beverage of your choice. &lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Simply install the &lt;a href="https://www.nuget.org/packages/ImageProcessor.Web.PostProcessor/"&gt;package&lt;/a&gt; from Nuget and it will instantly kick in; there's no configuration required so go and get it now.&lt;/p&gt;
&lt;p&gt;As ever the source code can be found &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cheers M'dears!&lt;/p&gt;
</description>
      <pubDate>Thu, 18 Dec 2014 02:32:46 Z</pubDate>
      <a10:updated>2014-12-18T02:32:46Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1116</guid>
      <link>http://jamessouth.me/archive/imageprocessorweb-410-released/</link>
      <category>System.String[]</category>
      <title>ImageProcessor.Web 4.1.0 Released!</title>
      <description>&lt;p&gt;Following yesterdays &lt;a href="http://jamessouth.me/archive/imageprocessor-210-released/"&gt;post&lt;/a&gt; charting the updates in the the core ImageProcessor library I'm going to take the time to chart the updates in the new 4.1.0 release of &lt;a href="https://www.nuget.org/packages/ImageProcessor.Web/"&gt;ImageProcessor.Web&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;New Stuff&lt;/h1&gt;
&lt;h3&gt;Methods&lt;/h3&gt;
&lt;p&gt;All the new methods available to ImageProcessor are available to ImageProcessor.Web. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pixelate &lt;/li&gt;
&lt;li&gt;DetectEdges &lt;/li&gt;
&lt;li&gt;EntropyCrop &lt;/li&gt;
&lt;li&gt;Mask &lt;/li&gt;
&lt;li&gt;Overlay &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Syntactically they are invoked using familiar rules similar to preexisting methods.&lt;/p&gt;
&lt;p&gt;For example.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http://your-image?detectedges=prewitt&amp;amp;greyscale=false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Will produce an image with a &lt;a href="http://en.wikipedia.org/wiki/Prewitt_operator"&gt;Prewitt&lt;/a&gt; operator applied that also retains the original image colours.&lt;/p&gt;
&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1024/mana.jpg" alt="enter image description here" /&gt;&lt;/p&gt;
&lt;h3&gt;Processed&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1024/mana.jpg?detectedges=prewitt&amp;amp;greyscale=false" alt="enter image description here" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Swish!&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Handling Images in Instructions&lt;/h3&gt;
&lt;p&gt;Two of the new methods: &lt;a href="http://imageprocessor.org/imageprocessor-web/imageprocessingmodule/mask.html"&gt;Mask&lt;/a&gt; &amp;amp; &lt;a href="http://imageprocessor.org/imageprocessor-web/imageprocessingmodule/overlay.html"&gt;Overlay&lt;/a&gt; accept images as parameters in part of their instruction sets. 
Rather than passing the entire path to the url (which would open up all sorts of security issues) you set the image name only as a parameter. These are mapped to two preconfigured locations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mask- &lt;code&gt;~/images/imageprocessor/mask/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Overlay - &lt;code&gt;~/images/imageprocessor/overlay/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These can both be overwritten by installing the &lt;a href="https://www.nuget.org/packages/ImageProcessor.Web.Config/"&gt;ImageProcessor.Web.Config&lt;/a&gt; package from Nuget and changing the settings in the &lt;code&gt;processing.config&lt;/code&gt;
file.&lt;/p&gt;
&lt;p&gt;Here's the two of them in action.&lt;/p&gt;
&lt;h3&gt;Mask&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;http://your-image??mask=mask.png&amp;amp;mask.position=30,30&amp;amp;format=png
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1022/lock.jpg" alt="Locks on a gate" /&gt;&lt;/p&gt;
&lt;h3&gt;Masked&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1022/lock.jpg?mask=mask.png&amp;amp;mask.position=30,30&amp;amp;format=png" alt="Masked image of locks on a gate" /&gt;&lt;/p&gt;
&lt;h3&gt;Overlay&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;http://your-image?overlay=monster.png&amp;amp;overlay.position=30,30&amp;amp;overlay.size=100,100&amp;amp;overlay.opacity=80
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1042/bear.jpg" alt="A Grizzly bear" /&gt;&lt;/p&gt;
&lt;h3&gt;Overlay Applied&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1042/bear.jpg?overlay=monster.png&amp;amp;overlay.position=30,30&amp;amp;overlay.size=100,100&amp;amp;overlay.opacity=80" alt="A Grizzly bear" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Moar New Stuff&lt;/h1&gt;
&lt;h3&gt;IImageService&lt;/h3&gt;
&lt;p&gt;With this version comes a new system for supplying ImageProcessor.Web images to process; &lt;code&gt;IImageService&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;The &lt;code&gt;IImageService&lt;/code&gt; interface defines methods and properties which allow developers to extend ImageProcessor.Web to retrieve images from alternate locations to process. Think pulling images from from a &lt;a href="https://www.simple-talk.com/sql/learn-sql-server/an-introduction-to-sql-server-filestream/"&gt;SqlServer filestream&lt;/a&gt; or from another custom service.&lt;/p&gt;
&lt;p&gt;Creating a new service simply requires implementing the interface to supply a prefix and a byte array.&lt;/p&gt;
&lt;p&gt;The interface looks like this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
///  Defines properties and methods for allowing retrieval of image from different sources.
/// &amp;lt;/summary&amp;gt;
public interface IImageService
{
    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the prefix for the given implementation.
    /// &amp;lt;remarks&amp;gt;
    /// This value is used as a prefix for any image requests that should use this service.
    /// &amp;lt;/remarks&amp;gt;
    /// &amp;lt;/summary&amp;gt;
    string Prefix { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets a value indicating whether the image service requests files from
    /// the locally based file system.
    /// &amp;lt;/summary&amp;gt;
    bool IsFileLocalService { get; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or sets any additional settings required by the service.
    /// &amp;lt;/summary&amp;gt;
    Dictionary&amp;lt;string, string&amp;gt; Settings { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets or sets the white list of &amp;lt;see cref=&amp;quot;System.Uri&amp;quot; /&amp;gt;. 
    /// &amp;lt;/summary&amp;gt;
    Uri[] WhiteList { get; set; }
    /// &amp;lt;summary&amp;gt;
    /// Gets a value indicating whether the current request passes sanitizing rules.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;path&amp;quot;&amp;gt;
    /// The image path.
    /// &amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;
    /// &amp;lt;c&amp;gt;True&amp;lt;/c&amp;gt; if the request is valid; otherwise, &amp;lt;c&amp;gt;False&amp;lt;/c&amp;gt;.
    /// &amp;lt;/returns&amp;gt;
    bool IsValidRequest(string path);
    /// &amp;lt;summary&amp;gt;
    /// Gets the image using the given identifier.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&amp;quot;id&amp;quot;&amp;gt;
    /// The value identifying the image to fetch.
    /// &amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;
    /// The &amp;lt;see cref=&amp;quot;System.Byte&amp;quot; /&amp;gt; array containing the image data.
    /// &amp;lt;/returns&amp;gt;
    Task&amp;lt;byte[]&amp;gt; GetImage(object id);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Both the local and remote image service implement this interface. View the &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/tree/master/src/ImageProcessor.Web/Services"&gt;source code&lt;/a&gt; to see examples.&lt;/p&gt;
&lt;h1&gt;Extras&lt;/h1&gt;
&lt;p&gt;With this release I upped the cache to hold 100 images per folder. This now increases the theoretical cache limit to &lt;strong&gt;409,600,000,000&lt;/strong&gt; images though I don't think anyone will be hitting that kind of limit any time soon.&lt;/p&gt;
&lt;p&gt;There's a few performance improvements thrown in also that will make things snappier than ever.&lt;/p&gt;
&lt;h1&gt;In Summary&lt;/h1&gt;
&lt;p&gt;I'm pleased with this release and the benefits it offers. There's only a few feature I think that ImageProcessor.Web is missing (Face detection being one) so I hope  you are enjoying using it as much as I do building it.&lt;/p&gt;
</description>
      <pubDate>Wed, 12 Nov 2014 06:14:43 Z</pubDate>
      <a10:updated>2014-11-12T06:14:43Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1115</guid>
      <link>http://jamessouth.me/archive/imageprocessor-210-released/</link>
      <category>System.String[]</category>
      <title>ImageProcessor 2.1.0 Released!</title>
      <description>&lt;p&gt;Today marks the release of the latest version of &lt;a href="http://imageprocessor.org/"&gt;ImageProcessor&lt;/a&gt; My super, fantastic open source imaging library.&lt;/p&gt;
&lt;p&gt;This is a pretty big release with a multitude of new functionality, performance improvements and bug fixes. I'll run through some of them here and try not to ramble on too much in the process. It's gonna be very image heavy so I recommend a broadband connection.&lt;/p&gt;
&lt;h1&gt;New Stuff&lt;/h1&gt;
&lt;h2&gt;Pixelate&lt;/h2&gt;
&lt;p&gt;This new method allows you to pixelate an image by passing a pixel size to the &lt;code&gt;ImageFactory&lt;/code&gt; in the following format.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public ImageFactory Pixelate(int pixelSize, Rectangle? rectangle = null)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If a rectangle is passed that will constrain the method to only pixelate a portion of the original image.&lt;/p&gt;
&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1042/bear.jpg" alt="Original picture of a really cool bear" /&gt;&lt;/p&gt;
&lt;h3&gt;Pixelated&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1042/bear.jpg?pixelate=10" alt="Pixilated picture of a really cool bear" /&gt;&lt;/p&gt;
&lt;p&gt;Cool eh?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;DetectEdges&lt;/h2&gt;
&lt;p&gt;This method allows you to detect points within an image where the brightness changes sharply. There's lots of different algorithms available to do this using some pretty wild maths see &lt;a href="http://en.wikipedia.org/wiki/Edge_detection"&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The method is called as follows.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public ImageFactory DetectEdges(IEdgeFilter filter, bool greyscale = true)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've added 9 different detection methods to get started with.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KayyaliEdgeFilter &lt;/li&gt;
&lt;li&gt;KirschEdgeFilter &lt;/li&gt;
&lt;li&gt;Laplacian3X3EdgeFilter&lt;/li&gt;
&lt;li&gt;Laplacian5X5EdgeFilter &lt;/li&gt;
&lt;li&gt;LaplacianOfGaussianEdgeFilter&lt;/li&gt;
&lt;li&gt;PrewittEdgeFilter &lt;/li&gt;
&lt;li&gt;RobertsCrossEdgeFilter &lt;/li&gt;
&lt;li&gt;ScharrEdgeFilter&lt;/li&gt;
&lt;li&gt;SobelEdgeFilter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here an example of it in action using the &lt;code&gt;PrewittEdgeFilter&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1045/bridge.jpg" alt="Original picture of a bridge" /&gt;&lt;/p&gt;
&lt;h3&gt;Edges Detected&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1045/bridge.jpg?detectedges=prewitt" alt="Greyscale picture of a bridge with edges detected" /&gt;&lt;/p&gt;
&lt;h3&gt;Edges Detected  - Keeping Original Colours&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1045/bridge.jpg?detectedges=prewitt&amp;amp;greyscale=false" alt="Picture of a bridge with edges detected" /&gt;&lt;/p&gt;
&lt;p&gt;Edge detection is one of the fundamental tools of image processing. I use it internally for this method.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;EntropyCrop&lt;/h2&gt;
&lt;p&gt;This one I built for my good friend &lt;a href="https://twitter.com/crumpled_jeavon"&gt;Jeavon Leopold&lt;/a&gt; who preyed upon by inability to resist a challenge. It looks for the area of highest entropy within an image and crops around it. It works particularly well with images containing large areas of a single color or similar colors around the edges.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public ImageFactory EntropyCrop(byte threshold = 128)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1014/field.jpg" alt="Picture of a field" /&gt;&lt;/p&gt;
&lt;h3&gt;Cropped to Area of Highest Entropy&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1014/field.jpg?entropycrop=128" alt="Picture of a field cropped" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;There's three other new methods added to the &lt;code&gt;Imagefactory&lt;/code&gt; class but I'll just link to the docs as I don't want to go on.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://imageprocessor.org/imageprocessor/imagefactory/replacecolor.html"&gt;ReplaceColor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://imageprocessor.org/imageprocessor/imagefactory/mask.html"&gt;Mask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://imageprocessor.org/imageprocessor/imagefactory/overlay.html"&gt;Overlay&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Moar New Stuff&lt;/h2&gt;
&lt;p&gt;In this release I've also managed to add a shiny new quantizer based on a vastly improved version of &lt;a href="http://nquant.codeplex.com/"&gt;nQuant&lt;/a&gt;. This dramatically improves the output of indexed png files.
Considering these images contain only 256 colors the output is extraordinary! &lt;/p&gt;
&lt;h3&gt;Original&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1027/new-york.jpg" alt="New York Scene" /&gt;&lt;/p&gt;
&lt;h3&gt;Indexed PNG&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1027/new-york.jpg?format=png8" alt="New York Scene" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Performance&lt;/h1&gt;
&lt;p&gt;Performance under the hood has been vastly improved. Using a combination of Parallelisation techniques and a new &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor/blob/master/src/ImageProcessor/Imaging/FastBitmap.cs"&gt;FastBitmap&lt;/a&gt; class I was able to improve methods such as &lt;code&gt;GaussianBlur&lt;/code&gt; by up to 7X which was very pleasing.  Every single method that could be has been rewritten to take advantage of the new techniques which has made ImageProcessor purr like a wolverine.&lt;/p&gt;
&lt;p&gt;I've also been testing continuously to ensure that memory usage is kept consistently low  - I'm very pleased with the results.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Bug Fixes&lt;/h1&gt;
&lt;p&gt;Version 2.1 now correctly handles images of different resolutions. In some circumstances it was possible to throw certain combinations of methods off  like &lt;code&gt;Resize&lt;/code&gt; and &lt;code&gt;Rotate&lt;/code&gt; for example by passing them an image of a higher resolution than the default 96dpi. This has now been fixed.&lt;/p&gt;
&lt;p&gt;I've also fixed a timing ( rounding error) issue within animated gifs and an encoding one which was making them impossible to share on Twitter. You can now share them anywhere you like.&lt;/p&gt;
&lt;p&gt;On that note I bet you didn't realise that all the methods can be applied to animated gifs did you?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://jamessouth.me/blog/media/1003/mccoy-kirk.gif?pixelate=8&amp;amp;rotate=45" alt="Pixelated, rotated Kirk" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Anyhoo&lt;/h1&gt;
&lt;p&gt;I hope this has got you all excited and you find it useful. &lt;/p&gt;
&lt;p&gt;This release has been a &lt;strong&gt;LOT&lt;/strong&gt; of hard work and as ever if you think you can help in anyway then please do. The .NET community needs a tool like this and I can only keep supporting and improving it with your help to please &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor"&gt;Get Involved&lt;/a&gt;. &lt;/p&gt;
</description>
      <pubDate>Tue, 11 Nov 2014 07:14:07 Z</pubDate>
      <a10:updated>2014-11-11T07:14:07Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1113</guid>
      <link>http://jamessouth.me/archive/image-processing-for-everybody/</link>
      <category>System.String[]</category>
      <title>Image Processing for Everybody!</title>
      <description>&lt;h2&gt;Happy ImageProcessing Day!&lt;/h2&gt;
&lt;p&gt;Today marks the new release of my open source project &lt;a href="http://imageprocessor.org/"&gt;ImageProcessor&lt;/a&gt;. I'm very proud of it.&lt;/p&gt;
&lt;p&gt;Inspired by the frantic codings of the brilliant people I met at this years &lt;a href="http://codegarden14.com/"&gt;Umbraco CodeGarden&lt;/a&gt; retreat this release has turned into an almost complete rewrite of the library. I've dramatically simplified the code required to write plugins whilst making the library much more robust and modular adding a few very cool (I think so anyway) features.&lt;/p&gt;
&lt;p&gt;We now have the following:&lt;/p&gt;
&lt;h3&gt;ImageProcessor&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Automatic image file type detection&lt;/li&gt;
&lt;li&gt;Automatic plugin detection&lt;/li&gt;
&lt;li&gt;Ability to extend image file type support via the &lt;code&gt;ISupportedImageFormat&lt;/code&gt; interface&lt;/li&gt;
&lt;li&gt;Ability to extend individual processors via the &lt;code&gt;IGraphicsProcessor&lt;/code&gt; interface &lt;/li&gt;
&lt;li&gt;Methods to load embedded native (unmanaged) libraries from within plugins&lt;/li&gt;
&lt;li&gt;True separation of concerns from the .Web extension.&lt;/li&gt;
&lt;li&gt;More specific error handling feedback&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ImageProcessor.Web&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Automatic plugin detection&lt;/li&gt;
&lt;li&gt;Ability to extend individual processors via the &lt;code&gt;IWebGraphicsProcessor&lt;/code&gt; interface &lt;/li&gt;
&lt;li&gt;Improved and more consistent parsing syntax.&lt;/li&gt;
&lt;li&gt;Improved processing and caching performance&lt;/li&gt;
&lt;li&gt;More images are now cached (theoretically 409,600,000,000)&lt;/li&gt;
&lt;li&gt;Post processing events to tap into. &lt;code&gt;ImageProcessingModule.OnPostProcessing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Improved error handling for remote image requests&lt;/li&gt;
&lt;li&gt;Url configurable EXIF preservation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There's more but it's probably best for you to read the &lt;a href="http://imageprocessor.org/"&gt;documentation&lt;/a&gt;. As ever, it's a work in progress but I've tried to make them readable and precise. If you want to help at any point to improve the library, there is always a good place to start.&lt;/p&gt;
&lt;p&gt;I'd really like to thank &lt;a href="http://www.hanselman.com/"&gt;Scott Hanselman&lt;/a&gt; for sharing the library on his blog and the &lt;a href="http://umbraco.com/"&gt;Umbraco&lt;/a&gt; team and community for their continuing support and faith in my ability. You guys absolutely rock! #h5yr's and approving nods all round! 
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;img src="http://jamessouth.me/blog/media/1003/mccoy-kirk.gif" alt="Kirk McCoy nodding original" /&gt;
&lt;img src="http://jamessouth.me/blog/media/1003/mccoy-kirk.gif?width=150" alt="Kirk McCoy nodding resized" /&gt;&lt;/p&gt;
</description>
      <pubDate>Wed, 27 Aug 2014 02:51:45 Z</pubDate>
      <a10:updated>2014-08-27T02:51:45Z</a10:updated>
    </item>
  </channel>
</rss>