Android EXIF数据一直是0,怎么改?
Android EXIF data always 0, how to change it?
我有一个应用程序可以使用本机 Camera
拍摄照片,然后将它们上传到服务器。我的问题是所有照片的 EXIF 方向值为 0,这会弄乱其他地方的显示。
如何更改 EXIF 方向?我不是在寻找一种方法来针对每种情况进行更正,只是将其更改为不同的值。
我使用的是三星 Galaxy Note 4
我尝试了这个在拍照前设置相机方向的解决方案:Setting Android Photo EXIF Orientation
Camera c = Camera.open();
c.setDisplayOrientation(90);
Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);
但它不会影响生成的 EXIF 数据,它仍然始终为 0
我还尝试了这些解决方案,其中图像在拍摄后旋转:EXIF orientation tag value always 0 for image taken with portrait camera app android
虽然这会旋转照片,但 EXIF 方向仍然始终为 0。
我也试过直接设置EXIF数据:How to save Exif data after bitmap compression in Android
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
fos.write(data);
fos.close();
//upload photo..
}
}
}
但上传后 EXIF 方向仍然为 0。
我也看过这些解决方案:
Exif data TAG_ORIENTATION always 0
How to write exif data to image in Android?
How to get the Correct orientation of the image selected from the Default Image gallery
但是都是通过旋转校正方向,不影响EXIF数据,或者直接设置EXIF数据,好像不行。
如何将文件的 EXIF 方向数据从 0 更改为 3?
更新:
这是我的上传代码:
Bitmap sBitmap = null;
final File sResizedFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "_2");
try {
sBitmap = BitmapFactory.decodeStream(new FileInputStream(pictureFile), null, options);
} catch (FileNotFoundException e) {
Log.e("App", "[MainActivity] unable to convert pictureFile to bitmap");
e.printStackTrace();
return;
}
// ... compute sw and sh int values
Bitmap sOut = Bitmap.createScaledBitmap(sBitmap, sw, sh, false);
Bitmap rotatedBitmap = rotateBitmap(sOut, 3);
FileOutputStream sfOut;
try {
sfOut = new FileOutputStream(sResizedFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, sfOut);
sfOut.flush();
sfOut.close();
sBitmap.recycle();
sOut.recycle();
rotatedBitmap.recycle();
} catch (Exception e) {
Log.e("App", "[MainActivity] unable to save thumbnail");
e.printStackTrace();
return;
}
// upload small thumbnail
TransferObserver sObserver = transferUtility.upload(
"stills/small", /* The bucket to upload to */
filename + ".jpg", /* The key for the uploaded object */
sResizedFile /* The file where the data to upload exists */
);
如您所见,EXIF 信息在 Android(尤其是三星设备)上不可靠。
然而,phone SQL 保存媒体对象引用的数据库是可靠的。我建议走这条路。
从 Uri 获取方向:
private static int getOrientation(Context context, Uri photoUri) {
Cursor cursor = context.getContentResolver().query(photoUri,
new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
if (cursor.getCount() != 1) {
cursor.close();
return -1;
}
cursor.moveToFirst();
int orientation = cursor.getInt(0);
cursor.close();
cursor = null;
return orientation;
}
然后初始化旋转Bitmap
:
public static Bitmap rotateBitmap(Context context, Uri photoUri, Bitmap bitmap) {
int orientation = getOrientation(context, photoUri);
if (orientation <= 0) {
return bitmap;
}
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
return bitmap;
}
如果您想更改图片的方向,请尝试以下代码段:
public static boolean setOrientation(Context context, Uri fileUri, int orientation) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.ORIENTATION, orientation);
int rowsUpdated = context.getContentResolver().update(fileUri, values, null, null);
return rowsUpdated > 0;
}
如果您设置了图片的方向,以后它会一直设置在正确的方向。稍后需要使用ExifInterface
,因为图像已经以适当的方式旋转。
如果这个方法不理想,可以试试this method
参考这个GitHub项目https://github.com/pandiaraj44/Camera. It has the custom camera activity where EXIF TAG_ORIENTATION was handled correctly. You can clone the project and check. For code details please refer https://github.com/pandiaraj44/Camera/blob/master/app/src/main/java/com/pansapp/cameraview/CameraFragment.java
有一个class读取和更新图像的这些信息。
要更新属性,您可以像这样使用
ExifInterface ef = new ExifInterface(filePath);
ef.setAttribute(MAKE_TAG, MAKE_TAG);
ef.setAttribute(ExifInterface.TAG_ORIENTATION, orientation+"");
ef.saveAttributes();
阅读时可以这样使用
ExifInterface exif = null;
try {
exif = new ExifInterface(absolutePath+path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
希望对你有所帮助
原来我的代码能够设置 EXIF 数据,但是 Android 解释此数据的方式与 iOS 和 Chrome 在 [=30 上的解释方式之间存在差异=](我检查结果文件的地方)解释它。
这是设置 EXIF 方向所需的唯一代码:
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
但是,设置 3
在 iOS 上显示为 0
,并且图像在 Chrome 中是横向的。
设置 6
在 iOS 上显示为 3
,图像在 Chrome.
中显示正确
您已接受您自己的答案作为解决方案。无论如何,我的咆哮只是有用的附带信息......
您的答案中的 "However..." 表明虽然您现在知道原因,但您没有解决办法。
Turns out my code was able to set the EXIF data, but there is a
discrepancy between how Android interprets this data and how iOS...
interprets it.
这可能是字节顺序问题。您可以尝试通过在十六进制编辑器中打开您的 jpeg 并找到...来手动更改 Exif 的字节序设置...
- 字节
45 78 69 66
(构成 "Exif" 文本)后跟两个零字节 00 00
。
- 那么应该是
49 49
(makes "II" text),表示以little endian格式读取数据。
- 如果换成
4D 4D
(或"MM"文字)则阅读端
会将数据视为大端。
在 iOS 中进行测试,看看数字现在是否正确。
关于这个……
However, setting 3
shows up as0
on iOS and the image is sideways in
Chrome.
Setting 6
shows up as 3
on iOS and the image looks right in Chrome.
我唯一可以补充的是 iOS Mac 是 Big Endian* 和 Android/PC 是 小字节序。本质上 Little Endian reads/writes 字节是从右到左,而 Big Endian 相反。
在二进制中:011
表示 3,110
表示 6。 3 和 6 之间的区别只是那些 1 和 0 的位的读取顺序。因此,读取为 zero-one-one
的系统得到 3 的结果,但另一个 Endian 系统将读取一个与 one-one-zero
具有相同位的字节并告诉你结果是6。我无法解释为什么 "3 在没有分析字节的测试文件的情况下显示为 0",但这对我来说是一个奇怪的结果。
</end rant>
<sleep>
*注意:虽然Mac是Big Endian,仔细检查说iOS毕竟使用Little Endian系统。不过,您的数字仍然表明存在 Big vs Little Endian 问题。
我有一个应用程序可以使用本机 Camera
拍摄照片,然后将它们上传到服务器。我的问题是所有照片的 EXIF 方向值为 0,这会弄乱其他地方的显示。
如何更改 EXIF 方向?我不是在寻找一种方法来针对每种情况进行更正,只是将其更改为不同的值。
我使用的是三星 Galaxy Note 4
我尝试了这个在拍照前设置相机方向的解决方案:Setting Android Photo EXIF Orientation
Camera c = Camera.open();
c.setDisplayOrientation(90);
Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);
但它不会影响生成的 EXIF 数据,它仍然始终为 0
我还尝试了这些解决方案,其中图像在拍摄后旋转:EXIF orientation tag value always 0 for image taken with portrait camera app android
虽然这会旋转照片,但 EXIF 方向仍然始终为 0。
我也试过直接设置EXIF数据:How to save Exif data after bitmap compression in Android
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
fos.write(data);
fos.close();
//upload photo..
}
}
}
但上传后 EXIF 方向仍然为 0。
我也看过这些解决方案:
Exif data TAG_ORIENTATION always 0
How to write exif data to image in Android?
How to get the Correct orientation of the image selected from the Default Image gallery
但是都是通过旋转校正方向,不影响EXIF数据,或者直接设置EXIF数据,好像不行。
如何将文件的 EXIF 方向数据从 0 更改为 3?
更新:
这是我的上传代码:
Bitmap sBitmap = null;
final File sResizedFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "_2");
try {
sBitmap = BitmapFactory.decodeStream(new FileInputStream(pictureFile), null, options);
} catch (FileNotFoundException e) {
Log.e("App", "[MainActivity] unable to convert pictureFile to bitmap");
e.printStackTrace();
return;
}
// ... compute sw and sh int values
Bitmap sOut = Bitmap.createScaledBitmap(sBitmap, sw, sh, false);
Bitmap rotatedBitmap = rotateBitmap(sOut, 3);
FileOutputStream sfOut;
try {
sfOut = new FileOutputStream(sResizedFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, sfOut);
sfOut.flush();
sfOut.close();
sBitmap.recycle();
sOut.recycle();
rotatedBitmap.recycle();
} catch (Exception e) {
Log.e("App", "[MainActivity] unable to save thumbnail");
e.printStackTrace();
return;
}
// upload small thumbnail
TransferObserver sObserver = transferUtility.upload(
"stills/small", /* The bucket to upload to */
filename + ".jpg", /* The key for the uploaded object */
sResizedFile /* The file where the data to upload exists */
);
如您所见,EXIF 信息在 Android(尤其是三星设备)上不可靠。
然而,phone SQL 保存媒体对象引用的数据库是可靠的。我建议走这条路。
从 Uri 获取方向:
private static int getOrientation(Context context, Uri photoUri) {
Cursor cursor = context.getContentResolver().query(photoUri,
new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
if (cursor.getCount() != 1) {
cursor.close();
return -1;
}
cursor.moveToFirst();
int orientation = cursor.getInt(0);
cursor.close();
cursor = null;
return orientation;
}
然后初始化旋转Bitmap
:
public static Bitmap rotateBitmap(Context context, Uri photoUri, Bitmap bitmap) {
int orientation = getOrientation(context, photoUri);
if (orientation <= 0) {
return bitmap;
}
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
return bitmap;
}
如果您想更改图片的方向,请尝试以下代码段:
public static boolean setOrientation(Context context, Uri fileUri, int orientation) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.ORIENTATION, orientation);
int rowsUpdated = context.getContentResolver().update(fileUri, values, null, null);
return rowsUpdated > 0;
}
如果您设置了图片的方向,以后它会一直设置在正确的方向。稍后需要使用ExifInterface
,因为图像已经以适当的方式旋转。
如果这个方法不理想,可以试试this method
参考这个GitHub项目https://github.com/pandiaraj44/Camera. It has the custom camera activity where EXIF TAG_ORIENTATION was handled correctly. You can clone the project and check. For code details please refer https://github.com/pandiaraj44/Camera/blob/master/app/src/main/java/com/pansapp/cameraview/CameraFragment.java
有一个class读取和更新图像的这些信息。
要更新属性,您可以像这样使用
ExifInterface ef = new ExifInterface(filePath);
ef.setAttribute(MAKE_TAG, MAKE_TAG);
ef.setAttribute(ExifInterface.TAG_ORIENTATION, orientation+"");
ef.saveAttributes();
阅读时可以这样使用
ExifInterface exif = null;
try {
exif = new ExifInterface(absolutePath+path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
希望对你有所帮助
原来我的代码能够设置 EXIF 数据,但是 Android 解释此数据的方式与 iOS 和 Chrome 在 [=30 上的解释方式之间存在差异=](我检查结果文件的地方)解释它。
这是设置 EXIF 方向所需的唯一代码:
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
但是,设置 3
在 iOS 上显示为 0
,并且图像在 Chrome 中是横向的。
设置 6
在 iOS 上显示为 3
,图像在 Chrome.
您已接受您自己的答案作为解决方案。无论如何,我的咆哮只是有用的附带信息......
您的答案中的 "However..." 表明虽然您现在知道原因,但您没有解决办法。
Turns out my code was able to set the EXIF data, but there is a discrepancy between how Android interprets this data and how iOS... interprets it.
这可能是字节顺序问题。您可以尝试通过在十六进制编辑器中打开您的 jpeg 并找到...来手动更改 Exif 的字节序设置...
- 字节
45 78 69 66
(构成 "Exif" 文本)后跟两个零字节00 00
。 - 那么应该是
49 49
(makes "II" text),表示以little endian格式读取数据。 - 如果换成
4D 4D
(或"MM"文字)则阅读端 会将数据视为大端。
在 iOS 中进行测试,看看数字现在是否正确。
关于这个……
However, setting
3
shows up as0
on iOS and the image is sideways in Chrome.
Setting6
shows up as3
on iOS and the image looks right in Chrome.
我唯一可以补充的是 iOS Mac 是 Big Endian* 和 Android/PC 是 小字节序。本质上 Little Endian reads/writes 字节是从右到左,而 Big Endian 相反。
在二进制中:011
表示 3,110
表示 6。 3 和 6 之间的区别只是那些 1 和 0 的位的读取顺序。因此,读取为 zero-one-one
的系统得到 3 的结果,但另一个 Endian 系统将读取一个与 one-one-zero
具有相同位的字节并告诉你结果是6。我无法解释为什么 "3 在没有分析字节的测试文件的情况下显示为 0",但这对我来说是一个奇怪的结果。
</end rant>
<sleep>
*注意:虽然Mac是Big Endian,仔细检查说iOS毕竟使用Little Endian系统。不过,您的数字仍然表明存在 Big vs Little Endian 问题。