ทำไมรูปภาพที่ถ่ายโดยใช้จุดประสงค์กล้องถูกหมุนบนอุปกรณ์บางอย่างใน Android?


376

ฉันกำลังจับภาพและตั้งค่าเป็นมุมมองภาพ

public void captureImage() {

    Intent intentCamera = new Intent("android.media.action.IMAGE_CAPTURE");
    File filePhoto = new File(Environment.getExternalStorageDirectory(), "Pic.jpg");
    imageUri = Uri.fromFile(filePhoto);
    MyApplicationGlobal.imageUri = imageUri.getPath();
    intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(intentCamera, TAKE_PICTURE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intentFromCamera) {
    super.onActivityResult(requestCode, resultCode, intentFromCamera);

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

        if (intentFromCamera != null) {
            Bundle extras = intentFromCamera.getExtras();
            if (extras.containsKey("data")) {
                bitmap = (Bitmap) extras.get("data");
            }
            else {
                bitmap = getBitmapFromUri();
            }
        }
        else {
            bitmap = getBitmapFromUri();
        }
        // imageView.setImageBitmap(bitmap);
        imageView.setImageURI(imageUri);
    }
    else {
    }
}

public Bitmap getBitmapFromUri() {

    getContentResolver().notifyChange(imageUri, null);
    ContentResolver cr = getContentResolver();
    Bitmap bitmap;

    try {
        bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri);
        return bitmap;
    }
    catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

แต่ปัญหาคือภาพในบางอุปกรณ์ทุกครั้งที่หมุน ตัวอย่างเช่นบนอุปกรณ์ Samsung มันใช้งานได้ดี แต่บนSony Xperiaภาพจะหมุน 90 องศาและบนToshiba Thrive (แท็บเล็ต) 180 องศา


1
ลองสิ่งนี้ในกิจกรรมของคุณ Android android: configChanges = "ปฐมนิเทศ" android: screenOrientation = "portrait"
Narendra Pal

@ ไม่สามารถใช้งานได้ตอนนี้รูปภาพจะหมุนเป็น 90 องศาแทนที่จะเป็น 180 องศาบนแท็บ
Shirish Herwade

1
อย่างที่ฉันคิดว่าเมื่อคุณใช้ความตั้งใจภายในเพื่อจัดการกับแอพกล้องแล้วมันจะหมุนภาพขึ้นอยู่กับว่าคุณถืออุปกรณ์อย่างไรในการจับภาพ ดังนั้นคุณสามารถ จำกัด ผู้ใช้ในการถ่ายภาพในลักษณะเฉพาะหมายความว่าผู้ใช้มักจะจับภาพโดยถืออุปกรณ์ในแนวตั้งหรือแนวนอน หลังจากนั้นคุณสามารถเปลี่ยนเป็นมุมที่เฉพาะเจาะจงเพื่อให้ได้ภาพตามที่คุณต้องการ .. หรือตัวเลือกอื่นทำแอปกล้องของคุณเอง
Narendra Pal

@nick "คุณสามารถ จำกัด ผู้ใช้ในการถ่ายภาพในลักษณะที่เจาะจง" หมายความว่าเหมือนกับการตั้งค่าการวางแนว = "potrait" หรือไม่ และวิธีการ "หลังจากนั้นคุณสามารถเปลี่ยนเป็นมุมเฉพาะเพื่อให้ได้ภาพตามที่คุณต้องการ" ได้อย่างไร โปรดให้ลิงก์ที่มีประโยชน์กับคุณได้บ้าง
Shirish Herwade

3
ฉันเชื่อว่าความตั้งใจในการจับภาพจะแสดงแอพกล้องถ่ายรูปเริ่มต้นที่มีการวางแนวเฉพาะในแต่ละอุปกรณ์และดังนั้น - การวางแนวภาพถ่ายแบบคงที่ มันไม่ได้ขึ้นอยู่กับวิธีที่ผู้ใช้ถืออุปกรณ์หรือการวางแนวของกิจกรรมของคุณที่เรียกใช้เจตนา
Alex Cohn

คำตอบ:


440

กล้องโทรศัพท์ส่วนใหญ่เป็นแนวนอนหมายความว่าถ้าคุณถ่ายภาพในแนวตั้งภาพถ่ายที่ได้จะหมุน 90 องศา ในกรณีนี้ซอฟต์แวร์กล้องควรเติมข้อมูลExifด้วยการวางแนวที่ควรดูภาพถ่าย

โปรดทราบว่าการแก้ปัญหาด้านล่างขึ้นอยู่กับผู้ผลิตซอฟต์แวร์กล้อง / อุปกรณ์ที่บรรจุข้อมูล Exif ดังนั้นจึงสามารถใช้งานได้ในกรณีส่วนใหญ่ แต่ไม่ใช่โซลูชันที่เชื่อถือได้ 100%

ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                                     ExifInterface.ORIENTATION_UNDEFINED);

