3

I'm having a problem with my camera app. My app has:

1) a CameraActivity.class and

2) a CameraPreview.class.

CameraPreview implement a surfaceView where it's called from CameraActivity for the actual preview. (Also in CameraActivity I have the parameters)

Now the problem: When the preview is starting the preview is stretched. I tried a lot of things (so many that I cannot recall) I need someone to tell me what to write and where. Thanks in advance.

Here is the CameraActivity(Not all the code but the important I think)

    private PictureCallback mPicture = new PictureCallback() {

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

        // Replacing the button after a photho was taken.
        flBtnContainer.setVisibility(View.GONE);
        ibRetake.setVisibility(View.VISIBLE);
        ibUse.setVisibility(View.VISIBLE);

        // File name of the image that we just took.
        fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()).toString() + ".jpg";

        // Creating the directory where to save the image. Sadly in older
        // version of Android we can not get the Media catalog name
        File mkDir = new File(sdRoot, dir);
        mkDir.mkdirs();

        // Main file where to save the data that we recive from the camera
        File pictureFile = new File(sdRoot, dir + fileName);

        try {
            FileOutputStream purge = new FileOutputStream(pictureFile);
            purge.write(data);
            purge.close();
        } catch (FileNotFoundException e) {
            Log.d("DG_DEBUG", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
        }

        // Adding Exif data for the orientation. For some strange reason the
        // ExifInterface class takes a string instead of a file.
        try {
            exif = new ExifInterface("/sdcard/" + dir + fileName);
            exif.setAttribute(ExifInterface.TAG_ORIENTATION, "" + orientation);
            exif.saveAttributes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Intent intent = new Intent(CameraActivity.this, PicturePreview.class);
        Bundle extras = new Bundle();
        extras.putString("ImagePath", String.valueOf(pictureFile));
        intent.putExtras(extras);
        startActivity(intent);

        //SendBroadcasts let's us instantly update the SD card with our image
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+Environment.getExternalStorageDirectory())));

    }



};



private void createCamera() {
    // Create an instance of Camera
    mCamera = getCameraInstance();

//        Setting the right parameters in the camera
    Camera.Parameters params = mCamera.getParameters();
    params.setRotation(90);
    mCamera.setParameters(params);

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview, 0);
}


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

    // Test if there is a camera on the device and if the SD card is
    // mounted.
    if (!checkCameraHardware(this)) {
        Intent i = new Intent(this, NoCamera.class);
        startActivity(i);
        finish();
    } else if (!checkSDCard()) {
        Intent i = new Intent(this, NoSDCard.class);
        startActivity(i);
        finish();
    }

    // Creating the camera
    createCamera();

    // Register this class as a listener for the accelerometer sensor
    ////sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
    super.onPause();
    // release the camera immediately on pause event
    releaseCamera();

    // removing the inserted view - so when we come back to the app we
    // won't have the views on top of each other.
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.removeViewAt(0);
} 

And here is the CameraPreview.class

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
boolean isPreviewRunning = true;




public CameraPreview(Context context, Camera camera) {
    super(context);
    mCamera = camera;

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mHolder.setFixedSize(100, 100);

}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, now tell the camera where to draw the
    // preview.
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.setDisplayOrientation(90);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.d("DG_DEBUG", "Error setting camera preview: " + e.getMessage());
    }

}

public void surfaceChanged(SurfaceHolder holder,
                           int format, int width, int height) {


    if (isPreviewRunning){
        return;
    }
    isPreviewRunning = true;

    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.


    if (mHolder.getSurface() == null) {
        // preview surface does not exist
        return;
    }

    // stop preview before making changes
    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        // ignore: tried to stop a non-existent preview
    }




    // make any resize, rotate or reformatting changes here

    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();


    } catch (Exception e) {
        Log.d("DG_DEBUG", "Error starting camera preview: " + e.getMessage());
    }

}



public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
}



}

Can someone tell what am I missing? If possible I can chat in Facebook or something for faster resolve of my problem..

Update: @LikeWhiteOnRice's solution.

Here is my original code

enter image description here

Here is with LikeWhiteOnRice's code:

enter image description here

Any thoughts?

1 Answers1

1

I added the code below to my camera preview class and it works for most devices. Just so you are aware, the camera library in Android is horrible and a huge pain to work with.

Put this function in your CameraPreview class:

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

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

In your surefaceCreated function, add this before you start your preview:

Camera.Parameters cameraParameters = mCamera.getParameters();
List<Camera.Size> previewSizes = cameraParameters.getSupportedPreviewSizes();
Camera.Size optimalPreviewSize = getOptimalSize(previewSizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
cameraParameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
mCamera.setParameters(cameraParameters);

Edit: Also, I'm not sure if you want

mHolder.setFixedSize(100, 100);

in your constructor.

Jay
  • 324
  • 2
  • 14
  • And this is how I did it.. Check it if u want and tell me if its right.. Its my code in a txt file.. [link](https://www.sendspace.com/file/wl2k0o) – Thanos Tokmakis Jun 06 '16 at 22:11
  • Have you tried making your surfaceView full screen and then adding your capture button over the top of it? Your image may not be distorted if you use the full screen to display it. – Jay Jun 06 '16 at 22:42
  • I also had the same thought.. I will try it now and I will let u know.. Tons of thanks brother – Thanos Tokmakis Jun 06 '16 at 22:53
  • There is a slight difference in taken picture with the preview but not so importand.. Thank you mister.. You re a little God.. Many respects for spending time on me... – Thanos Tokmakis Jun 06 '16 at 23:01
  • Ok.. Now Im facing another issue.. I have a button to change the front/back camera but I cant resolve it.. It just does nothing.. Can someone explain what to do? – Thanos Tokmakis Jun 07 '16 at 13:24