• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.SparseIntArray;
21 
22 import com.android.camera.debug.Log;
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 Log.Tag TAG = new Log.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 
FlashState(int state)73         public FlashState(int state) {
74             mState = state;
75         }
76 
isFlashFired()77         public boolean isFlashFired() {
78             return (mState & FLASH_FIRED_MASK) != 0;
79         }
80     }
81 
addDetail(int index, Object value)82     public void addDetail(int index, Object value) {
83         mDetails.put(index, value);
84     }
85 
getDetail(int index)86     public Object getDetail(int index) {
87         return mDetails.get(index);
88     }
89 
size()90     public int size() {
91         return mDetails.size();
92     }
93 
94     @Override
iterator()95     public Iterator<Entry<Integer, Object>> iterator() {
96         return mDetails.entrySet().iterator();
97     }
98 
setUnit(int index, int unit)99     public void setUnit(int index, int unit) {
100         mUnits.put(index, unit);
101     }
102 
hasUnit(int index)103     public boolean hasUnit(int index) {
104         return mUnits.indexOfKey(index) >= 0;
105     }
106 
getUnit(int index)107     public int getUnit(int index) {
108         return mUnits.get(index);
109     }
110 
setExifData(MediaDetails details, ExifTag tag, int key)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));
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      */
extractExifInfo(MediaDetails details, String filePath)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      */
formatDuration(final Context context, long seconds)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