Paint.NET 4.0 “fine grained history” and other stuff

One nice thing about the Move tools in Paint.NET is that they implement something I call fine-grained history. When you go to edit a selection or move its pixels around, you get 1 history entry for each adjustment you make. This allows you to move it around, rotate it, etc. and then when you press “Undo” it only backs out of the most recent adjustment you made. Contrast this to the Gradient, Line/Curve, and Text tools which don’t keep track of each edit you make and can only undo things wholesale.

Recently I’ve been working on adding this to the Gradient tool for 4.0. This support will then make its way into the shape tools, and probably the Text tool as well (also, shapes will be undergoing an overhaul soon). The reason I’ve been working on the Gradient tool is that it is a fairly simple tool and this allows me to get the code for fine-grained history working without having to worry about as many “moving parts.”

Here’s a screenshot showing the Gradient tool having gone through it’s initial “draw” operation, followed by two “edit” operations:

(click for full resolution version)

Once this makes its way to the new Shapes tool (not yet written unfortunately), you’ll be able to: 1) draw a shape, 2) move, rotate, resize the shape, 3) change the colors, 4) change the stroke, 5) change any other properties, and then 6) finish/commit it to the layer. Currently the shape tools in v3.5 are fairly barbaric and don’t even let you change their color or other properties once you’ve pressed down the mouse button. It can be quite painful if you are consistently off by a few pixels and have to constantly redo your Rectangle until it’s just right.

There are some other important benefits to doing this. I’ll be able to significantly reduce memory usage, for starters. In Paint.NET v3.5, the tools are implemented in a rather cumbersome way. While you draw, it’s modifying the layer data so it contains what you’re drawing … then it draws that to the screen. Then, when you move the mouse it has to copy back the original contents of the layer before drawing the new stuff. When you’re done, it has to copy back the original pixels, save it to disk, then redraw everything one last time. This is implemented with a very carefully debugged protocol that requires all sorts of data to be copied around various buffers before, during, and after any edit operation. Any bug in the protocol for drawing, copying, and emitting history entries can lead to data loss.

With the new system, the gradient (et. al.) draws itself using a layer overlay, which only affects the rendering pipeline and not the image itself. Undoing the edit before it’s committed is a simple matter of throwing away the overlay. When it’s time to commit the drawing, the code just says “hey I changed this rectangular area” and then a simple diffing algorithm copies away only the parts of the layer that changed. There’s no need for me to manage complicated geometry masks and dirty regions any more (other than what’s needed for an active selection, of course). All the large and temporary (and permanent, ack!) buffers are simply no longer needed.

This is all very important! Reducing memory usage is very important for an application like Paint.NET, especially on 32-bit systems. This also removes another barrier toward migrating to a fully tile-based memory allocator, which then opens up doors for many other very, very cool features.

Another benefit to doing this is that it moves the tool rendering code off of the UI thread and into the rendering pipeline (which was already moved off the UI thread for 4.0). The UI will always be responsive while you’re drawing, even if the canvas is still “catching up” to what you’ve done. It’s pretty cool to be able to throw around the Gradient tool’s “handles” (aka “nubs”) and see them responding at a much higher framerate than the canvas itself. If you’ve ever had to work with an image that is very large, or has a lot of layers, or both, then you probably already know that this will be a great thing.

Also, right now the Move Selected Pixels tool is a monster (for me that is; not for you). While it does work perfectly well, the code is wildly complicated and fragile. Adding or changing any features would be a recipe for disaster. By migrating it to this much simpler system, I’ll be able to reduce memory usage further, increase performance and quality, and remove any “hitch” you may notice at the start of a move operation. The reason the “hitch” happens is that the history data (the layer’s pixels) must be saved off into a temporary buffer before any rendering can be done. Afterward, there’s a frightening dance of copying pixel data from the layer to a scratch area, and then transforming pixels from a 2nd copy back to the layer, and then undoing it all before redoing it, etc. The nightmare gets worse when history entries come into the mix. The code is basically the worst time travel paradox you could possibly imagine – I can’t honestly say I fully understand how it works, even though I wrote it. What I can say is that it works, but only because it’s been thoroughly and exhaustively tested, debugged, and bugfixed.

Oh, and you’ll notice in this screenshot that I’ve finished up the last bits of UI reorganizing. I’ve done away with the Window and Utilities menus. Instead, each of the floating windows has its own toggle button at the top-right. The gear icon opens up the Settings dialog, and the question mark icon gives you the traditional help menu. Anything that was in the Utilities menu has either been moved into the Settings dialog, or removed. I‘ve also increased the size of these icons to 24×24 because I found they were just too darn small at 16×16.

Within the Settings dialog I’ve added a Diagnostics page which gives you a peek at your system information as Paint.NET sees it (basically the information that’s printed at the top of a crash log, and more). It will also give you access to the crash logs folder and some other simple things that should make troubleshooting a bit simpler. Oh, and for those who don’t like the “dancing ants” (animated selection outline), I’ve included a checkbox to control whether this is on or off (not on the Diagnostics tab though).

In time, I hope to elaborate further on what I mean by “this stuff opening doors for other very cool features.” I’ve been throwing around ideas for the last few days and it’s exciting how much things are radically simplified by all this. I’m hoping that 4.0 will serve as a solid basis for many, many features over its lifetime. 4.0 won’t have all the features everyone wants, but it will enable me to finally add so many more of them!


