जब विकल्प सेट किए जाते हैं, तो बिटमैप फ़्रीमेंट


90

मैं मुद्दों के साथ कर रहा हूँ BitmapFactory.decodeStream(inputStream)। विकल्पों के बिना इसका उपयोग करते समय, यह एक छवि लौटाएगा। लेकिन जब मैं इसे विकल्पों के साथ उपयोग करता हूं क्योंकि .decodeStream(inputStream, null, options)यह कभी भी बिटमैप्स को वापस नहीं करता है।

इससे पहले कि मैं वास्तव में मेमोरी को बचाने के लिए लोड करूं, मैं एक बिटमैप को डाउनप्लस करने की कोशिश कर रहा हूं। मैंने कुछ अच्छे मार्गदर्शक पढ़े हैं, लेकिन कोई भी उपयोग नहीं कर रहा है .decodeStream

बस काम ठीक है

URL url = new URL(sUrl);
HttpURLConnection connection  = (HttpURLConnection) url.openConnection();

InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);

काम नहीं करता है

InputStream is = connection.getInputStream();
Bitmap img = BitmapFactory.decodeStream(is, null, options);

InputStream is = connection.getInputStream();

Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

BitmapFactory.decodeStream(is, null, options);

Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH);

if (options.outHeight * options.outWidth * 2 >= 200*100*2){
    // Load, scaling to smallest power of 2 that'll get it <= desired dimensions
    double sampleSize = scaleByHeight
    ? options.outHeight / TARGET_HEIGHT
    : options.outWidth / TARGET_WIDTH;
    options.inSampleSize =
        (int)Math.pow(2d, Math.floor(
        Math.log(sampleSize)/Math.log(2d)));
}

// Do the actual decoding
options.inJustDecodeBounds = false;
Bitmap img = BitmapFactory.decodeStream(is, null, options);

1
आपके System.out.println ("नमूने:" ...) कथन से आउटपुट क्या है? क्या संकेत दिया जा रहा है कि options.inSampleSize एक स्वीकार्य मूल्य है?
स्टीव हेली

हां, यह हर बार स्वीकार्य मूल्य देता है।
रॉबर्ट फॉस

डिबग होने के कारण बयान को हटा दिया।
रॉबर्ट फॉस

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

समुदाय में एकीकृत करने के लिए एक नए उपयोगकर्ता की मदद करने के लिए धन्यवाद :)
रॉबर्ट फॉस

जवाबों:


114

समस्या यह थी कि एक बार आपने इमेज मेटाडेटा लाने के लिए एक HttpUrlConnection से एक इनपुटस्ट्रीम का उपयोग किया है, तो आप उसी इनपुटस्ट्रीम को फिर से रिवाइंड और उपयोग नहीं कर सकते।

इसलिए आपको छवि के वास्तविक नमूने के लिए एक नया InputStream बनाना होगा।

  Options options = new BitmapFactory.Options();
  options.inJustDecodeBounds = true;

  BitmapFactory.decodeStream(is, null, options);

  Boolean scaleByHeight = Math.abs(options.outHeight - TARGET_HEIGHT) >= Math.abs(options.outWidth - TARGET_WIDTH);

  if(options.outHeight * options.outWidth * 2 >= 200*200*2){
         // Load, scaling to smallest power of 2 that'll get it <= desired dimensions
        double sampleSize = scaleByHeight
              ? options.outHeight / TARGET_HEIGHT
              : options.outWidth / TARGET_WIDTH;
        options.inSampleSize = 
              (int)Math.pow(2d, Math.floor(
              Math.log(sampleSize)/Math.log(2d)));
     }

        // Do the actual decoding
        options.inJustDecodeBounds = false;

        is.close();
        is = getHTTPConnectionInputStream(sUrl);
        Bitmap img = BitmapFactory.decodeStream(is, null, options);
        is.close();

17
इसका मतलब यह है कि छवि को दो बार डाउनलोड करना है? एक बार आकार प्राप्त करने के लिए और एक बार पिक्सेल डेटा प्राप्त करने के लिए?
user123321

1
@Robert आपको शायद इस विशेष व्यवहार की व्याख्या करनी चाहिए ताकि अन्य उपयोगकर्ताओं को इसके बारे में एक स्पष्ट विचार मिल सके
मुहम्मद बाबर

1
मैं सोच रहा था कि यह उसी
इनपुटस्ट्रीम के

1
आपको इसे पुनः बनाने की आवश्यकता नहीं है, इसे रीसेट करने से उद्देश्य पूरा हो जाएगा। मेरा उत्तर देखें
शशांक तोमर

5
मुझे एंड्रॉइड बेकार का बिटमैप वर्ग कहना है। यह बहुत भ्रामक और उपयोग करने के लिए निराशाजनक है।
नियॉन वारगे ने

30

BufferedInputStream के साथ InputStream रैप करने का प्रयास करें।

InputStream is = new BufferedInputStream(conn.getInputStream());
is.mark(is.available());
// Do the bound decoding
// inJustDecodeBounds =true
is.reset();  
// Do the actual decoding

2
क्या यह हमेशा आपके लिए काम करता था? किसी कारण के लिए, मैं इस पद्धति का उपयोग करते हुए कुछ बहुत विशिष्ट मामलों पर शून्य हो जाता हूं। मैंने इसके बारे में एक पोस्ट यहाँ लिखी है: stackoverflow.com/questions/17774442/…
एंड्रॉइड डेवलपर

