BitmapExtensionsGetReadWriteBitmapData(Bitmap, WorkingColorSpace, Color, Byte) Method

Gets an IReadWriteBitmapData instance, which provides fast read-write access to the actual data of the specified bitmap. The bitmap can have any PixelFormat.

Definition

Namespace: KGySoft.Drawing
Assembly: KGySoft.Drawing (in KGySoft.Drawing.dll) Version: 8.0.0
C#
public static IReadWriteBitmapData GetReadWriteBitmapData(
	this Bitmap bitmap,
	WorkingColorSpace workingColorSpace,
	Color backColor = default,
	byte alphaThreshold = 128
)

Parameters

bitmap  Bitmap
A Bitmap instance, whose data is about to be accessed.
workingColorSpace  WorkingColorSpace
Specifies the preferred color space that should be used when working with the result bitmap data. Determines the behavior of some operations such as setting pixels with transparency when the pixel format of the source bitmap does not support transparency or alpha gradient. See also the backColor and alphaThreshold parameters.
See the Remarks section of the WorkingColorSpace enumeration for more details.
backColor  Color  (Optional)
When setting pixels of indexed bitmaps and bitmaps without alpha support or with single bit alpha, specifies the color of the background. Color values with alpha, which are considered opaque will be blended with this color before setting the pixel in the result bitmap data. The alpha value (Color.A property) of the specified background color is ignored. This parameter is optional.
Default value: Color.Empty, which has the same RGB values as Black.
alphaThreshold  Byte  (Optional)
When setting pixels of bitmaps with single bit alpha or with a palette that has a transparent color, then specifies a threshold value for the Color.A property, under which the color is considered transparent. If 0, then the pixels to be set will never be transparent. This parameter is optional.
Default value: 128.

Return Value

IReadWriteBitmapData
An IReadWriteBitmapData instance, which provides fast read-write access to the actual data of the specified bitmap.

Usage Note

In Visual Basic and C#, you can call this method as an instance method on any object of type Bitmap. When you use instance method syntax to call this method, omit the first parameter. For more information, see Extension Methods (Visual Basic) or Extension Methods (C# Programming Guide).

Remarks

All possible PixelFormats are supported, of which a Bitmap can be created in the current operating system.

If alphaThreshold is zero, then setting a fully transparent pixel in a bitmap with indexed or single-bit-alpha pixel format will blend the pixel to set with backColor even if the bitmap can handle transparent pixels.

If alphaThreshold is 1, then the result color of setting a pixel of a bitmap with indexed or single-bit-alpha pixel format will be transparent only if the color to set is completely transparent (has zero alpha).

If alphaThreshold is 255, then the result color of setting a pixel of a bitmap with indexed or single-bit-alpha pixel format will be opaque only if the color to set is completely opaque (its alpha value is 255).

If a pixel of a bitmap without alpha gradient support is set by the IWritableBitmapData.SetPixel/IWritableBitmapDataRow.SetColor methods or by the IReadWriteBitmapDataRow indexer, and the pixel has an alpha value that is greater than alphaThreshold, then the pixel to set will be blended with backColor.

The workingColorSpace parameter indicates the preferred color space mode when working with the result bitmap data. Blending operations performed by this library (eg. by IWritableBitmapData.SetPixel when blending in necessary as described above, or by the DrawInto extension methods) respect the value of this parameter. Blending in the linear color space produces natural results but the operation is a bit slower if the actual pixel format is not in the linear color space and the result is different from the results of most applications including popular image processors and web browsers.
See the Remarks section of the WorkingColorSpace enumeration for more details.

Example

The following example demonstrates how easily you can copy the content of a 32-bit ARGB image into an 8-bit indexed one by using the GetReadableBitmapData and GetWritableBitmapData methods:

C#
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())
    {
        for (int y = 0; y < dataSrc.Height; y++)
        {
            for (int x = 0; x < dataSrc.Width; x++)
            {
                // Please note that bmpDst.SetPixel would not work for indexed formats
                // and even when it can be used it would be much slower.
                dataDst.SetPixel(x, y, dataSrc.GetPixel(x, y));
            }
        }
    }

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

The example above produces the following results:

bmpSrc.pngShield icon with transparent background
bmpDst.png8 BPP shield icon with system default palette

If the pixels are not accessed randomly, then the sequential enumeration of rows can be a bit faster:

C#
// Replace the body of the inner using block of the previous example with the following code:
IReadableBitmapDataRowMovable rowSrc = dataSrc.FirstRow;
IWritableBitmapDataRowMovable rowDst = dataDst.FirstRow;
do
{
    for (int x = 0; x < dataSrc.Width; x++)
        rowDst[x] = rowSrc[x];
} while (rowSrc.MoveNextRow() && rowDst.MoveNextRow());

For parallel processing you can retrieve multiple rows by the indexer and process them concurrently. When targeting .NET Framework 4.0 or newer, the example above can be easily re-written to use parallel processing:

C#
// The parallel version of same body as in the previous example:
Parallel.For(0, dataSrc.Height, y =>
{
    IReadableBitmapDataRow rowSrc = dataSrc[y];
    IWritableBitmapDataRow rowDst = dataDst[y];
    for (int x = 0; x < dataSrc.Width; x++)
        rowDst[x] = rowSrc[x];
});

The following example demonstrates how to use the read-write IReadWriteBitmapData returned by the GetReadWriteBitmapData method to manipulate a Bitmap in-place:

C#
// This example produces the same result as the MakeGrayscale extension method without a ditherer:
using (Bitmap bmp = Icons.Shield.ExtractBitmap(new Size(256, 256)))
{
    bmp.SaveAsPng(@"c:\temp\before.png");

    using (IReadWriteBitmapData bmpData = bmp.GetReadWriteBitmapData())
    {
        IReadWriteBitmapDataRowMovable row = bmpData.FirstRow;
        do
        {
            for (int x = 0; x < bmpData.Width; x++)
                row[x] = row[x].ToGray();
        } while (row.MoveNextRow());
    }

    bmp.SaveAsPng(@"c:\temp\after.png");
}

The example above produces the following results:

before.pngColor shield icon
after.pngGrayscale shield icon

See Also