Android: บิตแมปที่โหลดจากแกลเลอรี่จะหมุนใน ImageView


138

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


ฉันมีคำตอบที่แท้จริงstackoverflow.com/questions/29971319/image-orientation-android/…
A.Sanchez.SD

คำตอบ:


40

คุณดูข้อมูล EXIF ​​ของรูปภาพหรือยัง มันอาจจะรู้ทิศทางของกล้องเมื่อถ่ายภาพ


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

182

ดังนั้นเป็นตัวอย่าง ...

ก่อนอื่นคุณต้องสร้าง ExifInterface:

ExifInterface exif = new ExifInterface(filename);

จากนั้นคุณสามารถคว้าการวางแนวของภาพ:

orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

นี่คือความหมายของค่าการปฐมนิเทศ: http://sylvana.net/jpegcrop/exif_orientation.html

ดังนั้นค่าที่สำคัญที่สุดคือ 3, 6 และ 8 หากการวางแนวคือExifInterface.ORIENTATION_ROTATE_90(ซึ่งก็คือ 6) คุณสามารถหมุนภาพดังนี้:

Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);

นั่นเป็นเพียงตัวอย่างด่วน ฉันแน่ใจว่ามีวิธีอื่นในการหมุนตามจริง แต่คุณจะพบกับ StackOverflow เช่นกัน


5
ต่อไปนี้เป็นค่าการหมุนสำหรับการหมุนที่แตกต่างกัน: 3: 180, 6: 90, 8: 270
ชื่อที่ปรากฏ

103
อย่าใช้หมายเลขเวทย์มนตร์เมื่อคุณสามารถใช้ค่าคงที่ที่มีชื่อ: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270
d60402

29
ระวังOutOfMemoryErrorเมื่อใช้วิธีนี้ในขณะที่คุณถือสองบิตแมปในหน่วยความจำในเวลาเดียวกัน
Alex Bonel

อีกตัวอย่างที่สมบูรณ์ ... stackoverflow.com/questions/14066038/…
CGR

64

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

public static int getOrientation(Context context, Uri photoUri) {
    /* it's on the external media. */
    Cursor cursor = context.getContentResolver().query(photoUri,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

    if (cursor.getCount() != 1) {
        return -1;
    }

    cursor.moveToFirst();
    return cursor.getInt(0);
}

จากนั้นคุณจะได้บิตแมปที่หมุนดังนี้ รหัสนี้ย่อขนาดภาพ (น่าเสียดายอย่างมาก) ถึง MAX_IMAGE_DIMENSION มิฉะนั้นคุณอาจมีหน่วยความจำไม่เพียงพอ

public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
    InputStream is = context.getContentResolver().openInputStream(photoUri);
    BitmapFactory.Options dbo = new BitmapFactory.Options();
    dbo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, dbo);
    is.close();

    int rotatedWidth, rotatedHeight;
    int orientation = getOrientation(context, photoUri);

    if (orientation == 90 || orientation == 270) {
        rotatedWidth = dbo.outHeight;
        rotatedHeight = dbo.outWidth;
    } else {
        rotatedWidth = dbo.outWidth;
        rotatedHeight = dbo.outHeight;
    }

    Bitmap srcBitmap;
    is = context.getContentResolver().openInputStream(photoUri);
    if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
        float maxRatio = Math.max(widthRatio, heightRatio);

        // Create the bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = (int) maxRatio;
        srcBitmap = BitmapFactory.decodeStream(is, null, options);
    } else {
        srcBitmap = BitmapFactory.decodeStream(is);
    }
    is.close();

    /*
     * if the orientation is not 0 (or -1, which means we don't know), we
     * have to do a rotation.
     */
    if (orientation > 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(orientation);

        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                srcBitmap.getHeight(), matrix, true);
    }

    return srcBitmap;
}

1
MAX_IMAGE_DIMENDION นั้นหมายความว่าอย่างไร
Sazzad Hissain Khan

