2012-10-03 23 views
51

जहां तक ​​मैं कह सकता हूं, बिटमैप की प्रतिलिपि बनाने के दो तरीके हैं।बिटमैप.क्लोन() और नया बिटमैप (बिटमैप) के बीच क्या अंतर है?

Bitmap.Clone()

Bitmap A = new Bitmap("somefile.png"); 
Bitmap B = (Bitmap)A.Clone(); 

नया बिटमैप()

Bitmap A = new Bitmap("somefile.png"); 
Bitmap B = new Bitmap(A); 

कैसे इन तरीकों अलग हैं? मैं विशेष रूप से स्मृति और थ्रेडिंग के मामले में अंतर में रूचि रखता हूं।

+3

मैं एक मामले में जहां फ़ाइल मैं पढ़ रहा था एक प्रति पिक्सेल 1 बिट TIFF फ़ाइल था। 'नया बिटमैप (ए) '32 बिट प्रति पिक्सेल बिटमैप लौटा, जबकि' (बिटमैप) एक्लोन() 'अभी भी 1 बिट प्रति पिक्सेल था। चूंकि मैं बाद में ईमेलिंग के लिए पीडीएफ में छवि को एम्बेड कर रहा था, इसलिए छवि को 1 बिट पर रखना महत्वपूर्ण था। @ एलीओस @ हंसपैसेंट – gmlobdell

उत्तर

49

यह "गहरी" और "उथले" प्रतिलिपि के बीच आम अंतर है, जो लगभग-बहिष्कृत आईसीएलओबल इंटरफेस के साथ भी एक मुद्दा है। क्लोन() विधि एक नया बिटमैप ऑब्जेक्ट बनाता है लेकिन पिक्सेल डेटा को मूल बिटमैप ऑब्जेक्ट के साथ साझा किया जाता है। बिटमैप (छवि) कन्स्ट्रक्टर भी एक नया बिटमैप ऑब्जेक्ट बनाता है लेकिन जिसकी पिक्सेल डेटा की अपनी प्रति है।

क्लोन का उपयोग() बहुत शायद ही कभी उपयोगी है। एसओ पर इसके बारे में बहुत सारे प्रश्न जहां प्रोग्रामर उम्मीद करता है कि क्लोन() बिटमैप्स के साथ सामान्य परेशानी से बचाता है, जिस फ़ाइल से इसे लोड किया गया था उस पर लॉक। यह नहीं है केवल क्लोन() का उपयोग करें जब आप कोड के संदर्भ को पास करते हैं जो बिटमैप का निपटारा करता है और आप ऑब्जेक्ट को खोना नहीं चाहते हैं।

+4

सहमत हुए। हमने उस मामले में क्लोन() का उपयोग किया जहां हमें उपयोग करने की आवश्यकता है, जहां कई जगहों पर एक ही बिटमैप का उपयोग किया जाता है (असम्बद्ध), लेकिन हम प्रतियों द्वारा उपयोग की जाने वाली मेमोरी की मात्रा को कम करना चाहते थे। एक बात मुझे नहीं पता कि अगर आप क्लोन (यानी सेटपिक्सेल) में से किसी एक को संशोधित करते हैं, तो यदि यह सभी साझा पिक्सेल डेटा को संशोधित करने का कारण बनता है, या यदि यह संशोधित व्यक्ति को अपने स्वयं के पिक्सेल डेटा आवंटित करने का कारण बनता है (इस प्रकार बस अपना स्वयं का संशोधन)। –

+0

@ मैटस्मिथ, डेटा को लॉक कमांड के बाद कॉपी किया जाएगा, यहां तक ​​कि रेन्डऑनली फ्लैग के साथ भी। – Pedro77

+0

