Камера Android сохраняет изображения с неправильной ориентацией

У меня есть приложение камеры, которое использует только портретный режим (ограничено файлом манифеста Android). Следующий код - это мой SurfaceView, используемый для камеры.

public class CameraPreview extends SurfaceView implements SensorEventListener, SurfaceHolder.Callback {
    private SurfaceHolder mSurfaceHolder;
    private Camera mCamera;
    private Activity mActivity;

    private static boolean DEBUGGING = true;
    private static final String LOG_TAG = "CameraPreviewSample";
    private static final String CAMERA_PARAM_ORIENTATION = "orientation";
    private static final String CAMERA_PARAM_LANDSCAPE = "landscape";
    private static final String CAMERA_PARAM_PORTRAIT = "portrait";

    protected List<Camera.Size> mPreviewSizeList;
    protected List<Camera.Size> mPictureSizeList;
    protected Camera.Size mPreviewSize;
    protected Camera.Size mPictureSize;

    // Constructor that obtains context and camera
    @SuppressWarnings("deprecation")
    public CameraPreview(Context context, Camera camera) {
        super(context);
        mActivity=(Activity)context;
        mCamera = camera;
        this.mCamera = camera;
        this.mSurfaceHolder = this.getHolder();
        this.mSurfaceHolder.addCallback(this);
        this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        try {
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.startPreview();
        } catch (IOException e) {
            // left blank for now
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        mCamera.stopPreview();
        mCamera.release();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
        if (mSurfaceHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        try {
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.startPreview();
        } catch (Exception e) {
            // intentionally left blank for a test
        }

       try {
            Camera.Parameters cameraParams = mCamera.getParameters();
            boolean portrait = isPortrait();
            configureCameraParameters(cameraParams, portrait);
            mCamera.setPreviewDisplay(mSurfaceHolder);
            mCamera.startPreview();

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

    protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
            if (portrait) {
                cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
            } else {
                cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
            }
        } else { // for 2.2 and later
            int angle;
            Display display = mActivity.getWindowManager().getDefaultDisplay();
            switch (display.getRotation()) {
                case Surface.ROTATION_0: // This is display orientation
                    angle = 90; // This is camera orientation
                    break;
                case Surface.ROTATION_90:
                    angle = 0;
                    break;
                case Surface.ROTATION_180:
                    angle = 270;
                    break;
                case Surface.ROTATION_270:
                    angle = 180;
                    break;
                default:
                    angle = 90;
                    break;
            }
            Log.v(LOG_TAG, "angle: " + angle);
            mCamera.setDisplayOrientation(angle);
        }

        cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
        if (DEBUGGING) {
            Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height);
            Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height);
        }

        mCamera.setParameters(cameraParams);
    }

    public boolean isPortrait() {
        return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onSensorChanged(SensorEvent arg0) {
        // TODO Auto-generated method stub

    }
}

Когда приложение сохраняет изображения (снятые в портретном режиме), они будут сохранены в перевернутом виде. Но в ландшафтном режиме сохраняет изображение корректно. И, как я уже упоминал, приложение ограничило ориентацию только портретным режимом.

Также я попытался изменить EXIF ​​в данных действия (на самом деле я использую фрагмент) файла изображения после его сохранения, а затем воссоздать растровое изображение с новыми данными exif, используя следующий код, но все равно безуспешно.

    private Bitmap changeExifData(String imagePath){
Bitmap correctBmp = null;
            try {
                File f = new File(imagePath);
                ExifInterface exif = new ExifInterface(f.getPath());
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

                int angle = 0;

                if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
                    angle = 90;
                } 
                else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
                    angle = 180;
                } 
                else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
                    angle = 270;
                }

                Matrix mat = new Matrix();
                mat.postRotate(angle);

                Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
                correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);

            }
            catch (IOException e) {
                Log.w("TAG", "-- Error in setting image");
            }   
            catch(OutOfMemoryError oom) {
                Log.w("TAG", "-- OOM Error in setting image");
            }
            return correctBmp;
        }

Ваша помощь очень ценится.


person Yrol    schedule 10.08.2014    source источник
comment
Кто-нибудь хочет мне помочь??   -  person Yrol    schedule 11.08.2014
comment
Удалось решить проблему?   -  person lschlessinger    schedule 09.06.2015
comment
@lschlessinger, да, видел   -  person Yrol    schedule 10.06.2015
comment
@Yrol, можешь опубликовать ответ, пожалуйста?   -  person Makks129    schedule 17.06.2015
comment
@Makks129Makks129, пожалуйста, посмотрите мой обновленный ответ   -  person Yrol    schedule 18.06.2015


Ответы (1)