3
มันคือความกว้างหรือความสูงสูงสุดของภาพที่คุณได้รับ กล่าวคือคุณต้องการเพียงภาพขนาด 512x512 เท่านั้นหากคุณเปิดภาพขนาด 24 ล้านพิกเซลจะมีประสิทธิภาพมากกว่าในการเปิดภาพย่อยแล้วกว่าจะเปิดภาพทั้งหมดแล้วย่อขนาดลงซึ่งอาจทำให้หน่วยความจำของคุณหมด
Timmmm

ในโปรแกรมของฉันฉันพบว่ามีประโยชน์ในการกำหนดตัวแปรบิตแมปในกิจกรรม / ชิ้นส่วนเป็นสแตติกส่วนตัวและตั้งค่าเป็นโมฆะในฟังก์ชั่น มีปัญหาหน่วยความจำน้อยลง
Gunnar Bernstein

มันฉลาดกว่าที่จะแทนที่ MAX_IMAGE_DIMENDION เป็น MAX_IMAGE_WIDTH และ MAX_IMAGE_HEIGHT
fnc12

ช่วยประหยัดเวลาของฉันได้ :) ขอบคุณมาก สำหรับผู้ที่ได้รับเคอร์เซอร์ null คุณอาจลองExifInterface exif = new ExifInterface(photoUri.getPath());แล้วexif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)จะได้รับการปฐมนิเทศ (เช่นORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180)
Atul

60

แก้ไขในกรณีของฉันด้วยรหัสนี้โดยใช้ความช่วยเหลือของโพสต์นี้:

            Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());

            try {
                ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                Log.d("EXIF", "Exif: " + orientation);
                Matrix matrix = new Matrix();
                if (orientation == 6) {
                    matrix.postRotate(90);
                }
                else if (orientation == 3) {
                    matrix.postRotate(180);
                }
                else if (orientation == 8) {
                    matrix.postRotate(270);
                }
                myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
            }
            catch (Exception e) {

            }
            ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
            img.setImageBitmap(myBitmap);

หวังว่ามันจะช่วยประหยัดเวลาของใครบางคน!


ข้อเสนอแนะการแก้ไข: ไม่มีค่าคงที่ชื่อเหมาะสมสำหรับการวางแนว 6, 3, 8 หรือไม่? เราไม่สามารถข้ามบิตแมปใหม่ได้ถ้าไม่จำเป็นต้องมีการหมุน?
Cee McSharpface

ดังที่ @ d60402 พูดไว้ก่อนหน้านี้ในความคิดเห็นคุณสามารถใช้ค่าคงที่ที่มีชื่อ: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270
เอเดรียน

42

ใช้ยูทิลิตี้เพื่อทำการยกของหนัก

9re ได้สร้างยูทิลิตี้ง่าย ๆ เพื่อจัดการกับการยกของข้อมูล EXIF ​​และหมุนภาพไปในทิศทางที่ถูกต้อง

คุณสามารถค้นหารหัสยูทิลิตี้ได้ที่นี่: https://gist.github.com/9re/1990019

เพียงดาวน์โหลดสิ่งนี้เพิ่มลงในsrcไดเรกทอรีของโครงการและใช้ExifUtil.rotateBitmap()เพื่อให้ได้แนวที่ถูกต้องเช่น:

String imagePath = photoFile.getAbsolutePath();             // photoFile is a File class.
Bitmap myBitmap  = BitmapFactory.decodeFile(imagePath);

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);

2
ใช้งานได้สำหรับฉัน! ฉันเพิ่งปรับขนาดบิตแมปเป็นรูปแบบ HD ก่อนส่งผ่านไปยัง ExifUtil.rotateBitmap () เพื่อหลีกเลี่ยง OutOfMemoryError เช่นนั้น: บิตแมปปรับขนาด = Bitmap.createScaledBitmap (myBitmap, 720, 1280, จริง); photo = ExifUtil.rotateBitmap (picturePath ปรับขนาด);
Phil

@Phil นอกจากนี้ที่ดี ฉันไม่ได้พบเจอสิ่งใด (ฉันใช้อุปกรณ์ Android รุ่นเก่ากว่า) แต่ก็ดีที่จะรู้
Joshua Pinter

3
คุณเป็นพระเอกเพื่อนของฉัน :)
Klutch

@ klutch คุณทำวันของฉันแล้ว :) เพื่อความยุติธรรม 9re ได้เขียนโค้ดยูทิลิตี้ดังนั้นเขาจึงเป็นฮีโร่ตัวจริง
Joshua Pinter

