Taking image from custom camera is stretched when save in ImageView
Asked Answered
P

7

10

I am using this code to save pic in Imageview but the image is stretched when dsave in imageview. Camera preview is prefect and click right image but when i set that image in imageview the image is stetched.

    public void onPicTaken(byte[] data) {

    if (data != null) {
        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int screenHeight = getResources().getDisplayMetrics().heightPixels;
        Bitmap bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);

        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            // Notice that width and height are reversed
            Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
            int w = scaled.getWidth();
            int h = scaled.getHeight();
            // Setting post rotate to 90
            Matrix mtx = new Matrix();
            mtx.postRotate(90);
            // Rotating Bitmap
            bm = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
        }else{// LANDSCAPE MODE
            //No need to reverse width and height
            Bitmap scaled = Bitmap.createScaledBitmap(bm, screenWidth,screenHeight , true);
            bm=scaled;
        }
        ivCaptureImagePreview.setImageBitmap(bm);
        ivCaptureImagePreview.setVisibility(View.VISIBLE);
    }

}
Prim answered 29/2, 2016 at 7:28 Comment(0)
R
6

Use following class for creating scaled bitmap

public class ScalingUtilities 
{
     /**
     * Utility function for decoding an image resource. The decoded bitmap will
     * be optimized for further scaling to the requested destination dimensions
     * and scaling logic.
     *
     * @param res The resources object containing the image data
     * @param resId The resource id of the image data
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Decoded bitmap
     */
    public static Bitmap decodeResource(Resources res, int resId, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        options.inJustDecodeBounds = false;
        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth,
                dstHeight, scalingLogic);
        Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);

        return unscaledBitmap;
    }

    /**
     * Utility function for creating a scaled version of an existing bitmap
     *
     * @param unscaledBitmap Bitmap to scale
     * @param dstWidth Wanted width of destination bitmap
     * @param dstHeight Wanted height of destination bitmap
     * @param scalingLogic Logic to use to avoid image stretching
     * @return New scaled bitmap object
     */
    public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
                dstWidth, dstHeight, scalingLogic);
        Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
                dstWidth, dstHeight, scalingLogic);
        Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(),
                Config.ARGB_8888);
        Canvas canvas = new Canvas(scaledBitmap);
        canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));

        return scaledBitmap;
    }

    /**
     * ScalingLogic defines how scaling should be carried out if source and
     * destination image has different aspect ratio.
     *
     * CROP: Scales the image the minimum amount while making sure that at least
     * one of the two dimensions fit inside the requested destination area.
     * Parts of the source image will be cropped to realize this.
     *
     * FIT: Scales the image the minimum amount while making sure both
     * dimensions fit inside the requested destination area. The resulting
     * destination dimensions might be adjusted to a smaller size than
     * requested.
     */
    public static enum ScalingLogic {
        CROP, FIT
    }

    /**
     * Calculate optimal down-sampling factor given the dimensions of a source
     * image, the dimensions of a destination area and a scaling logic.
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal down scaling sample size for decoding
     */
    public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.FIT) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return srcWidth / dstWidth;
            } else {
                return srcHeight / dstHeight;
            }
        } else {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return srcHeight / dstHeight;
            } else {
                return srcWidth / dstWidth;
            }
        }
    }

    /**
     * Calculates source rectangle for scaling bitmap
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal source rectangle
     */
    public static Rect calculateSrcRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.CROP) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                final int srcRectWidth = (int)(srcHeight * dstAspect);
                final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
                return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight);
            } else {
                final int srcRectHeight = (int)(srcWidth / dstAspect);
                final int scrRectTop = (int)(srcHeight - srcRectHeight) / 2;
                return new Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight);
            }
        } else {
            return new Rect(0, 0, srcWidth, srcHeight);
        }
    }

    /**
     * Calculates destination rectangle for scaling bitmap
     *
     * @param srcWidth Width of source image
     * @param srcHeight Height of source image
     * @param dstWidth Width of destination area
     * @param dstHeight Height of destination area
     * @param scalingLogic Logic to use to avoid image stretching
     * @return Optimal destination rectangle
     */
    public static Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight,
            ScalingLogic scalingLogic) {
        if (scalingLogic == ScalingLogic.FIT) {
            final float srcAspect = (float)srcWidth / (float)srcHeight;
            final float dstAspect = (float)dstWidth / (float)dstHeight;

            if (srcAspect > dstAspect) {
                return new Rect(0, 0, dstWidth, (int)(dstWidth / srcAspect));
            } else {
                return new Rect(0, 0, (int)(dstHeight * srcAspect), dstHeight);
            }
        } else {
            return new Rect(0, 0, dstWidth, dstHeight);
        }
    }


}

