Development Tip

세로로 사진을 찍도록 카메라를 제어해도 최종 이미지가 회전하지 않습니다.

yourdevel 2020. 12. 14. 20:54
반응형

세로로 사진을 찍도록 카메라를 제어해도 최종 이미지가 회전하지 않습니다.


세로 앱에서 사진을 찍기 위해 Android 카메라를 제어하려고하는데 사진을 저장하면 가로 모드입니다. setCameraDisplayOrientation()방법으로 이미지를 90 단계 회전 했지만 작동하지 않습니다.

그럼이 발견했습니다 게시물을 하지만이 TAG_ORIENTATION됩니다 0(정의되지 않은). 이 값을 잡고 회전 값을 적용하면 작동하지 않습니다.

세로로 사진을 찍고 좋은 방향으로 저장하려면 어떻게해야합니까?

    /** Initializes the back/front camera */
private boolean initPhotoCamera() {
    try {
        camera = getCameraInstance(selected_camera);

        Camera.Parameters parameters = camera.getParameters();
   //           parameters.setPreviewSize(width_video, height_video);
   //           parameters.set("orientation", "portrait");
   //           parameters.set("rotation", 1);
   //           camera.setParameters(parameters);


        checkCameraFlash(parameters);

   //            camera.setDisplayOrientation( 0);
        setCameraDisplayOrientation(selected_camera, camera);


        surface_view.getHolder().setFixedSize(width_video, height_video);


        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width_video, height_video);
        surface_view.setLayoutParams(lp);

        camera.lock();

        surface_holder = surface_view.getHolder();
        surface_holder.addCallback(this);
        surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        setPreviewCamera();

    } catch (Exception e) {
        Log.v("RecordVideo", "Could not initialize the Camera");
        return false;
    }
    return true;
}

public void setCameraDisplayOrientation(int cameraId, Camera camera) {
     Camera.CameraInfo info = new Camera.CameraInfo();
     Camera.getCameraInfo(cameraId, info);
     int rotation = 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);
 }

     public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
   //       mtx.postRotate(degree);
    mtx.setRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

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



    String timeStamp = Calendar.getInstance().getTime().toString();
    output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";

    File pictureFile = new File(output_file_name);
    if (pictureFile.exists()) {
        pictureFile.delete();
    }

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);

        Bitmap realImage = BitmapFactory.decodeFile(output_file_name);

        ExifInterface exif=new ExifInterface(pictureFile.toString());

        Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
        if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
            realImage= rotate(realImage, 90);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
            realImage= rotate(realImage, 270);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
            realImage= rotate(realImage, 180);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
            realImage= rotate(realImage, 45);
        }

        boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        fos.close();

        Log.d("Info", bo + "");

    } catch (FileNotFoundException e) {
        Log.d("Info", "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d("TAG", "Error accessing file: " + e.getMessage());
    }
}

문제는 이미지를 저장했을 때 잘하지 못했다는 것입니다.

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

    String timeStamp = new SimpleDateFormat( "yyyyMMdd_HHmmss").format( new Date( ));
    output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";

    File pictureFile = new File(output_file_name);
    if (pictureFile.exists()) {
        pictureFile.delete();
    }

    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);

        Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);

        ExifInterface exif=new ExifInterface(pictureFile.toString());

        Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
        if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
            realImage= rotate(realImage, 90);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
            realImage= rotate(realImage, 270);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
            realImage= rotate(realImage, 180);
        } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
            realImage= rotate(realImage, 90);
        }

        boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        fos.close();

        ((ImageView) findViewById(R.id.imageview)).setImageBitmap(realImage);

        Log.d("Info", bo + "");

    } catch (FileNotFoundException e) {
        Log.d("Info", "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d("TAG", "Error accessing file: " + e.getMessage());
    }
}

public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
   //       mtx.postRotate(degree);
    mtx.setRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

setCameraDisplayOrientation () 메서드를 사용하면 방법을 변경할 수 있도록 미리보기가 표시됩니다 에 영향을주지 않고 이미지 (기록 방법 소스 ).

실제 녹화 된 이미지를 변경 하려면 카메라회전 매개 변수 를 설정해야합니다 . 다음과 같이합니다.

//STEP #1: Get rotation degrees
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
    case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
        case Surface.ROTATION_90: degrees = 90; break; //Landscape left
        case Surface.ROTATION_180: degrees = 180; break;//Upside down
        case Surface.ROTATION_270: degrees = 270; break;//Landscape right
    }
int rotate = (info.orientation - degrees + 360) % 360;