1
@SananthKarumanaghat เป็นคำถามที่ดีมาก! ฉันอาจจะรู้ว่าทำไมเรื่องนี้ถึงสมเหตุสมผลเมื่อฉันลึกเข้าไปในเรื่องนี้ แต่ตอนนี้ดูเหมือนว่ามันซ้ำซ้อนสำหรับฉันเช่นกัน เคยใช้เวลามากเกินไปใน React Native บางที
Joshua Pinter

8

มันเป็นเพราะแกลเลอรี่ที่ถูกต้องแสดงภาพที่หมุน แต่ไม่ใช่ ImageView ดูที่นี่:

                    myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
                    ExifInterface exif = new ExifInterface(selectedImagePath);
                    int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                    int rotationInDegrees = exifToDegrees(rotation);
                    deg = rotationInDegrees;
                    Matrix matrix = new Matrix();
                    if (rotation != 0f) {
                        matrix.preRotate(rotationInDegrees);
                        myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
                    }

และคุณต้องการสิ่งนี้:

private static int exifToDegrees(int exifOrientation) {        
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }            
    return 0;    
} 

5

ได้รับมันไปใช้งานหลังจากความพยายามหลายครั้งต้องขอบคุณโพสต์ฉันไม่สามารถหา :-(

Exif ดูเหมือนว่าจะทำงานอยู่เสมอความยากลำบากคือการได้รับพา ธ รหัสที่ฉันพบทำให้แตกต่างกันระหว่าง API ที่เก่ากว่า 4.4 และหลัง 4.4 โดยทั่วไปรูปภาพ URI สำหรับ 4.4+ จะมี "com.android.providers" สำหรับ URI ประเภทนี้รหัสใช้ DocumentsContract เพื่อรับ id รูปภาพจากนั้นเรียกใช้แบบสอบถามโดยใช้ ContentResolver ในขณะที่สำหรับ SDK รุ่นเก่ารหัสจะตรงไปสอบถาม URI ด้วย ContentResolver

นี่คือรหัส (ขออภัยฉันไม่สามารถเครดิตที่โพสต์ได้):

/**
 * Handles pre V19 uri's
 * @param context
 * @param contentUri
 * @return
 */
public static String getPathForPreV19(Context context, Uri contentUri) {
    String res = null;

    String[] proj = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
    if(cursor.moveToFirst()){;
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        res = cursor.getString(column_index);
    }
    cursor.close();

    return res;
}

/**
 * Handles V19 and up uri's
 * @param context
 * @param contentUri
 * @return path
 */
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPathForV19AndUp(Context context, Uri contentUri) {
    String wholeID = DocumentsContract.getDocumentId(contentUri);

    // Split at colon, use second item in the array
    String id = wholeID.split(":")[1];
    String[] column = { MediaStore.Images.Media.DATA };

    // where id is equal to
    String sel = MediaStore.Images.Media._ID + "=?";
    Cursor cursor = context.getContentResolver().
            query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{ id }, null);

    String filePath = "";
    int columnIndex = cursor.getColumnIndex(column[0]);
    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }

    cursor.close();
    return filePath;
}

public static String getRealPathFromURI(Context context,
        Uri contentUri) {
    String uriString = String.valueOf(contentUri);
    boolean goForKitKat= uriString.contains("com.android.providers");

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
            Log.i("KIKAT","YES");
            return getPathForV19AndUp(context, contentUri);
        } else {

            return getPathForPreV19(context, contentUri);
        }
}

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

3

คุณสามารถอ่านเส้นทางจากการ์ด sd และทำรหัสต่อไปนี้ ... มันจะแทนที่ภาพที่มีอยู่หลังจากหมุนมัน ..

