เมื่อฉันโหลดรูปภาพจากแกลเลอรี่สื่อเป็นบิตแมปทุกอย่างทำงานได้ดียกเว้นว่ารูปภาพที่ถ่ายด้วยกล้องขณะถือโทรศัพท์ในแนวตั้งจะหมุนเพื่อให้ฉันได้ภาพแนวนอนเสมอแม้ว่าจะปรากฏในแนวตั้ง เฉลียง เพราะเหตุใดและฉันจะโหลดอย่างถูกต้องได้อย่างไร
เมื่อฉันโหลดรูปภาพจากแกลเลอรี่สื่อเป็นบิตแมปทุกอย่างทำงานได้ดียกเว้นว่ารูปภาพที่ถ่ายด้วยกล้องขณะถือโทรศัพท์ในแนวตั้งจะหมุนเพื่อให้ฉันได้ภาพแนวนอนเสมอแม้ว่าจะปรากฏในแนวตั้ง เฉลียง เพราะเหตุใดและฉันจะโหลดอย่างถูกต้องได้อย่างไร
คำตอบ:
คุณดูข้อมูล EXIF ของรูปภาพหรือยัง มันอาจจะรู้ทิศทางของกล้องเมื่อถ่ายภาพ
ดังนั้นเป็นตัวอย่าง ...
ก่อนอื่นคุณต้องสร้าง 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 เช่นกัน
OutOfMemoryError
เมื่อใช้วิธีนี้ในขณะที่คุณถือสองบิตแมปในหน่วยความจำในเวลาเดียวกัน
นี่เป็นโซลูชันที่สมบูรณ์ (พบได้ในตัวอย่าง 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;
}
ExifInterface exif = new ExifInterface(photoUri.getPath());
แล้วexif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)
จะได้รับการปฐมนิเทศ (เช่นORIENTATION_ROTATE_90
, ORIENTATION_ROTATE_180
)
แก้ไขในกรณีของฉันด้วยรหัสนี้โดยใช้ความช่วยเหลือของโพสต์นี้:
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);
หวังว่ามันจะช่วยประหยัดเวลาของใครบางคน!
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);
มันเป็นเพราะแกลเลอรี่ที่ถูกต้องแสดงภาพที่หมุน แต่ไม่ใช่ 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;
}
ได้รับมันไปใช้งานหลังจากความพยายามหลายครั้งต้องขอบคุณโพสต์ฉันไม่สามารถหา :-(
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);
}
}
คุณสามารถอ่านเส้นทางจากการ์ด 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();
}
}
รหัส 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)
}
ฉันปรับปรุงคำตอบของ 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);
สิ่งแรกที่คุณต้องการคือพา ธ ไฟล์จริงหากคุณใช้งานได้ดีถ้าคุณใช้ 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;
}
นั่นคือตอนนี้คุณมีบิตแมปที่หมุนไปยังตำแหน่งที่ถูกต้อง
ไชโย
วิธีนี้ใช้ได้ผล แต่อาจไม่ใช่วิธีที่ดีที่สุดที่จะทำ แต่อาจช่วยคนได้
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;
}
อาจจะช่วยได้ (หมุน 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;
}
เคอร์เซอร์ควรจะปิดหลังจากเปิดมัน
นี่คือตัวอย่าง
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;
}
ฉันละลายคำตอบ @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;
}
มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน ฉันหวังว่านี่จะช่วยคนอื่นได้
การปรับปรุงวิธีการแก้ปัญหาข้างต้นโดย 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;
}
ใช้รหัสต่อไปนี้เพื่อหมุนรูปภาพอย่างถูกต้อง:
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;
}
วิธีการด้านล่างปรับขนาดและหมุนบิตแมปตามทิศทาง:
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());
}
}
ฉันแก้ไขปัญหาด้วยวิธีแก้ปัญหาต่อไปนี้ โปรดทราบว่าฉันกำลังขยายภาพซึ่งจำเป็นต้องหลีกเลี่ยง 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
ไชโย