//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = mCamera.getParameters();
params.setRotation(rotate); 
mCamera.setParameters(params);

이미지가 이미 기록 된 후 수정하기 때문에 솔루션은 일종의 해결 방법입니다. 이 솔루션은 더 깨끗하며 이미지를 저장하기 전에 이러한 'if'문을 모두 필요로하지 않습니다.


전면 카메라를 사용할 때 아래 방법을 사용하여 올바르게 미리보기를 생성 할 수 있습니다.

이 코드는 카메라 미리보기의 surfaceChanged 메서드에 들어갑니다.

@Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     int angleToRotate=CommonMethods.getRoatationAngle(mActivity, Camera.CameraInfo.CAMERA_FACING_FRONT);
     mCamera.setDisplayOrientation(angleToRotate);
}

이 코드는 정적 클래스에 넣을 수 있습니다.

 /**
     * Get Rotation Angle
     * 
     * @param mContext
     * @param cameraId
     *            probably front cam
     * @return angel to rotate
     */
    public static int getRoatationAngle(Activity mContext, int cameraId) {
        android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = mContext.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;
        }
        return result;
    }

이 방법으로 이미지를 회전 할 수 있습니다. 이것은 이미지를 촬영하고 이미지를 저장하려고 할 때만 사용됩니다.

public static Bitmap rotate(Bitmap bitmap, int degree) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        Matrix mtx = new Matrix();
        mtx.postRotate(degree);

        return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
    }

사진 촬영에 사용되는 방법

  @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        int angleToRotate = getRoatationAngle(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_FRONT);
        // Solve image inverting problem
        angleToRotate = angleToRotate + 180;
        Bitmap orignalImage = BitmapFactory.decodeByteArray(data, 0, data.length);
        Bitmap bitmapImage = rotate(orignalImage, angleToRotate);
    }

bitmapImage올바른 이미지가 포함되어 있습니다.


이것은 작동해야합니다. ExifInterface는 모든 제조업체에서 작동하지 않으므로 대신 CameraInfo를 사용하고 카메라가 기본 회전으로 이미지를 캡처하도록 한 다음 PictureCallback에서 결과 데이터를 회전합니다.

private PictureCallback mPicture = new PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File dir = new File(Constant.SDCARD_CACHE_PREFIX);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File pictureFile = new File(Constant.SDCARD_TAKE_PHOTO_CACHE_PREFIX);                       
        try {
            Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
            android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
            android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
            Bitmap bitmap = rotate(realImage, info.orientation);

            FileOutputStream fos = new FileOutputStream(pictureFile);               
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.close();                
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }

        resultFileUri = Uri.fromFile(pictureFile);
        startEffectFragment();
    }
};

public static Bitmap rotate(Bitmap bitmap, int degree) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
    mtx.postRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

레이아웃이 세로 모드로 고정되었을 때 (아래 언급 됨)을 사용하는 가장 좋은 방법입니다.

@Override
protected void onResume() {
    super.onResume();
    if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) {
        alertCameraDialog();
    }
    if (cOrientationEventListener == null) {
        cOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {


            public void onOrientationChanged(int orientation) {

                // determine our orientation based on sensor response
                int lastOrientation = mOrientation;


                    if (orientation == ORIENTATION_UNKNOWN) return;
                    Camera.CameraInfo info =
                            new android.hardware.Camera.CameraInfo();
                    android.hardware.Camera.getCameraInfo(cameraId, info);
                    orientation = (orientation + 45) / 90 * 90;
                    int rotation = 0;
                    if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
                        rotation = (info.orientation - orientation + 360) % 360;
                    } else {  // back-facing camera
                        rotation = (info.orientation + orientation) % 360;
                    }
                        Parameters params = camera.getParameters();
                        params.setRotation(rotation);
                        camera.setParameters(params);




            }

            };


        }


    if (cOrientationEventListener.canDetectOrientation()) {
        cOrientationEventListener.enable();
    }
    }

OrientEventListener를 사용하고이 콜백 메서드를 구현합니다. onOrientationChanged는 방향이 변경 될 때마다 호출되므로 카메라 회전이 설정되고 저장할 때 사진이 회전됩니다.

      private PictureCallback myPictureCallback_JPG = new PictureCallback() 

       { 

   @Override
   public void onPictureTaken(byte[] arg0, Camera arg1) {
    try {  
               File pictureFile = getOutputMediaFile();
           if (pictureFile == null) {
               return;
           }
               FileOutputStream fos = new FileOutputStream(pictureFile);
               fos.write(arg0);
               fos.close();     
              camera.startPreview();
       } catch (Exception e) {
           e.printStackTrace();
       }
   } 
 };

