diff --git a/BioImager.csproj b/BioImager.csproj
index ebbf48c..742a458 100644
--- a/BioImager.csproj
+++ b/BioImager.csproj
@@ -14,12 +14,12 @@
Microscopy;Biology;
GPL-3.0-only
A .NET microscopy imaging application based on Bio library. Supports various microscopes by using imported libraries & GUI automation. Supported libraries include Prior® & Zeiss® & all devices supported by Micromanager 2.0 and python-microscope.
- 3.9.1
+ 4.0.0
https://github.com/BiologyTools/BioImager
True
- Accelerated graphics fix.
+ OME type slides fix. Support for 16 bit slides.
AnyCPU;x86;x64
diff --git a/Source/Bio/ISlideSource.cs b/Source/Bio/ISlideSource.cs
index 4e5b68b..fe2d6cb 100644
--- a/Source/Bio/ISlideSource.cs
+++ b/Source/Bio/ISlideSource.cs
@@ -8,6 +8,7 @@
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using AForge;
+using Image = SixLabors.ImageSharp.Image;
namespace BioImager
{
public class LruCache
@@ -62,6 +63,13 @@ public void Add(Info key, TValue value)
lruList.AddLast(newNode);
cacheMap[key] = newNode;
}
+ public void Dispose()
+ {
+ foreach (LinkedListNode<(Info key, TValue value)> item in cacheMap.Values)
+ {
+ lruList.Remove(item);
+ }
+ }
}
public class TileCache
{
@@ -110,6 +118,10 @@ private async Task LoadTile(TileInformation tileId)
return null;
}
}
+ public void Dispose()
+ {
+ cache.Dispose();
+ }
}
public class TileInformation
@@ -160,7 +172,6 @@ public static ISlideSource Create(BioImage source, SlideImage im, bool enableCac
}
#endregion
public double MinUnitsPerPixel { get; protected set; }
- public static byte[] LastSlice;
public static Extent destExtent;
public static Extent sourceExtent;
public static double curUnitsPerPixel = 1;
@@ -194,9 +205,12 @@ public async Task GetSlice(SliceInfo sliceInfo)
{
try
{
- NetVips.Image im = OpenSlideGTK.ImageUtil.JoinVips(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
- LastSlice = im.WriteToMemory();
- return LastSlice;
+ NetVips.Image im = null;
+ if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format16bppGrayScale)
+ im = ImageUtil.JoinVips16(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
+ else if(this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format24bppRgb)
+ im = ImageUtil.JoinVipsRGB24(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
+ return im.WriteToMemory();
}
catch (Exception e)
{
@@ -207,16 +221,28 @@ public async Task GetSlice(SliceInfo sliceInfo)
}
try
{
- Image im = OpenSlideGTK.ImageUtil.Join(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
- LastSlice = GetRgb24Bytes(im);
- im.Dispose();
+ Image im = null;
+ if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format16bppGrayScale)
+ {
+ im = ImageUtil.Join16(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
+ byte[] bts = Get16Bytes((Image)im);
+ im.Dispose();
+ return bts;
+ }
+ else if (this.Image.BioImage.Resolutions[curLevel].PixelFormat == PixelFormat.Format24bppRgb)
+ {
+ im = ImageUtil.JoinRGB24(tiles, srcPixelExtent, new Extent(0, 0, dstPixelWidth, dstPixelHeight));
+ byte[] bts = GetRgb24Bytes((Image)im);
+ im.Dispose();
+ return bts;
+ }
}
catch (Exception er)
{
Console.WriteLine(er.Message);
return null;
}
- return LastSlice;
+ return null;
}
public byte[] GetRgb24Bytes(Image image)
{
@@ -230,14 +256,34 @@ public byte[] GetRgb24Bytes(Image image)
for (int x = 0; x < width; x++)
{
Rgb24 pixel = image[x, y];
- rgbBytes[byteIndex++] = pixel.R;
- rgbBytes[byteIndex++] = pixel.G;
rgbBytes[byteIndex++] = pixel.B;
+ rgbBytes[byteIndex++] = pixel.G;
+ rgbBytes[byteIndex++] = pixel.R;
}
}
return rgbBytes;
}
+ public byte[] Get16Bytes(Image image)
+ {
+ int width = image.Width;
+ int height = image.Height;
+ byte[] bytes = new byte[width * height * 2];
+
+ int byteIndex = 0;
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ L16 pixel = image[x, y];
+ byte[] bts = BitConverter.GetBytes(pixel.PackedValue);
+ bytes[byteIndex++] = bts[0];
+ bytes[byteIndex++] = bts[1];
+ }
+ }
+
+ return bytes;
+ }
public SlideImage Image { get; set; }
@@ -291,11 +337,7 @@ public async Task GetTileAsync(TileInformation tileInfo)
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight,tileInfo.Coordinate);
- //We check to see if the data is valid.
- if (bgraData.Length != curTileWidth * curTileHeight * 4)
- return null;
- byte[] bm = ConvertRgbaToRgb(bgraData);
- return bm;
+ return bgraData;
}
public async Task GetTileAsync(BruTile.TileInfo tileInfo)
{
@@ -309,11 +351,7 @@ public async Task GetTileAsync(BruTile.TileInfo tileInfo)
var curTileWidth = (int)(tileInfo.Extent.MaxX > Schema.Extent.Width ? tileWidth - (tileInfo.Extent.MaxX - Schema.Extent.Width) / r : tileWidth);
var curTileHeight = (int)(-tileInfo.Extent.MinY > Schema.Extent.Height ? tileHeight - (-tileInfo.Extent.MinY - Schema.Extent.Height) / r : tileHeight);
var bgraData = await Image.ReadRegionAsync(tileInfo.Index.Level, (long)curLevelOffsetXPixel, (long)curLevelOffsetYPixel, curTileWidth, curTileHeight, new ZCT());
- //We check to see if the data is valid.
- if (bgraData.Length != curTileWidth * curTileHeight * 4)
- return null;
- byte[] bm = ConvertRgbaToRgb(bgraData);
- return bm;
+ return bgraData;
}
public static byte[] ConvertRgbaToRgb(byte[] rgbaArray)
{
diff --git a/Source/Bio/SlideBase.cs b/Source/Bio/SlideBase.cs
index d191df4..6c9820e 100644
--- a/Source/Bio/SlideBase.cs
+++ b/Source/Bio/SlideBase.cs
@@ -7,7 +7,6 @@
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
-using AForge;
namespace BioImager
{
diff --git a/Source/Bio/SlideImage.cs b/Source/Bio/SlideImage.cs
index 66ea767..8bcd850 100644
--- a/Source/Bio/SlideImage.cs
+++ b/Source/Bio/SlideImage.cs
@@ -1,7 +1,6 @@
using AForge;
using OpenSlideGTK;
using OpenSlideGTK.Interop;
-using org.checkerframework.common.returnsreceiver.qual;
using System;
using System.Collections.Generic;
using System.IO;
@@ -224,7 +223,7 @@ public int GetBestLevelForDownsample(double downsample)
///
public unsafe byte[] ReadRegion(int level, long x, long y, long width, long height)
{
- return BioImage.GetTile(BioImage, App.viewer.GetCoordinate(), level, (int)x, (int)y, (int)width, (int)height).RGBBytes;
+ return BioImage.GetTile(BioImage, App.viewer.GetCoordinate(), level, (int)x, (int)y, (int)width, (int)height).Bytes;
}
///
@@ -237,22 +236,13 @@ public unsafe byte[] ReadRegion(int level, long x, long y, long width, long heig
/// The height of the region. Must be non-negative.
/// The BGRA pixel data of this region.
///
- public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, ZCT coord, out byte[] data)
+ public unsafe bool TryReadRegion(int level, long x, long y, long width, long height, out byte[] data, ZCT zct)
{
- try
- {
- data = BioImage.GetTile(BioImage, coord, level, (int)x, (int)y, (int)width, (int)height).RGBBytes;
- if (data == null)
- return false;
- else
- return true;
- }
- catch (Exception e)
- {
- data = null;
+ data = BioImage.GetTile(BioImage, zct, level, (int)x, (int)y, (int)width, (int)height).Bytes;
+ if (data == null)
return false;
- }
-
+ else
+ return true;
}
///
@@ -308,7 +298,7 @@ public async Task ReadRegionAsync(int level, long curLevelOffsetXPixel,
try
{
byte[] bts;
- TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight, coord,out bts);
+ TryReadRegion(level, curLevelOffsetXPixel, curLevelOffsetYPixel, curTileWidth, curTileHeight,out bts,coord);
return bts;
}
catch (Exception e)
diff --git a/Source/Bio/SlideTileLayer.cs b/Source/Bio/SlideTileLayer.cs
index 06e8b49..6c72f5c 100644
--- a/Source/Bio/SlideTileLayer.cs
+++ b/Source/Bio/SlideTileLayer.cs
@@ -30,7 +30,7 @@ public SlideTileLayer(
int minExtraTiles = -1,
int maxExtraTiles = -1,
Func> fetchTileAsFeature = null)
- : base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, fetchTileAsFeature)
+ : base(source, minTiles, maxTiles, dataFetchStrategy, renderFetchStrategy, minExtraTiles, maxExtraTiles, (Func>)fetchTileAsFeature)
{
Name = "TileLayer";
_slideSource = source;
diff --git a/Source/Bio/Utilities.cs b/Source/Bio/Utilities.cs
new file mode 100644
index 0000000..b19ae34
--- /dev/null
+++ b/Source/Bio/Utilities.cs
@@ -0,0 +1,367 @@
+using BruTile;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+using System.IO;
+using NetVips;
+using System.Drawing.Imaging;
+using SharpDX.Direct2D1.Effects;
+using AForge;
+namespace BioImager
+{
+ public class ImageUtil
+ {
+ ///
+ /// Join by and cut by then scale to (only height an width is useful).
+ ///
+ /// tile with tile extent collection
+ /// canvas extent
+ /// jpeg output size
+ ///
+ public static Image JoinRGB24(IEnumerable> srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
+ {
+ if (srcPixelTiles == null || srcPixelTiles.Count() == 0)
+ return null;
+ srcPixelExtent = srcPixelExtent.ToIntegerExtent();
+ dstPixelExtent = dstPixelExtent.ToIntegerExtent();
+ int canvasWidth = (int)srcPixelExtent.Width;
+ int canvasHeight = (int)srcPixelExtent.Height;
+ var dstWidth = (int)dstPixelExtent.Width;
+ var dstHeight = (int)dstPixelExtent.Height;
+ Image canvas = new Image(canvasWidth, canvasHeight);
+ foreach (var tile in srcPixelTiles)
+ {
+ try
+ {
+ var tileExtent = tile.Item1.ToIntegerExtent();
+ var intersect = srcPixelExtent.Intersect(tileExtent);
+ if (intersect.Width == 0 || intersect.Height == 0)
+ continue;
+ if(tile.Item2 == null)
+ continue;
+ Image tileRawData = (Image)CreateImageFromBytes(tile.Item2, (int)tileExtent.Width, (int)tileExtent.Height,AForge.PixelFormat.Format24bppRgb);
+ var tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
+ var tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
+ var canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
+ var canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
+ //We copy the tile region to the canvas.
+ for (int y = 0; y < intersect.Height; y++)
+ {
+ for (int x = 0; x < intersect.Width; x++)
+ {
+ int indx = canvasOffsetPixelX + x;
+ int indy = canvasOffsetPixelY + y;
+ int tindx = tileOffsetPixelX + x;
+ int tindy = tileOffsetPixelY + y;
+ canvas[indx, indy] = tileRawData[tindx, tindy];
+ }
+ }
+ tileRawData.Dispose();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+
+ }
+ if (dstWidth != canvasWidth || dstHeight != canvasHeight)
+ {
+ try
+ {
+ canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
+ return canvas;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.Message);
+ }
+
+ }
+ return canvas;
+ }
+
+ ///
+ /// Join by and cut by then scale to (only height an width is useful).
+ ///
+ /// tile with tile extent collection
+ /// canvas extent
+ /// jpeg output size
+ ///
+ public static ImageJoin16(IEnumerable> srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
+ {
+ if (srcPixelTiles == null || srcPixelTiles.Count() == 0)
+ return null;
+ srcPixelExtent = srcPixelExtent.ToIntegerExtent();
+ dstPixelExtent = dstPixelExtent.ToIntegerExtent();
+ int canvasWidth = (int)srcPixelExtent.Width;
+ int canvasHeight = (int)srcPixelExtent.Height;
+ var dstWidth = (int)dstPixelExtent.Width;
+ var dstHeight = (int)dstPixelExtent.Height;
+ Image canvas = new Image(canvasWidth, canvasHeight);
+ foreach (var tile in srcPixelTiles)
+ {
+ try
+ {
+ var tileExtent = tile.Item1.ToIntegerExtent();
+ var intersect = srcPixelExtent.Intersect(tileExtent);
+ if (intersect.Width == 0 || intersect.Height == 0)
+ continue;
+ if (tile.Item2 == null)
+ continue;
+ Image tileRawData = (Image)CreateImageFromBytes(tile.Item2, (int)tileExtent.Width, (int)tileExtent.Height, AForge.PixelFormat.Format16bppGrayScale);
+ var tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
+ var tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
+ var canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
+ var canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
+ //We copy the tile region to the canvas.
+ for (int y = 0; y < intersect.Height; y++)
+ {
+ for (int x = 0; x < intersect.Width; x++)
+ {
+ int indx = canvasOffsetPixelX + x;
+ int indy = canvasOffsetPixelY + y;
+ int tindx = tileOffsetPixelX + x;
+ int tindy = tileOffsetPixelY + y;
+ canvas[indx, indy] = tileRawData[tindx, tindy];
+ }
+ }
+ tileRawData.Dispose();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ }
+
+ }
+ if (dstWidth != canvasWidth || dstHeight != canvasHeight)
+ {
+ try
+ {
+ canvas.Mutate(x => x.Resize(dstWidth, dstHeight));
+ return canvas;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.Message);
+ }
+
+ }
+ return canvas;
+ }
+
+ ///
+ /// Join by and cut by then scale to (only height an width is useful).
+ ///
+ /// tile with tile extent collection
+ /// canvas extent
+ /// jpeg output size
+ ///
+ public static unsafe NetVips.Image JoinVipsRGB24(IEnumerable> srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
+ {
+ if (srcPixelTiles == null || !srcPixelTiles.Any())
+ return null;
+
+ srcPixelExtent = srcPixelExtent.ToIntegerExtent();
+ dstPixelExtent = dstPixelExtent.ToIntegerExtent();
+ int canvasWidth = (int)srcPixelExtent.Width;
+ int canvasHeight = (int)srcPixelExtent.Height;
+
+ // Create a base canvas. Adjust as necessary, for example, using a transparent image if needed.
+ NetVips.Image canvas = NetVips.Image.Black(canvasWidth, canvasHeight, bands: 3);
+
+ foreach (var tile in srcPixelTiles)
+ {
+ if (tile.Item2 == null)
+ continue;
+
+ fixed (byte* pTileData = tile.Item2)
+ {
+ var tileExtent = tile.Item1.ToIntegerExtent();
+ NetVips.Image tileImage = NetVips.Image.NewFromMemory((IntPtr)pTileData, (ulong)tile.Item2.Length, (int)tileExtent.Width, (int)tileExtent.Height, 3, Enums.BandFormat.Uchar);
+
+ // Calculate positions and sizes for cropping and inserting
+ var intersect = srcPixelExtent.Intersect(tileExtent);
+ if (intersect.Width == 0 || intersect.Height == 0)
+ continue;
+
+ int tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
+ int tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
+ int canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
+ int canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
+
+ using (var croppedTile = tileImage.Crop(tileOffsetPixelX, tileOffsetPixelY, (int)intersect.Width, (int)intersect.Height))
+ {
+ // Instead of inserting directly, we composite over the base canvas
+ canvas = canvas.Composite2(croppedTile, Enums.BlendMode.Over, canvasOffsetPixelX, canvasOffsetPixelY);
+ }
+ }
+ }
+
+ // Resize if the destination extent differs from the source canvas size
+ if ((int)dstPixelExtent.Width != canvasWidth || (int)dstPixelExtent.Height != canvasHeight)
+ {
+ double scaleX = (double)dstPixelExtent.Width / canvasWidth;
+ double scaleY = (double)dstPixelExtent.Height / canvasHeight;
+ canvas = canvas.Resize(scaleX, vscale: scaleY, kernel: Enums.Kernel.Nearest);
+ }
+
+ return canvas;
+ }
+
+ ///
+ /// Join by and cut by then scale to (only height an width is useful).
+ ///
+ /// tile with tile extent collection
+ /// canvas extent
+ /// jpeg output size
+ ///
+ public static unsafe NetVips.Image JoinVips16(IEnumerable> srcPixelTiles, Extent srcPixelExtent, Extent dstPixelExtent)
+ {
+ if (srcPixelTiles == null || !srcPixelTiles.Any())
+ return null;
+
+ srcPixelExtent = srcPixelExtent.ToIntegerExtent();
+ dstPixelExtent = dstPixelExtent.ToIntegerExtent();
+ int canvasWidth = (int)srcPixelExtent.Width;
+ int canvasHeight = (int)srcPixelExtent.Height;
+
+ // Create a base canvas. Adjust as necessary, for example, using a transparent image if needed.
+ AForge.Bitmap bf = new AForge.Bitmap(canvasWidth, canvasHeight, AForge.PixelFormat.Format16bppGrayScale);
+ NetVips.Image canvas = NetVips.Image.NewFromMemory(bf.Bytes, bf.SizeX, bf.SizeX, 1, Enums.BandFormat.Ushort);
+
+ foreach (var tile in srcPixelTiles)
+ {
+ if (tile.Item2 == null)
+ continue;
+
+ fixed (byte* pTileData = tile.Item2)
+ {
+ var tileExtent = tile.Item1.ToIntegerExtent();
+ NetVips.Image tileImage = NetVips.Image.NewFromMemory((IntPtr)pTileData, (ulong)tile.Item2.Length, (int)tileExtent.Width, (int)tileExtent.Height, 1, Enums.BandFormat.Ushort);
+
+ // Calculate positions and sizes for cropping and inserting
+ var intersect = srcPixelExtent.Intersect(tileExtent);
+ if (intersect.Width == 0 || intersect.Height == 0)
+ continue;
+
+ int tileOffsetPixelX = (int)Math.Ceiling(intersect.MinX - tileExtent.MinX);
+ int tileOffsetPixelY = (int)Math.Ceiling(intersect.MinY - tileExtent.MinY);
+ int canvasOffsetPixelX = (int)Math.Ceiling(intersect.MinX - srcPixelExtent.MinX);
+ int canvasOffsetPixelY = (int)Math.Ceiling(intersect.MinY - srcPixelExtent.MinY);
+
+ using (var croppedTile = tileImage.Crop(tileOffsetPixelX, tileOffsetPixelY, (int)intersect.Width, (int)intersect.Height))
+ {
+ // Instead of inserting directly, we composite over the base canvas
+ canvas = canvas.Composite2(croppedTile, Enums.BlendMode.Over, canvasOffsetPixelX, canvasOffsetPixelY);
+ }
+ }
+ }
+
+ // Resize if the destination extent differs from the source canvas size
+ if ((int)dstPixelExtent.Width != canvasWidth || (int)dstPixelExtent.Height != canvasHeight)
+ {
+ double scaleX = (double)dstPixelExtent.Width / canvasWidth;
+ double scaleY = (double)dstPixelExtent.Height / canvasHeight;
+ canvas = canvas.Resize(scaleX, vscale: scaleY, kernel: Enums.Kernel.Nearest);
+ }
+
+ return canvas;
+ }
+
+ public static SixLabors.ImageSharp.Image CreateImageFromBytes(byte[] rgbBytes, int width, int height, AForge.PixelFormat px)
+ {
+ if (px == AForge.PixelFormat.Format24bppRgb)
+ {
+ if (rgbBytes.Length != width * height * 3)
+ {
+ throw new ArgumentException("Byte array size does not match the dimensions of the image");
+ }
+
+ // Create a new image of the specified size
+ Image image = new Image(width, height);
+
+ // Index for the byte array
+ int byteIndex = 0;
+
+ // Iterate over the image pixels
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ // Create a color from the next three bytes
+ Rgb24 color = new Rgb24(rgbBytes[byteIndex], rgbBytes[byteIndex + 1], rgbBytes[byteIndex + 2]);
+ byteIndex += 3;
+ // Set the pixel
+ image[x, y] = color;
+ }
+ }
+
+ return image;
+ }
+ else
+ if (px == AForge.PixelFormat.Format16bppGrayScale)
+ {
+ if (rgbBytes.Length != width * height * 2)
+ {
+ throw new ArgumentException("Byte array size does not match the dimensions of the image");
+ }
+
+ // Create a new image of the specified size
+ Image image = new Image(width, height);
+
+ // Index for the byte array
+ int byteIndex = 0;
+
+ // Iterate over the image pixels
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ // Create a color from the next three bytes
+ L16 color = new L16(BitConverter.ToUInt16(rgbBytes, byteIndex));
+ byteIndex += 2;
+ // Set the pixel
+ image[x, y] = color;
+ }
+ }
+
+ return image;
+ }
+ else
+ if (px == AForge.PixelFormat.Format32bppArgb)
+ {
+ if (rgbBytes.Length != width * height * 4)
+ {
+ throw new ArgumentException("Byte array size does not match the dimensions of the image");
+ }
+
+ // Create a new image of the specified size
+ Image image = new Image(width, height);
+
+ // Index for the byte array
+ int byteIndex = 0;
+
+ // Iterate over the image pixels
+ for (int y = 0; y < height; y++)
+ {
+ for (int x = 0; x < width; x++)
+ {
+ // Create a color from the next three bytes
+ Bgra32 color = new Bgra32(rgbBytes[byteIndex], rgbBytes[byteIndex + 1], rgbBytes[byteIndex + 2], rgbBytes[byteIndex + 3]);
+ byteIndex += 4;
+ // Set the pixel
+ image[x, y] = color;
+ }
+ }
+
+ return image;
+ }
+ return null;
+ }
+
+ }
+
+}