Android EXIF数据总是0,如何更改呢?

Cba*_*bas 25 camera android exif image orientation

我有一个应用程序,使用本机捕获照片Camera,然后将它们上传到服务器.我的问题是所有照片的EXIF方向值都为0,这会使显示器在其他地方混乱.

如何更改EXIF方向?我不是在寻找一种方法来纠正每种情况,只需将其更改为不同的值.

我正在使用三星Galaxy Note 4

我尝试了这个在拍照前设置相机方向的解决方案:设置Android Photo EXIF方向

Camera c = Camera.open();
c.setDisplayOrientation(90);

Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);
Run Code Online (Sandbox Code Playgroud)

但它不会影响生成的EXIF数据,它仍然始终为0

我也试过这些解决方案,在拍摄后旋转图像:EXIF方向标记值始终为0,用于使用肖像相机app拍摄的图像

当旋转照片时,EXIF方向始终为0.

我还尝试直接设置EXIF数据:如何在Android中进行位图压缩后保存Exif数据

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..
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但上传后EXIF Orientation仍为0.

我也看过这些解决方案:

Exif数据TAG_ORIENTATION始终为0

如何在Android中将exif数据写入图像?

如何获取从默认图像库中选择的图像的正确方向

如何设置相机图像方向?

但它们都涉及通过旋转来校正方向,这不会影响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 */
);
Run Code Online (Sandbox Code Playgroud)

R. *_*ski 22

如您所见,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;
}
Run Code Online (Sandbox Code Playgroud)

然后初始化旋转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;
}
Run Code Online (Sandbox Code Playgroud)

如果要更改图像的方向,请尝试以下代码段:

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;
}
Run Code Online (Sandbox Code Playgroud)

如果您设置图像的方向,稍后它将始终设置在正确的方向.ExifInterface以后需要使用,因为图像已经以适当的方式旋转.

如果这种方法不能令人满意,那么你可以尝试这种方法

  • `java.lang.NullPointerException: 不幸的是,尝试在空对象引用上调用接口方法 'int android.database.Cursor.getCount()' (3认同)

VC.*_*One 12

您已接受自己的答案作为解决方案.无论如何,我的咆哮只是有用的侧面信息......

你的答案中的"然而......"表明,虽然你现在知道原因,但你没有修复.

事实证明我的代码能够设置EXIF数据,但Android解释这些数据的方式与iOS解释它的方式之间存在差异.

这可能是一个字节序问题.您可以尝试通过在十六进制编辑器中打开jpeg并查找...来手动更改Exif的endianness设置.

  • 字节45 78 69 66(使"Exif"文本)后跟两个零字节00 00.
  • 那么它应该是49 49(制作"II"文本),这意味着将数据读取为小端格式.
  • 如果用4D 4D(或"MM"文本)替换它,则读取方将数据视为大端.

在iOS中测试这个以查看数字现在是否正确.

关于这个......

但是,设置在iOS上3显示,0图像在Chrome中横向显示.
设置在iOS上6显示,3图像在Chrome中显示正确.

我唯一可以添加的是iOS Mac是Big Endian*而Android/PC是Little Endian.基本上Little Endian从右到左读/写字节,而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问题.


Cba*_*bas 10

事实证明我的代码能够设置EXIF数据,但Android解释这些数据的方式与Mac上的iOS和Chrome(我在检查生成的文件的位置)如何解释它之间存在差异.

这是设置EXIF方向所需的唯一代码:

ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
Run Code Online (Sandbox Code Playgroud)

但是,设置在iOS上3显示,0图像在Chrome中横向显示.

设置在iOS上6显示,3图片在Chrome中显示正确.