অ্যান্ড্রয়েডের স্কেলড আউটপুট ফাইলটিতে একটি বড় বিটম্যাপ ফাইলটিকে পুনরায় আকার দিন


218

আমার একটি ফাইলে একটি বড় বিটম্যাপ রয়েছে (3888x2592 বলুন)। এখন, আমি সেই বিটম্যাপটিকে 800x533 এ আকার দিতে এবং এটি অন্য একটি ফাইলে সংরক্ষণ করতে চাই। আমি সাধারণত Bitmap.createBitmapপদ্ধতিটি কল করে বিটম্যাপটি স্কেল করব তবে এটি প্রথম যুক্তি হিসাবে একটি উত্স বিটম্যাপের প্রয়োজন, যা আমি সরবরাহ করতে পারি না কারণ বিটম্যাপ অবজেক্টে মূল চিত্রটি লোড করা অবশ্যই স্মৃতি ছাড়িয়ে যায় ( উদাহরণস্বরূপ এখানে দেখুন )।

আমি বিটম্যাপটিও পড়তে পারি না, উদাহরণস্বরূপ, BitmapFactory.decodeFile(file, options)একটি সরবরাহ করে BitmapFactory.Options.inSampleSize, কারণ আমি এটিকে যথাযথ প্রস্থ এবং উচ্চতায় আকার দিতে চাই। ব্যবহার inSampleSizeকরে বিটম্যাপটিকে 972x648 (যদি আমি ব্যবহার করি inSampleSize=4) বা 778x518 (যদি আমি ব্যবহার করি তবে inSampleSize=5এটি 2 এর শক্তিও নয় ) আকার পরিবর্তন করতে পারে।

আমি নমুনা আকারের ইন-স্যাম্পল সাইজ ব্যবহার করে চিত্রটি পড়া এড়াতেও চাই, উদাহরণস্বরূপ, প্রথম ধাপে 972x648 এবং তারপরে দ্বিতীয় ধাপে একেবারে 800x533 এ আকার দিন, কারণ মূল চিত্রটির সরাসরি আকার পরিবর্তনের তুলনায় মানটি খারাপ হবে।

আমার প্রশ্নের সংক্ষিপ্তসার হিসাবে: কোনও আউটআউফ-মেমরি ব্যতিক্রম না পেয়ে 10 এমপি বা আরও বেশি কিছু সহ একটি বড় চিত্র ফাইলটি পড়ার এবং একটি নতুন চিত্র ফাইলে এটি সংরক্ষণ করার কোনও উপায় আছে কি?

আমি BitmapFactory.decodeFile(file, options)অপশন.আউটহাইট এবং অপশনস.আরউইথথের মানগুলি ম্যানুয়ালি 800 এবং 533 এ সেট করার চেষ্টা করেছি এবং এটি সেভাবে কাজ করে না।


না, আউটহাইট এবং আউটউইথটি ডিকোড পদ্ধতি থেকে আউট প্যারামিটার। বলা হচ্ছে, আপনার চেয়ে আমারও একই সমস্যা আছে এবং আমি 2 টি পদক্ষেপের কাছে কখনও সন্তুষ্ট নই।
rd

প্রায়শই, ধার্মিকতার জন্য ধন্যবাদ, আপনি কোডের একটি লাইন ব্যবহার করতে পারেন .. stackoverflow.com/a/17733530/294884
ফ্যাটি

পাঠক, দয়া করে এটি একেবারে সমালোচিত QA নোট করুন !!! stackoverflow.com/a/24135522/294884
ফ্যাটি

1
প্লিজ নোট করুন যে এই প্রশ্নটি এখন 5 বছরের পুরানো, এবং এর সম্পূর্ণ সমাধানটি হল .. stackoverflow.com/a/24135522/294884 চিয়ার্স!
ফ্যাটি

2
সেই বিষয়ে এখন একটি অফিসিয়াল ডকুমেন্টেশন রয়েছে: developer.android.com/training/displaying-bitmaps/…
ভিনস

উত্তর:


146

না, আমি কেউ আমাকে সংশোধন করতে চাই, তবে আপনি আপোষ হিসাবে চেষ্টা করেছেন এমন লোড / আকার পরিবর্তন পদ্ধতির কাছে আমি গ্রহণ করেছি accepted

যে কেউ ব্রাউজ করার জন্য পদক্ষেপ এখানে:

  1. সর্বাধিক সম্ভব গণনা করুন inSampleSizeযা এখনও আপনার টার্গেটের চেয়ে বড় একটি চিত্র দেয়।
  2. BitmapFactory.decodeFile(file, options)বিকল্প হিসাবে স্যাম্পল সাইজ পাস করে চিত্রটি লোড করুন ।
  3. ব্যবহার করে কাঙ্ক্ষিত মাত্রায় পুনরায় আকার দিন Bitmap.createScaledBitmap()

আমি তা এড়াতে চেষ্টা করেছি। সুতরাং কেবলমাত্র এক ধাপে কোনও বৃহত চিত্র সরাসরি আকার পরিবর্তন করার কোন উপায় নেই?
ম্যানুয়েল

