Wednesday, March 9, 2016

Taking image from custom camera is stretched when save in ImageView

Leave a Comment

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);     }  } 

7 Answers

Answers 1

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);     }  } 

Answers 2

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.

Answers 3

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" 

Answers 4

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;     } } 

Answers 5

You can set scaleType in xml

<ImageView         android:id="@+id/iv_imageview"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:scaleType="fitCenter" /> 

In Java code you can achieve same like this

ImageView mImageView = (ImageView) findViewById(R.id.iv_imageview);  mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);  

Answers 6

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).

Answers 7

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); 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment