Search code examples
androidcameraaspect-ratio

stretched image in custom camera using surfaceview


In some device the the image become stretched, I'm using surfaceView in may camera preview.

    public class vp02ImageCapture extends SuperVP {

    private static final String TAG = "vp02ImageCapture";


    private Camera camera;
    @Bind(R.id.TransparentView) SurfaceView transparentView;
    @Bind(R.id.sv_camera) SurfaceView sv;
    @Bind(R.id.relative) RelativeLayout rl;
    @Bind(R.id.mask) FrameLayout mask;


    private ProgressDialog dp;
    private boolean front = true;
    private SurfaceHolder sh,holderTransparent;
    int orient = 1;

    private Handler h = new Handler();
    View v;
    //private UserInfo info;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         v = inflater.inflate(R.layout.vp02imagecapture, null);


        ButterKnife.bind(this, v);

        sh = sv.getHolder();

        holderTransparent = transparentView.getHolder();

        holderTransparent.setFormat(PixelFormat.TRANSPARENT);

        transparentView.setZOrderMediaOverlay(true);




        return v;
    }
    public int getscrOrientation()
    {
        Display getOrient = getActivity().getWindowManager().getDefaultDisplay();

        int orientation = getOrient.getOrientation();

        // Sometimes you may get undefined orientation Value is 0
        // simple logic solves the problem compare the screen
        // X,Y Co-ordinates and determine the Orientation in such cases
        if(orientation==Configuration.ORIENTATION_UNDEFINED){

            Configuration config = getResources().getConfiguration();
            orientation = config.orientation;

            if(orientation== Configuration.ORIENTATION_UNDEFINED){
                //if height and widht of screen are equal then
                // it is square orientation
                if(getOrient.getWidth()==getOrient.getHeight()){
                    orientation = Configuration.ORIENTATION_SQUARE;
                }else{ //if widht is less than height than it is portrait
                    if(getOrient.getWidth() < getOrient.getHeight()){
                        orientation = Configuration.ORIENTATION_PORTRAIT;
                    }else{ // if it is not any of the above it will defineitly be landscape
                        orientation = Configuration.ORIENTATION_LANDSCAPE;
                    }
                }
            }
        }
        return orientation; // return value 1 is portrait and 2 is Landscape Mode
    }

openCamera() method

    private void openCamera() {

        int cameraId;
        if (front) {
            cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);

        } else{

            cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
            camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        }

        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = getActivity().getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }

        camera.setDisplayOrientation(result);


        final Camera.Parameters parameters = camera.getParameters();
        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
        Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
        parameters.setPreviewSize(optimalSize.width, optimalSize.height);
        transparentView.requestLayout();
        sv.requestLayout();




        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    Draw();