ไม่: Exif ไม่ทำงานบนอุปกรณ์ส่วนใหญ่มันให้ข้อมูลที่ไม่ถูกต้องดังนั้นจึงเป็นการดีที่จะเขียนโค้ดที่มีการหมุนเวียนยากก่อนที่จะบันทึกในระดับที่คุณต้องการคุณเพียงแค่เปลี่ยนค่ามุมใน postRotate เป็นสิ่งที่คุณต้องการ

    String photopath = tempphoto.getPath().toString();
    Bitmap bmp = BitmapFactory.decodeFile(photopath);

    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);

    FileOutputStream fOut;
    try {
        fOut = new FileOutputStream(tempphoto);
        bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
        fOut.flush();
        fOut.close();

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

}

2
นี่คือการหมุน แต่เราไม่รู้ว่ารูปภาพต้องการการหมุนหรือไม่
MSaudi

3

รหัส Kotlin:

if (file.exists()){
    val bitmap = BitmapFactory.decodeFile(file.absolutePath)

    val exif = ExifInterface(file.absoluteFile.toString())
    val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
    val matrix = Matrix()

    when(orientation){
        ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
        ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
        ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
    }

    val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
    bitmap.recycle()
    iv_capture.setImageBitmap(rotatedBitmap)
}

2

ฉันปรับปรุงคำตอบของ Teo Inke มันไม่หมุนรูปภาพอีกต่อไปเว้นแต่จำเป็นจริงๆ นอกจากนี้ยังง่ายต่อการอ่านและควรทำงานได้เร็วขึ้น

// Load Image
Bitmap bitmap = BitmapFactory.decodeFile(filePath);

// Rotate Image if Needed
try
{
    // Determine Orientation
    ExifInterface exif = new ExifInterface(filePath);
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

    // Determine Rotation
    int rotation = 0;
    if      (orientation == 6)      rotation = 90;
    else if (orientation == 3)      rotation = 180;
    else if (orientation == 8)      rotation = 270;

    // Rotate Image if Necessary
    if (rotation != 0)
    {
        // Create Matrix
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);

        // Rotate Bitmap
        Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 

        // Pretend none of this ever happened!
        bitmap.recycle();
        bitmap = rotated;
        rotated = null;
     }
}
catch (Exception e)
{
    // TODO: Log Error Messages Here
}

// TODO: Use Result Here
xxx.setBitmap(bitmap);

2

สิ่งแรกที่คุณต้องการคือพา ธ ไฟล์จริงหากคุณใช้งานได้ดีถ้าคุณใช้ URI ให้ใช้วิธีนี้เพื่อรับพา ธ จริง:

 public static String getRealPathFromURI(Uri contentURI,Context context) {
    String path= contentURI.getPath();
    try {
        Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
        cursor.moveToFirst();
        String document_id = cursor.getString(0);
        document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
        cursor.close();

        cursor = context.getContentResolver().query(
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
        cursor.moveToFirst();
        path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
    }
    catch(Exception e)
    {
        return path;
    }
    return path;
}

แยกบิตแมปของคุณตัวอย่างเช่น:

  try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);

                        }
                        catch (IOException e)
                        {
                            Log.e("IOException",e.toString());
                        }

คุณสามารถใช้ decodeFile () แทนหากคุณต้องการ

ตอนนี้คุณมีบิตแมปและเส้นทางที่แท้จริงได้รับการวางแนวของภาพ:

 private static int getExifOrientation(String src) throws IOException {
        int orientation = 1;

        ExifInterface exif = new ExifInterface(src);
        String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        try {
            orientation = Integer.parseInt(orientationString);
        }
        catch(NumberFormatException e){}

        return orientation;
    }

และในที่สุดก็หมุนไปยังตำแหน่งที่เหมาะสมดังนี้:

