setDisplayOrientation in Camera make wrong orientation when save image

你离开我真会死。 提交于 2019-12-14 03:13:49

问题


I'm making an OCR app in Android and already installed OCR engine, and now want to create Surfaceview of Camera and have an area box on top to select capture area.

I meet the problem with Orientation of surfaceview display: it rotated 90 degree to left:

and I overcome with

Camera.setDisplayOrientation(90)

But, seem to be the bug of camera when I capture image, it rotated 90 degree to left.

If I don't use setDisplayOrientation function, the sufaceview is wrong orientation display (landscape) but captured image is same orientation with displayed.

So that, I think, natural orientation of sensor is landscape and I did not adjust it to portrait, I just force display to portrait and when I capture, image has real orientation of camera: landscape.

I DON'T want to save image and rotate it, because the size and sharp of image depend on area user was selected on top of surfaceview. Any body can hint me anything to solve that problem, or give a short document/TUT about that?


回答1:


you can use this method.

protected Bitmap decodeFileUpgaded(Bitmap bitmap) {
            int orientation;
            try {
                if (bitmap == null) {
                    return null;
                }

                ExifInterface exif = new ExifInterface(camera_pathname);
                orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                Log.e("ExifInteface .........", "rotation =" + orientation);
                // exif.setAttribute(ExifInterface.ORIENTATION_ROTATE_90, 90);
                Log.e("orientation", "" + orientation);
                if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
                    Log.i("orientation in", "" + orientation);
                    bitmap = rotateImage(bitmap, 180);
                    //RotateBitmap rotateBitmap = new RotateBitmap(bitmap);
                } else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
                    Log.i("orientation in", "" + orientation);
                    bitmap = rotateImage(bitmap, 90);
                    //RotateBitmap rotateBitmap = new RotateBitmap(bitmap);
                } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
                    Log.i("orientation in", "" + orientation);
                    bitmap = rotateImage(bitmap, 270);
                    //RotateBitmap rotateBitmap = new RotateBitmap(bitmap);

                }
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
                //Toast.makeText(CropImage.this,"Memory low! please try again.",Toast.LENGTH_LONG).show();
                return null;
            }
        }



回答2:


Try this class it will handle all rotation and scaling task for you :-

package com.serveroverload.cube.controller;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;

public class CamerHandler {

    private CamerHandler() {

        getAllImages();
    }

    private static CamerHandler camerHandler;

    public static CamerHandler GetCamerHandlerInstance() {
        if (null == camerHandler) {
            camerHandler = new CamerHandler();
        }
        return camerHandler;
    }

    private static final String CAM_DIRECTORY = "CamDirectory";
    private static final int MAX_HEIGHT = 1024;
    private static final int MAX_WIDTH = 1280;

    private ArrayList<File> imageURL = new ArrayList<File>();

    public ArrayList<File> getImageURL() {
        return imageURL;
    }

    public void setImageURL(ArrayList<File> imageURL) {
        this.imageURL = imageURL;
    }

    public void getAllImages() {

        imageURL.clear();

        File folder = new File(getImageDirectory());
        File[] listOfFiles = folder.listFiles();

        if (null != listOfFiles && listOfFiles.length != 0) {

            for (int i = 0; i < listOfFiles.length; i++) {
                if (listOfFiles[i].isFile()) {

                    imageURL.add(listOfFiles[i]);

                    System.out.println("File " + listOfFiles[i].getName());
                } else if (listOfFiles[i].isDirectory()) {
                    System.out.println("Directory " + listOfFiles[i].getName());
                }
            }
        }
    }