2
আমার জ্ঞানের কাছে নয়, তবে এটি আপনাকে আরও অনুসন্ধান থেকে বিরত রাখবেন না।
জাস্টিন

ঠিক আছে, আমি আমার গ্রহণযোগ্য উত্তরের জন্য এটি গ্রহণ করব। যদি আমি অন্য কোনও পদ্ধতি খুঁজে বের করি তবে আমি আপনাকে জানাব।
ম্যানুয়েল

PSIXO উত্তর উল্লেখিত হিসাবে, আপনি হতে পারে এছাড়াও অ্যান্ড্রয়েড ব্যবহার করতে চান: largeHeap যদি এখনও inSampleSize ব্যবহার করে পরে বিষয় আছে।
ব্যবহারকারী 276648

বিটম্যাপ ভেরিয়েবলটি খালি পেয়ে যাচ্ছিল
প্রসাদ

99

জাস্টিন উত্তর কোড অনুবাদ (আমার জন্য নিখুঁত কাজ করে):

private Bitmap getBitmap(String path) {

Uri uri = getImageUri(path);
InputStream in = null;
try {
    final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
    in = mContentResolver.openInputStream(uri);

    // Decode image size
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in, null, options);
    in.close();



    int scale = 1;
    while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) > 
          IMAGE_MAX_SIZE) {
       scale++;
    }
    Log.d(TAG, "scale = " + scale + ", orig-width: " + options.outWidth + ", 
       orig-height: " + options.outHeight);

    Bitmap resultBitmap = null;
    in = mContentResolver.openInputStream(uri);
    if (scale > 1) {
        scale--;
        // scale to max possible inSampleSize that still yields an image
        // larger than target
        options = new BitmapFactory.Options();
        options.inSampleSize = scale;
        resultBitmap = BitmapFactory.decodeStream(in, null, options);

        // resize to desired dimensions
        int height = resultBitmap.getHeight();
        int width = resultBitmap.getWidth();
        Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
           height: " + height);

        double y = Math.sqrt(IMAGE_MAX_SIZE
                / (((double) width) / height));
        double x = (y / height) * width;

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(resultBitmap, (int) x, 
           (int) y, true);
        resultBitmap.recycle();
        resultBitmap = scaledBitmap;

        System.gc();
    } else {
        resultBitmap = BitmapFactory.decodeStream(in);
    }
    in.close();

    Log.d(TAG, "bitmap size - width: " +resultBitmap.getWidth() + ", height: " + 
       resultBitmap.getHeight());
    return resultBitmap;
} catch (IOException e) {
    Log.e(TAG, e.getMessage(),e);
    return null;
}

15
আপনি যখন "বি" এর মতো ভেরিয়েবল ব্যবহার করেন তবে পড়া ভাল হয় তবে ভাল উত্তর কম হয়।
অলিভার ডিকসন

@ ওফির: getImageUri (পথ); এই পদ্ধতিতে আমার কী পাস করতে হবে?
বিগুইনার

1
( ডাব্লু এইচ) / ম্যাথ.পাউ (স্কেল, 2) এর পরিবর্তে এটি ( ডাব্লু এইচ) >> স্কেল ব্যবহার করা আরও দক্ষ
ডেভিড.প্রেজ

2
System.gc()দয়া করে কল করবেন না
gw0

ধন্যবাদ @ ওফির তবে এই রূপান্তরটি চিত্রের ওরিয়েন্টেশনটি সংরক্ষণ করে না: - /
জো কুলম্যান

43

এটি 'মোজো রিসিনস এবং' অফিরের সমাধানগুলি "সম্মিলিত"। এটি আপনাকে সর্বাধিক প্রস্থ এবং সর্বাধিক উচ্চতার সীমানা সহ একটি আনুপাতিক আকারে পরিবর্তনশীল চিত্র দেবে।

  1. এটি কেবলমাত্র মূল আকারটি পাওয়ার জন্য মেটা ডেটা পড়ে (অপশন.জাস্টডেকোডবাউন্ডস)
  2. এটি মেমোরিটি সংরক্ষণ করতে একটি রোড রাইজাইজ ব্যবহার করে (itmap.createScaledBitmap)
  3. এটি পূর্বে তৈরি মোটামুটি বিট্যাম্পের উপর ভিত্তি করে একটি সুনির্দিষ্ট আকার পরিবর্তন করা চিত্র ব্যবহার করে।

আমার জন্য এটি নীচে 5 মেগাপিক্সেল চিত্রগুলিতে দুর্দান্ত পারফর্ম করছে।

try
{
    int inWidth = 0;
    int inHeight = 0;

    InputStream in = new FileInputStream(pathOfInputImage);

    // decode image size (decode metadata only, not the whole image)
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in, null, options);
    in.close();
    in = null;

    // save width and height
    inWidth = options.outWidth;
    inHeight = options.outHeight;

    // decode full image pre-resized
    in = new FileInputStream(pathOfInputImage);
    options = new BitmapFactory.Options();
    // calc rought re-size (this is no exact resize)
    options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);
    // decode full image
    Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);

    // calc exact destination size
    Matrix m = new Matrix();
    RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
    RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
    m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
    float[] values = new float[9];
    m.getValues(values);

    // resize bitmap
    Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);

    // save image
    try
    {
        FileOutputStream out = new FileOutputStream(pathOfOutputImage);
        resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
    }
    catch (Exception e)
    {
        Log.e("Image", e.getMessage(), e);
    }
}
catch (IOException e)
{
    Log.e("Image", e.getMessage(), e);
}

