Image.Save (..) एक GDI + अपवाद फेंकता है क्योंकि मेमोरी स्ट्रीम बंद है


108

मुझे कुछ बाइनरी डेटा मिले हैं जो मैं एक छवि के रूप में सहेजना चाहता हूं। जब मैं छवि को बचाने की कोशिश करता हूं, तो यह एक अपवाद को फेंक देता है यदि छवि बनाने के लिए उपयोग की जाने वाली मेमोरी स्ट्रीम को सहेजने से पहले बंद कर दिया गया था। ऐसा करने का कारण यह है क्योंकि मैं गतिशील रूप से चित्र बना रहा हूं और जैसे कि .. मुझे मेमोरी स्ट्रीम का उपयोग करने की आवश्यकता है।

यह कोड है:

[TestMethod]
public void TestMethod1()
{
    // Grab the binary data.
    byte[] data = File.ReadAllBytes("Chick.jpg");

    // Read in the data but do not close, before using the stream.
    Stream originalBinaryDataStream = new MemoryStream(data);
    Bitmap image = new Bitmap(originalBinaryDataStream);
    image.Save(@"c:\test.jpg");
    originalBinaryDataStream.Dispose();

    // Now lets use a nice dispose, etc...
    Bitmap2 image2;
    using (Stream originalBinaryDataStream2 = new MemoryStream(data))
    {
        image2 = new Bitmap(originalBinaryDataStream2);
    }

    image2.Save(@"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}

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

मैं वास्तव में उलझन में हूँ :(


1
मुझे यह टिप्पणी @ हंसपसंद के एक अन्य प्रश्न में मिली । जब भी कोडेक को फ़ाइल लिखने में समस्या होती है, तो आपको यह अपवाद मिलेगा। जोड़ने के लिए एक अच्छा डीबगिंग कथन System.IO.File.WriteAllText (पथ, "परीक्षण") सेव () कॉल से पहले है, यह फ़ाइल बनाने की मूल क्षमता की पुष्टि करता है। अब आपको एक अच्छा अपवाद मिलेगा जो बताता है कि आपने क्या गलत किया।
जुआन कार्लोस ओरोपेज़ा

आपको छवि 2 चाहिए using। ब्लॉक के अंदर रखें । मुझे लगता originalBinaryDataStream2 है कि उपयोग के अंत में स्वचालित रूप से निपटारा किया गया था। और वह अपवाद को फेंक देगा।
taynguyen

जवाबों:


172

जैसा कि यह एक मेमोरीस्ट्रीम है, आपको वास्तव में स्ट्रीम को बंद करने की आवश्यकता नहीं है - यदि आप नहीं करते हैं तो कुछ भी बुरा नहीं होगा, हालांकि जाहिर है कि किसी भी चीज को डिस्पोज करने के लिए यह अच्छा अभ्यास है। ( इस सवाल को इस पर और देखें ।)

हालाँकि, आपको बिटमैप का निपटान करना चाहिए - और यह आपके लिए स्ट्रीम को बंद कर देगा। मूल रूप से एक बार जब आप Bitmap कंस्ट्रक्टर को एक स्ट्रीम देते हैं, तो यह स्ट्रीम का "मालिक" होता है और आपको इसे बंद नहीं करना चाहिए। जैसा कि उस निर्माता के डॉक्स कहते हैं:

आपको बिटमैप के जीवनकाल के लिए स्ट्रीम को खुला रखना होगा।

जब आप बिटमैप का निपटान करते हैं, तो मैं किसी भी डॉक्स को स्ट्रीम को बंद करने का वादा नहीं कर सकता, लेकिन आपको इसे आसानी से सत्यापित करने में सक्षम होना चाहिए।


2
बहुत बढ़िया! यह एक महान जवाब जॉन है। परिपूर्ण सेंस बनाता है (और डॉक्स में स्ट्रीम के बारे में मुझे थोड़ी याद आती है)। दो अंगूठे उपर! मैं रिपोर्ट करूँगा जब मैंने इसे जाने दिया :)
Pure.Krome

अगर हम CA2000 के नियम का पालन करना चाहते हैं तो इस बारे में कोई टिप्पणी कैसे की जाए? (msdn.microsoft.com/en-us/library/ms182289.aspx)
पैट्रिक

@ पैट्रिक: यह लागू नहीं है - आपने मूल रूप से संसाधन का स्वामित्व स्थानांतरित कर दिया है। निकटतम आप "नॉनक्लोजिंगस्ट्रीम" रैपर बनाने के लिए हो सकते हैं जो डिस्पोजल कॉल को अनदेखा करता है। मुझे लगता है कि मैं MiscUtil में एक हो सकता है - निश्चित नहीं ...
जॉन स्केट

जानकारी @Jon के लिए धन्यवाद। मेरे लिए, कुछ अजीब कारण से यह स्थानीय देव वातावरण में निपटान () के साथ भी काम कर रहा था, लेकिन उत्पादन में काम नहीं कर रहा था।
ऑक्सॉन

92

GDI + में एक सामान्य त्रुटि हुई। गलत सेव पथ से भी परिणाम हो सकता है ! मुझे नोटिस करने के लिए आधा दिन लगा। इसलिए सुनिश्चित करें कि आपने छवि को बचाने के लिए डबल चेक किया है।


4
मुझे खुशी है कि मैंने यह देखा, मेरा रास्ता था C\Users\mason\Desktop\pic.png। लापता बृहदान्त्र! मैंने उस पर गौर करने से पहले हमेशा के लिए खर्च किया होगा।
राजमिस्त्री

4
गलत का मतलब यह भी है कि आप जिस फ़ोल्डर को छवि को सहेजना चाहते हैं, वह मौजूद नहीं है।
रोमेर

14

शायद यह ध्यान देने योग्य है कि यदि C: \ Temp निर्देशिका मौजूद नहीं है, तो यह अपवाद भी छोड़ देगा भले ही आपकी स्ट्रीम अभी भी मौजूद हो।


+1 यह अपवाद कई प्रकार के परिदृश्यों में घटित होता है। अमान्य पथ वह है जिसका मैंने आज सामना किया है।
कर्क ब्रॉडहर्स्ट

4

मुझे भी यही समस्या थी लेकिन वास्तव में इसका कारण यह था कि एप्लिकेशन के पास सी पर फ़ाइलों को सहेजने की अनुमति नहीं थी। जब मैं "D: \ .." में बदल गया तो चित्र को सहेज लिया गया है।


2

बिटमैप की प्रतिलिपि बनाएँ। आपको बिटमैप के जीवनकाल के लिए स्ट्रीम को खुला रखना होगा।

छवि बनाते समय: System.Runtime.InteropServices.ExternalException: GDI में एक सामान्य त्रुटि हुई

    public static Image ToImage(this byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        using (var image = Image.FromStream(stream, false, true))
        {
            return new Bitmap(image);
        }
    }

    [Test]
    public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
    {
        var imageBytes = File.ReadAllBytes("bitmap.bmp");

        var image = imageBytes.ToImage();

        image.Save("output.bmp");
    }

1
यह ठीक काम नहीं करता है; ToImage () में आपके कोड में, स्थानीय "छवि" सही रूप से एक .RawFormat होगी जो कि मूल फ़ाइल (jpeg या png, आदि) थी, जबकि ToImage का रिटर्न मान () अप्रत्याशित रूप से होगा .RawFormat MemoryBmp।
पैट्रिक सज्जापस्की

RawFormatहालांकि यह तय नहीं है कि यह कितना मायने रखता है। आपको लगता है कि उपयोग करना चाहते हैं, रास्ते में वस्तु कहीं से इसे पुनः प्राप्त है, लेकिन बचाने आप वास्तव में चाहते हैं जो कुछ प्रकार के रूप में, सामान्य रूप में करने के लिए है
Nyerguds

2

आप बिटमैप की एक और प्रतिलिपि बनाने का प्रयास कर सकते हैं:

using (var memoryStream = new MemoryStream())
{
    // write to memory stream here

    memoryStream.Position = 0;
    using (var bitmap = new Bitmap(memoryStream))
    {
        var bitmap2 = new Bitmap(bitmap);
        return bitmap2;
    }
}

2

यह त्रुटि मुझे तब हुई जब मैं Citrix से कोशिश कर रहा था। सर्वर में छवि फ़ोल्डर C: \ पर सेट किया गया था, जिसके लिए मेरे पास विशेषाधिकार नहीं है। एक बार छवि फ़ोल्डर को साझा ड्राइव पर ले जाने के बाद, त्रुटि चली गई थी।


1

GDI + में एक सामान्य त्रुटि हुई। यह छवि भंडारण पथ के मुद्दों के कारण हो सकता है, मुझे यह त्रुटि मिली क्योंकि मेरा भंडारण पथ बहुत लंबा है, मैंने पहले छवि को कम से कम पथ में संग्रहीत करके इसे ठीक किया और इसे लंबे पथ हैंडलिंग तकनीकों के साथ सही स्थान पर ले गया।


1

मुझे यह त्रुटि मिल रही थी, क्योंकि मैं जिस स्वचालित परीक्षण को निष्पादित कर रहा था, वह स्नैपशॉट को एक फ़ोल्डर में संग्रहीत करने की कोशिश कर रहा था जो मौजूद नहीं था। फ़ोल्डर बनाने के बाद, त्रुटि हल हो गई


0

एक अजीब समाधान जिसने मेरे कोड को काम किया। छवि को पेंट में खोलें और इसे उसी प्रारूप (.jpg) के साथ एक नई फ़ाइल के रूप में सहेजें। अब इस नई फ़ाइल के साथ प्रयास करें और यह काम करता है। यह आपको स्पष्ट रूप से समझाता है कि फ़ाइल किसी में दूषित हो सकती है। यह तभी मदद कर सकता है जब आपके कोड में हर दूसरे बग्स हों


0

यह मेरे साथ भी दिखाई दिया जब मैं एक छवि को पथ में सहेजने का प्रयास कर रहा था

C:\Program Files (x86)\some_directory

और .exeव्यवस्थापक के रूप में चलाने के लिए निष्पादित नहीं किया गया था, मुझे आशा है कि यह किसी ऐसे व्यक्ति की मदद कर सकता है जिसके पास समान मुद्दा है।


0

मेरे लिए नीचे दिए गए कोड के साथ दुर्घटनाग्रस्त हो A generic error occurred in GDI+गया, जो एक बचत करता है MemoryStream। कोड एक वेब सर्वर पर चल रहा था और मैंने साइट को चलाने वाले एप्लिकेशन पूल को रोककर और शुरू करके इसे हल किया।

GDI + में कुछ आंतरिक त्रुटि रही होगी

    private static string GetThumbnailImageAsBase64String(string path)
    {
        if (path == null || !File.Exists(path))
        {
            var log = ContainerResolver.Container.GetInstance<ILog>();
            log.Info($"No file was found at path: {path}");
            return null;
        }

        var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;

        using (var image = Image.FromFile(path))
        {
            using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
            {
                using (var memoryStream = new MemoryStream())
                {
                    thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here 
                    var bytes = new byte[memoryStream.Length];
                    memoryStream.Position = 0;
                    memoryStream.Read(bytes, 0, bytes.Length);
                    return Convert.ToBase64String(bytes, 0, bytes.Length);
                }
            }
        }
    }

0

जब मैं एक WPF ऐप में एक साधारण छवि संपादन की कोशिश कर रहा था तो मुझे यह त्रुटि आई।

बिटमैप के लिए एक छवि तत्व के स्रोत को सेट करना फ़ाइल की बचत को रोकता है। यहां तक ​​कि सोर्स = नल सेट करने से फाइल रिलीज नहीं होती है।

अब मैं छवि के स्रोत के रूप में छवि का उपयोग कभी नहीं करता, इसलिए मैं संपादन के बाद अधिलेखित कर सकता हूं!

संपादित करें

CacheOption प्रॉपर्टी (@Nyerguds के लिए धन्यवाद) के बारे में सुनने के बाद मुझे इसका समाधान मिला: इसलिए बिटमैप निर्माता का उपयोग करने के बजाय मुझे सेटिंग करने के बाद उड़ी को सेट करना होगा CacheOption BitmapCacheOption.OnLoad। ( Image1नीचे Wpf Imageतत्व है)

के बजाय

Image1.Source = new BitmapImage(new Uri(filepath));

उपयोग:

var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;

इसे देखें: WPF इमेज कैशिंग


1
WPF छवियों को BitmapCacheOption.OnLoadलोडिंग स्रोत से डिस्कनेक्ट करने के लिए एक विशिष्ट पैरामीटर है।
Nyerguds

धन्यवाद @Nyerguds, जब तक आपकी टिप्पणी मैं सही सवाल पूछने में विफल रही
mkb

0

इस कोड को आज़माएं:

static void Main(string[] args)
{
    byte[] data = null;
    string fullPath = @"c:\testimage.jpg";

    using (MemoryStream ms = new MemoryStream())
    using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
    using (Bitmap bm = new Bitmap(tmp))
    {
        bm.SetResolution(96, 96);
        using (EncoderParameters eps = new EncoderParameters(1))
        {   
            eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
            bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
        }

        data = ms.ToArray();
    }

    File.WriteAllBytes(fullPath, data);
}

private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
        ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();

        for (int j = 0; j < encoders.Length; ++j)
        {
            if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
                return encoders[j];
        }
    return null;
}

0

मैंने छवियों को आकार देने के लिए इमेजप्रोसेसर का इस्तेमाल किया और एक दिन मुझे "GDI +" में एक सामान्य त्रुटि मिली।

थोड़ी देर देखने के बाद मैंने एप्लीकेशन पूल और बिंगो को रीसायकल करने की कोशिश की । इसलिए मैं इसे यहाँ नोट करता हूँ, आशा है कि यह मदद करेगा;)

चियर्स

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.