Bitmap rotatedBitmap = null;
switch(orientation) {

    case ExifInterface.ORIENTATION_ROTATE_90:
        rotatedBitmap = rotateImage(bitmap, 90);
        break;

    case ExifInterface.ORIENTATION_ROTATE_180:
        rotatedBitmap = rotateImage(bitmap, 180);
        break;

    case ExifInterface.ORIENTATION_ROTATE_270:
        rotatedBitmap = rotateImage(bitmap, 270);
        break;

    case ExifInterface.ORIENTATION_NORMAL:
    default:
        rotatedBitmap = bitmap;
}

นี่คือrotateImageวิธีการ:

public static Bitmap rotateImage(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
                               matrix, true);
}

1
จาก @JasonRobinson รหัสฉันเรียนรู้วิธีการวางแนวจริงและโดยรวมกับรหัสเหล่านี้ฉันสำเร็จการจัดการปฐมนิเทศ
Raditya Kurnianto

ตัวเลือกที่สองของการexif.getAttributeIntใช้ExifInterface.ORIENTATION_UNDEFINEDเกือบเหมือนกันเนื่องจากพารามิเตอร์ตัวที่สองเป็นค่าเริ่มต้นในกรณีที่ฟังก์ชันไม่สามารถระบุค่าได้
Darpan

5
รหัสนี้ใช้สำหรับภาพที่เขียนไปยังดิสก์แล้วใช่ไหม ฉันไม่ได้ผลลัพธ์โดยใช้วิธีนี้สำหรับบิตแมปที่จะเขียนลงดิสก์
ธราเซียน

4
มันจะคืนค่า 0 ให้ฉันเสมอ โปรดบอกวิธีรับปฐมนิเทศจริง
Anurag Srivastava

3
ได้ 0 เสมอความคิดใด ๆ
Navya Ramesan

186

โดยการรวมเจสันโรบินสัน 's คำตอบกับเฟลิกซ์ ' s คำตอบและเติมส่วนที่ขาดหายไปนี่เป็นโซลูชั่นที่สมบูรณ์ขั้นสุดท้ายสำหรับปัญหานี้ที่จะทำต่อไปนี้หลังจากการทดสอบบน Android Android 4.1 ( Jelly Bean ) Android 4.4 ( KitKat ) และAndroid 5.0 ( อมยิ้ม )

ขั้นตอน

  1. ลดขนาดภาพหากภาพมีขนาดใหญ่กว่า 1024x1024

  2. หมุนรูปภาพไปในทิศทางที่ถูกต้องเฉพาะเมื่อหมุน 90, 180 หรือ 270 องศา

  3. รีไซเคิลภาพหมุนเพื่อความจำ

นี่คือส่วนของรหัส:

เรียกวิธีต่อไปนี้ด้วยกระแสContextและรูปURIที่คุณต้องการแก้ไข

/**
 * 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 static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage)
        throws IOException {
    int MAX_HEIGHT = 1024;
    int MAX_WIDTH = 1024;

    // 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(context, img, selectedImage);
    return img;
}

นี่คือCalculateInSampleSizeวิธีการจากแหล่งที่กล่าวถึงล่วงหน้า:

/**
  * 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 static 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;
}

จากนั้นวิธีการที่จะตรวจสอบการวางแนวภาพปัจจุบันเพื่อตัดสินมุมการหมุน

 /**
 * Rotate an image if required.
 *
 * @param img           The image bitmap
 * @param selectedImage Image URI
 * @return The resulted Bitmap after manipulation
 */
private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage) throws IOException {

InputStream input = context.getContentResolver().openInputStream(selectedImage);
ExifInterface ei;
if (Build.VERSION.SDK_INT > 23)
    ei = new ExifInterface(input);
else
    ei = new ExifInterface(selectedImage.getPath());

    int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            return rotateImage(img, 90);
        case ExifInterface.ORIENTATION_ROTATE_180:
            return rotateImage(img, 180);
        case ExifInterface.ORIENTATION_ROTATE_270:
            return rotateImage(img, 270);
        default:
            return img;
    }
}

ในที่สุดวิธีการหมุนตัวเอง

private static Bitmap rotateImage(Bitmap img, int degree) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
    img.recycle();
    return rotatedImg;
}

- อย่าลืมโหวตให้คนเหล่านั้นตอบสำหรับความพยายามของพวกเขาและShirish Herwadeที่ถามคำถามที่เป็นประโยชน์นี้


2
มันเป็นเรื่องที่ดีสำหรับฉันอย่างสมบูรณ์
ขอขอบคุณ

1
วิธี rotateImageIfRequired () ทำงานได้ดีมาก .. ขอบคุณ !!
mapo

5
ไม่ได้ผลสำหรับฉัน บางครั้งโทรศัพท์ของฉันให้แนวตั้งบางครั้งภาพถ่ายแนวนอน แต่การวางแนวที่ตรวจพบจะเป็น 0 องศาเสมอ
Makalele

@Makalele ปัญหานี้เกิดขึ้นในขณะที่ถ่ายภาพและเชื่อมต่อผ่าน WhatsApp หรือไม่?
Manoj Perumarath

