2

为了让我的问题更容易理解,我给你伪代码片段:

// dx (i.e. offset value) can be arbitrary. 
for(i = 0; i < bitmap.columnsCount - dx; i++)
{
    // "=" means copy pixels from one column to another.
    bitmap.column[i] = bitmap.column[i+dx];
}

我该怎么做?当然,我可以通过 LockBitmap 获取原始像素,然后以某种方式使用 MarshalCopy 或不安全部分......但这很难看而且太复杂了。有没有更好的办法?

我试图找到类似于MoveBitmapRegion()方法的东西,但我不能。给自己画位图的想法没有奏效:

Graphics g = Graphics.FromImage(bmp);
g.DrawImage(bmp, 0, 0, new Rectangle(dx, 0, bmp.Width - dx, bmp.Height), GraphicsUnit.Pixel);

制作位图的副本会有所帮助,但我认为它的操作成本太高:

Graphics g = Graphics.FromImage(bmp);
g.DrawImage(new Bitmap(bmp), 0, 0, new Rectangle(dx, 0, bmp.Width - dx, bmp.Height), GraphicsUnit.Pixel);
4

1 回答 1

1

好的,只是在一天结束时很快就完成了,所以可能会有一些错误,但在我测试的图像中,它似乎工作正常。

private static void CopyBmpRegion(Bitmap image, Rectangle srcRect, Point destLocation)
{
    //do some argument sanitising.
    if (!((srcRect.X >= 0 && srcRect.Y >= 0) && ((srcRect.X + srcRect.Width) <= image.Width) && ((srcRect.Y + srcRect.Height) <= image.Height)))
        throw new ArgumentException("Source rectangle isn't within the image bounds.");

    if ((destLocation.X < 0 || destLocation.X > image.Width) || (destLocation.Y < 0 || destLocation.Y > image.Height))
        throw new ArgumentException("Destination must be within the image.");

    // Lock the bits into memory
    BitmapData bmpData = image.LockBits(new Rectangle(Point.Empty, image.Size), ImageLockMode.ReadWrite, image.PixelFormat);
    int pxlSize = (bmpData.Stride / bmpData.Width); //calculate the pixel width (in bytes) of the current image.
    int src = 0; int dest = 0; //source/destination pixels.

    //account for the fact that not all of the source rectangle may be able to copy into the destination:
    int width = (destLocation.X + srcRect.Width) <= image.Width ? srcRect.Width : (image.Width - (destLocation.X + srcRect.Width)); 
    int height = (destLocation.Y + srcRect.Height) <= image.Height ? srcRect.Height : (image.Height - (destLocation.Y + srcRect.Height));

    //managed buffer to hold the current pixel data.
    byte[] buffer = new byte[pxlSize];

    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            //calculate the start of the current source pixel and destination pixel.
            src = ((srcRect.Y + y) * bmpData.Stride) + ((srcRect.X + x) * pxlSize);
            dest = ((destLocation.Y + y) * bmpData.Stride) + ((destLocation.X + x) * pxlSize);

            // Can replace this with unsafe code, but that's up to you.
            Marshal.Copy(new IntPtr(bmpData.Scan0.ToInt32() + src), buffer, 0, pxlSize);
            Marshal.Copy(buffer, 0, new IntPtr(bmpData.Scan0.ToInt32() + dest), pxlSize);
        }
    }

    image.UnlockBits(bmpData); //unlock the data.
}

本质上,您描述了您希望复制的区域的源矩形(以像素为单位,而不是以字节为单位),即 Rectangle(0, 0, 100, 100) 将描述从图像左上角开始的 100x100 像素宽的块。

接下来,描述目标矩形的左上角。尽可能多的源矩形将被复制到目标,但如果图像不够宽/高以容纳整个矩形,它将被剪裁。

使用示例如下:

Image img = Image.FromFile(@"C:\Users\254288b\Downloads\mozodojo-original-image.jpg");
CopyBmpRegion((Bitmap)img, new Rectangle(5, 5, 100, 100), new Point(100, 100));
img.Save(@"C:\Users\254288b\Downloads\mozodojo-new-image.jpg", ImageFormat.Jpeg);

结果如下:

mozodojo-原始图像.jpg

mozodojo-new-image.jpg

看看情况如何。

于 2012-07-10T10:10:46.113 回答