user3864752
user3864752

Reputation: 143

Bitmap size exceeds 32bits

I am scaling a Bitmap by using a seekbar. Whenever i increase the progress of seekbar, image scaling fails by giving error "Bitmap size exceeds 32bits". If i scale the image with default seekbar value. it gives an error "Illegal argument exception: Width and height must be > 0".

Log Report

07-26 05:20:23.189: E/AndroidRuntime(1145): FATAL EXCEPTION: main
07-26 05:20:23.189: E/AndroidRuntime(1145): java.lang.IllegalArgumentException: bitmap size exceeds 32bits
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.graphics.Bitmap.nativeCreate(Native Method)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.graphics.Bitmap.createBitmap(Bitmap.java:697)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.graphics.Bitmap.createBitmap(Bitmap.java:674)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.graphics.Bitmap.createBitmap(Bitmap.java:607)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at com.example.navigationexample.QRCodeGenerator.scaleImage(QRCodeGenerator.java:127)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at com.example.navigationexample.MainActivity$3.onClick(MainActivity.java:356)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:166)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.os.Looper.loop(Looper.java:137)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at android.app.ActivityThread.main(ActivityThread.java:5103)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at java.lang.reflect.Method.invokeNative(Native Method)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at java.lang.reflect.Method.invoke(Method.java:525)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
07-26 05:20:23.189: E/AndroidRuntime(1145):     at dalvik.system.NativeStart.main(Native Method)
07-26 05:20:25.857: I/Process(1145): Sending signal. PID: 1145 SIG: 9

Code snippet

public void showSaveDialog() {

    LayoutInflater inflater = getLayoutInflater();
    dialog = null;

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Save QR Image");

    View v = inflater.inflate(R.layout.save_dialog, null);
    builder.setView(v);

    final EditText et = (EditText) v.findViewById(R.id.qrName);
    et.setMaxLines(1);

    final TextView widthText = (TextView) v.findViewById(R.id.widthSize);
    final TextView heightText = (TextView) v.findViewById(R.id.heightSize);

    SeekBar seekBar = (SeekBar) v.findViewById(R.id.seekBar1);

    seekBar.setMax(16);

    // To set minimum value of seekbar
    seekMin = seekBar.getProgress();
    if (seekMin < 128) {
        seekBar.setProgress(1);
        widthText.setText("128");
        heightText.setText("128");
    }

    seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        @Override
        public void onStopTrackingTouch(SeekBar arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStartTrackingTouch(SeekBar arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progresValue,
                boolean fromUser) {
            // TODO Auto-generated method stub
            val = progresValue * 128;
            String size = String.valueOf(val);
            widthText.setText(size);
            heightText.setText(size);
        }
    });

    builder.setPositiveButton("Save", new OnClickListener() {

        @Override
        public void onClick(DialogInterface arg0, int arg1) {
            // TODO Auto-generated method stub
            qrName = et.getText().toString();

            if (qrName.isEmpty()) {
                Toast.makeText(getApplicationContext(),
                        "Please enter name", Toast.LENGTH_SHORT).show();
            } else {

                Bitmap sImg = classB.scaleImage(image, val, density);
                saveImage(sImg);
            }
        }
    });
    dialog = builder.create();
    dialog.show();
}

Function to scale image in Class B

public Bitmap scaleImage(Bitmap bitmap, int bound, int density) {

    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    // Get current dimensions AND the desired bounding box
    int bounding = dpToPx(bound, density);
    Log.i("Test", "original width = " + Integer.toString(w));
    Log.i("Test", "original height = " + Integer.toString(h));
    Log.i("Test", "bounding = " + Integer.toString(bounding));

    // Determine how much to scale: the dimension requiring less scaling is
    // closer to the its side. This way the image always stays inside your
    // bounding box AND either x/y axis touches it.
    float xScale = ((float) bounding) / w;
    float yScale = ((float) bounding) / h;
    float scale = (xScale <= yScale) ? xScale : yScale;
    Log.i("Test", "xScale = " + Float.toString(xScale));
    Log.i("Test", "yScale = " + Float.toString(yScale));
    Log.i("Test", "scale = " + Float.toString(scale));

    // Create a matrix for the scaling and add the scaling data
    Matrix matrix = new Matrix();
    matrix.postScale(scale, scale);

    // Create a new bitmap and convert it to a format understood by the
    // ImageView
    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix,
            true);
    sWidth = scaledBitmap.getWidth(); // re-use
    sHeight = scaledBitmap.getHeight(); // re-use
    @SuppressWarnings("deprecation")
    BitmapDrawable result = new BitmapDrawable(scaledBitmap);
    Log.i("Test", "scaled width = " + Integer.toString(sWidth));
    Log.i("Test", "scaled height = " + Integer.toString(sHeight));

    return scaledBitmap;
}

Function to get bounding value in scaleImage() function

private int dpToPx(int dp, int density) {
    int result = Math.round((float) dp * density);
    return result;
}

Upvotes: 3

Views: 5964

Answers (1)

Barend
Barend

Reputation: 17419

Which value are you passing into the density argument of your dpToPx(int,int) method?

Your method declares density as int, which leads me to believe you may be passing in DisplayMetrics.densityDpi, a three-digit int number. What you meant to use DisplayMetrics.density, a single digit float number. This will have pushed your image dimension outside 32 bits:

threshold 32 bits signed int = 2^31 -1         =  2147483647

progressValue = 16
bitmap edge   = 16 * 128     = 2048
bitmap size   = 2048^2       = 4194304
at 32 bpp     = 4194304 * 32 = 134217728

multiplied by densityDpi     = 134217728 * 460 = 61740154880  // kaboom
multiplied by density        = 134217728 * 3   =   402653184  // ok

Upvotes: 4

Related Questions