Reputation: 1314
I'm trying to merge an array of Bitmap
s into a single Bitmap
. Given a Bitmap[,]
array b
like the following (assume these are images that look like characters):
b[0,0] = 1
b[1,0] = 2
b[0,1] = 3
b[1,1] = 4
I want to generate
result = 12
34
For example, given the following four Bitmap
s:
b[0,0] =
;
b[1,0] =
;
b[0,1] =
;
b[1,1] =
;
I want to generate
result =
;
Here's my code so far:
public static Bitmap Moisac(ref Bitmap[,] b)
{
BitmapData[,] bmData = new BitmapData[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
IntPtr[,] scan0 = new IntPtr[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
unsafe
{
byte*[,] p = new byte*[b.GetUpperBound(0) + 1,b.GetUpperBound(1) + 1];
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
if (b[i, j].Width != b[0, 0].Width | b[i, j].Height != b[0, 0].Height)
throw new ArgumentException(
"Width and Height properties of all elements of b must be equal.",
"b");
int oneW = b[0, 0].Width;
int oneH = b[0, 0].Height;
int overallWidth = oneW * (b.GetUpperBound(0) + 1);
int overallHeight = oneH * (b.GetUpperBound(1) + 1);
Bitmap result = new Bitmap(b[0, 0], overallWidth, overallHeight);
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
{
bmData[i, j] = b[i, j].LockBits(new Rectangle(0, 0, oneW, oneH),
ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
scan0[i, j] = bmData[i, j].Scan0;
p[i, j] = (byte*)(void*)scan0[i, j];
}
BitmapData rbmData = result.LockBits(new Rectangle(0, 0, overallWidth, overallHeight),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData[0, 0].Stride;
int nOffset = stride - 3*b[0, 0].Width;
int rStride = rbmData.Stride;
IntPtr rScan0 = rbmData.Scan0;
byte* rp = (byte*) (void*) rScan0;
for (int imgY = 0; imgY < b.GetUpperBound(1); ++imgY)
{
for (int imgX = 0; imgX <= b.GetUpperBound(0); ++imgX)
{
byte* currp = p[imgX, imgY];
for (int y = 0; y < oneH; ++y)
{
for (int x = 0; x < 3*oneW; ++x)
{
rp[rStride*(imgY*oneH + y) + 3*imgX*oneW + x] = currp[0];
++currp;
}
currp += nOffset;
}
}
}
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
b[i, j].UnlockBits(bmData[i,j]);
result.UnlockBits(rbmData);
return result;
}
}
See the images in the album here. All of them won't display here.
Upvotes: 1
Views: 819
Reputation: 1
I made a version based on your code that copies lines of pixels rather than pixels. Seems to work (faster) on my box at least. Maybe you like it. Minimal changes just within the for each loops. Im using it really only for concatenating...before warping images into a donut for a 360 simple degree view of multiple camera images...
public static Bitmap Mosaic(ref Bitmap[,] b)
{
BitmapData[,] bmData = new BitmapData[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
IntPtr[,] scan0 = new IntPtr[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
unsafe
{
byte*[,] p = new byte*[b.GetUpperBound(0) + 1, b.GetUpperBound(1) + 1];
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
if (b[i, j].Width != b[0, 0].Width | b[i, j].Height != b[0, 0].Height)
throw new ArgumentException(
"Width and Height properties of all elements of b must be equal.",
"b");
int oneW = b[0, 0].Width;
int oneH = b[0, 0].Height;
int overallWidth = oneW * (b.GetUpperBound(0) + 1);
int overallHeight = oneH * (b.GetUpperBound(1) + 1);
Bitmap result = new Bitmap(b[0, 0], overallWidth, overallHeight);
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
{
bmData[i, j] = b[i, j].LockBits(new Rectangle(0, 0, oneW, oneH),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
scan0[i, j] = bmData[i, j].Scan0;
p[i, j] = (byte*)(void*)scan0[i, j];
}
BitmapData rbmData = result.LockBits(new Rectangle(0, 0, overallWidth, overallHeight),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int stride = bmData[0, 0].Stride;
int nOffset = stride - 4 * b[0, 0].Width;
int rStride = rbmData.Stride;
IntPtr rScan0 = rbmData.Scan0;
byte* rp = (byte*)(void*)rScan0;
for (int imgY = 0; imgY <= b.GetUpperBound(1); ++imgY)
{
for (int y = 0; y < oneH; ++y)
{
byte* currp = p[0, imgY];
for (int imgX = 0; imgX <= b.GetUpperBound(0); ++imgX)
{
currp = p[imgX, imgY];
currp += stride*y;
byte[] buffer = new byte[stride];
Marshal.Copy(new IntPtr(currp), buffer, 0, buffer.Length);
Marshal.Copy(buffer, 0, new IntPtr(rp), buffer.Length);
rp += stride;
}
}
}
for (int i = 0; i <= b.GetUpperBound(0); i++)
for (int j = 0; j <= b.GetUpperBound(1); j++)
b[i, j].UnlockBits(bmData[i, j]);
result.UnlockBits(rbmData);
return result;
}
}
Upvotes: 0
Reputation: 1314
I made the most stupid mistake ever. However, if it may help anyone, change
for (int imgY = 0; imgY < b.GetUpperBound(1); ++imgY)
to
for (int imgY = 0; imgY <= b.GetUpperBound(1); ++imgY)
(the <
should be <=
).
Upvotes: 1