Search code examples
androidandroid-cameraandroid-imageview

Taking image from custom camera is stretched when save in ImageView


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

}

Solution

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