C#绘制图像实现

C#绘制图像实现,c#,image-processing,graphics,C#,Image Processing,Graphics,我试图用不安全的代码和指针来实现Grahpics.DrawImage 在这种情况下,我试图在更大的宽度上绘制一个小位图(都是32bppArgb) 这是我的密码 private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint) { BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Hei

我试图用不安全的代码和指针来实现Grahpics.DrawImage

在这种情况下,我试图在更大的宽度上绘制一个小位图(都是32bppArgb)

这是我的密码

   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);
    }
private静态绘制(位图bmp、位图bmp2、int-xPoint、int-yPoint)
{
BitmapData bmData=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),System.Drawing.ImageLockMode.WriteOnly,bmp.PixelFormat);
BitmapData bmData2=bmp2.LockBits(新矩形(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-stripe2=bmData2.stripe;
int nWidth=bmp2.宽度;
int nHeight=bmp2.高度;
int sourceX=0;
int sourceY=0;
字节*p=(字节*)scan0.ToPointer();
p+=yPoint*stride+xPoint*4;
字节*p2=(字节*)scan02.ToPointer();
p2+=sourceY*2+sourceX*4;
int字节=nWidth*4;
对于(int y=0;y对于(int x=0;x我做了一些更改以使其工作:

  • 使用
    LockBits
    中的
    ImageLockMode.WriteOnly
    调用要写入的图像
  • 不要根据
    xPoint
    yPoint
    移动
    p2
我看到您将指针设置在外循环内,因此不需要移动循环末尾的指针。我建议您计算外循环外的起点,然后将指针移动到外循环内

我还建议进行以下更改:

  • 添加对图像边界的检查,以避免意外尝试在图像外部绘制

  • 使方法
    无效
    。返回位图表明它创建了一个新位图,而不是更改传递给它的位图之一

我添加了一个
pixelBytes
参数,使其可用于不同的像素格式(主要是因为我碰巧使用了JPEG,而不是PNG进行测试)

代码:

private静态绘制(位图bmp、位图bmp2、int-xPoint、int-yPoint、int-pixelBytes){
BitmapData bmData=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),System.Drawing.ImageLockMode.WriteOnly,bmp.PixelFormat);
BitmapData bmData2=bmp2.LockBits(新矩形(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-stripe2=bmData2.stripe;
int nWidth=bmp2.宽度;
int nHeight=bmp2.高度;
int sourceX=0;
int sourceY=0;
if(xPoint<0){
sourceX=-xPoint;
nWidth-=sourceX;
xPoint=0;
}
如果(yPoint<0){
sourceY=-yPoint;
nHeight-=源代码;
yPoint=0;
}
if(xPoint+nWidth>bmp.Width){
nWidth=bmp.Width-xPoint;
}
如果(yPoint+nHeight>bmp.Height){
nHeight=bmp.Height-yPoint;
}
如果(nWidth>0&&n宽度>0){
字节*p=(字节*)scan0.ToPointer();
p+=yPoint*stride+xPoint*pixelBytes;
字节*p2=(字节*)scan02.ToPointer();
p2+=sourceY*strip2+sourceX*pixelBytes;
int字节=nWidth*像素字节;
对于(int y=0;y
您正在将图像复制到自身。对于
b2
您应该使用
scan02
而不是
scan0
。对于
b2
,您还应该使用
stride
stride2
b
b2
移动到下一行,而不是假设下一行在当前行之后立即开始。行之间可能有填充,当图像在内存中颠倒存储时,步幅甚至可能为负值。@Guffa ohh..没有看到它…谢谢!Guffa等等..现在我在这里遇到一个异常`p[0]=p2[0];**试图读取或写入受保护的内存**我刚刚在上面的评论中添加了更多内容。@Guffa首先是它的
p
哈哈。关于移动
p
元素而不是
p+=4
来只使用`
p+=(yPoint*stride)+(xPoint*4)
?谢谢你,伙计,你太棒了!你的代码直截了当了!+1最后一件事是,这个方法的执行时间比我的慢多了(我知道它不起作用,但仍然有效).我认为主要的瓶颈是内部循环正在运行
字节
时间..难道它不能运行得更快吗?你能更新我的代码中的一些东西使其工作吗?非常感谢兄弟!你的答案非常棒,但有点慢..提前感谢!@Slashy:如果你删除
像素字节
参数并使其循环pixels而不是字节,你应该恢复性能。删除了参数。现在我应该改为写
4
,对吗?什么意思?让它循环像素@Guffa@Slashy:是。在循环中使用
x
,将所有
p[0]
复制到
p[3]
,并使用
+=4
增加指针。
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);
}