android - "बिटमैप को बनावट में अपलोड करने के लिए बहुत बड़ा"




android-imageview android-image (12)

( AndroidManifest.xml ) में निम्नलिखित 2 विशेषताओं का AndroidManifest.xml मेरे लिए काम किया:

android:largeHeap="true"
android:hardwareAccelerated="false"

मैं एक छवि दृश्य में बिटमैप लोड कर रहा हूं, और यह त्रुटि देख रहा हूं। मैं यह सीमा ओपनजीएल हार्डवेयर बनावट (2048x2048) के लिए आकार सीमा से संबंधित है। जिस छवि को मुझे लोड करने की आवश्यकता है वह लगभग 4,000 पिक्सेल ऊंची की चुटकी-ज़ूम छवि है।

मैंने मैनिफेस्ट में हार्डवेयर त्वरण को बंद करने का प्रयास किया है, लेकिन कोई खुशी नहीं है।

    <application
        android:hardwareAccelerated="false"
        ....
        >

क्या एक छवि दृश्य में 2048 पिक्सेल से बड़ी छवि लोड करना संभव है?


इस सब डाउनस्प्लिंग कोड को मैन्युअल रूप से लिखने / डीबग करने की कोशिश करने के घंटों पर घंटों खर्च करने के बजाय, Picasso उपयोग क्यों न करें? यह सभी प्रकारों और / या आकारों के bitmaps से निपटने के लिए बनाया गया था।

मैंने अपनी "बिटमैप बहुत बड़ी ...." समस्या को हटाने के लिए कोड की इस एकल पंक्ति का उपयोग किया है:

Picasso.with(context).load(resourceId).fit().centerCrop().into(imageView);

एपीआई स्तर 10 से शुरू होने वाले लारको द्वारा इंगित किए गए अनुसार, आप छवि से विशिष्ट क्षेत्रों को लोड करने के लिए BitmapRegionDecoder का उपयोग कर सकते हैं और इसके साथ ही, आप आवश्यक क्षेत्रों में स्मृति आवंटित करके उच्च रिज़ॉल्यूशन में एक बड़ी छवि दिखाने के लिए पूरा कर सकते हैं। मैंने हाल ही में एक lib विकसित किया है जो स्पर्श इशारा हैंडलिंग के साथ बड़ी छवियों के दृश्य प्रदान करता है। स्रोत कोड और नमूने यहां उपलब्ध हैं


चित्र नीचे स्केल करें:

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

// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);

int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
    pow += 1;
options.inSampleSize = 1 << pow; 
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);

छवि reqHeight और reqWidth के आकार पर स्केल किया जाएगा। जैसा कि मैं समझता हूं नमूना आकार केवल 2 मानों की शक्ति में लेता है।


मैं एक ही समस्या से भाग गया, मेरा समाधान यहाँ है। छवि की चौड़ाई को एंड्रॉइड स्क्रीन चौड़ाई के समान सेट करें और फिर ऊंचाई को स्केल करें

Bitmap myBitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Screen width ", " "+width);
Log.e("Screen height ", " "+height);
Log.e("img width ", " "+myBitmap.getWidth());
Log.e("img height ", " "+myBitmap.getHeight());
float scaleHt =(float) width/myBitmap.getWidth();
Log.e("Scaled percent ", " "+scaleHt);
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, width, (int)(myBitmap.getWidth()*scaleHt), true);
myImage.setImageBitmap(scaled);

यह किसी भी आकार एंड्रॉइड स्क्रीन के लिए बेहतर है। अगर यह आप के लिए काम करता है तो मुझे बतलाएगा।


मैंने उपरोक्त सभी समाधानों की कोशिश की, एक-दूसरे के बाद, कई घंटों तक, और कोई काम नहीं कर रहा था! आखिरकार, मैंने एंड्रॉइड के कैमरे के साथ छवियों को कैप्चर करने और उन्हें प्रदर्शित करने के संबंध में एक आधिकारिक उदाहरण के लिए चारों ओर देखने का फैसला किया। आधिकारिक उदाहरण ( here ), अंततः मुझे एकमात्र तरीका दिया जो काम करता था। नीचे मैं उस उदाहरण ऐप में मिला समाधान प्रस्तुत करता हूं:

public void setThumbnailImageAndSave(final ImageView imgView, File imgFile) {

            /* There isn't enough memory to open up more than a couple camera photos */
    /* So pre-scale the target bitmap into which the file is decoded */

    /* Get the size of the ImageView */
    int targetW = imgView.getWidth();
    int targetH = imgView.getHeight();

    /* Get the size of the image */
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    /* Figure out which way needs to be reduced less */
    int scaleFactor = 1;
    if ((targetW > 0) || (targetH > 0)) {
        scaleFactor = Math.min(photoW/targetW, photoH/targetH);
    }

    /* Set bitmap options to scale the image decode target */
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    /* Decode the JPEG file into a Bitmap */
    Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);

    /* Associate the Bitmap to the ImageView */
    imgView.setImageBitmap(bitmap);
    imgView.setVisibility(View.VISIBLE);
}