ฉันไม่ได้ใช้ WhatsApp ดังนั้นฉันไม่สามารถพูดได้ แต่ส่วนใหญ่อาจจะใช่ นั่นเป็นเพราะมันเกิดขึ้นในแอพถ่ายรูปหุ้น (Google Stock Camera)
Makalele

45

ง่ายต่อการตรวจจับการวางแนวภาพและแทนที่บิตแมปโดยใช้:

 /**
 * Rotate an image if required.
 * @param img
 * @param selectedImage
 * @return
 */
private static Bitmap rotateImageIfRequired(Context context,Bitmap img, Uri selectedImage) {

    // Detect rotation
    int rotation = getRotation(context, selectedImage);
    if (rotation != 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);
        Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
        img.recycle();
        return rotatedImg;
    }
    else{
        return img;
    }
}

/**
 * Get the rotation of the last image added.
 * @param context
 * @param selectedImage
 * @return
 */
private static int getRotation(Context context,Uri selectedImage) {

    int rotation = 0;
    ContentResolver content = context.getContentResolver();

    Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                                       new String[] { "orientation", "date_added" },
                                       null, null, "date_added desc");

    if (mediaCursor != null && mediaCursor.getCount() != 0) {
        while(mediaCursor.moveToNext()){
            rotation = mediaCursor.getInt(0);
            break;
        }
    }
    mediaCursor.close();
    return rotation;
}

หากต้องการหลีกเลี่ยงความทรงจำที่มีภาพใหญ่ขอแนะนำให้คุณลดขนาดภาพโดยใช้:

private static final int MAX_HEIGHT = 1024;
private static final int MAX_WIDTH = 1024;
public static Bitmap decodeSampledBitmap(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);
    return img;
}

ไม่สามารถใช้ ExifInterface เพื่อรับการวางแนวเนื่องจากปัญหา Android OS: https://code.google.com/p/android/issues/detail?id=19268

และนี่คือ calculateInSampleSize

/**
 * 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
 */
public static 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;
}

1
เป็นวิธีการคำนวณ
เท่าใดตัวอย่าง

1
@madhukotagiri ที่นี่คุณมีตัวอย่างของ implementantion สำหรับcalculInSampleSize
Felix

ขอบคุณชายคุณแน่นอน! ฉันแค่สงสัยว่าการปรับขนาดจะมีประโยชน์มากแค่ไหนหากมีการดำเนินการเป็นครั้งคราว
Marino

4
พารามิเตอร์ Uri selectedImage ไม่ได้ใช้ในวิธี getRotation (... ) เราต้องการใช้มันอย่างไร? ขอบคุณ.
valerybodak

1
ดูเหมือนจะไม่ได้ใช้พารามิเตอร์ 'SelectedImage' ที่ใดก็ได้ มีเหตุผลอะไรที่จะอยู่ที่นั่น?
อเล็กซ์

20

โซลูชันเดียว:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

หรือ

Picasso.with(context).load("file:" + photoPath).into(imageView);

วิธีนี้จะตรวจจับการหมุนโดยอัตโนมัติและวางภาพในทิศทางที่ถูกต้อง

Picasso เป็นห้องสมุดที่ทรงพลังมากสำหรับจัดการรูปภาพในแอพของคุณรวมถึง: การ แปลงภาพที่ซับซ้อนพร้อมการใช้หน่วยความจำน้อยที่สุด


1
ทางออกที่น่าสนใจ
Bhavik Mehta

8
มันเพียงแค่โหลดภาพลงในมุมมองมันไม่ให้บิตแมปหรือไฟล์ที่คุณสามารถจัดการหรืออัปโหลดไปยังเซิร์ฟเวอร์
flawyte

4
รูปภาพที่แสดงนั้นคลิกตามที่เป็นอยู่ มันไม่หมุนตามที่ต้องการ
seema