23

এপিআই কেন ব্যবহার করবেন না?

int h = 48; // height in pixels
int w = 48; // width in pixels    
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);

21
কারণ এটি আমার সমস্যার সমাধান করবে না। যা হ'ল: "... এটি প্রথম যুক্তি হিসাবে একটি উত্স বিটম্যাপের প্রয়োজন, যা আমি সরবরাহ করতে পারি না কারণ বিটম্যাপ অবজেক্টে মূল চিত্রটি লোড করা অবশ্যই স্মৃতিশক্তি ছাড়িয়ে যাবে" " সুতরাং, আমি .createScaledBitmap পদ্ধতিতে একটি বিটম্যাপ পাস করতে পারি না, কারণ আমার এখনও বিটম্যাপ অবজেক্টে একটি বৃহত চিত্র লোড করতে হবে।
ম্যানুয়েল

2
ঠিক। আমি আপনার প্রশ্নটি পুনরায় পড়ি এবং মূলত (যদি আমি এটি সঠিকভাবে বুঝতে পারি) তবে এটি "উত্সাহিত করতে পারি মূল ফাইলটিকে মেমরিতে লোড না করে আমি কি চিত্রটিকে সঠিক মাত্রায় আকার দিতে পারি?" যদি তা হয় - তবে এর উত্তরের জন্য চিত্র প্রক্রিয়াকরণের জটিলতা সম্পর্কে আমি যথেষ্ট পরিমাণে জানি না তবে কিছু আমাকে বলে যে এটি 1. এপিআই থেকে উপলব্ধ নয়, ২. এটি 1-লাইনার হবে না। আমি এটিকে প্রিয় হিসাবে চিহ্নিত করব - আপনি (বা অন্য কেউ) এটি সমাধান করবেন কিনা তা আকর্ষণীয় হবে।
বোস্টোন

এটি আমার পক্ষে কাজ করেছে কারণ আমি ইউরি পাচ্ছি এবং বিটম্যাপে রূপান্তর করছি তাই এগুলি স্কেলিং আমার পক্ষে সহজতর জন্য সহজতর 1+।
হামজা

22

এখনও অবধি অন্য দুর্দান্ত উত্তর স্বীকার করে নিয়েছি, এর জন্য আমি এখনও দেখা সবচেয়ে ভাল কোডটি ফটো তোলার সরঞ্জামের জন্য ডকুমেন্টেশনে রয়েছে।

"একটি আকারযুক্ত চিত্র ডিকোড করুন" শিরোনামে বিভাগটি দেখুন।

http://developer.android.com/training/camera/photobasics.html

সমাধানটির প্রস্তাব এটি হ'ল অন্যদের মতো আকার পরিবর্তন ও স্কেল সলিউশন, তবে এটি বেশ ঝরঝরে।

সুবিধার জন্য আমি নীচে কোডটি অন-টু-গড ফাংশন হিসাবে অনুলিপি করেছি।

private void setPic(String imagePath, ImageView destination) {
    int targetW = destination.getWidth();
    int targetH = destination.getHeight();
    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
    destination.setImageBitmap(bitmap);
}

1
প্রথমে আপনি পূর্ণসংখ্যার দিকে মনোনিবেশ করছেন যে ফলাফলটি কী করবে। দ্বিতীয়টি টার্গেটডাব্লু বা টার্গেটএইচ 0 হওয়ার সাথে কোড ক্র্যাশ হয়ে গেছে (যদিও এটি আমার জানার খুব বেশি অর্থ হয় না)। তৃতীয় ইনস্যাম্পল সাইজটি 2 এর শক্তি হওয়া উচিত
সাইবারজেন

আমাকে ভুল করবেন না। এটি অবশ্যই কোনও চিত্র লোড করবে তবে ফ্লোরগুলি যদি অন্তর্নিহিত হয় তবে এটি তেমন দেখাচ্ছে না। এবং এটি অবশ্যই সঠিক উত্তর নয় কারণ প্রত্যাশার মতো চিত্রটি ছোট করা হবে না। ইমেজ ভিউটি চিত্রের অর্ধেক আকার বা ছোট না হওয়া পর্যন্ত এটি কিছুই করবে না। তারপরে চিত্রের চিত্রটি 1/4 আকার না হওয়া পর্যন্ত কিছুই হয় না। এবং তাই দুটি ক্ষমতা দিয়ে!
সাইবারজেন

18

এই উত্তরগুলি এবং অ্যান্ড্রয়েড ডকুমেন্টেশনগুলি পড়ার পরে এটিকে মেমরিতে লোড না করে বিটম্যাপটির আকার পরিবর্তন করার কোড এখানে রয়েছে:

public Bitmap getResizedBitmap(int targetW, int targetH,  String imagePath) {

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    //inJustDecodeBounds = true <-- will not load the bitmap into memory
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
    return(bitmap);
}

