我有一个应用程序,使用本机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
how to set camera Image orientation?
但它们都涉及通过旋转来校正方向,这不会影响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 */
);
答案 0 :(得分:16)
如您所见,EXIF信息在Android(特别是三星设备)上不可靠。
但是,持有Media对象引用的手机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
答案 1 :(得分:9)
原来我的代码能够设置EXIF数据,但Android解释这些数据的方式与Mac上的iOS和Chrome(我检查结果文件的位置)如何解释它之间存在差异。
这是设置EXIF方向所需的唯一代码:
Activity
但是,设置ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
在iOS上显示为3
,图片在Chrome中横向显示。
设置0
在iOS上显示为6
,图片在Chrome中显示正确。
答案 2 :(得分:9)
您已接受自己的答案作为解决方案。无论如何,我的咆哮只是有用的侧面信息......
你的答案中的&#34;然而......&#34; 建议你现在知道原因,但你没有解决问题。
原来我的代码能够设置EXIF数据,但有一个 Android如何解释这些数据与iOS之间的差异...... 解释它。
这可能是一个字节序问题。您可以尝试通过在十六进制编辑器中打开jpeg并查找...来手动更改Exif的endianness设置。
45 78 69 66
(使&#34; Exif&#34;文本)后跟两个零字节00 00
。 49 49
(使&#34; II&#34;文本),这意味着将数据读取为小端格式。4D 4D
(或&#34; MM&#34;文字)替换它,那么阅读方
将数据视为大端。在iOS中测试此内容以查看数字现在是否正确。
关于这个...
但是,在iOS上设置
3
会显示为0
,而且图片是横向显示的 Chrome浏览器。
设置6
在iOS上显示为3
,图片在Chrome中显示正确。
我唯一可以添加的是 iOS Mac Big Endian * ,Android / PC Little Endian 。基本上Little Endian从右到左读/写字节,而Big Endian则相反。
二进制:011
表示 3 ,110
表示 6 。 3和6之间的差异仅仅是那些1和6位的读取顺序。零。因此,读取为zero-one-one
的系统会得到 3 的结果,但另一个Endian系统将读取与one-one-zero
相同位的字节,并告诉您结果为 6 即可。我无法解释为什么&#34; 3显示为0&#34; 没有用于分析字节的测试文件,但这对我来说是一个奇怪的结果。
</end rant>
<sleep>
* note :虽然Mac是Big Endian,但仔细检查说iOS毕竟使用Little Endian系统。你的数字仍然表明Big vs. Little Endian问题。
答案 3 :(得分:3)
请参阅此GitHub项目https://github.com/pandiaraj44/Camera。它具有正确处理EXIF TAG_ORIENTATION的自定义相机活动。您可以克隆项目并检查。有关代码详情,请参阅https://github.com/pandiaraj44/Camera/blob/master/app/src/main/java/com/pansapp/cameraview/CameraFragment.java
答案 4 :(得分:3)
有一个类可以读取和更新这些图像信息。
更新您可以使用的属性
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);
我希望它能帮到你