For my use I choose to use one or more array of double, it is more efficient than bitmap. Not sure it is very good programming but it works and helps me for BlueNoise (not published), Making an image with a single thread (not here),

```
public class ImageGreyScale
{
public double[,] image;
public double[,] imageAlpha;
int width;
int height;
double initialWidth;
double initialHeight;
Point3d LowerLeftPoint;
double ScaleX;
double ScaleY;
/// <summary>
/// Image with a gradiant
/// </summary>
/// <param name="curve"></param>
/// <param name="dMax"></param>
/// <param name="maxPixelWidth"></param>
public ImageGreyScale(Curve curve, double dMax, int maxPixelWidth, double power)
{
power = Math.Min(10, Math.Max(0.1, power));
PolylineCurve plCurve = curve.ToPolyline(dMax / 1000, 0.01, dMax / 1000, dMax);
BoundingBox bb = curve.GetBoundingBox(true);
width = maxPixelWidth;
ScaleX = (double)(width - 1) / bb.Diagonal.X;
LowerLeftPoint = bb.PointAt(0, 0, 0);
height = (int)(bb.Diagonal.Y * ScaleX);
ScaleY = (double)(height - 1) / bb.Diagonal.Y;
image = new double[width, height];
imageAlpha = new double[width, height];
System.Threading.Tasks.Parallel.For(0, height, j =>
{
for (int i = 0; i < width; i++)
{
Point3d pt = GetPoint(i, j);
//Pas la peine de passer en polyline on gagne rien !
PointContainment ptCt = curve.Contains(pt, Plane.WorldXY, 0.01);
double t = 0.0;
curve.ClosestPoint(pt, out t);
double distance = curve.PointAt(t).DistanceTo(pt);
if (ptCt == PointContainment.Outside)
{
image[i, j] = 1;
imageAlpha[i, j] = 0;
}
else
{
image[i, j] = Math.Pow(Math.Max(0, Math.Min(1, distance / dMax)), power);
imageAlpha[i, j] = 1;
}
}
});
}
public ImageGreyScale(string fileName)
{
Bitmap bitmap = new Bitmap(fileName);
PrivateImageGreyScale(fileName, bitmap.Width);
bitmap.Dispose();
}
public void Save(string fileName)
{
Image img = ToImage();
img.Save(fileName);
}
public Image ToImage()
{
Bitmap bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.White);
for (int j = 0; j < bmp.Height; j++)
{
for (int i = 0; i < bmp.Width; i++)
{
int alpha = (int)(Math.Max(0, Math.Min(imageAlpha[i, j], 1)) * 255);
int val = (int)(Math.Max(0, Math.Min(image[i, j], 1)) * 255);
bmp.SetPixel(i, j, Color.FromArgb(alpha, val, val, val));
}
}
return (Bitmap)bmp;
}
public Mesh GetMesh()
{
Mesh mesh = new Mesh();
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
mesh.Vertices.Add(this.GetPoint(i, j));
int alpha = (int)(Math.Max(0, Math.Min(imageAlpha[i, j], 1)) * 255);
int val = (int)(Math.Max(0, Math.Min(image[i, j], 1)) * 255);
mesh.VertexColors.Add(Color.FromArgb(alpha, val, val, val));
}
}
for (int j = 0; j < height - 1; j++)
{
for (int i = 0; i < width - 1; i++)
{
mesh.Faces.AddFace(new MeshFace(i + j * width, i + 1 + j * width, i + 1 + (j + 1) * width, i + (j + 1) * width));
}
}
mesh.RebuildNormals();
return mesh;
}
```