Bitmap.Clone ()과 새 Bitmap (Bitmap)의 차이점은 무엇입니까?
내가 알 수있는 한, 비트 맵을 복사하는 방법에는 두 가지가 있습니다.
Bitmap.Clone ()
Bitmap A = new Bitmap("somefile.png");
Bitmap B = (Bitmap)A.Clone();
새로운 Bitmap ()
Bitmap A = new Bitmap("somefile.png");
Bitmap B = new Bitmap(A);
이러한 접근 방식은 어떻게 다릅니 까? 특히 메모리와 스레딩의 차이에 관심이 있습니다.
"깊은"복사본과 "얕은"복사본의 공통적 인 차이점이며 거의 사용되지 않는 IClonable 인터페이스의 문제이기도합니다. Clone () 메서드는 새 Bitmap 객체를 만들지 만 픽셀 데이터는 원본 비트 맵 객체와 공유됩니다. Bitmap (Image) 생성자는 또한 새 Bitmap 객체를 만들지 만 픽셀 데이터의 자체 복사본이있는 객체를 만듭니다.
프로그래머가 비트 맵과 관련된 일반적인 문제,로드 된 파일에 대한 잠금을 피하고자하는 Clone ()에 대한 많은 질문이 있습니다. 그렇지 않습니다. 실용적인 사용법은 전달 된 비트 맵에서 Dispose ()를 부적절하게 호출하는 라이브러리 메서드의 문제를 피하는 것입니다.
오버로드는 픽셀 형식 변환 또는 자르기 옵션을 활용하여 유용 할 수 있습니다.
이전 답변을 읽으면서 비트 맵의 복제 된 인스턴스간에 픽셀 데이터가 공유 될까 걱정했습니다. 그래서 Bitmap.Clone()
와 의 차이점을 찾기 위해 몇 가지 테스트를 수행했습니다 new Bitmap()
.
Bitmap.Clone()
원본 파일을 잠근 상태로 유지합니다.
Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
original.Dispose();
File.Delete("Test.jpg"); // Will throw System.IO.IOException
new Bitmap(original)
대신 사용 하면 파일이 잠금 해제되고 original.Dispose()
예외가 발생하지 않습니다. Graphics
클래스를 사용하여 복제본 (로 생성됨 .Clone()
)을 수정하면 원본이 수정되지 않습니다.
Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
Graphics gfx = Graphics.FromImage(clone);
gfx.Clear(Brushes.Magenta);
Color c = original.GetPixel(0, 0); // Will not equal Magenta unless present in the original
마찬가지로이 LockBits
메서드를 사용하면 원본 및 복제본에 대해 다른 메모리 블록이 생성됩니다.
Bitmap original = new Bitmap("Test.jpg");
Bitmap clone = (Bitmap) original.Clone();
BitmapData odata = original.LockBits(new Rectangle(0, 0, original.Width, original.Height), ImageLockMode.ReadWrite, original.PixelFormat);
BitmapData cdata = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadWrite, clone.PixelFormat);
Assert.AreNotEqual(odata.Scan0, cdata.Scan0);
결과는 object ICloneable.Clone()
및 모두 동일합니다 Bitmap Bitmap.Clone(Rectangle, PixelFormat)
.
다음으로 다음 코드를 사용하여 몇 가지 간단한 벤치 마크를 시도했습니다.
목록에 50 개의 사본을 저장하는 데 6.2 초가 걸렸고 1.7GB의 메모리 사용량이 발생했습니다 (원본 이미지는 24bpp, 3456 x 2400 픽셀 = 25MB).
Bitmap original = new Bitmap("Test.jpg");
long mem1 = Process.GetCurrentProcess().PrivateMemorySize64;
Stopwatch timer = Stopwatch.StartNew();
List<Bitmap> list = new List<Bitmap>();
Random rnd = new Random();
for(int i = 0; i < 50; i++)
{
list.Add(new Bitmap(original));
}
long mem2 = Process.GetCurrentProcess().PrivateMemorySize64;
Debug.WriteLine("ElapsedMilliseconds: " + timer.ElapsedMilliseconds);
Debug.WriteLine("PrivateMemorySize64: " + (mem2 - mem1));
Clone()
대신 사용하면 0.7 초 동안 0.9GB를 사용하여 1,000,000 개의 사본을 목록에 저장할 수 있습니다. 예상대로 다음과 Clone()
비교하여 매우 가볍습니다 new Bitmap()
.
for(int i = 0; i < 1000000; i++)
{
list.Add((Bitmap) original.Clone());
}
Clones using the Clone()
method are copy-on-write. Here I change one random pixel to a random color on the clone. This operation seems to trigger a copy of all pixel data from the original, because we're now back at 7.8 seconds and 1.6 GB:
Random rnd = new Random();
for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
clone.SetPixel(rnd.Next(clone.Width), rnd.Next(clone.Height), Color.FromArgb(rnd.Next(0x1000000)));
list.Add(clone);
}
Just creating a Graphics
object from the image will not trigger the copy:
for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
Graphics.FromImage(clone).Dispose();
list.Add(clone);
}
You have to draw something using the Graphics
object in order to trigger the copy. Finally, using LockBits
on the other hand, will copy the data even if ImageLockMode.ReadOnly
is specified:
for(int i = 0; i < 50; i++)
{
Bitmap clone = (Bitmap) original.Clone();
BitmapData data = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadOnly, clone.PixelFormat);
clone.UnlockBits(data);
list.Add(clone);
}
'Program Tip' 카테고리의 다른 글
이 경우 bool과 not bool이 모두 true를 반환하는 이유는 무엇입니까? (0) | 2020.11.04 |
---|---|
Android에서 데이터 바인딩을 사용하여 ImageView의 android : src에서 드로어 블 리소스 ID 설정 (0) | 2020.11.04 |
OWIN HttpListener를 찾을 수 없습니다. (0) | 2020.11.03 |
Pandas 및 matplotlib를 사용하여 범주 형 데이터 플로팅 (0) | 2020.11.03 |
Windows Forms DateTimePicker 컨트롤에서 날짜 값만 가져 오는 방법은 무엇입니까? (0) | 2020.11.03 |