@ हंसपैसेंट, * "डिस्पोजेस" * से, क्या आपका मतलब है, * "कॉल करें"। (डिसोस्पेक्ट() 'विधि "* जब आप यह कहते हैं: *" केवल क्लोन() का उपयोग करें जब आप कोड का संदर्भ पास करते हैं जो निपटान करता है बिटमैप और आप ऑब्जेक्ट को खोना नहीं चाहते हैं। "* – kdbanman

87

पिछले उत्तरों को पढ़ते हुए, मुझे चिंता हो गई कि पिक्सेल डेटा बिटमैप के क्लोन उदाहरणों के बीच साझा किया जाएगा। इसलिए मैंने 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() के बाद फ़ाइल अनलॉक हो जाएगा, और अपवाद उत्पन्न नहीं किया जाएगा। क्लोन (.Clone() के साथ बनाया) को संशोधित करने के Graphics वर्ग का उपयोग करते हुए मूल में बदलाव नहीं करेगी:

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

:

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 पद्धति का उपयोग करके मूल और क्लोन के लिए अलग स्मृति ब्लॉक पैदावार परिणाम object ICloneable.Clone() और Bitmap Bitmap.Clone(Rectangle, PixelFormat) दोनों के साथ समान हैं।

अगला, मैंने निम्नलिखित कोड का उपयोग करके कुछ सरल मानकों का प्रयास किया।

सूची में 50 प्रतियां भंडारण 6.2 सेकंड लिया और परिणामस्वरूप 1.7 जीबी मेमोरी उपयोग में (मूल छवि 24 bpp और 3456 x 2400 पिक्सल = 25 MB):

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 सेकंड के दौरान सूची में 1 000 000 प्रतियां और 0.9 जीबी का उपयोग कर। जैसी उम्मीद थी, Clone() बहुत new Bitmap() की तुलना में हल्के वजन है:

for(int i = 0; i < 1000000; i++) 
    { 
    list.Add((Bitmap) original.Clone()); 
    } 

Clone() पद्धति का उपयोग करके क्लोन कॉपी-ऑन-राइट कर रहे हैं। यहां मैं क्लोन पर एक यादृच्छिक रंग में एक यादृच्छिक पिक्सेल बदलता हूं।इस आपरेशन, मूल से सभी पिक्सेल डेटा की एक प्रतिलिपि को गति प्रदान करने लगता है क्योंकि अब हम 7.8 सेकंड और 1.6 जीबी में वापस आ गए हैं:

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

बस छवि से एक Graphics वस्तु बनाने की नकल ट्रिगर नहीं करेगा:

for(int i = 0; i < 50; i++) 
    { 
    Bitmap clone = (Bitmap) original.Clone(); 
    Graphics.FromImage(clone).Dispose(); 
    list.Add(clone); 
    } 

आपको कॉपी को ट्रिगर करने के लिए Graphics ऑब्जेक्ट का उपयोग करके कुछ आकर्षित करना होगा। अंत में, दूसरे हाथ पर LockBits का उपयोग कर, डेटा की प्रतिलिपि जाएगा, भले ही ImageLockMode.ReadOnly निर्दिष्ट किया जाता है:

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); 
    } 
+5

बहुत अच्छा पोस्ट मैन! – Pedro77

+1

तो, छवि और सभी डेटा की पूरी तरह से अलग प्रति प्राप्त करने के लिए कौन सी विधि सर्वोत्तम है? – Don

+0

यदि आपको एक अलग प्रति की आवश्यकता है, तो मैं नया बिटमैप() का उपयोग करूंगा। यह मूल फ़ाइल पर फ़ाइल लॉक नहीं रखेगा और सीपीयू समय और स्मृति की प्रतिलिपि प्रतिलिपि के स्थान पर उपयोग की जाएगी, न कि उस स्थान पर जहां आप प्रतिलिपि को संशोधित करना शुरू करते हैं। लेकिन अगर आप सुनिश्चित नहीं हैं कि प्रतिलिपि संशोधित की जाएगी या नहीं, तो क्लोन() शायद एक बेहतर विकल्प है। – Anlo