দয়া করে লক্ষ্য করুন যে bmOptions.inPurbable = সত্য; অবচয় করা হয়।
রবিত

6

যখন আমার কাছে বিটম্যাপগুলি বড় হয় এবং আমি সেগুলি পুনরায় আকার দিয়ে ডিকোড করতে চাই আমি নীচেরটি ব্যবহার করি

BitmapFactory.Options options = new BitmapFactory.Options();
InputStream is = null;
is = new FileInputStream(path_to_file);
BitmapFactory.decodeStream(is,null,options);
is.close();
is = new FileInputStream(path_to_file);
// here w and h are the desired width and height
options.inSampleSize = Math.max(options.outWidth/w, options.outHeight/h);
// bitmap is the resized bitmap
Bitmap bitmap = BitmapFactory.decodeStream(is,null,options);

1
ইনসাম্পল সাইজ যেহেতু একটি পূর্ণসংখ্যা তাই আপনি খুব কমই সঠিক পিক্সেলের প্রস্থ এবং উচ্চতা পেতে চান। আপনি মাঝে মাঝে কাছাকাছি যেতে পারেন তবে দশমিকের উপর নির্ভর করে আপনি এ থেকে অনেক দূরেও থাকতে পারেন।
ম্যানুয়েল

সকালে, আমি আপনার কোড চেষ্টা করেছি (এই থ্রেডের উপরে পোস্ট), তবে কাজ করছে না বলে মনে হচ্ছে, আমি কোথায় ভুল করেছি? যে কোনও পরামর্শ স্বাগত :-)
আরআরটিডব্লিউ

5

এই প্রশ্নটি দেখার জন্য কারও পক্ষে এটি কার্যকর হতে পারে। আমি জাস্টিনের কোডটি আবারও লিখেছি যাতে পদ্ধতিটি প্রয়োজনীয় টার্গেট সাইজের অবজেক্টটিও পেতে দেয়। ক্যানভাস ব্যবহার করার সময় এটি খুব ভাল কাজ করে। সমস্ত ক্রেডিট তার দুর্দান্ত প্রাথমিক কোডের জন্য জাস্টিনে যেতে হবে।

    private Bitmap getBitmap(int path, Canvas canvas) {

        Resources resource = null;
        try {
            final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
            resource = getResources();

            // Decode image size
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(resource, path, options);

            int scale = 1;
            while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) > 
                  IMAGE_MAX_SIZE) {
               scale++;
            }
            Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);

            Bitmap pic = null;
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                options = new BitmapFactory.Options();
                options.inSampleSize = scale;
                pic = BitmapFactory.decodeResource(resource, path, options);

                // resize to desired dimensions
                int height = canvas.getHeight();
                int width = canvas.getWidth();
                Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);

                double y = Math.sqrt(IMAGE_MAX_SIZE
                        / (((double) width) / height));
                double x = (y / height) * width;

                Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
                pic.recycle();
                pic = scaledBitmap;

                System.gc();
            } else {
                pic = BitmapFactory.decodeResource(resource, path);
            }

            Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
            return pic;
        } catch (Exception e) {
            Log.e("TAG", e.getMessage(),e);
            return null;
        }
    }

জাস্টিনের কোড বড় বিটম্যাপসের সাথে কাজ করার ওভারহেড হ্রাস করতে খুব কার্যকর।


4

আমার সমাধানটি সর্বোত্তম অনুশীলন কিনা তা আমি জানি না তবে আমি বিকল্পগুলি inDensityএবং inTargetDensityবিকল্পগুলি ব্যবহার করে আমার পছন্দসই স্কেলিং দিয়ে একটি বিটম্যাপ লোডিং অর্জন করেছি । inDensityহয় 0যখন একটি অঙ্কনযোগ্য সংস্থান লোড না, তাই এই পদ্ধতির লোড অ রিসোর্স ইমেজ জন্য হয় প্রাথমিকভাবে।

ভেরিয়েবলগুলি imageUri, maxImageSideLengthএবং contextআমার পদ্ধতির পরামিতি। আমি স্পষ্টতার জন্য AsyncTask মোড়ানো ছাড়াই কেবল পদ্ধতি বাস্তবায়ন পোস্ট করেছি।

            ContentResolver resolver = context.getContentResolver();
            InputStream is;
            try {
                is = resolver.openInputStream(imageUri);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Image not found.", e);
                return null;
            }
            Options opts = new Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is, null, opts);

            // scale the image
            float maxSideLength = maxImageSideLength;
            float scaleFactor = Math.min(maxSideLength / opts.outWidth, maxSideLength / opts.outHeight);
            // do not upscale!
            if (scaleFactor < 1) {
                opts.inDensity = 10000;
                opts.inTargetDensity = (int) ((float) opts.inDensity * scaleFactor);
            }
            opts.inJustDecodeBounds = false;

            try {
                is.close();
            } catch (IOException e) {
                // ignore
            }
            try {
                is = resolver.openInputStream(imageUri);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Image not found.", e);
                return null;
            }
            Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts);
            try {
                is.close();
            } catch (IOException e) {
                // ignore
            }

            return bitmap;

