Download

In Visual Studio

The preferred way is by the NuGet Package Manager in Visual Studio

  • You can use either the Package Manager Console:
    PM> Install-Package KGySoft.Drawing
  • Or the Package Manger GUI by the Manage NuGet Packages… context menu item of the project.

Direct Download

Alternatively, you can download the package directly from nuget.org.

If you prefer a .zip file containing the binaries see the releases on GitHub.

Source Code

The source is available on GitHub.

You can find both the source code and the binaries as .zip files among the releases.

Demo Application and Debugger Visualizers

KGy SOFT Imaging Tools is a desktop application in the KGySoft.Drawing.Tools repository, which nicely demonstrates a sort of features of Drawing Libraries, such as quantizing and dithering, resizing, adjusting brightness, contrast and gamma, etc. The tool is packed also with some debugger visualizers for several System.Drawing types including Bitmap, Metafile, Icon, Graphics and more.

If you use Visual Studio 2013 or newer the simplest way is to download the installer package from the VisualStudio Marketplace.

Otherwise, you can download the binaries for other versions from the GitHub repo.

Help

Browse the online documentation for examples and detailed descriptions.

Examples

Icon Manipulation

Icon images of different resolutions and color depth can be extracted from an Icon, whereas Bitmap and Icon instances can be combined into a new Icon. PNG compressed icons are also supported.

// extracting the 256x256 image from an icon:
Bitmap bmp = Icons.ExtractBitmap(new Size(256, 256));

// combining an existing icon with a bitmap:
Icon combined = myIcon.Combine(bmp);

💡 Tip: See more details at the Icons and IconExtensions classes.


Fast Bitmap Manipulation

As it is well known, Bitmap.SetPixel/GetPixel methods are very slow. Additionally, they do not support every pixel format. A typical solution can be to obtain a BitmapData by the LockBits method, which has further drawbacks: you need to use unsafe code and pointers, and the way you need to access the bitmap data depends on the actual PixelFormat of the bitmap.

KGy SOFT Drawing Libraries offer very fast and convenient way to overcome these issues. A managed accessor can be obtained by the GetReadableBitmapData, GetWritableBitmapData and GetReadWriteBitmapData methods.

var targetFormat = PixelFormat.Format8bppIndexed; // feel free to try other formats as well
using (Bitmap bmpSrc = Icons.Shield.ExtractBitmap(new Size(256, 256)))
using (Bitmap bmpDst = new Bitmap(256, 256, targetFormat))
{
    using (IReadableBitmapData dataSrc = bmpSrc.GetReadableBitmapData())
    using (IWritableBitmapData dataDst = bmpDst.GetWritableBitmapData())
    {
        IReadableBitmapDataRow rowSrc = dataSrc.FirstRow;
        IWritableBitmapDataRow rowDst = dataDst.FirstRow;
        do
        {
            for (int x = 0; x < dataSrc.Width; x++)
                rowDst[x] = rowSrc[x]; // works also between different pixel formats

        } while (rowSrc.MoveNextRow() && rowDst.MoveNextRow());
    }

    bmpSrc.SaveAsPng(@"c:\temp\bmpSrc.png");
    bmpDst.SaveAsPng(@"c:\temp\bmpDst.png"); // or saveAsGif/SaveAsTiff to preserve the indexed format
}

💡 Tip: See more examples with images at the GetReadWriteBitmapData extension method.

If you know the actual pixel format you can also access the raw data in a managed way. See the IReadableBitmapDataRow.ReadRaw and IWritableBitmapDataRow.WriteRaw methods for details and examples.


Managed Bitmap Data Manipulation

Not only for the native Bitmap type can you obtain a managed accessor (as described above) but you can also create a completely managed bitmap data instance by the BitmapDataFactory class. There are more benefits of using managed bitmap data: not just that they don’t use any GDI or other native resources but also that they support every PixelFormat on any platform. See the BitmapDataExtensions for the available operations on bitmap data where bitmap data can be either a managed one or a managed accessor to a native Bitmap instance.

The BitmapDataFactory class has many CreateBitmapData overloads. The ones whose first parameter is Size allocate the underlying buffer by themselves, which is not directly accessible from outside. But you are also able to use predefined arrays of any primitive element type (one or two dimensional ones), and also ArraySection<T> or Array2D<T> buffers to create a managed bitmap data for.


WriteableBitmap and Other 3rd Party Bitmap Types Support

The BitmapDataFactory class has also CreateBitmapData overloads to support unmanaged memory. This makes possible to support any bitmap representation that expose its buffer by a pointer.

For example, this is how you can create a managed accessor for a WriteableBitmap instance commonly used in WPF/WinRT/UWP and other XAML-based environments, which exposes such a pointer:

// Though naming is different, PixelFormats.Pbgra32 is the same as PixelFormat.Format32bppPArgb.
var bitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Pbgra32, null);

// creating the managed bitmap data for WriteableBitmap:
using (var bitmapData = BitmapDataFactory.CreateBitmapData(
    bitmap.BackBuffer,
    new Size(bitmap.PixelWidth, bitmap.PixelHeight),
    bitmap.BackBufferStride,
    PixelFormat.Format32bppPArgb)
{
    // Do whatever with bitmapData
}

// Actualizing changes. But see also the next example to see how to do these along with disposing.
bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
bitmap.Unlock();

Supporting Custom Pixel Formats

The previous example demonstrated how we can create a managed accessor for a WriteableBitmap. But it worked only because we used a pixel format that happen to have built-in support also in KGy SOFT Drawing Libraries. In fact, the libraries provide support for any custom pixel format. The CreateBitmapData methods have several overloads that allow you to specify a custom pixel format along with a couple of delegates to be called when pixels are read or written:

// Gray8 format has no built-in support
var bitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Gray8, null);

