57

Android アプリがデバイスのカメラを使用して写真を撮り、サイズを変更する場合 (これは、アップロードのサイズを縮小するために非常によくあることです)、このサイズ変更操作が Exif メタデータを削除することに気付かないかもしれませ

これは問題を引き起こす可能性があります。特に、問題のデバイスが「向き」タグに依存して画像を正しく表示する場合に問題が発生する可能性があります。

さまざまな Android デバイスがさまざまな方法でカメラ/画像の回転を処理します。私の信頼できる古い Nexus One は、キャプチャ後すぐに画像を常に回転させるように見えるため、ファイルのネイティブ コンテンツは表示時に常に「直立」しています。

ただし、他のデバイス (特に私のテストでは Samsung の携帯電話) は、画像ファイルの内容を回転させ、Exif 'Orientation' タグを設定します。画像が後で表示されるときはいつでも、関連する画像コードは方向「タグ」の存在を検出し、画像を適切に回転させる必要があります。ただし、画像にビットマップ処理を行って新しいファイルに保存すると、その Exif データはすべて失われます。

方向データに加えて、メーカー/モデルなどの他の重要なメタデータも失われる可能性があります。

これは私を数週間混乱させました(電話ギャラリーに表示すると画像は縦に表示されますが、サーバーには方向が正しくなく、明らかなメタデータがありません)。他の人を助けるために、ここにこの自問自答を追加します。このブログ投稿は非常に役に立ちました。

EXIF情報を失うことなくAndroidで画像のサイズを変更する

4

5 に答える 5

51

私が知る限り、メタデータを自動的に保持したり、そこにあるもののスナップショットを作成して一括転送したりするメカニズムはありません。

むしろ、特定のプロパティを明示的に確認し、ExifInterface を使用してそれらを新しい画像ファイルに自分でコピーする必要があるようです。

http://developer.android.com/reference/android/media/ExifInterface.html

次のようなものです:

ExifInterface oldExif = new ExifInterface(oldImagePath);
String exifOrientation = oldExif.getAttribute(ExifInterface.TAG_ORIENTATION);

if (exifOrientation != null) {
   ExifInterface newExif = new ExifInterface(imagePath);
   newExif.setAttribute(ExifInterface.TAG_ORIENTATION, exifOrientation);
   newExif.saveAttributes();
}
于 2012-11-28T01:52:43.747 に答える
39

怠惰な人のために、再利用可能な関数を次に示します。

public static void copyExif(String oldPath, String newPath) throws IOException
{
    ExifInterface oldExif = new ExifInterface(oldPath);

    String[] attributes = new String[]
    {
            ExifInterface.TAG_APERTURE,
            ExifInterface.TAG_DATETIME,
            ExifInterface.TAG_DATETIME_DIGITIZED,
            ExifInterface.TAG_EXPOSURE_TIME,
            ExifInterface.TAG_FLASH,
            ExifInterface.TAG_FOCAL_LENGTH,
            ExifInterface.TAG_GPS_ALTITUDE,
            ExifInterface.TAG_GPS_ALTITUDE_REF,
            ExifInterface.TAG_GPS_DATESTAMP,
            ExifInterface.TAG_GPS_LATITUDE,
            ExifInterface.TAG_GPS_LATITUDE_REF,
            ExifInterface.TAG_GPS_LONGITUDE,
            ExifInterface.TAG_GPS_LONGITUDE_REF,
            ExifInterface.TAG_GPS_PROCESSING_METHOD,
            ExifInterface.TAG_GPS_TIMESTAMP,
            ExifInterface.TAG_IMAGE_LENGTH,
            ExifInterface.TAG_IMAGE_WIDTH,
            ExifInterface.TAG_ISO,
            ExifInterface.TAG_MAKE,
            ExifInterface.TAG_MODEL,
            ExifInterface.TAG_ORIENTATION,
            ExifInterface.TAG_SUBSEC_TIME,
            ExifInterface.TAG_SUBSEC_TIME_DIG,
            ExifInterface.TAG_SUBSEC_TIME_ORIG,
            ExifInterface.TAG_WHITE_BALANCE
    };

    ExifInterface newExif = new ExifInterface(newPath);
    for (int i = 0; i < attributes.length; i++)
    {
        String value = oldExif.getAttribute(attributes[i]);
        if (value != null)
            newExif.setAttribute(attributes[i], value);
    }
    newExif.saveAttributes();
}
于 2015-11-05T19:38:53.460 に答える
21

他の人が示したように、Exif データを元の画像から最終的なサイズ変更された画像にコピーする必要があります。これには通常、Sanselan Android ライブラリが最適です。Android OS のバージョンによっては、ExifInterface が Exifdata を破損することがあります。

さらに、ExifInterface は限られた数の Exif タグ、つまり「認識している」タグのみを処理します。一方、Sanselan はすべての Exiftag とマーカー ノートを保持します。

Here is a blog post that shows how to use Sanselan for copying image data:

Copying Exif metadata using Sanselan

BTW, on Android I also tend to rotate the images and remove the Orientation Exiftag. For example, on a Nexus S with Android 4.03, the camera was setting an orientation tag in the Exifmetadata, but the webview was ignoring that information and displaying the image incorrectly. Sadly, rotating the actual image data and removing the Exiforientation tag is the only way to get every program to display images correctly.

于 2012-12-09T02:23:29.097 に答える
1

タグごとにタグを指定する必要がないように、ExifInterface ソースを変更し、独自の実装を追加して一括での読み取り/書き込みをサポートしてみませんか。これが私がすることのスニペットです。

内部属性を公開する新しいメソッドを追加します。

public HashMap<String, ExifAttribute>[] getAllAttributes() {
    return mAttributes;
}

すべての属性を設定する新しいメソッドを追加します。

public void setAttributes(HashMap<String, ExifAttribute>[] attributes) {
    for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
        mAttributes[i] = attributes[i];
    }
}

次に、このように使用してExifを保存し、別のファイルに保存します

// Grab all the original exif attributes from an image file and save to memory or wherever
let attributes = ExifInterface2(sourceImagePath).attributes

// Later on you can just copy those attributes to another image
ExifInterface2(destImagePath)
    .setAttributes(attributes)
    .saveAttributes();
于 2020-06-26T18:19:07.193 に答える