Hameer Abbasi
Hameer Abbasi

Reputation: 1314

Merge an array of Bitmaps into a single Bitmap

I'm trying to merge an array of Bitmaps 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 Bitmaps:

b[0,0] =Image 0,0;

b[1,0] =Image 1,1;

b[0,1] =Image 0,1;

b[1,1] =Image 1,1;

I want to generate result =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

Answers (2)

oooPhilippooo
oooPhilippooo

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

Hameer Abbasi
Hameer Abbasi

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

Related Questions