//                    camera.setParameters(parameters);
                    camera.setPreviewDisplay(sh);
                    camera.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, 200);

    }



    @Override
    public void releaseUI() {
        rl.setVisibility(View.GONE);
//        hideProgressDialog();
        camera.release();
    }

    @Override
    public void updateUI() {
        super.updateUI();
        Log.e("sample","asd   " + TAG);
        if (TAG.equals("vp02ImageCapture")){
            parent.btnNext.setVisibility(View.GONE);
            parent.btnBack.setVisibility(View.GONE);
        }else{
            parent.btnNext.setVisibility(View.VISIBLE);
            parent.btnBack.setVisibility(View.VISIBLE);
        }
        getActivity().setTitle("Image Capture");
        rl.setVisibility(View.VISIBLE);
        openCamera();


    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("isfront", front);
    }

    @OnClick(R.id.btnSwitch)void switchCamera(){

        camera.stopPreview();
        camera.release();

        front = front ? false : true;

        openCamera();

    }

    @OnClick(R.id.btnCapture) void capture(){

//        showProgressDialog("Loading...");


        camera.takePicture(new Camera.ShutterCallback() {
            @Override
            public void onShutter() {
            }
        }, new Camera.PictureCallback() {

            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
            }
        }, new Camera.PictureCallback() {

            @Override
            public void onPictureTaken(byte[] data, Camera camera) {

                // rotate capture image
                Display display = getActivity().getWindowManager().getDefaultDisplay();
                int rotation = 0;
                switch (display.getRotation()) {
                    case Surface.ROTATION_0: // This is display orientation
                        rotation = 90;
                        break;
                    case Surface.ROTATION_90:
                        rotation = 0;
                        break;
                    case Surface.ROTATION_180:
                        rotation = 270;
                        break;
                    case Surface.ROTATION_270:
                        rotation = 180;
                        break;
                }


                //Crop image size
                Bitmap bitmap = ImageFactory.byteArrayToBitmap(data);
                if (front) {
                    bitmap = rotate(bitmap, rotation);
                }

                int l = sv.getWidth() / 8;
                int t = (sv.getHeight() / 2) - (l*4);

                // 2.3 Size of rotated bitmap
                int bitWidth = bitmap.getWidth();
                int bitHeight = bitmap.getHeight();


                Log.e("SIZES", "" + sv.getHeight() + "----" + bitHeight + "-----");

                // 3. Size of camera preview on screen
                int preWidth = sv.getWidth();
                int preHeight = sv.getHeight();

                // 4. Scale it.
                // Assume you draw Rect as "canvas.drawRect(60, 50, 210, 297, paint);" command

//                canvas.drawRect(l,t,l*7,t + l*8,paint1);
//                int startx = (l * bitWidth / preWidth);
//                int starty = (t * bitHeight / preHeight);
//                int endx = ((l * 6) * bitWidth / preWidth);
//                int endy = (((t * 4) * bitHeight / preHeight));


                int startx = (l * bitWidth / preWidth);
                int starty = (t * bitHeight / preHeight);
                int endx = ((l * 6) * bitWidth / preWidth);
                int endy = (((t + (l*7)) * bitHeight / preHeight));


                Log.e("ELIBOY!", "" + l + "----" + t + "------" + l * 7 + "----" + t * 5);
                Log.e("ELI!!!!", "" + startx + "----" + starty + "------" + endx + "----" + endy);

                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                byte[] byteArray = stream.toByteArray();

                setImageByteArray(byteArray);
                setStartX(startx);
                setStartY(starty);
                setEndX(endx);
                setEndY(endy);

                viewPager.setCurrentItem(viewPager.getCurrentItem() + 1); //set next page to display ; current page + 1


                /*Fragment f = new vp03ImagePreview();
                f.setArguments(b);
                getParentFragment().getChildFragmentManager().beginTransaction().replace(R.id.imagefrag_container,f).commit();*/
                //ScreenManager.getInstance().replaceScreen(Screens.Enroll02b,b);
            }
        });
    }


    boolean fromPause = false;

    @Override
    public void onResume() {
        super.onResume();


        if(fromPause)
            if(((ScreenTransaction)getParentFragment()).viewPager.getCurrentItem()==1)
                openCamera();

        fromPause = false;
    }

    @Override
    public void onPause() {
        super.onPause();
        try{
            camera.release();
        }catch (NullPointerException e){

        }

        h.removeCallbacksAndMessages(null);
        fromPause = true;

        //viewPager.removeOnPageChangeListener(viewpagerChangeListener);
    }











    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.5;
        double targetRatio=(double)h / w;

        if (sizes == null) return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;

        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }



    @OnClick(R.id.mask)void autofocus(){
        camera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {

            }
        });
    }

    public void showProgressDialog(String message){
        dp = new ProgressDialog(getActivity());
        dp.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        dp.setCancelable(false);
        dp.setMessage(message);
        dp.show();
    }


    public void hideProgressDialog(){
        dp.hide();
    }


}

I want to support all screen . How can I solve this? in some screen its working but in some specially when its default camera is not in full screen.