public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
        try {
            int orientation = getExifOrientation(src);

            if (orientation == 1) {
                return bitmap;
            }

            Matrix matrix = new Matrix();
            switch (orientation) {
                case 2:
                    matrix.setScale(-1, 1);
                    break;
                case 3:
                    matrix.setRotate(180);
                    break;
                case 4:
                    matrix.setRotate(180);
                    matrix.postScale(-1, 1);
                    break;
                case 5:
                    matrix.setRotate(90);
                    matrix.postScale(-1, 1);
                    break;
                case 6:
                    matrix.setRotate(90);
                    break;
                case 7:
                    matrix.setRotate(-90);
                    matrix.postScale(-1, 1);
                    break;
                case 8:
                    matrix.setRotate(-90);
                    break;
                default:
                    return bitmap;
            }

            try {
                Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                bitmap.recycle();
                return oriented;
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmap;
    }

นั่นคือตอนนี้คุณมีบิตแมปที่หมุนไปยังตำแหน่งที่ถูกต้อง

ไชโย


1

วิธีนี้ใช้ได้ผล แต่อาจไม่ใช่วิธีที่ดีที่สุดที่จะทำ แต่อาจช่วยคนได้

String imagepath = someUri.getAbsolutePath();
imageview = (ImageView)findViewById(R.id.imageview);
imageview.setImageBitmap(setImage(imagepath, 120, 120));    

public Bitmap setImage(String path, final int targetWidth, final int targetHeight) {
    Bitmap bitmap = null;
// Get exif orientation     
    try {
        ExifInterface exif = new ExifInterface(path);
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
        if (orientation == 6) {
            orientation_val = 90;
        }
        else if (orientation == 3) {
            orientation_val = 180;
        }
        else if (orientation == 8) {
            orientation_val = 270;
        }
    }
        catch (Exception e) {
        }

        try {
// First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, options);

// Adjust extents
            int sourceWidth, sourceHeight;
            if (orientation_val == 90 || orientation_val == 270) {
                sourceWidth = options.outHeight;
                sourceHeight = options.outWidth;
            } else {
                sourceWidth = options.outWidth;
                sourceHeight = options.outHeight;
            }

// Calculate the maximum required scaling ratio if required and load the bitmap
            if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
                float widthRatio = (float)sourceWidth / (float)targetWidth;
                float heightRatio = (float)sourceHeight / (float)targetHeight;
                float maxRatio = Math.max(widthRatio, heightRatio);
                options.inJustDecodeBounds = false;
                options.inSampleSize = (int)maxRatio;
                bitmap = BitmapFactory.decodeFile(path, options);
            } else {
                bitmap = BitmapFactory.decodeFile(path);
            }

// Rotate the bitmap if required
            if (orientation_val > 0) {
                Matrix matrix = new Matrix();
                matrix.postRotate(orientation_val);
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            }

// Re-scale the bitmap if necessary
            sourceWidth = bitmap.getWidth();
            sourceHeight = bitmap.getHeight();
            if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
                float widthRatio = (float)sourceWidth / (float)targetWidth;
                float heightRatio = (float)sourceHeight / (float)targetHeight;
                float maxRatio = Math.max(widthRatio, heightRatio);
                sourceWidth = (int)((float)sourceWidth / maxRatio);
                sourceHeight = (int)((float)sourceHeight / maxRatio);
                bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth,     sourceHeight, true);
            }
        } catch (Exception e) {
        }
        return bitmap;
    }

1

อาจจะช่วยได้ (หมุน 90 องศา) (ใช้งานได้สำหรับฉัน)

private Bitmap rotateBitmap(Bitmap image){
        int width=image.getHeight();
        int height=image.getWidth();

        Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());

        for (int y=width-1;y>=0;y--)
            for(int x=0;x<height;x++)
                srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
        return srcBitmap;

    }

1

เคอร์เซอร์ควรจะปิดหลังจากเปิดมัน

นี่คือตัวอย่าง

 public static int getOrientation(Context context, Uri selectedImage)
{
    int orientation = -1;
    Cursor cursor = context.getContentResolver().query(selectedImage,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
    if (cursor.getCount() != 1)
       return orientation;

    cursor.moveToFirst();
    orientation = cursor.getInt(0);
    cursor.close(); // ADD THIS LINE
   return orientation;
}

1

ฉันละลายคำตอบ @Timmmm และ @Manuel แล้ว ถ้าคุณทำวิธีนี้คุณจะไม่ได้รับข้อยกเว้นหน่วยความจำหมด

วิธีนี้จะดึงการจัดแนวภาพ:

private static final int ROTATION_DEGREES = 90;
// This means 512 px
private static final Integer MAX_IMAGE_DIMENSION = 512;

public static int getOrientation(Uri photoUri) throws IOException {

    ExifInterface exif = new ExifInterface(photoUri.getPath());
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            orientation = ROTATION_DEGREES;
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            orientation = ROTATION_DEGREES * 2;
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            orientation = ROTATION_DEGREES * 3;
            break;
        default:
            // Default case, image is not rotated
            orientation = 0;
    }

    return orientation;
}

