さて、一日の終わりにこれを非常に迅速に作成したので、いくつかの間違いがあるかもしれませんが、テストした画像ではうまく機能しているように見えました.
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-original-image.jpg
mozodojo-new-image.jpg
それがどうなるか見てください。