1
@Flawyte คุณสามารถทำได้โดยการโหลดไฟล์เข้าสู่เป้าหมายแทนการดูด้วยการเรียกกลับที่ส่งกลับบิตแมปที่ถูกครอบตัด / ปรับขนาด: Picasso.with (นี้). load (cropUriToLoad.resize (1080, 810) .centerInside () เข้าสู่ (target); โดยที่ target = new Target () {แทนที่โมฆะสาธารณะใน onBitmapLoaded (บิตแมปบิตแมป, Picasso.LoadedFrom จาก) {
voytez

ปัญหาที่ฉันยังเผชิญอยู่นั้นใช้เวลาไม่กี่วินาทีในการแสดงภาพ
Anu

12

ฉันใช้เวลามากมายในการค้นหาวิธีแก้ไขปัญหานี้ และสุดท้ายก็สามารถทำสิ่งนี้ได้ อย่าลืม upvote @Jason Robinson ตอบเพราะฉันมีพื้นฐานมาจากเขา

ดังนั้นสิ่งแรกที่คุณ sholuld ทราบว่าตั้งแต่ Android 7.0 เราจะต้องใช้FileProviderและสิ่งที่เรียกว่ามิฉะนั้นคุณจะได้รับข้อผิดพลาดที่น่ารำคาญพยายามที่จะก่อให้เกิดของคุณContentUri Intentนี่คือตัวอย่างรหัส:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriFromPath(context, "[Your path to save image]"));
startActivityForResult(intent, CAPTURE_IMAGE_RESULT);

getUriFromPath(Context, String)พื้นฐานของวิธีการที่ผู้ใช้ Android สร้างขึ้นFileUri (file://...)หรือContentUri (content://...)มี:

public Uri getUriFromPath(Context context, String destination) {
    File file =  new File(destination);

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
    } else {
        return Uri.fromFile(file);
    }
}

หลังจากที่onActivityResultคุณสามารถจับuriภาพว่ามีการบันทึกภาพด้วยกล้อง แต่ตอนนี้คุณต้องตรวจจับการหมุนของกล้องที่นี่เราจะใช้ moddified @Jason Robinson คำตอบ:

ก่อนอื่นเราต้องสร้างExifInterfaceจากUri

@Nullable
public ExifInterface getExifInterface(Context context, Uri uri) {
    try {
        String path = uri.toString();
        if (path.startsWith("file://")) {
            return new ExifInterface(path);
        }
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            if (path.startsWith("content://")) {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                return new ExifInterface(inputStream);
            }
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

โค้ดด้านบนสามารถทำให้ง่ายขึ้น แต่ฉันต้องการแสดงทุกอย่าง ดังนั้นจากFileUriเราสามารถสร้างExifInterfaceขึ้นอยู่กับString pathแต่จากContentUriที่เราไม่สามารถ Android ไม่สนับสนุนว่า

ในกรณีที่เราต้องใช้คอนสตรัคอื่น ๆ InputStreamตาม โปรดจำไว้ว่าตัวสร้างนี้ไม่พร้อมใช้งานโดยค่าเริ่มต้นคุณต้องเพิ่มห้องสมุดเพิ่มเติม:

compile "com.android.support:exifinterface:XX.X.X"

ตอนนี้เราสามารถใช้getExifInterfaceวิธีการรับมุมของเรา:

public float getExifAngle(Context context, Uri uri) {
    try {
        ExifInterface exifInterface = getExifInterface(context, uri);
        if(exifInterface == null) {
            return -1f;
        }

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

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                return 90f;
            case ExifInterface.ORIENTATION_ROTATE_180:
                return 180f;
            case ExifInterface.ORIENTATION_ROTATE_270:
                return 270f;
            case ExifInterface.ORIENTATION_NORMAL:
                return 0f;
            case ExifInterface.ORIENTATION_UNDEFINED:
                return -1f;
            default:
                return -1f;
        }
    }
    catch (Exception e) {
        e.printStackTrace();
        return -1f;
    }
}

ตอนนี้คุณมี Angle ที่จะหมุนภาพของคุณอย่างเหมาะสมแล้ว :)


2
การใช้งาน 'androidx.exifinterface: exifinterface: XXX' นี่สำหรับผู้ที่ใช้ androidx ขอบคุณสำหรับการโพสต์ของคุณ
Doongsil

11
// Try this way,hope this will help you to solve your problem...

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center">
        <ImageView
            android:id="@+id/imgFromCameraOrGallery"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:src="@drawable/ic_launcher"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btnCamera"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Camera"/>
        <Button
            android:id="@+id/btnGallery"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_marginLeft="5dp"
            android:layout_height="wrap_content"
            android:text="Gallery"/>

    </LinearLayout>
</LinearLayout>

MainActivity.java

    public class MainActivity extends Activity {

    private ImageView imgFromCameraOrGallery;
    private Button btnCamera;
    private Button btnGallery;

    private String imgPath;
    final private int PICK_IMAGE = 1;
    final private int CAPTURE_IMAGE = 2;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imgFromCameraOrGallery = (ImageView) findViewById(R.id.imgFromCameraOrGallery);
        btnCamera = (Button) findViewById(R.id.btnCamera);
        btnGallery = (Button) findViewById(R.id.btnGallery);

        btnCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri());
                startActivityForResult(intent, CAPTURE_IMAGE);
            }
        });

        btnGallery.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setType("image/*");
                intent.setAction(Intent.ACTION_GET_CONTENT);
                startActivityForResult(Intent.createChooser(intent, ""), PICK_IMAGE);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == CAPTURE_IMAGE) {
                setCapturedImage(getImagePath());
            } else if (requestCode == PICK_IMAGE) {
                imgFromCameraOrGallery.setImageBitmap(BitmapFactory.decodeFile(getAbsolutePath(data.getData())));
            }
        }

    }

    private String getRightAngleImage(String photoPath) {

        try {
            ExifInterface ei = new ExifInterface(photoPath);
            int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            int degree = 0;

            switch (orientation) {
                case ExifInterface.ORIENTATION_NORMAL:
                    degree = 0;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
                case ExifInterface.ORIENTATION_UNDEFINED:
                    degree = 0;
                    break;
                default:
                    degree = 90;
            }

            return rotateImage(degree,photoPath);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return photoPath;
    }

    private String rotateImage(int degree, String imagePath){

        if(degree<=0){
            return imagePath;
        }
        try{
            Bitmap b= BitmapFactory.decodeFile(imagePath);

            Matrix matrix = new Matrix();
            if(b.getWidth()>b.getHeight()){
                matrix.setRotate(degree);
                b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(),
                        matrix, true);
            }

            FileOutputStream fOut = new FileOutputStream(imagePath);
            String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);
            String imageType = imageName.substring(imageName.lastIndexOf(".") + 1);

            FileOutputStream out = new FileOutputStream(imagePath);
            if (imageType.equalsIgnoreCase("png")) {
                b.compress(Bitmap.CompressFormat.PNG, 100, out);
            }else if (imageType.equalsIgnoreCase("jpeg")|| imageType.equalsIgnoreCase("jpg")) {
                b.compress(Bitmap.CompressFormat.JPEG, 100, out);
            }
            fOut.flush();
            fOut.close();

            b.recycle();
        }catch (Exception e){
            e.printStackTrace();
        }
        return imagePath;
    }

    private void setCapturedImage(final String imagePath){
        new AsyncTask<Void,Void,String>(){
            @Override
            protected String doInBackground(Void... params) {
                try {
                    return getRightAngleImage(imagePath);
                }catch (Throwable e){
                    e.printStackTrace();
                }
                return imagePath;
            }

            @Override
            protected void onPostExecute(String imagePath) {
                super.onPostExecute(imagePath);
                imgFromCameraOrGallery.setImageBitmap(decodeFile(imagePath));
            }
        }.execute();
    }

    public Bitmap decodeFile(String path) {
        try {
            // Decode deal_image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, o);
            // The new size we want to scale to
            final int REQUIRED_SIZE = 1024;

            // Find the correct scale value. It should be the power of 2.
            int scale = 1;
            while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
                scale *= 2;
            // Decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            return BitmapFactory.decodeFile(path, o2);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getAbsolutePath(Uri uri) {
        if(Build.VERSION.SDK_INT >= 19){
            String id = "";
            if(uri.getLastPathSegment().split(":").length > 1)
                id = uri.getLastPathSegment().split(":")[1];
            else if(uri.getLastPathSegment().split(":").length > 0)
                id = uri.getLastPathSegment().split(":")[0];
            if(id.length() > 0){
                final String[] imageColumns = {MediaStore.Images.Media.DATA };
                final String imageOrderBy = null;
                Uri tempUri = getUri();
                Cursor imageCursor = getContentResolver().query(tempUri, imageColumns, MediaStore.Images.Media._ID + "=" + id, null, imageOrderBy);
                if (imageCursor.moveToFirst()) {
                    return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
                }else{
                    return null;
                }
            }else{
                return null;
            }
        }else{
            String[] projection = { MediaStore.MediaColumns.DATA };
            Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            } else
                return null;
        }

    }

    private Uri getUri() {
        String state = Environment.getExternalStorageState();
        if(!state.equalsIgnoreCase(Environment.MEDIA_MOUNTED))
            return MediaStore.Images.Media.INTERNAL_CONTENT_URI;

        return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    }

    public Uri setImageUri() {
        Uri imgUri;
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/",getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis() + ".png");
            imgUri = Uri.fromFile(file);
            imgPath = file.getAbsolutePath();
        }else {
            File file = new File(getFilesDir() ,getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis()+ ".png");
            imgUri = Uri.fromFile(file);
            this.imgPath = file.getAbsolutePath();
        }
        return imgUri;
    }

    public String getImagePath() {
        return imgPath;
    }
}