    /**
     * This method is responsible for solving the rotation issue if exist. Also
     * scale the images to 1024x1024 resolution
     *
     * @param context
     *            The current context
     * @param selectedImage
     *            The Image URI
     * @return Bitmap image results
     * @throws IOException
     */
    public Bitmap handleSamplingAndRotationBitmap(Context context,
            Uri selectedImage) throws IOException {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        InputStream imageStream = context.getContentResolver().openInputStream(
                selectedImage);
        BitmapFactory.decodeStream(imageStream, null, options);
        imageStream.close();

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH,
                MAX_HEIGHT);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        imageStream = context.getContentResolver().openInputStream(
                selectedImage);
        Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);

        // img = rotateImageIfRequired(img, selectedImage);

        img = rotateBitmap(context, img, selectedImage);
        return img;
    }

    public Bitmap rotateBitmap(Context context, Bitmap bitmap, Uri selectedImage) {

        ExifInterface exif;
        try {
            exif = new ExifInterface(selectedImage.getPath());

            int orientation = exif.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);

            Matrix matrix = new Matrix();
            switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
            }
            // try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0,
                    bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();
            return bmRotated;

        } catch (IOException e) {

            e.printStackTrace();

            return null;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();

            return null;
        }
    }

    /**
     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options}
     * object when decoding bitmaps using the decode* methods from
     * {@link BitmapFactory}. This implementation calculates the closest
     * inSampleSize that will result in the final decoded bitmap having a width
     * and height equal to or larger than the requested width and height. This
     * implementation does not ensure a power of 2 is returned for inSampleSize
     * which can be faster when decoding but results in a larger bitmap which
     * isn't as useful for caching purposes.
     *
     * @param options
     *            An options object with out* params already populated (run
     *            through a decode* method with inJustDecodeBounds==true
     * @param reqWidth
     *            The requested width of the resulting bitmap
     * @param reqHeight
     *            The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    private int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            // Calculate ratios of height and width to requested height and
            // width
            final int heightRatio = Math.round((float) height
                    / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will
            // guarantee a final image
            // with both dimensions larger than or equal to the requested height
            // and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger
            // inSampleSize).

            final float totalPixels = width * height;

            // Anything more than 2x the requested pixels we'll sample down
            // further
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }

    public void openGallery(Context context) {
        Intent intent = new Intent(Intent.ACTION_VIEW,
                Uri.parse("content://media/internal/images/media"));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    private void convertToBase64(Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(CompressFormat.JPEG, 30, byteArrayOutputStream);
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP);

        // bitmap.recycle();

        encoded = null;
        byteArray = null;
    }

    public String getImageDirectory() {

        return createDirIfNotExists().getAbsolutePath();
    }

    public File createDirIfNotExists() {

        File imageDirectory = new File(
                Environment.getExternalStorageDirectory(), CAM_DIRECTORY);
        if (!imageDirectory.exists()) {

            if (!imageDirectory.mkdirs()) {

                Log.e("imageDirectory :: ", "Problem creating Image folder");
            }
        }
        return imageDirectory;
    }

}

This class take pics & handle rotation in background task

package com.serveroverload.cube.ui;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.camtest.R;
import com.serveroverload.cube.controller.CamerHandler;

public class HomeActivity extends Activity {

    static final int REQUEST_IMAGE_CAPTURE = 1;
    private ImageView previewLayout;
    private static final String TAG = "MainActivity";

    static Uri capturedImageUri = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        // Imageview to display Image
        previewLayout = (ImageView) findViewById(R.id.preview);

        findViewById(R.id.take_picture).setOnClickListener(
                new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        dispatchTakePictureIntent();

                    }
                });

    }

    private void dispatchTakePictureIntent() {

        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");

        if (intent.resolveActivity(getPackageManager()) != null) {

            Calendar cal = Calendar.getInstance();

            // store image in new File in image directory
            File file = new File(CamerHandler.GetCamerHandlerInstance()
                    .getImageDirectory(), (cal.getTimeInMillis() + ".png"));

            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(),
                            "Failed to make file", 500).show();
                }
            } else {
                file.delete();
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(),
                            "Failed to make file", 500).show();
                }
            }

            capturedImageUri = Uri.fromFile(file);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, capturedImageUri);
            startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
        }

    }

    @SuppressLint("NewApi")
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK && requestCode == REQUEST_IMAGE_CAPTURE) {

            // update file in gallery
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                    capturedImageUri));

            // Downsample image before displaying in imageview to avoi OOM
            // exception
            new LoadBitMap(previewLayout, HomeActivity.this)
                    .execute(capturedImageUri);

        } else {
            Log.e(TAG, "FAILED TO TAKE IMAGE");
        }
    }

}

class LoadBitMap extends AsyncTask<Uri, Void, Void> {

    public LoadBitMap(ImageView preview, Context context) {
        this.prevImageView = preview;
        this.mContext = context;
    }

    private Bitmap bitmap = null;
    private ImageView prevImageView;
    private Context mContext;

    @Override
    protected Void doInBackground(Uri... params) {
        try {

            bitmap = CamerHandler.GetCamerHandlerInstance()
                    .handleSamplingAndRotationBitmap(mContext, params[0]);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        if (null != bitmap) {

            prevImageView.setBackground(new BitmapDrawable(mContext
                    .getResources(), bitmap));
        }
        super.onPostExecute(result);
    }
}

Test layout file

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    android:orientation="vertical"
    android:background="#000"
    tools:context="com.serveroverload.cube.ui.HomeActivity" >

    <ImageView
        android:background="#fff"
        android:id="@+id/preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/take_picture"
        android:layout_alignParentTop="true"
        android:layout_margin="5dp" />

    <ImageView

        android:id="@+id/take_picture"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:layout_margin="10dp"
        android:padding="5dp"
        android:scaleType="fitXY"
        android:src="@drawable/take_pic" />

</RelativeLayout>

Result is this



来源:https://stackoverflow.com/questions/33950044/setdisplayorientation-in-camera-make-wrong-orientation-when-save-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!