2
খুব সুন্দর! বিটম্যাপের পরিবর্তে ইনডেনসিটি ব্যবহার করে ক্রেটস্কেলবিটম্যাপ আমাকে প্রচুর স্মৃতি হিপ বাঁচিয়েছে। আরও ভাল ইনস্যাম্পলসাইজের সাথে মিলিত।
অস্টকন্টেটিটান

2

আপনি সঠিক আকারের আকার পরিবর্তন করতে চান এবং প্রয়োজনীয় মানের হিসাবে যতটা রাখতে চান তা বিবেচনা করে আমি মনে করি আপনার এটি চেষ্টা করা উচিত।

  1. বিটম্যাপফ্যাক্ট্রি.ডেকোডফিলের কল দিয়ে এবং চেকসাইজঅ্যাপশনগুলি জাস্টডেকোডবাউন্ড সরবরাহ করে পুনরায় আকারিত চিত্রের আকারটি সন্ধান করুন
  2. সর্বাধিক সম্ভাব্য ইন-স্যাম্পল সাইজ গণনা করুন আপনি মেমরি অতিক্রম না করতে আপনার ডিভাইসে ব্যবহার করতে পারেন। বিটম্যাপ সাইজআইনবাইটস = 2 * প্রস্থ * উচ্চতা; সাধারণত আপনার ছবির জন্য নমুনা আকার = 2 ঠিক আছে যেহেতু আপনার কেবল 2 * 1944x1296) প্রয়োজন হবে = 4.8Mbб যা স্মৃতিতে পা রাখতে হবে
  3. বিটম্যাপটি লোড করতে ইন-নমুনা আকারের সাথে বিটম্যাপফ্যাক্টরি.ডেকোডফিল ব্যবহার করুন
  4. বিটম্যাপটি সঠিক আকারে স্কেল করুন।

অনুপ্রেরণা: একাধিক-পদক্ষেপের স্কেলিং আপনাকে উচ্চ মানের চিত্র উপহার দিতে পারে, তবে উচ্চ ইনস্যাম্পল সাইজের ব্যবহারের চেয়ে এটি আরও ভাল কাজ করবে এমন কোনও গ্যারান্টি নেই। প্রকৃতপক্ষে, আমি মনে করি যে আপনিও একটি অপারেশনে সরাসরি স্কেলিং করতে 5 এর মতো নমুনা আকার (2 এর পাও নয়) ব্যবহার করতে পারেন। বা কেবল 4 ব্যবহার করুন এবং তারপরে আপনি কেবল সেই চিত্রটি ইউআইতে ব্যবহার করতে পারেন। আপনি যদি এটি সার্ভারে প্রেরণ করেন - তবে আপনি সার্ভারের দিক থেকে সঠিক আকারে স্কেলিং করতে পারবেন যা আপনাকে উন্নত স্কেলিং কৌশলগুলি ব্যবহার করতে দেয়।

দ্রষ্টব্য: ধাপ -3 এ লোড বিটম্যাপটি যদি কমপক্ষে 4 গুণ বড় হয় (তবে 4 * টার্গেটউইথ <প্রস্থ) আপনি আরও ভাল মানের অর্জনের জন্য বেশ কয়েকটি আকার পরিবর্তন করতে পারেন। কমপক্ষে এটি জেনেরিক জাভাতে কাজ করে, অ্যান্ড্রয়েডে আপনার কাছে স্কেলিংয়ের জন্য ব্যবহৃত ইন্টারপোলেশন নির্দিষ্ট করার বিকল্প নেই don't http://today.java.net/pub/a/today/2007/04/03/perils-of- চিত্র getscaledinstance.html


2

আমি এই জাতীয় কোড ব্যবহার করেছি:

  String filePath=Environment.getExternalStorageDirectory()+"/test_image.jpg";
  BitmapFactory.Options options=new BitmapFactory.Options();
  InputStream is=new FileInputStream(filePath);
  BitmapFactory.decodeStream(is, null, options);
  is.close();
  is=new FileInputStream(filePath);
  // here w and h are the desired width and height
  options.inSampleSize=Math.max(options.outWidth/460, options.outHeight/288); //Max 460 x 288 is my desired...
  // bmp is the resized bitmap
  Bitmap bmp=BitmapFactory.decodeStream(is, null, options);
  is.close();
  Log.d(Constants.TAG, "Scaled bitmap bytes, "+bmp.getRowBytes()+", width:"+bmp.getWidth()+", height:"+bmp.getHeight());

আমি আসল চিত্রটি 1230 x 1230, এবং বিটম্যাপটি পেয়েছি বলে
চেষ্টা করেছি 330 x 330 And এবং যদি 2590 x 3849 চেষ্টা করা হয়, আমি আউটআফমিউরিওর পেয়ে যাব।

আমি এটি সনাক্ত করেছিলাম, এটি এখনও "বিটম্যাপফ্যাক্টরি.ডেকোড স্ট্রিম (এটি নাল, বিকল্পগুলি)" লাইনে আউটআফমিউরি ইরির ফেলে দিয়েছে; যদি মূল বিটম্যাপটি খুব বড় হয় ...


2