// But we can specify how to use it
var customPixelFormat = new PixelFormatInfo { BitsPerPixel = 8, Grayscale = true };
Func<ICustomBitmapDataRow, int, Color32> getPixel =
    (row, x) => Color32.FromGray(row.UnsafeGetRefAs<byte>(x));
Action<ICustomBitmapDataRow, int, Color32> setPixel =
    (row, x, c) => c.Blend(row.BitmapData.BackColor).GetBrightness();

// Now we specify also a dispose callback to be executed when the returned instance is disposed:
return BitmapDataFactory.CreateBitmapData(
    bitmap.BackBuffer, new Size(bitmap.PixelWidth, bitmap.PixelHeight), bitmap.BackBufferStride,
    customPixelFormat, getPixel, setPixel,
    disposeCallback: () =>
    {
        bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
        bitmap.Unlock();
    });

Note that there are different overloads for indexed formats where you have to specify how to read/write a palette index. Please also note that these delegates work with 32-bit color structures (just like usual GetPixel/SetPixel) so wider formats will be quantized into the ARGB8888 color space (or BGRA8888, using the alternative terminology) when getting/setting pixels but this is how regular formats work, too. Anyway, you can always access the actual underlying data of whatever format by the aforementioned IReadableBitmapDataRow.ReadRaw and IWritableBitmapDataRow.WriteRaw methods.


Quantizing and Dithering

KGy SOFT Drawing Libraries offer quantizing (reducing the number of colors of an image) and dithering (techniques for preserving the details of a quantized image) in several ways:

💡 Tip:

• For built-in quantizers see the PredefinedColorsQuantizer and OptimizedPaletteQuantizer classes. See their members for code samples and image examples.

• For built-in ditherers see the OrderedDitherer, ErrorDiffusionDitherer, RandomNoiseDitherer and InterleavedGradientNoiseDitherer classes. See their members for code samples and image examples.

See the following examples for the possible quantization results (click the images for displaying in full size):

Color hues with alpha gradient
Original image: Color hues with alpha gradient
Color hues quantized with custom 8 color palette and silver background
Color hues quantized with custom 8 color palette and silver background, no dithering. The bottom part turns white because white is the nearest color to silver.
Color hues quantized with custom 8 color palette and silver background, using Bayer 8x8 dithering
Color hues quantized with custom 8 color palette and silver background, using Bayer 8×8 dithering
Grayscale color shades
Original image: Grayscale color shades
Grayscale color shades quantized with black and white palette
Grayscale color shades quantized with black and white palette, no dithering
Grayscale color shades quantized with black and white palette, using blue noise dithering
Grayscale color shades quantized with black and white palette, using blue noise dithering
Test image "Lena"
Original test image “Lena”
Test image "Lena" quantized with system default 8 BPP palette
Test image “Lena” quantized with system default 8 BPP palette, no dithering
Test image "Lena" quantized with system default 8 BPP palette using Bayer 8x8 dithering
Test image “Lena” quantized with system default 8 BPP palette using Bayer 8×8 dithering
Test image "Lena" quantized with system default 8 BPP palette using Floyd-Steinberg dithering
Test image “Lena” quantized with system default 8 BPP palette using Floyd-Steinberg dithering
Test image "Cameraman"
Original test image “Cameraman”
Test image "Cameraman" quantized with black and white palette
Test image “Cameraman” quantized with black and white palette, no dithering
Test image "Cameraman" quantized with black and white palette using Floyd-Steinberg dithering
Test image “Cameraman” quantized with black and white palette using Floyd-Steinberg dithering

Advanced GIF Encoder with High Color Support

The KGy SOFT Drawing Libraries make possible creating high quality GIF images and animations:

  • For Image types the simplest and highest-level access is provided by the ImageExtension class and its SaveAs* methods.
  • Alternatively, you can use the static methods of the GifEncoder class to create animations or even high color still images. See also the AnimatedGifConfiguration class.
  • To create a GIF image or animation completely manually you can instantiate the GifEncoder class that provides you the lowest-level access.
True color GIF animation (29,731 colors)
True color GIF animation. The last frame has 29,731 colors. The Granger Rainbow has been generated from an alpha gradient bitmap by this code.
Warning icon as a high color GIF image
Warning icon encoded as a high color GIF. It has only single bit transparency but otherwise its colors have been preserved. It consists of 18 layers and has 4,363 colors.
Test image "Lena" encoded as a true color GIF
Test image “Lena” encoded as a true color GIF. It consists of 983 layers and has 148,702 colors. The file size is about twice as large as the PNG encoded version (by allowing full scanning the number of layers could be decreased to 584 but the file size would be even larger).
Test image "Lena" encoded as a high color GIF. Prequantized to the 16-bit RGB565 color space using Floyd-Steinberg dithering
Test image “Lena” encoded as a high color GIF. Before encoding it was prequantized with RGB565 16-bit quantizer using Floyd-Steinberg dithering. It consists of 18 layers and has 4,451 colors. The file size is about 80% of the original PNG encoded version but could be even smaller without the dithering.

⚠️ Note: Please note that multi layered high color GIF images might be mistakenly rendered as animations by some decoders, including browsers. Still images do not contain the Netscape application extension and do not have any delays. Such images are processed properly by GDI+ on Windows, by the System.Drawing.Bitmap and Image classes and applications relying on GDI+ decoders such as Windows Paint or KGy SOFT Imaging Tools.

License

This repository is under the KGy SOFT License 1.0, which is a permissive GPL-like license. It allows you to copy and redistribute the material in any medium or format for any purpose, even commercially. The only thing is not allowed is to distribute a modified material as yours: though you are free to change and re-use anything, do that by giving appropriate credit. See the LICENSE file for details.