Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.data;
     18 
     19 import android.content.Context;
     20 import android.util.Log;
     21 import android.util.SparseIntArray;
     22 
     23 import com.android.camera.exif.ExifInterface;
     24 import com.android.camera.exif.ExifTag;
     25 import com.android.camera2.R;
     26 
     27 import java.io.FileNotFoundException;
     28 import java.io.IOException;
     29 import java.util.Iterator;
     30 import java.util.Map.Entry;
     31 import java.util.TreeMap;
     32 
     33 public class MediaDetails implements Iterable<Entry<Integer, Object>> {
     34     @SuppressWarnings("unused")
     35     private static final String TAG = "MediaDetails";
     36 
     37     private TreeMap<Integer, Object> mDetails = new TreeMap<Integer, Object>();
     38     private SparseIntArray mUnits = new SparseIntArray();
     39 
     40     public static final int INDEX_TITLE = 1;
     41     public static final int INDEX_DESCRIPTION = 2;
     42     public static final int INDEX_DATETIME = 3;
     43     public static final int INDEX_LOCATION = 4;
     44     public static final int INDEX_WIDTH = 5;
     45     public static final int INDEX_HEIGHT = 6;
     46     public static final int INDEX_ORIENTATION = 7;
     47     public static final int INDEX_DURATION = 8;
     48     public static final int INDEX_MIMETYPE = 9;
     49     public static final int INDEX_SIZE = 10;
     50 
     51     // for EXIF
     52     public static final int INDEX_MAKE = 100;
     53     public static final int INDEX_MODEL = 101;
     54     public static final int INDEX_FLASH = 102;
     55     public static final int INDEX_FOCAL_LENGTH = 103;
     56     public static final int INDEX_WHITE_BALANCE = 104;
     57     public static final int INDEX_APERTURE = 105;
     58     public static final int INDEX_SHUTTER_SPEED = 106;
     59     public static final int INDEX_EXPOSURE_TIME = 107;
     60     public static final int INDEX_ISO = 108;
     61 
     62     // Put this last because it may be long.
     63     public static final int INDEX_PATH = 200;
     64 
     65     public static class FlashState {
     66         private static int FLASH_FIRED_MASK = 1;
     67         private static int FLASH_RETURN_MASK = 2 | 4;
     68         private static int FLASH_MODE_MASK = 8 | 16;
     69         private static int FLASH_FUNCTION_MASK = 32;
     70         private static int FLASH_RED_EYE_MASK = 64;
     71         private int mState;
     72 
     73         public FlashState(int state) {
     74             mState = state;
     75         }
     76 
     77         public boolean isFlashFired() {
     78             return (mState & FLASH_FIRED_MASK) != 0;
     79         }
     80     }
     81 
     82     public void addDetail(int index, Object value) {
     83         mDetails.put(index, value);
     84     }
     85 
     86     public Object getDetail(int index) {
     87         return mDetails.get(index);
     88     }
     89 
     90     public int size() {
     91         return mDetails.size();
     92     }
     93 
     94     @Override
     95     public Iterator<Entry<Integer, Object>> iterator() {
     96         return mDetails.entrySet().iterator();
     97     }
     98 
     99     public void setUnit(int index, int unit) {
    100         mUnits.put(index, unit);
    101     }
    102 
    103     public boolean hasUnit(int index) {
    104         return mUnits.indexOfKey(index) >= 0;
    105     }
    106 
    107     public int getUnit(int index) {
    108         return mUnits.get(index);
    109     }
    110 
    111     private static void setExifData(MediaDetails details, ExifTag tag,
    112             int key) {
    113         if (tag != null) {
    114             String value = null;
    115             int type = tag.getDataType();
    116             if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) {
    117                 value = String.valueOf(tag.getValueAsRational(0).toDouble());
    118             } else if (type == ExifTag.TYPE_ASCII) {
    119                 value = tag.getValueAsString();
    120             } else {
    121                 value = String.valueOf(tag.forceGetValueAsLong(0));
    122             }
    123             if (key == MediaDetails.INDEX_FLASH) {
    124                 MediaDetails.FlashState state = new MediaDetails.FlashState(
    125                         Integer.valueOf(value.toString()));
    126                 details.addDetail(key, state);
    127             } else {
    128                 details.addDetail(key, value);
    129             }
    130         }
    131     }
    132 
    133     /**
    134      * Extracts data from the EXIF of the given file and stores it in the
    135      * MediaDetails instance.
    136      */
    137     public static void extractExifInfo(MediaDetails details, String filePath) {
    138         ExifInterface exif = new ExifInterface();
    139         try {
    140             exif.readExif(filePath);
    141         } catch (FileNotFoundException e) {
    142             Log.w(TAG, "Could not find file to read exif: " + filePath, e);
    143         } catch (IOException e) {
    144             Log.w(TAG, "Could not read exif from file: " + filePath, e);
    145         }
    146 
    147         setExifData(details, exif.getTag(ExifInterface.TAG_FLASH),
    148                 MediaDetails.INDEX_FLASH);
    149         setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH),
    150                 MediaDetails.INDEX_WIDTH);
    151         setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH),
    152                 MediaDetails.INDEX_HEIGHT);
    153         setExifData(details, exif.getTag(ExifInterface.TAG_MAKE),
    154                 MediaDetails.INDEX_MAKE);
    155         setExifData(details, exif.getTag(ExifInterface.TAG_MODEL),
    156                 MediaDetails.INDEX_MODEL);
    157         setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE),
    158                 MediaDetails.INDEX_APERTURE);
    159         setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS),
    160                 MediaDetails.INDEX_ISO);
    161         setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE),
    162                 MediaDetails.INDEX_WHITE_BALANCE);
    163         setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME),
    164                 MediaDetails.INDEX_EXPOSURE_TIME);
    165         ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH);
    166         if (focalTag != null) {
    167             details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH,
    168                     focalTag.getValueAsRational(0).toDouble());
    169             details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm);
    170         }
    171     }
    172 
    173     /**
    174      * Returns a (localized) string for the given duration (in seconds).
    175      */
    176     public static String formatDuration(final Context context, long seconds) {
    177         long h = seconds / 3600;
    178         long m = (seconds - h * 3600) / 60;
    179         long s = seconds - (h * 3600 + m * 60);
    180         String durationValue;
    181         if (h == 0) {
    182             durationValue = String.format(context.getString(R.string.details_ms), m, s);
    183         } else {
    184             durationValue = String.format(context.getString(R.string.details_hms), h, m, s);
    185         }
    186         return durationValue;
    187     }
    188 }
    189