Now that I’m getting back into the swing of things after having moved across the country (Bay Area -> back to Seattle area, finally!), it’s time for a new update
This release is mostly focused on fixing, improving, and optimizing the quantization code. This is used when you save an image at 8-bit or lower color depth. There have been a number of bugs that have plagued this over the years, including 1) the generated palette is way too small (e.g. for a black->red gradient, it’d be 64 colors instead of 256), 2) the generated palette is slightly too small (e.g. 252 colors instead of 256), 3) the precision of the colors would be biased in favor of those that are at the top of the image, 4) the palette has colors removed from it that shouldn’t have been (this plagues Auto-detect), and more recently 5) the generated palette, especially for a low color depth, is complete trash.
#1 was a result of a bug in the Octree code that goes all the way back to the MSDN article it was pulled from, https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/aa479306(v=msdn.10)?redirectedfrom=MSDN . As it turns out, shifting right (via >>) by a negative amount results in 0 instead of a shift left. Maybe C works that way, but C# does not.
#2 was a result of the way that reduction/merging works in the Octree data structure. It can only merge an entire node’s children, meaning it can reduce 8 colors into 1, but never 8 colors into 2 through 7. This means it would undershoot the desired palette size as much as 6/7th of the time. I fixed that with a trick I learned at https://www.codeproject.com/Articles/109133/Octree-Color-Palette (search for the word "vomit" ).
#3 happens because the Octree code would reduce nodes in an order defined by how they were added to the octree. Since the image is processed top-to-bottom, this would thus favor colors that first appear at the top. I’ve fixed this by more evenly spreading out which leaf nodes are merged — those with lower frequencies are merged first, and if two colors have the same frequency then the ordering is deterministically pseudo-randomized by using the color’s hash code.
#4 was kind of a mix between 1, 2, and 5. There have been several reports of images that should be correctly auto-saving at 4-bit color depth (because of using <=16 colors), but colors are still trimmed. Auto-detect is strictly required to be lossless, and it has been failing at that. My new code for the Octree algorithm should fix this, but I’ve also added code to skip palette generation entirely if the desired color count is greater than the # of unique colors in the image (an obvious shortcut/fix, but the code was a bit snaky in terms of permitting this). This also means Median Cut will behave properly, because WIC’s code does not necessarily do this correctly either.
#5 was a result of switching from my Octree code to WIC’s Median Cut. As it turns out, Median Cut isn’t a good choice for a lot of images even when it’s correctly implemented. In addition to having some really bad bugs with large images that I’ve had to work around, WIC’s implementation also falls completely flat on its face when the palette size is small. Imagine a black->white gradient that gets bits of cyan and magenta sprinkled throughout. Ugh. I have retained the ability to use Median Cut, although Octree is the default.
I’ve also optimized these things to be a lot faster and use a lot less memory.
You can see all of this in effect if you save an image as a PNG, GIF, TIFF, or BMP at 8-bit, 4-bit, 2-bit, or 1-bit color depth. You can also use the new Effect -> Color -> Quantize effect to play around with it. It lets you specify an exact palette size instead of the bit-depth.
To get this update, make sure you have "Also check for pre-release (beta) versions" enabled in Settings, and then click on the Check Now button. (Unfortunately alpha/beta releases are not currently available for the Microsoft Store version of the app).
You can also download and install this build directly on the forum.
- New: Effect -> Color -> Quantize, which applies palette reduction to 256 colors or less, along with dithering. This is the same algorithm used when saving images at 8-bit color depth or lower.
- Fixed and improved palette generation when saving at 8-bit color depth or less
- Greatly optimized performance of palette generation and image quantization
- Added option to choose between Octree (default) and Median Cut algorithms for palette quantization when saving at 8-bit color depth or less
- Fixed a crash in Move tools when the selection was 0-width and/or 0-height
- Added tooltips w/ shortcut keys to the Tools dropdown in the toolbar
- Fixed IndirectUI ColorWheel rendering (thanks @toe_head2001!)
- Fixed a crash in the Text tool when using Ctrl+(Left,Right,Backspace,Delete) (thanks @Bruce Bowyer-Smyth!)
- Changed: New layers are now filled with #00000000 instead of #00FFFFFF
- Fixed a crash when working with selections (OutOfMemoryException)
- New: Effects can now access the Document’s DPI via EffectEnvironmentParameters.DocumentResolution
- Fixed drawing of the color palette in the Colors window when using some non-standard DPI scaling settings (e.g. 1.15x)
- Fixed a crash when using EdHarvey’s Threshold plugin
- Fixed the return value from PdnRegion.GetBoundsInt() so it’s not anchored at (0,0) unless it should be
- Fixed premultiplied-to-straight color conversion on some code paths (thanks @null54!)
- Updated bundled AvifFileType plugin to v18.104.22.168, which includes performance optimizations and bug fixes. See its GitHub releases page for more info.