উপরে কোডটি কিছুটা ক্লিনার তৈরি করেছে। ইনপুট স্ট্রিমগুলি অবশেষে বন্ধ হয়ে গেছে তা নিশ্চিত করার জন্য নিবিড়ভাবে মোড়ানো রয়েছে:

* দ্রষ্টব্য
ইনপুট: ইনপুট স্ট্রিম হ'ল, int ডাব্লু, ইন্ট
আউটপুট: বিটম্যাপ

    try
    {

        final int inWidth;
        final int inHeight;

        final File tempFile = new File(temp, System.currentTimeMillis() + is.toString() + ".temp");

        {

            final FileOutputStream tempOut = new FileOutputStream(tempFile);

            StreamUtil.copyTo(is, tempOut);

            tempOut.close();

        }



        {

            final InputStream in = new FileInputStream(tempFile);
            final BitmapFactory.Options options = new BitmapFactory.Options();

            try {

                // decode image size (decode metadata only, not the whole image)
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(in, null, options);

            }
            finally {
                in.close();
            }

            // save width and height
            inWidth = options.outWidth;
            inHeight = options.outHeight;

        }

        final Bitmap roughBitmap;

        {

            // decode full image pre-resized
            final InputStream in = new FileInputStream(tempFile);

            try {

                final BitmapFactory.Options options = new BitmapFactory.Options();
                // calc rought re-size (this is no exact resize)
                options.inSampleSize = Math.max(inWidth/w, inHeight/h);
                // decode full image
                roughBitmap = BitmapFactory.decodeStream(in, null, options);

            }
            finally {
                in.close();
            }

            tempFile.delete();

        }

        float[] values = new float[9];

        {

            // calc exact destination size
            Matrix m = new Matrix();
            RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
            RectF outRect = new RectF(0, 0, w, h);
            m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
            m.getValues(values);

        }

        // resize bitmap
        final Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);

        return resizedBitmap;

    }
    catch (IOException e) {

        logger.error("Error:" , e);
        throw new ResourceException("could not create bitmap");

    }

1

কোনও পিক্সেল এড়িয়ে না গিয়ে চিত্রটিকে "সঠিক" উপায়ে স্কেল করতে, সারি সারি ডাউন-স্যাম্পলিং সারিটি সম্পাদন করার জন্য আপনাকে চিত্রের ডিকোডারটিতে ঝুঁকে পড়তে হবে। অ্যান্ড্রয়েড (এবং এটি স্কাই লাইব্রেরি অন্তর্ভুক্ত করে) যেমন কোনও হুক সরবরাহ করে না, তাই আপনাকে নিজের রোল করতে হবে। ধরে নিই যে আপনি জেপিগ ছবিতে কথা বলছেন, আপনার সেরা বাজি হ'ল সরাসরি সিজে লিবজেপেগ ব্যবহার করা bet

জড়িত জটিলতাগুলির জন্য, দ্বি-পদক্ষেপের সাব-নমুনা-তারপরে পুনরুদ্ধার ব্যবহার ইমেজ-প্রাকদর্শন টাইপ অ্যাপ্লিকেশনগুলির জন্য সম্ভবত সেরা।


1

এখানে একটি নিবন্ধ যা পুনরায় আকার দেওয়ার জন্য একটি ভিন্ন পদ্ধতির গ্রহণ করে। এটি প্রক্রিয়াতে উপলব্ধ মেমরির উপর ভিত্তি করে মেমরিতে বৃহত্তম সম্ভাব্য বিটম্যাপটি লোড করার চেষ্টা করবে এবং তারপরে রূপান্তরগুলি সম্পাদন করবে।

http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/


1

আপনি যদি পুরোপুরি এক পদক্ষেপের আকার পরিবর্তন করতে চান তবে অ্যানড্রয়েড আপনি সম্ভবত পুরো বিটম্যাপটি লোড করতে পারেন: লার্জহীপ = সত্য তবে আপনি দেখতে পাচ্ছেন এটি সত্যই পরামর্শ দেওয়া উচিত নয়।

দস্তাবেজগুলি থেকে: অ্যান্ড্রয়েড: লার্জহীপ আপনার অ্যাপ্লিকেশনটির প্রক্রিয়াগুলি একটি বড় ডালভিক গাদা দিয়ে তৈরি করা উচিত। এটি প্রয়োগের জন্য তৈরি সমস্ত প্রক্রিয়াতে প্রযোজ্য। এটি কেবলমাত্র কোনও প্রক্রিয়াতে লোড হওয়া প্রথম অ্যাপ্লিকেশনটির জন্য প্রযোজ্য; যদি আপনি একাধিক অ্যাপ্লিকেশনগুলিকে কোনও প্রক্রিয়া ব্যবহারের অনুমতি দেওয়ার জন্য একটি ভাগ করা ব্যবহারকারী আইডি ব্যবহার করেন তবে তাদের সকলকে অবশ্যই এই বিকল্পটি ধারাবাহিকভাবে ব্যবহার করতে হবে বা তাদের অনাকাক্সিক্ষত ফলাফল হবে। বেশিরভাগ অ্যাপ্লিকেশনগুলির এগুলির প্রয়োজন হবে না এবং পরিবর্তে উন্নত পারফরম্যান্সের জন্য তাদের সামগ্রিক মেমরির ব্যবহার হ্রাস করার দিকে মনোনিবেশ করা উচিত। এটি সক্ষম করা উপলব্ধ মেমরিতে একটি নির্দিষ্ট বর্ধনের গ্যারান্টি দেয় না কারণ কিছু ডিভাইসগুলি তাদের মোট উপলব্ধ মেমরির দ্বারা সীমাবদ্ধ।



