1 /* 2 * Copyright (C) 2010 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.gallery3d.data; 18 19 import com.android.gallery3d.R; 20 import com.android.gallery3d.common.Utils; 21 import com.android.gallery3d.exif.ExifInterface; 22 import com.android.gallery3d.exif.ExifTag; 23 import com.android.gallery3d.exif.Rational; 24 25 import java.io.FileInputStream; 26 import java.io.FileNotFoundException; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.util.HashMap; 30 import java.util.Iterator; 31 import java.util.Map.Entry; 32 import java.util.TreeMap; 33 34 public class MediaDetails implements Iterable<Entry<Integer, Object>> { 35 @SuppressWarnings("unused") 36 private static final String TAG = "MediaDetails"; 37 38 private TreeMap<Integer, Object> mDetails = new TreeMap<Integer, Object>(); 39 private HashMap<Integer, Integer> mUnits = new HashMap<Integer, Integer>(); 40 41 public static final int INDEX_TITLE = 1; 42 public static final int INDEX_DESCRIPTION = 2; 43 public static final int INDEX_DATETIME = 3; 44 public static final int INDEX_LOCATION = 4; 45 public static final int INDEX_WIDTH = 5; 46 public static final int INDEX_HEIGHT = 6; 47 public static final int INDEX_ORIENTATION = 7; 48 public static final int INDEX_DURATION = 8; 49 public static final int INDEX_MIMETYPE = 9; 50 public static final int INDEX_SIZE = 10; 51 52 // for EXIF 53 public static final int INDEX_MAKE = 100; 54 public static final int INDEX_MODEL = 101; 55 public static final int INDEX_FLASH = 102; 56 public static final int INDEX_FOCAL_LENGTH = 103; 57 public static final int INDEX_WHITE_BALANCE = 104; 58 public static final int INDEX_APERTURE = 105; 59 public static final int INDEX_SHUTTER_SPEED = 106; 60 public static final int INDEX_EXPOSURE_TIME = 107; 61 public static final int INDEX_ISO = 108; 62 63 // Put this last because it may be long. 64 public static final int INDEX_PATH = 200; 65 66 public static class FlashState { 67 private static int FLASH_FIRED_MASK = 1; 68 private static int FLASH_RETURN_MASK = 2 | 4; 69 private static int FLASH_MODE_MASK = 8 | 16; 70 private static int FLASH_FUNCTION_MASK = 32; 71 private static int FLASH_RED_EYE_MASK = 64; 72 private int mState; 73 74 public FlashState(int state) { 75 mState = state; 76 } 77 78 public boolean isFlashFired() { 79 return (mState & FLASH_FIRED_MASK) != 0; 80 } 81 } 82 83 public void addDetail(int index, Object value) { 84 mDetails.put(index, value); 85 } 86 87 public Object getDetail(int index) { 88 return mDetails.get(index); 89 } 90 91 public int size() { 92 return mDetails.size(); 93 } 94 95 @Override 96 public Iterator<Entry<Integer, Object>> iterator() { 97 return mDetails.entrySet().iterator(); 98 } 99 100 public void setUnit(int index, int unit) { 101 mUnits.put(index, unit); 102 } 103 104 public boolean hasUnit(int index) { 105 return mUnits.containsKey(index); 106 } 107 108 public int getUnit(int index) { 109 return mUnits.get(index); 110 } 111 112 private static void setExifData(MediaDetails details, ExifTag tag, 113 int key) { 114 if (tag != null) { 115 String value = null; 116 int type = tag.getDataType(); 117 if (type == ExifTag.TYPE_UNSIGNED_RATIONAL || type == ExifTag.TYPE_RATIONAL) { 118 value = String.valueOf(tag.getValueAsRational(0).toDouble()); 119 } else if (type == ExifTag.TYPE_ASCII) { 120 value = tag.getValueAsString(); 121 } else { 122 value = String.valueOf(tag.forceGetValueAsLong(0)); 123 } 124 if (key == MediaDetails.INDEX_FLASH) { 125 MediaDetails.FlashState state = new MediaDetails.FlashState( 126 Integer.valueOf(value.toString())); 127 details.addDetail(key, state); 128 } else { 129 details.addDetail(key, value); 130 } 131 } 132 } 133 134 public static void extractExifInfo(MediaDetails details, String filePath) { 135 136 ExifInterface exif = new ExifInterface(); 137 try { 138 exif.readExif(filePath); 139 } catch (FileNotFoundException e) { 140 Log.w(TAG, "Could not find file to read exif: " + filePath, e); 141 } catch (IOException e) { 142 Log.w(TAG, "Could not read exif from file: " + filePath, e); 143 } 144 145 setExifData(details, exif.getTag(ExifInterface.TAG_FLASH), 146 MediaDetails.INDEX_FLASH); 147 setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_WIDTH), 148 MediaDetails.INDEX_WIDTH); 149 setExifData(details, exif.getTag(ExifInterface.TAG_IMAGE_LENGTH), 150 MediaDetails.INDEX_HEIGHT); 151 setExifData(details, exif.getTag(ExifInterface.TAG_MAKE), 152 MediaDetails.INDEX_MAKE); 153 setExifData(details, exif.getTag(ExifInterface.TAG_MODEL), 154 MediaDetails.INDEX_MODEL); 155 setExifData(details, exif.getTag(ExifInterface.TAG_APERTURE_VALUE), 156 MediaDetails.INDEX_APERTURE); 157 setExifData(details, exif.getTag(ExifInterface.TAG_ISO_SPEED_RATINGS), 158 MediaDetails.INDEX_ISO); 159 setExifData(details, exif.getTag(ExifInterface.TAG_WHITE_BALANCE), 160 MediaDetails.INDEX_WHITE_BALANCE); 161 setExifData(details, exif.getTag(ExifInterface.TAG_EXPOSURE_TIME), 162 MediaDetails.INDEX_EXPOSURE_TIME); 163 ExifTag focalTag = exif.getTag(ExifInterface.TAG_FOCAL_LENGTH); 164 if (focalTag != null) { 165 details.addDetail(MediaDetails.INDEX_FOCAL_LENGTH, 166 focalTag.getValueAsRational(0).toDouble()); 167 details.setUnit(MediaDetails.INDEX_FOCAL_LENGTH, R.string.unit_mm); 168 } 169 } 170 } 171