ネイティブCamera
を使用して写真をキャプチャし、それらをサーバーにアップロードするアプリがあります。私の問題は、すべての写真のEXIF方向の値が0であり、これが他の場所の表示を台無しにすることです。
EXIFの向きを変更するにはどうすればよいですか?私はすべての状況でそれを修正する方法を探しているのではなく、単に別の値に変更するだけです。
Samsung 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向きタグ値は、Androidのポートレートカメラアプリで撮影した画像では常に
これにより写真が回転しますが、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..
}
}
}
ただし、アップロード後、EXIFの方向はまだ0です。
私もこれらのソリューションを見てきました:
デフォルト画像ギャラリーから選択された画像の正しい方向を取得する方法
しかし、それらはすべて、回転によって方向を修正することを含みます。これは、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がこのデータを解釈する方法とiOSとChromeのMac(結果のファイルをチェックしていたところ)はそれを解釈します。
これは、EXIFの向きを設定するために必要な唯一のコードです。
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
ただし、3
は0
iOSの場合、画像はChromeの横向きです。
設定6
は3
iOSでは、画像はChromeで正しく表示されます。
ご覧のとおり、EXIF情報はAndroid(特にSamsungデバイス)では信頼できません。
ただし、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
を使用する必要があります。
この方法で満足できない場合は、 この方法
あなたはあなた自身の答えを解決策として受け入れました。とにかく私の暴言は便利なサイド情報です...
回答の "しかし..."は、原因がわかっているが修正できないことを示唆しています。
私のコードはEXIFデータを設定できましたが、Androidがこのデータを解釈する方法とiOS ...がそれを解釈する方法との間に矛盾があります。
これはエンディアンネスの問題である可能性があります。 16進エディタでjpegを開いて見つけることにより、Exifのエンディアン設定を手動で変更してみてください...
45 78 69 66
(「Exif」テキストを作成)の後に2つのゼロバイト00 00
が続きます。49 49
(「II」テキストを作成)にする必要があります。これは、リトルエンディアン形式としてデータを読み取ることを意味します。4D 4D
(または「MM」テキスト)に置き換えると、読み取り側はデータをビッグエンディアンと見なします。IOSでこれをテストして、数値が正しいかどうかを確認します。
そしてこれに関して...
ただし、
3
を設定すると、iOSではas0
と表示され、Chromeでは画像が横向きになります。
設定6
はiOSでは3
として表示され、Chromeで画像は正しく表示されます。
追加できるのはそれだけです iOS MacはBig Endian *であり、Android/PCはLittle Endianです。本質的にリトルエンディアンは、右から左にバイトを読み書きしますが、ビッグエンディアンは反対です。
バイナリ:011
は3を意味し、110
は6を意味します。 3と6の違いは、1と0のビットの読み取り順序です。したがって、zero-one-one
として読み取るシステムは3の結果を取得しますが、他のEndianシステムはone-one-zero
と同じビットのバイトを読み取り、結果を通知しますは6です。バイトを分析するためのテストファイルがないと、なぜ "3が0"と表示されるのか説明できませんが、奇妙な結果です。
</end rant>
<sleep>
*note:Macはビッグエンディアンですが、ダブルチェックではiOSはリトルエンディアンシステムを使用します。それでも、あなたの数字はビッグエンディアンとリトルエンディアンの問題を示唆しています。
画像のこれらの情報を読み取り、更新するクラスが1つあります。
このように使用できる属性を更新するには
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);
私はそれがあなたを助けることを願っています
この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 を参照してください。