ดังนั้นคุณจะใช้วิธีนี้เพื่อปรับขนาดภาพก่อนที่จะโหลดในหน่วยความจำ ด้วยวิธีนี้คุณจะไม่ได้รับการยกเว้นหน่วยความจำ

public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
    InputStream is = context.getContentResolver().openInputStream(photoUri);
    BitmapFactory.Options dbo = new BitmapFactory.Options();
    dbo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, dbo);
    is.close();

    int rotatedWidth, rotatedHeight;
    int orientation = getOrientation(photoUri);

    if (orientation == 90 || orientation == 270) {
        rotatedWidth = dbo.outHeight;
        rotatedHeight = dbo.outWidth;
    } else {
        rotatedWidth = dbo.outWidth;
        rotatedHeight = dbo.outHeight;
    }

    Bitmap srcBitmap;
    is = context.getContentResolver().openInputStream(photoUri);
    if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
        float maxRatio = Math.max(widthRatio, heightRatio);

        // Create the bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = (int) maxRatio;
        srcBitmap = BitmapFactory.decodeStream(is, null, options);
    } else {
        srcBitmap = BitmapFactory.decodeStream(is);
    }
    is.close();

    // if the orientation is not 0, we have to do a rotation.
    if (orientation > 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(orientation);

        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                srcBitmap.getHeight(), matrix, true);
    }

    return srcBitmap;
}

มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ฉันหวังว่านี่จะช่วยคนอื่นได้


0

การปรับปรุงวิธีการแก้ปัญหาข้างต้นโดย Timmmm เพื่อเพิ่มการขยายขนาดพิเศษในตอนท้ายเพื่อให้แน่ใจว่าภาพพอดีกับขอบเขต:

public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
    Bitmap bitmap = null;
    try {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Adjust extents
        int sourceWidth, sourceHeight;
        if (orientation == 90 || orientation == 270) {
            sourceWidth = options.outHeight;
            sourceHeight = options.outWidth;
        } else {
            sourceWidth = options.outWidth;
            sourceHeight = options.outHeight;
        }

        // Calculate the maximum required scaling ratio if required and load the bitmap
        if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            options.inJustDecodeBounds = false;
            options.inSampleSize = (int)maxRatio;
            bitmap = BitmapFactory.decodeFile(path, options);
        } else {
            bitmap = BitmapFactory.decodeFile(path);
        }

        // Rotate the bitmap if required
        if (orientation > 0) {
            Matrix matrix = new Matrix();
            matrix.postRotate(orientation);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }

        // Re-scale the bitmap if necessary
        sourceWidth = bitmap.getWidth();
        sourceHeight = bitmap.getHeight();
        if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            sourceWidth = (int)((float)sourceWidth / maxRatio);
            sourceHeight = (int)((float)sourceHeight / maxRatio);
            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
        }
    } catch (Exception e) {
    }
    return bitmap;
}

0

ใช้รหัสต่อไปนี้เพื่อหมุนรูปภาพอย่างถูกต้อง:

private Bitmap rotateImage(Bitmap bitmap, String filePath)
{
    Bitmap resultBitmap = bitmap;

    try
    {
        ExifInterface exifInterface = new ExifInterface(filePath);
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

        Matrix matrix = new Matrix();

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
        }
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_180);
        }
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_270);
        }

        // Rotate the bitmap
        resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }
    catch (Exception exception)
    {
        Logger.d("Could not rotate the image");
    }
    return resultBitmap;
}

คุณสามารถรวมเงื่อนไข if ทั้งหมดเข้าด้วยกันเพื่อให้ได้รหัสที่เล็กลง
Chandranshu

0

วิธีการด้านล่างปรับขนาดและหมุนบิตแมปตามทิศทาง:

