Raster Image Manipulation
In This Topic
Raster Image Representations
The NOV framework provides two classes for in-memory representation of raster images:
- NImageData – stores the image data in encoded form. This class can be used for obtaining the image format and decoding the image.
- NRaster – represents a decoded image. The image’s pixel data in stored in uncompressed form, which makes possible the reading and writing of individual pixels.
Following are more detailed reviews of the capabilities of these types.
Encoded Image Data
An instance of the NImageData type can be created by specifying a byte array that contains the image data. In the following example the data is obtained from a local file:
Creating an NImageData Object |
Copy Code
|
NFile file = NFileSystem.GetFile(@"D:\TestImage.png");
file.ReadAllBytes(
delegate (byte[] imageBytes)
{
NImageData imageData = new NImageData(imageBytes);
},
delegate (Exception ex)
{
// Reading of the file failed
}
);
|
Note that NImageData doesn’t create its own copy of the passed byte array, but only keeps a reference to it. Changes to the byte array are not recommended because they cannot be reflected in the NImageData object.
To decode the encoded image you have to use the NImageData.Decode method. This creates a new NRaster object:
Decoding an Image |
Copy Code
|
NRaster raster = imageData.Decode();
|
The NImageData object can also be used for obtaining the encoding format of the image:
Retrieving the Image Format |
Copy Code
|
NImageFormat imageFormat = imageData.ImageFormat;
|
When the image format for a particular NImageData instance is acquired for the first time, it is stored in the instance, so subsequent calls to the ImageFormat property do not need to perform format recognition again.
Creating Rasters
Decoded raster images are represented by the NRaster type. An NRaster instance keeps image information (width, height, pixel format, etc.) and an array in which the pixels are stored in uncompressed form (in one of the supported pixel formats). This representation allows for various image processing features, some of which are listed below:
- Reading and modification of the pixels of an existing image.
- Programmatic generation of an image.
- Image encoding (into the supported image formats).
- Rasterization of vector paintings.
- Pixel format conversions.
- Color conversions (like grayscale, invert colors).
- Transforms like image flipping and rotation.
There are different ways to create an NRaster object, depending on the purpose and the initial information. As mentioned previously, an NRaster instance can be produced by the NImageData.Decode method. It is also possible to create an NRaster object directly, using one of several constructors. For example, the following code creates a new image with certain dimensions and pixel format:
Creating an NRaster Object |
Copy Code
|
NRaster raster = new NRaster(200, 160, NPixelFormat.ARGB32);
|
The first two parameters are the image’s width and height specified in pixels. The pixel format is set to ARGB32 – this denotes a 32 bpp format with 4 channels (Alpha, Red, Green and Blue, 8-bits per channel).
The choice of pixel format not only determines the kind of color information that can be stored in the raster, but also affects the speed of pixel reading and writing operations. In general pixel formats with 32 bits per pixel provide the best performance.
To create a raster from an exsisting image you can also use the CreateRaster and the TryCreateRaster methods of the image's image source. The difference between the two methods is that CreateRaster throws and exception if a raster couldn't be created, but the TryCreateRaster doesn't throw an exception in this case and returns null instead. The following piece of code demonstrates how to create a raster from an image:
Creating a Raster from an Image |
Copy Code
|
NRaster raster = image.ImageSource.CreateRaster();
|
You can also create an NRaster object from an existing image by using the NImageData.Decode method:
Creating a Raster from an Image |
Copy Code
|
byte[] imageBytes = File.ReadAllBytes(@"D:\Gradient.png");
NImageData imageData = new NImageData(imageBytes);
NRaster raster = imageData.Decode();
|
Working with Rasters
Once the raster object is created, its pixels can be modified using the SetPixel method. The following code draws a gradient with Red, Black, Blue and Magenta colors in the four corners of the image.
Writing Pixels |
Copy Code
|
for (int j = 0; j < 160; j++)
{
for (int i = 0; i < 200; i++)
{
float red = i / 200.0f;
float blue = j / 160.0f;
raster.SetPixel(i, j, NColor.FromRGBA(red, 0.0f, blue, 1.0f));
}
}
|
The following code encodes the raster into PNG format and saves it to a local file:
Saving to a file |
Copy Code
|
NImage image = new NImage(raster);
image.Save(@"D:\Gradient.png", NImageFormat.Png);
|
The resulting image “Gradient.png” is presented below:
To create an NRaster object from an existing image, you can use the NImageData.Decode method. The following code reads the “Gradient.png” image (the one created in the previous example), decodes it to a raster and inverts its colors pixel by pixel:
Modifying Pixels |
Copy Code
|
byte[] imageBytes = NFile.ReadAllBytes(@"D:\Gradient.png");
NImageData imageData = new NImageData(imageBytes);
NRaster raster = imageData.Decode();
for (int j = 0; j < raster.Height; j++)
{
for (int i = 0; i < raster.Width; i++)
{
NColor color = raster.GetPixel(i, j);
raster.SetPixel(i, j, color.Invert());
}
}
|
The image below displays the result from the applied processing:
NRaster provides built-in methods for some common operations like the color inversion demonstrated above. Instead of the double for loop in the previous example you can simply use:
Inverting the Raster's Colors |
Copy Code
|
raster.InvertColors();
|
Using similar methods you can easily clear a raster, convert its pixels to grayscale, fill a part of it with a certain color, flip it horizontally or vertically, rotate it etc.
Certain situations require that a raster is represented in a specific pixel format. It is not possible to change the pixel format of an existing NRaster, but you create a new raster with the desired pixel format and convert the pixel data from the original one. This is a built-in functionality implemented by the Convert function:
Converting the Pixel Format |
Copy Code
|
NRaster rasterBGR24 = raster.Convert(NPixelFormat.BGR24, true);
|
In some cases the target pixel format cannot store the full information that is kept in the source format. For example if an ARGB32 raster is converted to BGR24, the alpha channel will be lost and the destination raster will not contain transparency information.
An important feature of NRaster is the ability to rasterize custom painted vector graphics. The RasterizePainting method creates a new raster and paints a vector scene inside it. The scene should be described in a paint method like the one below:
Vector Scene for Rasterization |
Copy Code
|
void PaintMethod(NPaintVisitor visitor)
{
visitor.SetFill(NColor.SlateBlue);
visitor.PaintRectangle(0, 0, 300, 200);
visitor.SetFill(NColor.Thistle);
visitor.PaintEllipse(0, 0, 300, 200);
visitor.SetStroke(NColor.Crimson, 2);
visitor.ClearFill();
visitor.PaintEllipse(30, 28, 50, 50);
}
|
The PaintMethod is passed as a parameter to the RasterizePainting method, along with the size and the resolution of the new raster:
Rasterization of a Vector Painting |
Copy Code
|
NRaster raster = NRaster.RasterizePainting(300, 200, 96, PaintMethod);
|
The generated raster is displayed below:
The NRaster class also provides some other useful methods, the most notable of them being:
- Resize - creates a new raster from the original one and resizes it to a given size.
- CreateSubRaster - creates a new raster as a portion of the original one.
- FlipX, FlipY - creates a new raster by flipping the original one horizontally of vertically.
- RotateClockwise, RotateCounterClockwise - creates a new raster by rotating the original one.
Encoding and Saving Rasters
Nevron Open Vision provides an easy way to encode rasters to a raster image format, so that you can easily save them as an image file. To do this, you should create an image from the raster and use the Save method of NImage. You can pass an encoder settings object to the Save method, which defines format specific settings to apply when encoding the raster, for example, the image quality of a JPEG image, the compression level and the color type (grayscale, true color, true color with alpha, palette, etc.) of a PNG image and so on.
The following example demonstrates how to create a simple raster, how to draw a red line at its forward diagonal and a blue one at its backward diagonal and how to save the result to a PNG file on disk:
Creating and saving a raster |
Copy Code
|
// Create a raster
NRaster raster = new NRaster(16, 16, NPixelFormat.ARGB32);
for (int i = 0; i < raster.Width; i++)
{
raster.SetPixel(i, i, NColor.Red);
raster.SetPixel(raster.Width - i - 1, i, NColor.Blue);
}
// Save the raster to a file
NImage image = new NImage(raster);
image.Save(NFileSystem.GetFile(@"D:\test.png"), NImageFormat.Png);
|
NRaster provides the Encode method for encoding of the image data into a specific image format. This method is used internall by the Save method of NImage to encode the raster. In the example above we used PNG format with default encoder settings. If you need to use specific encoder settings you can pass a settings object to the Save method of the image. Image formats that support encoder settings have corresponding types that are derived from NImageEncoderSettings. The following table shows these relations:
Image Format |
NImageFormat Instance |
Encoder Settings Type |
PNG |
NImageFormat.Png |
NPngEncoderSettings |
JPEG |
NImageFormat.Jpeg |
NJpegEncoderSettings |
Bitmap |
NImageFormat.Bmp |
NBitmapEncoderSettings |
GIF |
NImageFormat.Gif |
Encoding is not supported |
NRI |
NImageFormat.Nri |
Encoder settings are not available |
Encoding a PNG image with transparency is a common scenario that requires the usage of custom encoder settings. The default color type for the PNG encoder is ENPngColorType.Truecolor, which does not support an alpha channel. To encode a semi-transparent PNG, you have to create an NPngEncoderSettings object and set its ColorType property to ENPngColorType.TruecolorWithAlpha:
Image Encoding with Customized Encoder Settings |
Copy Code
|
NPngEncoderSettings settings = new NPngEncoderSettings();
settings.ColorType = ENPngColorType.TruecolorWithAlpha;
NImageData imgData = raster.Encode(NImageFormat.Png, settings);
|
Saving a Raster with Customized Encoder Settings |
Copy Code
|
NPngEncoderSettings settings = new NPngEncoderSettings();
settings.ColorType = ENPngColorType.TruecolorWithAlpha;
NImage image = new NImage(raster);
image.Save(NFileSyste.GetFile(@"D:\test.png"), NImageFormat.Png, settings, NImageFormat.Png.EncoderPreference);
|
See Also