September 2011 usage statistics

I last reported on usage stats back in February, when Windows 7 had finally tipped the scales to become the OS used by the majority of Paint.NET users. I’m going to use a briefer format this time and just report on the OS and CPU stats so that I can spend more time on another blog entry (in other words, no table and no language stats this time).

Windows 7 has hit 55.75% (previously 44.74%), XP has fallen to 32.99% (previously 39.57%), and Vista has tumbled to only 10.98% (previously 15.55). And in other good news, 64-bit has jumped all the way up to 34.26% (from 26.08%), while only 65.74% of Paint.NET users are trucking around with a 32-bit version of Windows (down from 73.92%). If you haven’t migrated to 64-bit yet, I highly recommend doing so! And also be sure to install the latest service pack for the version of Windows that you’re using (SP3 for XP, SP2 for Vista, and SP1 for Win7).

Some other stats that I haven’t included before:

  • Of the Windows 7 users, 37.70% are using the “RTM” version and 62.23% have upgraded to SP1.
  • Of the Windows Vista users, 19.14% are using SP1 while 79.40% are using SP2. Only 1.40% are using RTM (possibly due in part to having dropped RTM support awhile ago).
  • Of the Windows XP users, 2.63% are using SP2 while 97.34% are using SP3 (possibly due in part to having dropped SP2 support awhile ago).
  • About 98% of the user base is using Paint.NET v3.5.3 or newer.

Paint.NET v3.5.10 is now available

As promised, here’s the update that fixes the shortcut keys for View –> Actual Size.

And as usual, you can either use the built-in updater from the Utilities menu, or you can download and install directly from the website: There’s no need to worry about removing the old version; that is all handled automatically.

The official changelist:

  • Fixed: Ctrl+Shift+A now works again as a shortcut for View -> Actual Size (broken in 3.5.9)
  • Fixed: Ctrl+0 still works for View -> Actual Size even if 10 or more images are open (broken in 3.5.9, it would switch to the 10th image).


Paint.NET v3.5.9 and

Update: (October 4th, 4:30pm PST) is no longer doing this (at least, not with Paint.NET).

I just noticed that updated their listing of Paint.NET to version 3.5.9. Neat. Except that now they’re wrapping it in their download manager which tries to get you to install the “StartNow” toolbar. What a bunch of **** (insert your favorite 4-letter word).

I’ve already sent them an e-mail telling them that this is a violation of the Paint.NET license and to either cease this, or to remove Paint.NET from their site.

In the meantime, I obviously recommend not downloading Paint.NET from

More info on this despicable practice: wraps downloads in bloatware, lies about motivations (

Update: (October 4th, 9:30am PST) I received a reply from them at 2am stating they had removed the download manager from their listing of Paint.NET v3.5.9. However, as of 9am, they have not actually done this. If you go to the Paint.NET v3.5.9 listing on, it still has their spammy download manager attached to it!

A small bug in Paint.NET v3.5.9 with Ctrl+0

Yesterday, I released Paint.NET v3.5.9, which has some good bug fixes, as well as adding back the Korean translation and mapping Ctrl+0 to the View –> Actual Size command. Ctrl+0 is now the “primary” shortcut key listed in the View menu. As it turns out, I forgot to do one small thing. You see, Ctrl+1 through Ctrl+9 are shortcut keys for “switch to image 1” through “switch to image 9.”

As it turns out, I forgot to deactivate Ctrl+0 as a shortcut key for “switch to image 10.” So, if you have 10 or more images open, Ctrl+0 will not work for View –> Actual Size. Thankfully, it does not perform both actions in this case, and you can still use Ctrl+Shift+A or Ctrl+Alt+0. I will be rolling out an update called, you guessed it, Paint.NET v3.5.10, to fix this.

In the meantime, my recommendation is to install v3.5.9. However, if you’re planning on a deployment and would like to save some effort, I advise you to hold off until v3.5.10 is available. It should be next weekend (October 8th/9th) or the following (October 15th/16th). I may take the opportunity to fix another bug if any are found, or maybe to bundle in a performance improvement or two.

For some reason, I didn’t even think of this until precisely 5 minutes after I had finished releasing v3.5.9. Why is it that things always seem to work out like that? Smile

Paint.NET v3.5.9 is now available

As usual, you can either use the built-in updater from the Utilities menu, or you can download and install directly from the website: There’s no need to worry about removing the old version; that is all handled automatically.

Here’s the changes from v3.5.8:

  • Improved: The "Auto-detect" bit-depth setting for PNG, BMP, and TGA now also determines which bit-depth to use based on which one produces the smallest file size, as well as which ones can save the image without losing fidelity.
  • Improved: You can now use Ctrl+0 as a shortcut key for View -> Actual Size, in addition to Ctrl+Shift+A and Ctrl+Alt+0.
  • Fixed: Some text in the DirectDraw Surface (DDS) Save Configuration UI was not being loaded.
  • Fixed: Some DirectDraw Surface (DDS) files authored with other software (e.g. Unreal 2004) could not be loaded.
  • Fixed: In some rare circumstances, clicking on the Save button in the toolbar would crash.
  • Fixed: The Korean translation has been added back in, with the help of Bing machine translation to cover the few remaining strings that were untranslated.

Also, fixes since the 3.5.9 Beta include a few compatibility issues with plugins.