public Bitmap scaleAndRotateImage(String path, int orientation, final int targetWidth, final int targetHeight)
{
    Bitmap bitmap = null;

    try
    {
        // Check the dimensions of the Image
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Adjust the Width and Height
        int sourceWidth, sourceHeight;
        if (orientation == 90 || orientation == 270)
        {
            sourceWidth = options.outHeight;
            sourceHeight = options.outWidth;
        }
        else
        {
            sourceWidth = options.outWidth;
            sourceHeight = options.outHeight;
        }

        // Calculate the maximum required scaling ratio if required and load the bitmap
        if (sourceWidth > targetWidth || sourceHeight > targetHeight)
        {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            options.inJustDecodeBounds = false;
            options.inSampleSize = (int)maxRatio;
            bitmap = BitmapFactory.decodeFile(path, options);
        }
        else
        {
            bitmap = BitmapFactory.decodeFile(path);
        }

        // We need to rotate the bitmap (if required)
        int orientationInDegrees = exifToDegrees(orientation);
        if (orientation > 0)
        {
            Matrix matrix = new Matrix();
            if (orientation != 0f)
            {
                matrix.preRotate(orientationInDegrees);
            };

            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }

        // Re-scale the bitmap if necessary
        sourceWidth = bitmap.getWidth();
        sourceHeight = bitmap.getHeight();

        if (sourceWidth != targetWidth || sourceHeight != targetHeight)
        {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            sourceWidth = (int)((float)sourceWidth / maxRatio);
            sourceHeight = (int)((float)sourceHeight / maxRatio);
            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
        }
    }
    catch (Exception e)
    {
        Logger.d("Could not rotate the image");
        Logger.d(e.getMessage());
    }
    return bitmap;
}

ตัวอย่าง:

public void getPictureFromDevice(Uri Uri,ImageView imageView)
{
    try
    {
        ExifInterface exifInterface = new ExifInterface(Uri.getPath());
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        Bitmap bitmap = scaleAndRotateImage(Uri.getPath(), orientation, imageView.getWidth(), imageView.getHeight());
        imageView.setImageBitmap(bitmap);
    }
    catch (OutOfMemoryError outOfMemoryError)
    {
        Logger.d(outOfMemoryError.getLocalizedMessage());
        Logger.d("Failed to load image from filePath (out of memory)");
        Logger.d(Uri.toString());
    }
    catch (Exception e)
    {
        Logger.d("Failed to load image from filePath");
        Logger.d(Uri.toString());
    }
}

-3

ฉันแก้ไขปัญหาด้วยวิธีแก้ปัญหาต่อไปนี้ โปรดทราบว่าฉันกำลังขยายภาพซึ่งจำเป็นต้องหลีกเลี่ยง OutOfMemoryExceptions

ระวังว่าวิธีนี้จะไม่ทำงานอย่างถูกต้องกับภาพบุคคลหรือภาพคว่ำ (ขอบคุณ Timmmm สำหรับการสังเกต) โซลูชันของ Timmmm ด้านบนอาจเป็นตัวเลือกที่ดีกว่าหากจำเป็นและมันก็ดูดีกว่าเช่นกัน: https://stackoverflow.com/a/8914291/449918

File path = // ... location of your bitmap file
int w = 512; int h = 384; // size that does not lead to OutOfMemoryException on Nexus One
Bitmap b = BitmapFactory.decodeFile(path);


// Hack to determine whether the image is rotated
boolean rotated = b.getWidth() > b.getHeight();

Bitmap resultBmp = null;

// If not rotated, just scale it
if (!rotated) {
    resultBmp = Bitmap.createScaledBitmap(b, w, h, true);
    b.recycle();
    b = null;

// If rotated, scale it by switching width and height and then rotated it
} else {
    Bitmap scaledBmp = Bitmap.createScaledBitmap(b, h, w, true);
    b.recycle();
    b = null;

    Matrix mat = new Matrix();
    mat.postRotate(90);
    resultBmp = Bitmap.createBitmap(scaledBmp, 0, 0, h, w, mat, true);

    // Release image resources
    scaledBmp.recycle();
    scaledBmp = null;
}

// resultBmp now contains the scaled and rotated image

ไชโย


สิ่งนี้จะไม่ทำงานอย่างถูกต้อง แล้วภาพบุคคลล่ะ รูปภาพกลับหัว การใช้ข้อมูล exif นั้นดีกว่ามาก
Timmmm

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

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

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