โซลูชั่นที่สมบูรณ์แบบ Haresh Bhai
Sagar Pithiya

9

คุณสามารถอ่านการวางแนวของเซ็นเซอร์กล้องตามที่ Google ระบุไว้ในเอกสาร: https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html

SENSOR_ORIENTATION

Added in API level 21
Key<Integer> SENSOR_ORIENTATION
Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation.

Also defines the direction of rolling shutter readout, which is from top to bottom in the sensor's coordinate system.

Units: Degrees of clockwise rotation; always a multiple of 90

Range of valid values:
0, 90, 180, 270

This key is available on all devices.

รหัสตัวอย่าง:

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
int orientation = 0;
try {
    String cameraId = manager.getCameraIdList()[0];
    CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
    orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
}
catch (Exception e)
{
}

6

เจสันโรบินสันคำตอบและเซ Eltamawy คำตอบมี excelent

เพียงแค่การปรับปรุงให้เสร็จสมบูรณ์ aproach คุณควรใช้ compat ExifInterface

com.android.support:exifinterface:${lastLibVersion}

คุณจะสามารถยกตัวอย่าง ExifInterface (pior API <24) ด้วยInputStream(จากContentResolver) แทนเส้นทาง uri ที่หลีกเลี่ยง "ไฟล์ไม่พบข้อยกเว้น"