getOutputMediaFile

  private static File getOutputMediaFile() {
            File mediaStorageDir = new File(
               Environment


         .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp");
         if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
            .format(new Date());
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator
            + "IMG_" + timeStamp + ".jpg");

    return mediaFile;
  }

여기에 소스


댓글을 남길 담당자가 없기 때문에 Nvhausid 답변이 훌륭하고 크레딧을받을 자격이 있지만 대신 다른 답변을 남겨야합니다. 간단하고 우아하며 Exif 및 Media Cursor가 지원하지 않는 삼성 장치의 전면 및 후면 카메라 모두에서 작동합니다.

저에게 답이 없었던 유일한 것은 사용자를 향한 카메라의 미러 이미지를 처리하는 것뿐이었습니다.

이에 대한 코드 변경 사항은 다음과 같습니다.

Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);

그리고 새로운 회전 방법 :

public static Bitmap rotate(Bitmap bitmap, int degree, boolean mirror) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    Matrix mtx = new Matrix();
    if(mirror)mtx.setScale(1,-1);
    mtx.postRotate(degree);

    return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

나는 당신을 위해 강력한 답을 찾았습니다, 나는 단지 같은 문제를 만나고 파일을 저장하지 않고 해결합니다. 해결책은 OrientationEventListener를 등록하여 변경 될 때마다 방향을 가져 오는 것입니다. http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html 여기에 세부 정보를 제공하십시오. 내 코드는 다음과 같습니다.

private CameraOrientationListener myOrientationListener;
private int rotation;    

protected void onCreate(Bundle savedInstanceState) {
  setListeners();
  rotation = setCameraDisplayOrientation(CameraActivity.this, Camera.getNumberOfCameras()-1, mCamera);
}

public void setListeners(){
    myOrientationListener = new CameraOrientationListener(this);
    if(myOrientationListener.canDetectOrientation())
        myOrientationListener.enable();
}

public static int setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
     CameraInfo info = new CameraInfo();
     Camera.getCameraInfo(cameraId, info);
     int rotation = activity.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 == 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);

     return result;
 }

/*
 * record the rotation when take photo
 */
public void takePhoto(){
    myOrientationListener.rememberOrientation();
    rotation += myOrientationListener.getRememberedOrientation();
    rotation = rotation % 360;

    mCamera.takePicture(null, null, mPicture);
}    

class CameraOrientationListener extends OrientationEventListener {
    private int currentNormalizedOrientation;
    private int rememberedNormalizedOrientation;

    public CameraOrientationListener(Context context) {
        super(context, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    public void onOrientationChanged(int orientation) {
        // TODO Auto-generated method stub
        if (orientation != ORIENTATION_UNKNOWN) {
            currentNormalizedOrientation = normalize(orientation);
        }
    }

    private int normalize(int degrees) {
         if (degrees > 315 || degrees <= 45) {
            return 0;
        }

        if (degrees > 45 && degrees <= 135) {
            return 90;
        }

        if (degrees > 135 && degrees <= 225) {
            return 180;
        }

        if (degrees > 225 && degrees <= 315) {
            return 270;
        }

        throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies.");
    }

    public void rememberOrientation() {
        rememberedNormalizedOrientation = currentNormalizedOrientation;
    }

    public int getRememberedOrientation() {
        return rememberedNormalizedOrientation;
    }
}

도움이 되었기를 바랍니다.)


I used the new camera2 api to get sensor orientation and then rotate it accordingly:

  private void detectSensorOrientation()
  {
    CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
    try
    {
      for (String cameraId : manager.getCameraIdList())
      {
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);

        // We don't use a front facing camera in this sample.
        Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
        if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
        {
          continue;
        }

        cameraOrientaion = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
      }
    } catch (CameraAccessException e)
    {
      e.printStackTrace();
    }
  }

Then with the help of cameraOrientation parameter, I rotated my cameraPhoto:

  private void generateRotatedBitmap()
  {
    if (cameraOrientaion != 0)
    {
      Matrix matrix = new Matrix();
      matrix.postRotate(cameraOrientaion);
      rotatedPhoto =
          Bitmap.createBitmap(cameraPhoto, 0, 0, cameraPhoto.getWidth(), cameraPhoto.getHeight(),
              matrix, true);
      cameraPhoto.recycle();
    }
  }

참고URL : https://stackoverflow.com/questions/15808719/controlling-the-camera-to-take-pictures-in-portrait-doesnt-rotate-the-final-ima

반응형