Im trying to make kind of Grahpics.DrawImage
implemention using unsafe code and pointers of course.
In this case im trying to draw a small bitmap on a bigger width(both 32bppArgb).
This is my code
private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint)
{
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat);
BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int nWidth = bmp2.Width;
int nHeight = bmp2.Height;
int sourceX = 0;
int sourceY = 0;
byte* p = (byte*)scan0.ToPointer();
p += yPoint * stride + xPoint * 4;
byte* p2 = (byte*)scan02.ToPointer();
p2 += sourceY * stride2 + sourceX * 4;
int bytes = nWidth * 4;
for (int y = 0; y < nHeight; y++)
{
for (int x = 0; x <nWidth; x++)
{
p[0] = p2[0];
p[1] = p2[1];
p[2] = p2[2];
p[3] = p2[3];
}
p += 4;
p2 += 4;
}
bmp.UnlockBits(bmData);
bmp2.UnlockBits(bmData2);
}
this is the updated code
I made some changes to make it work:
- Use
ImageLockMode.WriteOnly
in the LockBits
call for the image that you want to write to.
- Don't move
p2
according to xPoint
and yPoint
.
I saw that you set the pointers inside the outer loop, so then you would not need to move the pointers at the end of the loop. I recommend that you calculcate the starting points outside the outer loop, and move the pointers inside it.
I also recommend these changes that I did:
Add checks for the bounds of the images, so that you don't accidentally try to draw outside the image.
Make the method void
. Returning a bitmap suggests that it creates a new bitmap rather than changing one of the bitmap that you pass into it.
I added a pixelBytes
parameter to make it usable for different pixel formats. (Mostly because I happened to have JPEGs, not PNGs to test with.)
Code:
private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint, int pixelBytes) {
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat);
BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int nWidth = bmp2.Width;
int nHeight = bmp2.Height;
int sourceX = 0;
int sourceY = 0;
if (xPoint < 0) {
sourceX = -xPoint;
nWidth -= sourceX;
xPoint = 0;
}
if (yPoint < 0) {
sourceY = -yPoint;
nHeight -= sourceY;
yPoint = 0;
}
if (xPoint + nWidth > bmp.Width) {
nWidth = bmp.Width - xPoint;
}
if (yPoint + nHeight > bmp.Height) {
nHeight = bmp.Height - yPoint;
}
if (nWidth > 0 && nHeight > 0) {
byte* p = (byte*)scan0.ToPointer();
p += yPoint * stride + xPoint * pixelBytes;
byte* p2 = (byte*)scan02.ToPointer();
p2 += sourceY * stride2 + sourceX * pixelBytes;
int bytes = nWidth * pixelBytes;
for (int y = 0; y < nHeight; y++) {
for (int x = 0; x < bytes; x++) {
p[0] = p2[0];
p++;
p2++;
}
p += stride - nWidth * pixelBytes;
p2 += stride2 - nWidth * pixelBytes;
}
}
bmp.UnlockBits(bmData);
bmp2.UnlockBits(bmData2);
}