Вот как я это решил (полная реализация, включающая сохранение изображения). Изображение, снятое в портретном режиме, будет повернуто на 90 градусов.

   import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.Handler;
    import android.provider.MediaStore;
    import android.telephony.TelephonyManager;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.Toast;

    public class ImageTakeAndShow extends Activity {

        private static final int ACTION_TAKE_PHOTO = 1;

        private static final String BITMAP_STORAGE_KEY = "viewbitmap";
        private static final String IMAGEVIEW_VISIBILITY_STORAGE_KEY = "imageviewvisibility";
        //private ImageView mImageView;
        private Bitmap mImageBitmap;
        private String mCurrentPhotoPath;

        private static final String JPEG_FILE_PREFIX = "IMG_";
        private static final String JPEG_FILE_SUFFIX = ".jpg";
        TelephonyManager myPhonenumber;
        static String device_id;  
        double latitude ,longitude;
        Button Btn;
        File f;

        //save picture
        private File getAlbumDir() {
            File file = null;

            if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
                file = Environment.getExternalStorageDirectory().getAbsoluteFile();
                file = new File(Environment.getExternalStorageDirectory()
                        + File.separator + "Snap/Capture_Image");
                Log.e("file", file.toString());

                if (file != null) {
                    if (! file.mkdirs()) {
                        if (! file.exists()){
                            Log.d("Camera", "failed to create directory");
                            return null;
                        }
                    }
                }
            } else {
                Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE.");
            }

            return file;
        }

        //create file name
        private File createImageFile() throws IOException {
            // Create an image file name
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
            File albumF = getAlbumDir();
            File imageF = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX, albumF);
            return imageF;
        }

        private File setUpPhotoFile() throws IOException {
            File f = createImageFile();
            mCurrentPhotoPath = f.getAbsolutePath();
            return f;
        }

        //set picture width and height and rotate 90 degrees
        private void setPic() {
            /* Get the size of the image */
            BitmapFactory.Options bmOptions = new BitmapFactory.Options();
            bmOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
            int photoW = bmOptions.outWidth/2;
            int photoH = bmOptions.outHeight/2;

             Log.e("photoW", Integer.valueOf(photoW).toString());
             Log.e("photoH", Integer.valueOf(photoH).toString());
            int scaleFactor = 1;
            bmOptions.inJustDecodeBounds = false;
            bmOptions.inSampleSize = scaleFactor;
            bmOptions.inPurgeable = true;

            try{
                Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);
                bitmap = Bitmap.createScaledBitmap(bitmap, 800, 600, true);
                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);

                File f = new File(mCurrentPhotoPath.toString());
                FileOutputStream fo = new FileOutputStream(f);
                fo.write(bytes.toByteArray());
                    fo.close();
                    Matrix matrix = new Matrix();
                    matrix.postRotate(90);    
                    Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, 800,640,matrix, true); 
                    FileOutputStream fos2 = new FileOutputStream(mCurrentPhotoPath.toString());
                    rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos2);
                    fos2.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }catch (OutOfMemoryError o) {
                    o.printStackTrace();
            }

        }

        private void galleryAddPic() {
                Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
                f = new File(mCurrentPhotoPath);
                Uri contentUri = Uri.fromFile(f);
                mediaScanIntent.setData(contentUri);
                this.sendBroadcast(mediaScanIntent);
                Log.e("path f", f.toString());
        }

        //Camera activity
        private void dispatchTakePictureIntent(int actionCode) {
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            switch(actionCode) {
            case ACTION_TAKE_PHOTO:
                File f = null;

                try {
                    f = setUpPhotoFile();
                    mCurrentPhotoPath = f.getAbsolutePath();
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                } catch (IOException e) {
                    e.printStackTrace();
                    f = null;
                    mCurrentPhotoPath = null;
                }
                break;

            default:
                break;          
            }
            startActivityForResult(takePictureIntent, actionCode);
        }

        private void handleBigCameraPhoto() {
            if (mCurrentPhotoPath != null) {
                setPic();
                galleryAddPic();
                mCurrentPhotoPath = null;
            }
        }

        Button.OnClickListener mTakePicOnClickListener = 
            new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                dispatchTakePictureIntent(ACTION_TAKE_PHOTO);
            }
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            myPhonenumber   = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
            device_id       =  myPhonenumber.getDeviceId();
            mImageBitmap = null;
            dispatchTakePictureIntent(ACTION_TAKE_PHOTO);
        }

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
            case ACTION_TAKE_PHOTO: {
                if (resultCode == RESULT_OK) {
                    handleBigCameraPhoto();

                    final Intent intent = new Intent(getApplicationContext(), Image_Priview.class);
                    intent.putExtra("image parth",  f.toString());
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    startActivity(intent);  
                    finish(); 


                      new Handler().postDelayed(new Runnable() {
                            public void run() {

                            }
                        }, 1000);


                }else if (resultCode == RESULT_CANCELED){
                     File file = new File(mCurrentPhotoPath);
                     file.delete();
                     finish();  

                }
                break;
            }
            }
        }

        // Some lifecycle callbacks so that the image can survive orientation change
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            outState.putParcelable(BITMAP_STORAGE_KEY, mImageBitmap);
            outState.putBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY, (mImageBitmap != null) );
            super.onSaveInstanceState(outState);
        }

        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
            mImageBitmap = savedInstanceState.getParcelable(BITMAP_STORAGE_KEY);
        }

        public static boolean isIntentAvailable(Context context, String action) {
            final PackageManager packageManager = context.getPackageManager();
            final Intent intent = new Intent(action);
            List<ResolveInfo> list =
                packageManager.queryIntentActivities(intent,
                        PackageManager.MATCH_DEFAULT_ONLY);
            return list.size() > 0;
        }
    }
person Yrol    schedule 18.06.2015
comment
Это не решает ваш вопрос, вместо этого, глядя на код, который вы указали выше, вы фиксируете поворот при установке изображения с помощью вашего метода setPic и не сохраняете изображение с правильной ориентацией. - person ClassA; 06.09.2018