Akshay
Akshay

Reputation: 6142

Custom camera image rotated at the time of saving

I'm trying to build a custom camera for my application and I'm done with that, but the problem is when I'm storing the captured image, it gets rotated by 90 degrees to the left. Following is my code, please tell me where am I getting wrong??

CamTestActivity class

public class CamTestActivity extends Activity {
private static final String TAG = "CamTestActivity";
public static final int REQUEST_CODE_GALLERY = 0x1;
private File mFileTemp;
Preview preview;
Button buttonClick, buttonGallery;
Camera camera;
Activity act;
Context ctx;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ctx = this;
    act = this;
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main);

    /**
     * Get internal storage directory path for image save
     */
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {// if
        mFileTemp = new File(Environment.getExternalStorageDirectory(), "temp_photo.png");
    } else {
        mFileTemp = new File(this.getFilesDir(), "temp_photo.png");
    }// End of if

    preview = new Preview(this, (SurfaceView) findViewById(R.id.surfaceView));
    preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    ((FrameLayout) findViewById(R.id.layout)).addView(preview);
    preview.setKeepScreenOn(true);

    // preview.setOnClickListener(new OnClickListener() {
    //
    // @Override
    // public void onClick(View arg0) {
    // camera.takePicture(shutterCallback, rawCallback, jpegCallback);
    // }
    // });

    // Toast.makeText(ctx, getString(R.string.take_photo_help), Toast.LENGTH_LONG).show();

    buttonClick = (Button) findViewById(R.id.btnCapture);
    buttonGallery = (Button) findViewById(R.id.btnGallery);

    buttonClick.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            // preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            Toast.makeText(ctx, ""+mFileTemp, Toast.LENGTH_LONG).show();
        }
    });

    buttonClick.setOnLongClickListener(new OnLongClickListener() {
        @Override
        public boolean onLongClick(View arg0) {
            camera.autoFocus(new AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean arg0, Camera arg1) {
                    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
                    Toast.makeText(ctx, ""+mFileTemp, Toast.LENGTH_LONG).show();
                }
            });
            return true;
        }
    });

    buttonGallery.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            /**
             * To select an image from existing files, use Intent.createChooser to open image chooser. Android will automatically display a list of supported applications, such as image gallery or file manager.
             */
            Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
            photoPickerIntent.setType("image/*");
            startActivityForResult(photoPickerIntent, REQUEST_CODE_GALLERY);
        }
    });
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK) {

        return;
    }

    switch (requestCode) {
    // pick image from gallery
        case REQUEST_CODE_GALLERY:

            try {

                InputStream inputStream = this.getContentResolver().openInputStream(data.getData());
                FileOutputStream fileOutputStream = new FileOutputStream(mFileTemp);
                copyStream(inputStream, fileOutputStream);
                fileOutputStream.close();
                inputStream.close();
                Toast.makeText(ctx, ""+mFileTemp, Toast.LENGTH_LONG).show();
            } catch (Exception e) {
            }
            break;

    }

    super.onActivityResult(requestCode, resultCode, data);
}// End of onactivityresult

/**
 * Function copyStream()-copy InputStream
 * 
 * @param input
 * @param output
 * @throws IOException
 * @return null
 */
public static void copyStream(InputStream input, OutputStream output) throws IOException {

    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = input.read(buffer)) != -1) {
        output.write(buffer, 0, bytesRead);
    }
}// End of copyStream method

@Override
protected void onResume() {
    super.onResume();
    int numCams = Camera.getNumberOfCameras();
    if (numCams > 0) {
        try {
            camera = Camera.open(0);
            camera.startPreview();
            preview.setCamera(camera);
        } catch (RuntimeException ex) {
            Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
        }
    }
}

@Override
protected void onPause() {
    if (camera != null) {
        camera.stopPreview();
        preview.setCamera(null);
        camera.release();
        camera = null;
    }
    super.onPause();
}

private void resetCam() {
    camera.startPreview();
    preview.setCamera(camera);
}

private void refreshGallery(File file) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    mediaScanIntent.setData(Uri.fromFile(file));
    sendBroadcast(mediaScanIntent);
}