मैंने पिकासो का इस्तेमाल किया और एक ही समस्या थी। छवि कम से कम आकार, चौड़ाई या ऊंचाई पर बहुत बड़ी थी। अंत में मुझे यहां समाधान मिला। आप प्रदर्शन आकार के अनुसार बड़ी छवि को स्केल कर सकते हैं और पहलू अनुपात भी रख सकते हैं:

    public Point getDisplaySize(Display display) {
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(size);
    } else {
        int width = display.getWidth();
        int height = display.getHeight();
        size = new Point(width, height);
    }

    return size;
}

और पिकासो द्वारा छवि लोड करने के लिए इस विधि का उपयोग करें:

    final Point displySize = getDisplaySize(getWindowManager().getDefaultDisplay());
        final int size = (int) Math.ceil(Math.sqrt(displySize.x * displySize.y));
        Picasso.with(this)
                .load(urlSource)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

बेहतर प्रदर्शन के लिए आप डिस्प्ले स्क्रीन की चौड़ाई और ऊंचाई के अनुसार छवि डाउनलोड कर सकते हैं, पूरी छवि नहीं:

    public String reviseImageUrl(final Integer displayWidth,     final Integer displayHeight,
        final String originalImageUrl) {
    final String revisedImageUrl;

    if (displayWidth == null && displayHeight == null) {
        revisedImageUrl = originalImageUrl;
    } else {
        final Uri.Builder uriBuilder = Uri.parse(originalImageUrl).buildUpon();

        if (displayWidth != null && displayWidth > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_WIDTH, String.valueOf(displayWidth));
        }

        if (displayHeight != null && displayHeight > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_HEIGHT, String.valueOf(displayHeight));
        }

        revisedImageUrl = uriBuilder.toString();
    }

    return revisedImageUrl;
}

    final String newImageUlr = reviseImageUrl(displySize.x, displySize.y, urlSource);

और फिर:

    Picasso.with(this)
                .load(newImageUlr)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

संपादित करें: getDisplaySize ()

display.getWidth()/getHeight() को बहिष्कृत किया गया है। Display उपयोग Display बजाय।

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}

यह प्रश्न का सीधा जवाब नहीं है (छवियों को लोड करना> 2048), लेकिन त्रुटि का सामना करने वाले किसी के लिए एक संभावित समाधान।

मेरे मामले में, छवि दोनों आयामों में 2048 से छोटी थी (1280x727 सटीक होने के लिए) और यह मुद्दा गैलेक्सी नेक्सस पर विशेष रूप से अनुभव किया गया था। छवि drawable फ़ोल्डर और योग्य फ़ोल्डर में से कोई भी नहीं थी। एंड्रॉइड मानता है कि घनत्व योग्यता के बिना ड्रॉबल्स एमडीपीआई हैं और अन्य घनत्व के लिए उन्हें ऊपर या नीचे स्केल करते हैं, इस मामले में xhdpi के लिए 2x बढ़ाया गया है। स्केलिंग को रोकने के लिए अपराधी छवि को drawable-nodpi जाना समस्या हल हो गई।


सही खींचने योग्य सबफ़ोल्डर का उपयोग करके यह मेरे लिए हल हो गया। मेरा समाधान ड्रॉबल फ़ोल्डर के बजाय, मेरी पूर्ण रिज़ॉल्यूशन छवि (1920x1200) को ड्रॉबल-एक्सएचडीपीआई फ़ोल्डर में रखना था।

मैंने ड्रैबल-एचडीपीआई फ़ोल्डर में एक स्केल डाउन इमेज (1280x800) भी लगाया।

ये दो प्रस्ताव 2013 और 2012 नेक्सस 7 टैबलेट से मेल खाते हैं जो मैं प्रोग्रामिंग कर रहा हूं। मैंने कुछ अन्य टैबलेट पर समाधान का भी परीक्षण किया।


सीधे छविदृश्य में लोड होने की बजाय ग्लाइड लाइब्रेरी का उपयोग करें

ग्लाइड: https://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);

BitmapRegionDecoder चाल करता है।

आप onDraw(Canvas canvas) को ओवरराइड कर सकते हैं, एक नया थ्रेड शुरू कर सकते हैं और उपयोगकर्ता को दिखाई देने वाले क्षेत्र को डीकोड कर सकते हैं।


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    ///*
    if (requestCode == PICK_FROM_FILE && resultCode == RESULT_OK && null != data){



        uri = data.getData();

        String[] prjection ={MediaStore.Images.Media.DATA};

        Cursor cursor = getContentResolver().query(uri,prjection,null,null,null);

        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(prjection[0]);

        ImagePath = cursor.getString(columnIndex);

        cursor.close();

        FixBitmap = BitmapFactory.decodeFile(ImagePath);

        ShowSelectedImage = (ImageView)findViewById(R.id.imageView);

      //  FixBitmap = new BitmapDrawable(ImagePath);
        int nh = (int) ( FixBitmap.getHeight() * (512.0 / FixBitmap.getWidth()) );
        FixBitmap = Bitmap.createScaledBitmap(FixBitmap, 512, nh, true);

       // ShowSelectedImage.setImageBitmap(BitmapFactory.decodeFile(ImagePath));

        ShowSelectedImage.setImageBitmap(FixBitmap);

    }
}

यह कोड काम है





android-bitmap