and use this class in your function as below

public void onPicTaken(byte[] data) {

    if (data != null) {
        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int screenHeight = getResources().getDisplayMetrics().heightPixels;
        Bitmap bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);

        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            // Notice that width and height are reversed
            Bitmap scaled = ScalingUtilities.createScaledBitmap(bm, screenHeight, screenWidth, ScalingLogic.FIT);
            int w = scaled.getWidth();
            int h = scaled.getHeight();
            // Setting post rotate to 90
            Matrix mtx = new Matrix();
            mtx.postRotate(90);
            // Rotating Bitmap
            bm = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
        }else{// LANDSCAPE MODE
            //No need to reverse width and height
            Bitmap scaled = ScalingUtilities.createScaledBitmap(bm, screenHeight, screenWidth, ScalingLogic.FIT);
            bm=scaled;
        }
        ivCaptureImagePreview.setImageBitmap(bm);
        ivCaptureImagePreview.setVisibility(View.VISIBLE);
    }

}
Ric answered 7/3, 2016 at 5:59 Comment(1)
@SrujanBarai its method of matrix call it on matrix object Matrix mtx = new Matrix(); mtx.postRotate(90);Ric
T
1

UIImageView Settings

<ImageView
    android:id="@id/img"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter" />

My Test Application for this Problem

For Getting the Picture From the Camera, I use the following methods:

private void pickImageIntent()
{
    Intent pickPhoto = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    getCurrentActivity().startActivityForResult(pickPhoto, REQUEST_PICK_IMAGE);
}