https://android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html


4

โดยปกติจะแนะนำให้แก้ปัญหาด้วยExifInterfaceเช่น@Jason Robinson ได้แนะนำ หากวิธีนี้ใช้ไม่ได้ผลคุณสามารถลองค้นหาทิศทางของภาพล่าสุดที่ถ่าย ...

private int getImageOrientation(){
    final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION };
    final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
    Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            imageColumns, null, null, imageOrderBy);

    if(cursor.moveToFirst()){
        int orientation = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION));
        cursor.close();
        return orientation;
    } else {
        return 0;
    }
}

1
ฉันคิดว่ารหัสนี้จะตรวจพบในสิ่งที่เกิดขึ้นในการหมุนระดับ ตอนนี้ฉันสามารถทำเช่นนั้นได้ แต่ไม่สามารถทำงานต่อไปได้เช่นหมุนภาพ
Shirish Herwade

คุณพูดถูก แต่คุณไม่ได้ขอการหมุนในเธรดนี้ดังนั้นให้มันสะอาด;) นั่นเป็นเหตุผลที่ฉันใส่คำตอบของปัญหาการหมุนในเธรดอื่นของคุณ ... หวังว่าจะช่วยได้ ฉัน: stackoverflow.com/questions/14123809/…
Chris Conway

4

น่าเศร้าที่ @ jason-robinson คำตอบข้างต้นไม่ได้ผลสำหรับฉัน

แม้ว่าฟังก์ชั่นหมุนจะทำงานได้อย่างสมบูรณ์แบบ:

public static Bitmap rotateImage(Bitmap source, float angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix,
            true);
}

ฉันต้องทำสิ่งต่อไปนี้เพื่อให้ได้การปฐมนิเทศเนื่องจากการวางแนว Exif เป็น 0 เสมอ

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode,resultCode,data);
    if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) {
            Uri selectedImage = data.getData();
            String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
            Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
            int orientation = -1;
            if (cur != null && cur.moveToFirst()) {
                    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
            }
            InputStream imageStream = getContentResolver().openInputStream(selectedImage);
            Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
            switch(orientation) {
                    case 90:
                            bitmap = rotateImage(chosen_image_bitmap, 90);
                            break;
                    case 180:
                            bitmap = rotateImage(chosen_image_bitmap, 180);
                            break;
                    case 270:
                            bitmap = rotateImage(chosen_image_bitmap, 270);
                            break;
                    default:
                            break;
            }
            imageView.setImageBitmap(bitmap );

1
alwasys 0, samsung 7
djdance

2

พยายามถ่ายภาพในแนวที่เฉพาะเจาะจงดีกว่า

android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden"

เพื่อผลลัพธ์ที่ดีที่สุดให้วางแนวนอนในกิจกรรมกล้องวิดีโอ


ขออภัยมันไม่ทำงาน ในความเป็นจริงบนแท็บทุกครั้งหลังจากเสร็จสิ้นการดำเนินการของ onActivityResult, onCreate ที่แปลกประหลาดได้รับเรียก
Shirish Herwade

1
ขออภัยปัญหาเป็นตามที่เป็น
Shirish Herwade

2

หากใครบางคนประสบปัญหากับการExifInterfaceเปิด Android 4.4 (KitKat) สำหรับการปฐมนิเทศมันอาจจะเป็นเพราะความผิดเส้นทางได้จาก URI ดูโซลูชันสำหรับผู้สนับสนุนgetPathในคำถาม Stack Overflow รับพา ธ จริงจาก URI, Android KitKat เฟรมเวิร์กการเข้าถึงหน่วยเก็บข้อมูลใหม่


ความคิดเห็นนี้เป็นสิ่งที่ฉันต้องการ เพื่อนขอบคุณมาก
Joel Nieman


1

คำตอบที่เลือกใช้วิธีที่พบบ่อยที่สุดที่ตอบคำถามนี้และคำถามที่คล้ายกัน อย่างไรก็ตามมันไม่สามารถใช้งานได้กับกล้องด้านหน้าและด้านหลังของ Samsung สำหรับผู้ที่มองหาวิธีแก้ปัญหาที่ใช้ได้ทั้งกับกล้องด้านหน้าและด้านหลังสำหรับ Samsung และผู้ผลิตรายใหญ่อื่น ๆ คำตอบของ nvhausid นี้ยอดเยี่ยม:

https://stackoverflow.com/a/18915443/6080472

สำหรับผู้ที่ไม่ต้องการคลิกผ่านเวทมนตร์ที่เกี่ยวข้องคือการใช้ CameraInfo แทนที่จะใช้ EXIF

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

รหัสเต็มในลิงค์


ไม่การหมุนผิดในมุมที่ต่างกัน (smasung s7) ฉันหมายถึงแกลเลอรี่ของหลักสูตร
djdance

1

สิ่งนี้อาจไปโดยไม่บอก แต่จำไว้เสมอว่าคุณสามารถจัดการกับปัญหาการจัดการอิมเมจเหล่านี้บนเซิร์ฟเวอร์ของคุณ ฉันใช้การตอบกลับเช่นเดียวกับที่มีอยู่ในชุดข้อความนี้เพื่อจัดการการแสดงภาพในทันที อย่างไรก็ตามแอปพลิเคชันของฉันต้องการรูปภาพที่จะเก็บไว้ในเซิร์ฟเวอร์ (นี่อาจเป็นข้อกำหนดทั่วไปหากคุณต้องการให้รูปภาพยังคงอยู่เมื่อผู้ใช้สลับโทรศัพท์)

โซลูชันที่มีอยู่ในหลายเธรดที่เกี่ยวข้องกับหัวข้อนี้ไม่ได้กล่าวถึงการขาดข้อมูล EXIF ​​ที่ไม่รอดจากการบีบอัดอิมเมจของบิตแมปซึ่งหมายความว่าคุณจะต้องหมุนรูปภาพในแต่ละครั้งที่เซิร์ฟเวอร์ของคุณโหลด หรือคุณสามารถส่งข้อมูลปฐมนิเทศ EXIF ​​ไปยังเซิร์ฟเวอร์ของคุณแล้วหมุนภาพไปที่นั่นหากจำเป็น

มันง่ายกว่าสำหรับฉันที่จะสร้างโซลูชันถาวรบนเซิร์ฟเวอร์เพราะฉันไม่ต้องกังวลเกี่ยวกับเส้นทางไฟล์ลับของ Android


คุณสามารถหมุนครั้งเดียวเมื่อถึงเวลาจับภาพและบันทึกด้วยวิธีนั้นจึงไม่จำเป็นต้องหมุนอีกครั้ง?
jk7

ใช่คุณทำได้และนั่นคือกระบวนการที่ฉันใช้ในท้ายที่สุด ฉันมีปัญหาในการขอเส้นทางไฟล์จากภาพบนโทรศัพท์ Android ที่จะทำให้ฉันทำอย่างนั้น นี่คือคำตอบที่ช่วย: stackoverflow.com/a/36714242/5443056
Braden Holt

1

ทางออกที่ง่ายที่สุดสำหรับปัญหานี้:

captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,
                   characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION));

