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 または unsafe セクションを使用することもできます...しかし、これは見苦しく、複雑すぎます。より良い方法はありますか?

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-original-image.jpg

mozodojo-new-image.jpg

それがどうなるか見てください。

于 2012-07-10T10:10:46.113 に答える