android - 使用 SurfaceView 在自定义相机中拉伸(stretch)图像

标签 android camera aspect-ratio

在某些设备中,图像会被拉伸(stretch),我在 5 月份的相机预览中使用 surfaceView

    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()方法

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


}

我想支持全屏。 我该如何解决这个问题? 在某些屏幕上它可以工作,但在某些情况下特别是当它的默认相机不是全屏时。

最佳答案

我已经编写了这段代码并且它运行得很好。

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

}

关于android - 使用 SurfaceView 在自定义相机中拉伸(stretch)图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39524494/

相关文章:

Android MediaRecorder 宽高比不正确

iphone - 通过SDK覆盖iPhone快门声音

android - 全高流体图像和 div 在一行中。 Div 必须占据剩余的水平空间

android - ListView item后台 hell

java - Android - 使用 Callable 进行联网

image-processing - 多种实时图像处理选择哪个开发板

android - 即使匹配视频大小和预览大小纵横比,MediaRecorder 也会失败

android - 使用packageReleaseJar取决于

android - 如何将按钮添加到自定义适配器?

c - 检测宽屏幕纵横比