0

এটি আমার পক্ষে কাজ করেছে। ফাংশনটি এসডি কার্ডের কোনও ফাইলে পাথ পায় এবং সর্বাধিক প্রদর্শনযোগ্য আকারে একটি বিটম্যাপ দেয়। কোডটি অফিরের পরিবর্তে এসডি এর পরিবর্তে একটি রিসোর্স এবং ইমেজ ফাইলের মতো কিছু পরিবর্তন সহ ডিসপ্লে অবজেক্ট থেকে পাওয়া যায়।

private Bitmap makeBitmap(String path) {

    try {
        final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
        //resource = getResources();

        // Decode image size
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        int scale = 1;
        while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
                IMAGE_MAX_SIZE) {
            scale++;
        }
        Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);

        Bitmap pic = null;
        if (scale > 1) {
            scale--;
            // scale to max possible inSampleSize that still yields an image
            // larger than target
            options = new BitmapFactory.Options();
            options.inSampleSize = scale;
            pic = BitmapFactory.decodeFile(path, options);

            // resize to desired dimensions

            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.y;
            int height = size.x;

            //int height = imageView.getHeight();
            //int width = imageView.getWidth();
            Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);

            double y = Math.sqrt(IMAGE_MAX_SIZE
                    / (((double) width) / height));
            double x = (y / height) * width;

            Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
            pic.recycle();
            pic = scaledBitmap;

            System.gc();
        } else {
            pic = BitmapFactory.decodeFile(path);
        }

        Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
        return pic;

    } catch (Exception e) {
        Log.e("TAG", e.getMessage(),e);
        return null;
    }

}

0

এখানে আমি ব্যবহার করি এমন কোড যা অ্যান্ড্রয়েডে মেমরির বৃহত চিত্রগুলি ডিকোড করার কোনও সমস্যা নেই। আমার ইনপুট প্যারামিটারগুলি 1024x1024 এর কাছাকাছি না হওয়া পর্যন্ত আমি 20MB এর চেয়ে বড় আকারের চিত্রগুলি ডিকোড করতে সক্ষম হয়েছি। আপনি ফিরে আসা বিটম্যাপটি অন্য একটি ফাইলে সংরক্ষণ করতে পারেন। এই পদ্ধতির নীচে অন্য পদ্ধতি যা আমি একটি নতুন বিটম্যাপে চিত্রগুলি স্কেল করতেও ব্যবহার করি। এই কোডটি আপনার ইচ্ছামত ব্যবহার করতে নির্দ্বিধায়

/*****************************************************************************
 * public decode - decode the image into a Bitmap
 * 
 * @param xyDimension
 *            - The max XY Dimension before the image is scaled down - XY =
 *            1080x1080 and Image = 2000x2000 image will be scaled down to a
 *            value equal or less then set value.
 * @param bitmapConfig
 *            - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
 *            Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
 * 
 * @return Bitmap - Image - a value of "null" if there is an issue decoding
 *         image dimension
 * 
 * @throws FileNotFoundException
 *             - If the image has been removed while this operation is
 *             taking place
 */
public Bitmap decode( int xyDimension, Bitmap.Config bitmapConfig ) throws FileNotFoundException
{
    // The Bitmap to return given a Uri to a file
    Bitmap bitmap = null;
    File file = null;
    FileInputStream fis = null;
    InputStream in = null;

    // Try to decode the Uri
    try
    {
        // Initialize scale to no real scaling factor
        double scale = 1;

        // Get FileInputStream to get a FileDescriptor
        file = new File( this.imageUri.getPath() );

        fis = new FileInputStream( file );
        FileDescriptor fd = fis.getFD();

        // Get a BitmapFactory Options object
        BitmapFactory.Options o = new BitmapFactory.Options();

        // Decode only the image size
        o.inJustDecodeBounds = true;
        o.inPreferredConfig = bitmapConfig;

        // Decode to get Width & Height of image only
        BitmapFactory.decodeFileDescriptor( fd, null, o );
        BitmapFactory.decodeStream( null );

        if( o.outHeight > xyDimension || o.outWidth > xyDimension )
        {
            // Change the scale if the image is larger then desired image
            // max size
            scale = Math.pow( 2, (int) Math.round( Math.log( xyDimension / (double) Math.max( o.outHeight, o.outWidth ) ) / Math.log( 0.5 ) ) );
        }

        // Decode with inSampleSize scale will either be 1 or calculated value
        o.inJustDecodeBounds = false;
        o.inSampleSize = (int) scale;

        // Decode the Uri for real with the inSampleSize
        in = new BufferedInputStream( fis );
        bitmap = BitmapFactory.decodeStream( in, null, o );
    }
    catch( OutOfMemoryError e )
    {
        Log.e( DEBUG_TAG, "decode : OutOfMemoryError" );
        e.printStackTrace();
    }
    catch( NullPointerException e )
    {
        Log.e( DEBUG_TAG, "decode : NullPointerException" );
        e.printStackTrace();
    }
    catch( RuntimeException e )
    {
        Log.e( DEBUG_TAG, "decode : RuntimeException" );
        e.printStackTrace();
    }
    catch( FileNotFoundException e )
    {
        Log.e( DEBUG_TAG, "decode : FileNotFoundException" );
        e.printStackTrace();
    }
    catch( IOException e )
    {
        Log.e( DEBUG_TAG, "decode : IOException" );
        e.printStackTrace();
    }

    // Save memory
    file = null;
    fis = null;
    in = null;

    return bitmap;

} // decode