private void takeImageIntent()
{
    try
    {
        File outputDir = getCurrentActivity().getExternalCacheDir();
        File outputFile = File.createTempFile("prefix", "extension", outputDir);
        selectedImageUri = Uri.fromFile(outputFile);

        Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePicture.putExtra(MediaStore.EXTRA_OUTPUT, selectedImageUri);
        getCurrentActivity().startActivityForResult(takePicture, REQUEST_TAKE_IMAGE);
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

For Getting the Result From the Camera or Image Picker, and show it in the imageView. Here this.myInterfaceImage:

public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    switch(requestCode)
    {
        case REQUEST_PICK_IMAGE:
            if(resultCode == Activity.RESULT_OK)
            {
                selectedImageUri = data.getData();
                initImage(selectedImageUri);
            }
            break;
        case REQUEST_TAKE_IMAGE:
            if(resultCode == Activity.RESULT_OK)
            {
                initImage(selectedImageUri);
            }
            break;
    }
}


protected void initImage(Uri selectedImageUri_) {
    try {
        ParcelFileDescriptor parcelFileDescriptor = getContext().getContentResolver().openFileDescriptor(selectedImageUri_, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Bitmap source = BitmapFactory.decodeFileDescriptor(fileDescriptor);
        float ratio = (float)source.getWidth() /  (float)source.getHeight();
        // here perhaps limit the size of the image
        int height =   Math.min(getContext().getResources().getDisplayMetrics().heightPixels, source.getHeight());
        int width = (int)(ratio*height);
        Bitmap result = Bitmap.createScaledBitmap(source, width, height, false);
        this.interfaceImage.setImageBitmap(result);
        if (result != source) {
            source.recycle();
        }
    } catch (Exception ex) {
        System.out.println("File not found");
    }
}

This is how I used this in My Test Application, and it works I don't have any orientation issues. I tested in Portrait mode with Portrait and Landscape Picture, and in Landscape mode with Portrait and Landscape Picture. And with both where I changed the orientation after before getting the Image.

If your are using Custom Camera and the orientation is wrong with the Code Above, just add this

There are two things needed:

  1. Camera preview need the same as your rotation. Set this by

    camera.setDisplayOrientation(result);

  2. Save the picture captured as your camera preview. Do this via Camera.Parameters.

    int mRotation = getCameraDisplayOrientation(); Camera.Parameters parameters = camera.getParameters(); parameters.setRotation(mRotation); //set rotation to save the picture camera.setDisplayOrientation(result); //set the rotation for preview camera camera.setParameters(parameters);

Then you can use your function without the orientation stuff

public void onPicTaken(byte[] data) {
    if (data != null) {
        Bitmap bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        float ratio = (float)bm.getWidth() /  (float)bm.getHeight();
        int screenHeight = (int)(ratio*screenWidth)
        Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
        if (scaled != bm) {
            source.recycle();
        }        
        ivCaptureImagePreview.setImageBitmap(scaled);
        ivCaptureImagePreview.setVisibility(View.VISIBLE);
    }
}

Hope that helps.

Thee answered 2/3, 2016 at 12:36 Comment(6)
it convert image orientatation to landscape modePrim
@NeerajSharma updated my code, and it works fine inside my testapplication.Thee
your code works fine only in landscape mode not ir portrait mode bro.Prim
@NeerajSharma Did you use my whole Code. takeImageIntent and initImage cause in my TestApplication it works fine. Should I add screenshots?Thee
@NeerajSharma Since i read from other questions that you are using custom camera see the last section. If you are using custom camera and the orientation is wrong. Just add this to the code. But you have to use my initImage function where the ratio is preserved.Thee
@NeerajSharma Look at the complete 2nd Section perhaps I can delete the first half of my Answer, cause you are using a custom camera or?.Thee
C
1

I use this function in my one of project please check if it is useful for you.

public static Bitmap Preview(String path) {
    //SCALE IMAGE
    int SCALE = 4;
    try {
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = SCALE;
        Bitmap bitmap = BitmapFactory.decodeFile(path, o2);
        OutputStream os = new FileOutputStream(path);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
        os.flush();
        os.close();
        File file = new File(path);

        while (file.length() > 800000) {
            SCALE += 2;
            o2.inSampleSize = SCALE;
            bitmap = BitmapFactory.decodeFile(path, o2);
            os = new FileOutputStream(path);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
            os.flush();
            os.close();
            file = new File(path);
        }

        bitmap = BitmapFactory.decodeFile(path, o2);
        return bitmap;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}
Coinsure answered 3/3, 2016 at 12:59 Comment(0)
S
0

Use this it will prevent image from stretching and maintaining the aspect ratio of image

android:scaleType="fitXY"  // or desired scale type
android:adjustViewBounds="true"
Sharl answered 29/2, 2016 at 11:36 Comment(0)
A
0

Scaling your bitmap with Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true); won't maintain aspect ratio because this will stretch the width and height of the bitmap to match the target.

An option would be to calculate the target height manually so no cropping occurs:

double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (screenWidth * aspectRatio);

And then use targetHeight instead of screenHeight as height argument in createScaledBitmap().

In addition, make sure the imageview you load your bitmap into has the appropriate scale type (e.g. FIT_CENTER or CENTER_CROP).

Ashtonashtonunderlyne answered 8/3, 2016 at 19:12 Comment(0)
H
0

As you can see in documentation enter link description here; you have to resize and rescale your bitmap before rendering so you can use code below for your BitmapFactory.Options :

mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity =  dstWidth;

// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(), 
      mImageIDs, mBitmapOptions);
Hotchkiss answered 7/2, 2021 at 7:24 Comment(0)
C
-1

use this putExtra in your intent call for camera

intent.putExtra("outputX", 80);
    intent.putExtra("outputY", 80);
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 20);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, Utility.REQUEST_FOR_CAMERA);
Coinsure answered 3/3, 2016 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.