Graphics Mill provides a wide range of methods to manipulate images: transformations, effects, filters, and so on. However you may want to implement some custom algorithms. In this case you need to get access to bitmap pixels.
There are two approaches to accessing pixels with Graphics Mill: high-level and low-level.
The Bitmap.GetPixel(Int32, Int32) and Bitmap.SetPixel(Int32, Int32, Color) methods allow for getting and setting the color of the pixel specified by its x and y coordinates.
The advantage of using the high-level access is run-time boundary check, which means that you will never get an access violation problem if you specify the wrong coordinates. Also, there is no need to learn the physical structure of the pixel to access it. The disadvantage of such an approach is its poor performance. If you need to simply change the color of several points, this method is convenient, but we do not recommend using high-level pixel access for intensive pixel processing.
If you use low-level pixel access you need to know how pixels are stored in memory. Pixel data in Graphics Mill are stored linearly. This means that the entire bitmap occupies a contiguous memory area. Rows of pixels are stored sequentially. Each row contains the same number of bytes.
The table below demonstrates the order of components in a pixel. The square brackets depict the content of one byte, while bits in a byte are separated by comma. Bytes are separated by a vertical line. A color name (and font color) specifies how the pixel part is interpreted. For example, the [pixel1,pixel2]|[pixel3,pixel4] string defines two bytes, where each byte describes two indexed pixels. And [Blue]|[Green]|[Red] describes one pixel, which consists of three colors (red, green, and blue), and each color component is one byte size.
Pixel Format Name | Memory Order |
---|---|
Format1bppIndexed | [pixel1,pixel2,pixel3,pixel4,pixel5,pixel6,pixel7,pixel8] |
Format4bppIndexed | [pixel1,pixel2]|[pixel3,pixel4] |
Format8bppIndexed | [pixel1] |
Format8bppGrayscale | [Grayscale] |
Format16bppGrayscale | [Grayscale]|[Grayscale] |
Format16bppAlphaGrayscale | [Grayscale]|[Alpha] |
Format32bppAlphaGrayscale | [Grayscale]|[Grayscale]|[Alpha]|[Alpha] |
Format24bppRgb | [Blue]|[Green]|[Red] |
Format32bppRgb | [Blue]|[Green]|[Red]|[Not Used] |
Format48bppRgb | [Blue]|[Blue]|[Green]|[Green]|[Red]|[Red] |
Format32bppArgb | [Blue]|[Green]|[Red]|[Alpha] |
Format64bppArgb | [Blue]|[Blue]|[Green]|[Green]|[Red]|[Red]|[Alpha]|[Alpha] |
Format32bppCmyk | [Black]|[Yellow]|[Magenta]|[Cyan] |
Format64bppCmyk | [Black]|[Black]|[Yellow]|[Yellow]|[Magenta]|[Magenta]|[Cyan]|[Cyan] |
Format40bppAcmyk | [Black]|[Yellow]|[Magenta]|[Cyan]|[Alpha] |
Format80bppAcmyk | [Black]|[Black]|[Yellow]|[Yellow]|[Magenta]|[Magenta]|[Cyan]|[Cyan]|[Alpha]|[Alpha] |
Format24bppLab | [Lightness]|[a]|[b] |
Format48bppLab | [Lightness]|[Lightness]|[a]|[a]|[b]|[b] |
Format32bppAlab | [Lightness]|[a]|[b]|[Alpha] |
Format64bppAlab | [Lightness]|[Lightness]|[a]|[a]|[b]|[b]|[Alpha]|[Alpha] |
Low-level pixel access in Graphics Mill is similar to that found in GDI+. Generally, you should perform the following steps to get access to a pixel:
To iterate through all the pixels of a bitmap you should start from the Scan0 position and increment the pointer by the PixelFormat.Size bits. To reach the next row, use the Stride property, which specifies how many bytes are taken by one row. The interpretation of the pixel depends on the PixelFormat property; the meaning of this property is described in the table above. So if you need to get a pixel which is in the same position as the current one, but in the following row, just add the value stored in the Stride property.
For example, the position of a pixel in the row i, column j of the bitmap
can be calculated as follows:
result = bitmap.Scan0 + bitmap.Stride * i + j * bitmap.PixelFormat.Size / 8
This formula is valid only if the pixel size is divisible by 8 (byte size). Otherwise (for example, if the pixel size is 1 or 4 bits), you need to perform bitwise shift operations to get the pixel.
The following code inverts an image (creates image negative):
using (var bitmap = new Bitmap(@"Images\in.jpg")) { unsafe { //A pointer to the beginning of the pixel data region byte* pointer = (byte*)(bitmap.Scan0.ToPointer()); //Number of bytes in a row int stride = bitmap.Stride; //Number of rows int height = bitmap.Height; for (int i = 0; i < height; i++) { byte* position = pointer + stride * i; for (int j = 0; j < stride; j++) { //Now we can modify the pixel, for example, invert it *position = (byte)(255 - *position); position++; } } } bitmap.Save(@"Images\Output\out.jpg"); }