正在移动位图区域



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

// 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);

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

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.
}

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

接下来,描述目标矩形的左上角。将尽可能多的源矩形复制到目标,但如果图像不够宽/不够高,无法容纳整个矩形,则会对其进行剪裁。

使用示例如下:

Image img = Image.FromFile(@"C:Users254288bDownloadsmozodojo-original-image.jpg");
CopyBmpRegion((Bitmap)img, new Rectangle(5, 5, 100, 100), new Point(100, 100));
img.Save(@"C:Users254288bDownloadsmozodojo-new-image.jpg", ImageFormat.Jpeg);

结果如下:

mozodojo-original-image.jpg

mozodojo-new-image.jpg

看看进展如何。

最新更新