ฉันกำลังบันทึกภาพในรูปแบบ jpg


0

นี่คือXamarin.Androidรุ่น:

จากคำตอบของ @Jason Robinson :

Bitmap rotate(Bitmap bitmap, int angle)
{
    var matrix = new Matrix();
    matrix.PostRotate(angle);

    return Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
}

Bitmap rotateIfRequired(Bitmap bitmap, string imagePath)
{
    var ei = new ExifInterface(imagePath);
    var orientation = ei.GetAttributeInt(ExifInterface.TagOrientation, (int)Android.Media.Orientation.Undefined);

    switch (orientation)
    {
        case (int)Android.Media.Orientation.Rotate90: return rotate(bitmap, 90);
        case (int)Android.Media.Orientation.Rotate180: return rotate(bitmap, 180);
        case (int)Android.Media.Orientation.Rotate270: return rotate(bitmap, 270);
        default: return bitmap;
    }
}

จากนั้นcalculateInSampleSizeวิธีการ:

int calculateInSampleSize(BitmapFactory.Options options, int reqW, int reqH)
{
    float h = options.OutHeight;
    float w = options.OutWidth;
    var inSampleSize = 1;

    if (h > reqH || w > reqW)
    {
        if (reqH == 0) inSampleSize = (int)Math.Floor(w / reqW);
        else if (reqW == 0) inSampleSize = (int)Math.Floor(h / reqH);
        else
        {
            var hRatio = (int)Math.Floor(h / reqH);
            var wRatio = (int)Math.Floor(w / reqW);
            inSampleSize = false ? Math.Max(hRatio, wRatio) : Math.Min(hRatio, wRatio);
        }
    }

    return inSampleSize;
}

จากคำตอบของ @Sami Eltamawy :

Bitmap handleSamplingAndRotationBitmap(string imagePath)
{
    var maxHeight = 1024;
    var maxWidth = 1024;

    var options = new BitmapFactory.Options();
    options.InJustDecodeBounds = true;
    BitmapFactory.DecodeFile(imagePath, options);

    options.InSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);

    options.InJustDecodeBounds = false;

    var bitmap = BitmapFactory.DecodeFile(imagePath, options);

    bitmap = rotateIfRequired(bitmap, imagePath);

    return bitmap;
}

0

หากคุณกำลังใช้ Fresco คุณสามารถใช้สิ่งนี้ -

final ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
.setRotationOptions(RotationOptions.autoRotate())
.build();

mSimpleDraweeView.setController(
Fresco.newDraweeControllerBuilder()
    .setImageRequest(imageRequest)
    .build());

สิ่งนี้จะหมุนรูปภาพตามข้อมูล Exif โดยอัตโนมัติ

ที่มา: https://frescolib.org/docs/rotation.html


0