ShutterCallback shutterCallback = new ShutterCallback() {
    public void onShutter() {
        // Log.d(TAG, "onShutter'd");
    }
};

PictureCallback rawCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
        // Log.d(TAG, "onPictureTaken - raw");
    }
};

PictureCallback jpegCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
        try {
            mFileTemp = new SaveImageTask().execute(data).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        resetCam();
        Log.d(TAG, "onPictureTaken - jpeg");
    }
};

private class SaveImageTask extends AsyncTask<byte[], Void, File> {

    @Override
    protected File doInBackground(byte[]... data) {
        FileOutputStream outStream = null;
        File outFile  = null;

        // Write to SD Card
        try {
            File sdCard = Environment.getExternalStorageDirectory();
            File dir = new File(sdCard.getAbsolutePath() + "/camtest");
            dir.mkdirs();

            String fileName = String.format("%d.jpg", System.currentTimeMillis());
            outFile = new File(dir, fileName);


            outStream = new FileOutputStream(outFile);
            outStream.write(data[0]);
            outStream.flush();
            outStream.close();

            Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length + " to " + outFile.getAbsolutePath());

            refreshGallery(outFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return outFile;
    }

}

}

Preview class,

   class Preview extends ViewGroup implements SurfaceHolder.Callback {
    private final String TAG = "Preview";

    SurfaceView mSurfaceView;
    SurfaceHolder mHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    Camera mCamera;
    Context mContext;

    Preview(Context context, SurfaceView sv) {
        super(context);
        mContext = context;
        mSurfaceView = sv;
//        addView(mSurfaceView);

        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();

            // get Camera parameters
            Camera.Parameters params = mCamera.getParameters();

            List<String> focusModes = params.getSupportedFocusModes();
            if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
                // set the focus mode
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
                // set Camera parameters
                mCamera.setParameters(params);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (changed && getChildCount() > 0) {
            final View child = getChildAt(0);

            final int width = r - l;
            final int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null) {
                previewWidth = mPreviewSize.width;
                previewHeight = mPreviewSize.height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth) {
                final int scaledChildWidth = previewWidth * height / previewHeight;
                child.layout((width - scaledChildWidth) / 2, 0,
                        (width + scaledChildWidth) / 2, height);
            } else {
                final int scaledChildHeight = previewHeight * width / previewWidth;
                child.layout(0, (height - scaledChildHeight) / 2,
                        width, (height + scaledChildHeight) / 2);
            }
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            }
        } catch (IOException exception) {
            Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }


    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null) return null;

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

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        for (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);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if(mCamera != null) {
            Camera.Parameters parameters = mCamera.getParameters(); 
//          parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

                if(display.getRotation() == Surface.ROTATION_0)
                {
                    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);                           
                    mCamera.setDisplayOrientation(90);
                }

                if(display.getRotation() == Surface.ROTATION_90)
                {
                    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);                           
                }

                if(display.getRotation() == Surface.ROTATION_180)
                {
                    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);               
                }

                if(display.getRotation() == Surface.ROTATION_270)
                {
                    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
                    mCamera.setDisplayOrientation(180);
                }

                requestLayout();


            mCamera.setParameters(parameters);
            mCamera.startPreview();
        }
    }

}

Upvotes: 0

Views: 840

Answers (2)

Nico.S
Nico.S

Reputation: 763

I solved a similar problem using the Camera rotation value:

Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int cameraRotation = info.orientation;

The image should be rotated of the same angle.

Upvotes: 1

grig
grig

Reputation: 847

This is not your fault. Different devices have different default camera angle. If you want to turn your picture:

String path = *your_image_path*;
Bitmap scaledBitmap = null;
ExifInterface ei = new ExifInterface(path);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
    scaledBitmap = ScalingUtilities.createScaledBitmap(unscaledBitmap, unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),ScalingLogic.FIT, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
    scaledBitmap = ScalingUtilities.createScaledBitmap(unscaledBitmap, unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),ScalingLogic.FIT, 180);

etc.

Upvotes: 1

Related Questions