Solution

  • I have made this code and its working very well.

    public class CameraActivity extends Activity implements Constants.Parameters {
    
    
        FrameLayout previewFrameLayout;
        ImageButton captureButton, switchCamera, flashImageButton, backImageButton;
    
        boolean isFlashEnabled = false, isFlashAvailable = false, isFrontCamera = false;
        Handler handler;
    
        private int mCameraId;
        private Camera mCamera;
        private CameraPreview mCameraPreview;
        public final int BACK_CAMERA = 0;
        public final int FRONT_CAMERA = 1;
    
        String className = "";
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_camera);
            handler = new Handler();
    
            isFlashAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
            isFrontCamera = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
    
            previewFrameLayout = (FrameLayout) findViewById(R.id.camera_preview);
    
            captureButton = (ImageButton) findViewById(R.id.button_capture);
            captureButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    mCamera.takePicture(null, null, mPicture);
    
                }
            });
    
    
    
            switchCamera = (ImageButton) findViewById(R.id.switchCamera);
            switchCamera.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Utils.scaleView(switchCamera);
    
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            previewFrameLayout.removeAllViews();
    
                            if (mCameraId == BACK_CAMERA) {
                                flashImageButton.setVisibility(View.INVISIBLE);
                                mCameraId = FRONT_CAMERA;
                                mCameraPreview = new CameraPreview(CameraNewActivity.this, FRONT_CAMERA);
                                previewFrameLayout.addView(mCameraPreview);
                            } else {
                                flashImageButton.setVisibility(View.VISIBLE);
                                mCameraId = BACK_CAMERA;
                                mCameraPreview = new CameraPreview(CameraNewActivity.this, BACK_CAMERA);
                                previewFrameLayout.addView(mCameraPreview);
                            }
                        }
                    }, 250);
    
                }
            });
    
            flashImageButton = (ImageButton) findViewById(R.id.flash);
            flashImageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Utils.scaleView(flashImageButton);
    
                    try {
                        Camera.Parameters parameters = mCamera.getParameters();
                        if (!isFlashEnabled) {
                            isFlashEnabled = true;
                            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
                            flashImageButton.setSelected(true);
                        } else {
                            isFlashEnabled = false;
                            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                            flashImageButton.setSelected(false);
                        }
                        mCamera.setParameters(parameters);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                }
            });
    
            if (!isFlashAvailable) {
                flashImageButton.setVisibility(View.GONE);
            }
    
            if (!isFrontCamera) {
                switchCamera.setVisibility(View.GONE);
            }
    
            backImageButton = (ImageButton) findViewById(R.id.back);
            backImageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    finish();
                }
            });
    
        }
    
        private void hideIcons() {
            switchCamera.setVisibility(View.GONE);
            captureButton.setVisibility(View.GONE);
            flashImageButton.setVisibility(View.GONE);
            backImageButton.setVisibility(View.GONE);
        }
    
        private void showIcons() {
            switchCamera.setVisibility(View.VISIBLE);
            captureButton.setVisibility(View.VISIBLE);
            flashImageButton.setVisibility(View.VISIBLE);
            backImageButton.setVisibility(View.VISIBLE);
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
            mCameraPreview = new CameraPreview(this, mCameraId);
            previewFrameLayout.addView(mCameraPreview);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mCameraPreview.stop();
            previewFrameLayout.removeView(mCameraPreview); // This is necessary.
            mCameraPreview = null;
        }
    
    
    
        Camera.PictureCallback mPicture = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(final byte[] data, Camera camera) {
    
                final File pictureFile = new File(Utils.profilePicPath + String.valueOf(System.currentTimeMillis()) + ".jpg");
                pictureFile.getParentFile().mkdirs();
                Utils.deleteCapture();
    
    
                if (pictureFile == null) {
                    return;
                }
    
    
                Thread thread = new Thread() {
                    @Override
                    public void run() {
    
                        try {
    
                            FileOutputStream fos = new FileOutputStream(pictureFile);
                            fos.write(data);
                            fos.close();
    
                            BitmapFactory.Options bmOptions = new BitmapFactory.Options();
                            bmOptions.inJustDecodeBounds = true;
                            BitmapFactory.decodeFile(pictureFile.getPath(), bmOptions);
    
                            final int height = bmOptions.outHeight;
                            final int width = bmOptions.outWidth;
    
                            if (height > width) {
                                if (height / width < 1.5) {
                                    Bitmap bitmap = Picasso.with(CameraNewActivity.this)
                                            .load(pictureFile).resize((int) (height / 1.65), height).centerCrop().get();
    
                                    if (mCameraId == FRONT_CAMERA) {
                                        bitmap = flip(bitmap);
                                    }
    
                                    FileOutputStream out = new FileOutputStream(pictureFile.getPath());
                                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
                                    out.flush();
                                    out.close();
                                }
                            }
    
    
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
    
    
                        }
    
                    }
                };
    
                thread.start();
    
    
            }
        };
    
    
        public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    
    
            private SurfaceHolder mHolder;
            protected List<Camera.Size> mPreviewSizeList;
            protected List<Camera.Size> mPictureSizeList;
            protected Camera.Size mPreviewSize;
            protected Camera.Size mPictureSize;
            private int mSurfaceChangedCallDepth = 0;
            private int mCenterPosX = -1;
            private int mCenterPosY = 0;
            protected boolean mSurfaceChanged = false;
    
            public CameraPreview(Activity activity, int cameraId) {
                super(activity);
                mHolder = getHolder();
                mHolder.addCallback(this);
                mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
                if (Camera.getNumberOfCameras() > cameraId) {
                    mCameraId = cameraId;
                } else {
                    mCameraId = 0;
                }
                mCamera = Camera.open(mCameraId);
                Camera.Parameters cameraParams = mCamera.getParameters();
                mPreviewSizeList = cameraParams.getSupportedPreviewSizes();
                mPictureSizeList = cameraParams.getSupportedPictureSizes();
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    mCamera.setPreviewDisplay(mHolder);
                } catch (IOException e) {
                    mCamera.release();
                    mCamera = null;
                }
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                mSurfaceChangedCallDepth++;
    
                mCamera.stopPreview();
    
                Camera.Parameters cameraParams = mCamera.getParameters();
    
                if (!mSurfaceChanged) {
                    Camera.Size previewSize = determinePreviewSize(width, height);
                    Camera.Size pictureSize = determinePictureSize(previewSize);
                    mPreviewSize = previewSize;
                    mPictureSize = pictureSize;
                    mSurfaceChanged = adjustSurfaceLayoutSize(previewSize, width, height);
    
                    if (mSurfaceChanged && (mSurfaceChangedCallDepth <= 1)) {
                        return;
                    }
                }
    
                if (mCameraId == BACK_CAMERA) {
                    cameraParams.setRotation(90);
                } else {
                    cameraParams.setRotation(270);
                }
    
                mCamera.setDisplayOrientation(90);
                cameraParams.set("orientation", "portrait");
                cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
                cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
    
                mCamera.setParameters(cameraParams);
    
                mSurfaceChanged = false;
    
                try {
                    mCamera.startPreview();
                } catch (Exception e) {
                    // Remove failed size
                    mPreviewSizeList.remove(mPreviewSize);
                    mPreviewSize = null;
    
                    // Reconfigure
                    if (mPreviewSizeList.size() > 0) { // prevent infinite loop
                        surfaceChanged(null, 0, width, height);
                    } else {
                        Utils.showToast(CameraNewActivity.this, "Can't start preview", Toast.LENGTH_LONG);
                    }
                }
    
                mSurfaceChangedCallDepth--;
            }
    
            protected Camera.Size determinePreviewSize(int reqWidth, int reqHeight) {
    
                int reqPreviewWidth = reqHeight; // requested width in terms of camera hardware
                int reqPreviewHeight = reqWidth; // requested height in terms of camera hardware
    
                // Adjust surface size with the closest aspect-ratio
                float reqRatio = ((float) reqPreviewWidth) / reqPreviewHeight;
                float curRatio, deltaRatio;
                float deltaRatioMin = Float.MAX_VALUE;
                Camera.Size retSize = null;
                for (Camera.Size size : mPreviewSizeList) {
                    curRatio = ((float) size.width) / size.height;
                    deltaRatio = Math.abs(reqRatio - curRatio);
                    if (deltaRatio < deltaRatioMin) {
                        deltaRatioMin = deltaRatio;
                        retSize = size;
                    }
                }
    
                return retSize;
            }
    
            protected Camera.Size determinePictureSize(Camera.Size previewSize) {
                Camera.Size retSize = null;
                for (Camera.Size size : mPictureSizeList) {
                    if (size.equals(previewSize)) {
                        return size;
                    }
                }
    
                // if the preview size is not supported as a picture size
                float reqRatio = ((float) previewSize.width) / previewSize.height;
                float curRatio, deltaRatio;
                float deltaRatioMin = Float.MAX_VALUE;
                for (Camera.Size size : mPictureSizeList) {
                    curRatio = ((float) size.width) / size.height;
                    deltaRatio = Math.abs(reqRatio - curRatio);
                    if (deltaRatio < deltaRatioMin) {
                        deltaRatioMin = deltaRatio;
                        retSize = size;
                    }
                }
    
                return retSize;
            }
    
            protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize,
                                                      int availableWidth, int availableHeight) {
    
                float tmpLayoutHeight = previewSize.width;
                float tmpLayoutWidth = previewSize.height;
    
                float factH, factW, fact;
                factH = availableHeight / tmpLayoutHeight;
                factW = availableWidth / tmpLayoutWidth;
    
                if (factH < factW) {
                    fact = factH;
                } else {
                    fact = factW;
                }
    
                FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.getLayoutParams();
    
                int layoutHeight = (int) (tmpLayoutHeight * fact);
                int layoutWidth = (int) (tmpLayoutWidth * fact);
    
                boolean layoutChanged;
                if ((layoutWidth != this.getWidth()) || (layoutHeight != this.getHeight())) {
                    layoutParams.height = layoutHeight;
                    layoutParams.width = layoutWidth;
                    if (mCenterPosX >= 0) {
                        layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
                        layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
                    }
                    this.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
                    layoutChanged = true;
                } else {
                    layoutChanged = false;
                }
    
                return layoutChanged;
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                stop();
            }
    
            public void stop() {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.release();
                    mCamera = null;
                }
            }
    
        }
    
        public Bitmap flip(Bitmap bitmap) {
            Matrix mtx = new Matrix();
            mtx.preScale(-1, 1);
            return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mtx, true);
        }
    
    }