โค้ดด้านล่างนี้ทำงานกับฉันได้รับบิตแมปจาก fileUri และทำการแก้ไขการหมุนหากต้องการ:

    private fun getCapturedImage(selectedPhotoUri: Uri): Bitmap {
        val bitmap = when {
            Build.VERSION.SDK_INT < 28 -> MediaStore.Images.Media.getBitmap(
                this.contentResolver,
                selectedPhotoUri
            )
            else -> {
                val source = ImageDecoder.createSource(this.contentResolver, selectedPhotoUri)
                ImageDecoder.decodeBitmap(source)
            }
        }

        // If the image is rotated, fix it
        return when (ExifInterface(contentResolver.run { openInputStream(selectedPhotoUri) }).getAttributeInt(
            ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
            ExifInterface.ORIENTATION_ROTATE_90 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(90F) }, true)
            ExifInterface.ORIENTATION_ROTATE_180 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(180F) }, true)
            ExifInterface.ORIENTATION_ROTATE_270 ->
                Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply {
                    postRotate(270F) }, true)
            else -> bitmap
        } 
    }

0

มีคำตอบสำหรับปัญหานี้โดยไม่ต้องใช้ExifInterface เราสามารถหมุนกล้องได้ทั้งกล้องหน้าหรือกล้องหลังไม่ว่าคุณจะใช้อะไรในขณะที่สร้างบิตแมปเราสามารถหมุนบิตแมปโดยใช้Matrix.postRotate (ดีกรี)

public int getRotationDegree() {
    int degree = 0;

    for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            degree = info.orientation;

            return degree;
        }
    }

    return degree;
}

หลังจากคำนวณการหมุนคุณสามารถหมุนบิตแมปได้ดังนี้:

 Matrix matrix = new Matrix();

 matrix.postRotate(getRotationDegree());

 Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);

Herare BMควรจะเป็นบิตแมปของคุณ

หากคุณต้องการทราบการหมุนของกล้องหน้าของคุณเพียงแค่เปลี่ยนCamera.CameraInfo.CAMERA_FACING_BACKเป็นCamera.CameraInfo.CAMERA_FACING_FRONTด้านบน

ฉันหวังว่านี่จะช่วยได้.


1
คำตอบที่น่ากลัว แต่ฉัน upvoted โดยไม่ตั้งใจ รหัสนี้จะถือว่าทุกภาพจากแกลเลอรี่ของคุณทำด้วยกล้องของคุณ นี่ไม่ใช่กรณี
Zun

-1

ฉันสร้างฟังก์ชันส่วนขยาย Kotlin ที่ทำให้การทำงานของนักพัฒนา Kotlin ง่ายขึ้นโดยอิงจากคำตอบของ @Jason Robinson ฉันหวังว่ามันจะช่วย

fun Bitmap.fixRotation(uri: Uri): Bitmap? {

    val ei = ExifInterface(uri.path)

    val orientation: Int = ei.getAttributeInt(
        ExifInterface.TAG_ORIENTATION,
        ExifInterface.ORIENTATION_UNDEFINED
    )

    return when (orientation) {
        ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage( 90f)
        ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage( 180f)
        ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage( 270f)
        ExifInterface.ORIENTATION_NORMAL -> this
        else -> this
    }
}

fun Bitmap.rotateImage(angle: Float): Bitmap? {
    val matrix = Matrix()
    matrix.postRotate(angle)
    return Bitmap.createBitmap(
        this, 0, 0, width, height,
        matrix, true
    )
}

1
ยอดเยี่ยม แต่ได้รับผลกระทบจากปัญหาเดียวกันกับโซลูชันทั้งหมดในฐานะส่วนขยายหรือฟังก์ชั่น - ไม่สามารถใช้งานบน Android 10.
Lior Iluz

-2

มีคำสั่งง่ายขึ้นเพื่อแก้ไขข้อผิดพลาดนี้

เพียงแค่เพิ่มหลังจาก yourImageView.setBitmap (บิตแมป); yourImageView.setRotation นี้ (90);

เหมืองนี้คงที่ หวังว่ามันจะช่วย!


6
ตามที่ OP ระบุไว้อุปกรณ์บางอย่างไม่หมุนภาพบางตัวหมุน 90 องศาบาง 180 และ .. เป็นต้น ดังนั้นการหมุน 90 จะไม่ถูกต้องในบางกรณี
jk7

-8

สิ่งนี้ใช้ได้สำหรับฉัน

ImageView display_image = findViewById(R.id.image);
this.display_image.setRotation(90);

lol สิ่งที่ประหลาดนี้ คุณจะรู้ได้อย่างไรว่ารูปถ่ายที่ถ่ายด้วยกล้องคือ -90 / 90/0 / ... ผู้ใช้อาจถ่ายภาพเป็นแนวนอนและไม่ว่าคุณจะหมุนภาพแบบใด ... lmao
Alex

ในกรณีนี้มันใช้งานได้สำหรับฉันตั้งแต่ในกรณีของฉันผู้ใช้มักจะถ่ายภาพด้วยโทรศัพท์ในแนวตั้ง
Christian Eduardo Galdamez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.