দ্রষ্টব্য: পদ্ধতির একে অপরের সাথে কিছুই করতে হবে উপরের ক্রিয়েস্লাডবিটম্যাপ কল ডিকোড পদ্ধতি ব্যতীত। নোটের প্রস্থ এবং উচ্চতা মূল চিত্র থেকে পরিবর্তন করতে পারে।

/*****************************************************************************
 * public createScaledBitmap - Creates a new bitmap, scaled from an existing
 * bitmap.
 * 
 * @param dstWidth
 *            - Scale the width to this dimension
 * @param dstHeight
 *            - Scale the height to this dimension
 * @param xyDimension
 *            - The max XY Dimension before the original image is scaled
 *            down - XY = 1080x1080 and Image = 2000x2000 image will be
 *            scaled down to a value equal or less then set value.
 * @param bitmapConfig
 *            - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
 *            Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
 * 
 * @return Bitmap - Image scaled - a value of "null" if there is an issue
 * 
 */
public Bitmap createScaledBitmap( int dstWidth, int dstHeight, int xyDimension, Bitmap.Config bitmapConfig )
{
    Bitmap scaledBitmap = null;

    try
    {
        Bitmap bitmap = this.decode( xyDimension, bitmapConfig );

        // Create an empty Bitmap which will contain the new scaled bitmap
        // This scaled bitmap should be the size we want to scale the
        // original bitmap too
        scaledBitmap = Bitmap.createBitmap( dstWidth, dstHeight, bitmapConfig );

        float ratioX = dstWidth / (float) bitmap.getWidth();
        float ratioY = dstHeight / (float) bitmap.getHeight();
        float middleX = dstWidth / 2.0f;
        float middleY = dstHeight / 2.0f;

        // Used to for scaling the image
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale( ratioX, ratioY, middleX, middleY );

        // Used to do the work of scaling
        Canvas canvas = new Canvas( scaledBitmap );
        canvas.setMatrix( scaleMatrix );
        canvas.drawBitmap( bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint( Paint.FILTER_BITMAP_FLAG ) );
    }
    catch( IllegalArgumentException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : IllegalArgumentException" );
        e.printStackTrace();
    }
    catch( NullPointerException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : NullPointerException" );
        e.printStackTrace();
    }
    catch( FileNotFoundException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : FileNotFoundException" );
        e.printStackTrace();
    }

    return scaledBitmap;
} // End createScaledBitmap

স্কেলের জন্য শক্তি গণনা এখানে কেবল ভুল; কেবল অ্যান্ড্রয়েড ডকো পৃষ্ঠায় গণনাটি ব্যবহার করুন।
ফ্যাটি

0
 Bitmap yourBitmap;
 Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);

বা:

 resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);

0

আমি Integer.numberOfLeadingZerosসেরা নমুনার আকার, আরও ভাল পারফরম্যান্স গণনা করতে ব্যবহার করি ।

কোটলিনে সম্পূর্ণ কোড:

@Throws(IOException::class)
fun File.decodeBitmap(options: BitmapFactory.Options): Bitmap? {
    return inputStream().use {
        BitmapFactory.decodeStream(it, null, options)
    }
}

@Throws(IOException::class)
fun File.decodeBitmapAtLeast(
        @androidx.annotation.IntRange(from = 1) width: Int,
        @androidx.annotation.IntRange(from = 1) height: Int
): Bitmap? {
    val options = BitmapFactory.Options()

    options.inJustDecodeBounds = true
    decodeBitmap(options)

    val ow = options.outWidth
    val oh = options.outHeight

    if (ow == -1 || oh == -1) return null

    val w = ow / width
    val h = oh / height

    if (w > 1 && h > 1) {
        val p = 31 - maxOf(Integer.numberOfLeadingZeros(w), Integer.numberOfLeadingZeros(h))
        options.inSampleSize = 1 shl maxOf(0, p)
    }
    options.inJustDecodeBounds = false
    return decodeBitmap(options)
}

-2

নিম্নলিখিত কোডটি ব্যবহার করে বিটম্যাপটিকে পুনরায় আকার দিন

    public static Bitmap decodeFile(File file, int reqWidth, int reqHeight){

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;        
    BitmapFactory.decodeFile(file.getPath(), options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(file.getPath(), options);
   }

    private static int calculateInSampleSize(
    BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
     }

     return inSampleSize;
   }    

নিম্নলিখিত টিপ / ট্রিকটিতেও একই ব্যাখ্যা করা হয়েছে

http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.