1
यह काम किया इसलिए मैंने इसे बढ़ा दिया लेकिन is.available () डॉक्टर चेतावनी के साथ आता है कि इसका उपयोग केवल यह जांचने के लिए किया जाना चाहिए कि क्या धारा खाली है या नहीं और आकार की गणना के लिए नहीं क्योंकि यह अविश्वसनीय है।
अभिषेक चौहान

1
डाउन-वोटेड, लेकिन विचाराधीन इनपुटस्ट्रीम कनेक्शन एक HTTP कनेक्शन और रीसेट () काम नहीं करेगा ....
जॉनी वू

3

मुझे लगता है कि समस्या "गणना-पैमाने-कारक" तर्क के साथ है क्योंकि बाकी कोड मुझे सही लगता है (यह मानते हुए कि इनपुटस्ट्रीम शून्य नहीं है)।

यह बेहतर होगा यदि आप इस दिनचर्या से सभी आकार गणना तर्क को एक विधि में बदल सकते हैं (इसे कैल्कुलसैक्टर () या जो भी कहते हैं) और उस पद्धति का स्वतंत्र रूप से परीक्षण करें।

कुछ इस तरह:

// Get the stream 
InputStream is = mUrl.openStream();

// get the Image bounds
BitmapFactory.Options options=new BitmapFactory.Options(); 
options.inJustDecodeBounds = true;

bitmap = BitmapFactory.decodeStream(is,null,options);

//get actual width x height of the image and calculate the scale factor
options.inSampleSize = getScaleFactor(options.outWidth,options.outHeight,
                view.getWidth(),view.getHeight());

options.inJustDecodeBounds = false;
bitmap=BitmapFactory.decodeStream(mUrl.openStream(),null,options);

और परीक्षण getScaleFactor (...) स्वतंत्र रूप से।

यदि यह पहले से ही नहीं किया गया है, तो कोशिश के साथ पूरे कोड को घेरने में मदद मिलेगी..चेक {} ब्लॉक।


उत्तर के लिए बहुत बहुत धन्यवाद! मैंने 'int.inSampleSize = 2' जैसे अंतिम int मान सेट करने का प्रयास किया। लेकिन यह एक ही मुद्दों में परिणाम है। Logcat 'SkImageDecoder :: Factory null' पढ़ता है, हर उस छवि के लिए जिसे मैंने डिकोड करने की कोशिश की थी। एक कोशिश / कैच ब्लॉक के अंदर कोड चलाने से मुझे मदद नहीं मिलेगी क्योंकि यह कुछ भी नहीं फेंक रहा है, है ना? हालाँकि, यदि यह एक img नहीं बना सकता है, तो बिटमैपफ़ैक्ट्री.ऑडस्ट्रीम, अशक्त वापस लौटता है, जब मैं एक नमूना उपयोग करने की कोशिश करता हूँ।
रॉबर्ट फॉस

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

BitmapFactory.decodeResource (this.getResources (), R.drawable.icon, विकल्प) == नल) पुनः नमूने के साथ ठीक काम करता है। विकल्प के साथ पहला BitmapFactory.decodeStream.inJDDecodeBounds = सही काम करता है और ठीक विकल्प देता है। लेकिन निम्न BitmapFactory.decodeStream Options.inJustDecodeBounds = false के साथ हर बार विफल रहता है।
राबर्ट फॉस

मुझे डर है कि यह मेरे से परे है ... मुझे यह जानने में दिलचस्पी होगी कि संभवतः यहां क्या गलत हो सकता है क्योंकि मैं समान कोड का उपयोग कर रहा हूं और यह मेरे लिए ठीक काम करता है।
सामू

4
ठीक। मैंने इसे हल कर लिया है। मुद्दा http-कनेक्शन में है। जब आप HttpUrlConnection द्वारा दिए गए इनपुट-स्ट्रीम से एक बार पढ़ चुके हैं, तो आप इसे फिर से नहीं पढ़ सकते हैं, और दूसरा डिकोडस्ट्रीम () करने के लिए फिर से कनेक्ट करना होगा।
रॉबर्ट फॉस

2

आप InputStream को बाइट सरणी में परिवर्तित कर सकते हैं, और डिकोडबाइट एरे () का उपयोग कर सकते हैं। उदाहरण के लिए,

public static Bitmap decodeSampledBitmapFromStream(InputStream inputStream, int reqWidth, int reqHeight) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {
        int n;
        byte[] buffer = new byte[1024];
        while ((n = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, n);
        }
        return decodeSampledBitmapFromByteArray(outputStream.toByteArray(), reqWidth, reqHeight);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

public static Bitmap decodeSampledBitmapFromByteArray(byte[] data, int reqWidth, int reqHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeByteArray(data, 0, data.length, options);
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(data, 0, data.length, options);
}

private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int
        reqHeight) {
    int width = options.outWidth;
    int height = options.outHeight;
    int inSampleSize = 1;
    if (width > reqWidth || height > reqHeight) {
        int halfWidth = width / 2;
        int halfHeight = height / 2;
        while (halfWidth / inSampleSize >= reqWidth && halfHeight / inSampleSize >= reqHeight) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.