blob: 2d1fca029c1c60b2aaa999b094f82e8351585655 [file] [log] [blame]
Julian Mancinib6505152017-06-27 13:29:09 -07001/*
2 * Copyright (C) 2017 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
17package android.provider;
18
19import android.annotation.Nullable;
20import android.media.ExifInterface;
21import android.os.Bundle;
22
23import java.io.IOException;
24import java.io.InputStream;
25import java.util.ArrayList;
26import java.util.HashMap;
27import java.util.List;
28import java.util.Map;
29
30/**
31 * Class providing support for extracting metadata from a file as a
32 * {@link Bundle} suitable for use with {@link DocumentsContract#getDocumentMetadata}.
33 * <p>Currently only EXIF data is supported.
34 * <p>TODO: Add support for common video and audio types, as well as PDF files.
35 * {@hide}
36 */
37public final class MetadataReader {
38
39 private MetadataReader() {
40 }
41
42 private static final String[] DEFAULT_EXIF_TAGS = {
43 ExifInterface.TAG_IMAGE_WIDTH,
44 ExifInterface.TAG_IMAGE_LENGTH,
45 ExifInterface.TAG_DATETIME,
46 ExifInterface.TAG_GPS_LATITUDE,
47 ExifInterface.TAG_GPS_LONGITUDE,
48 ExifInterface.TAG_MAKE,
49 ExifInterface.TAG_MODEL,
50 ExifInterface.TAG_APERTURE,
51 ExifInterface.TAG_SHUTTER_SPEED_VALUE
52 };
53
54 private static final Map<String, Integer> TYPE_MAPPING = new HashMap<>();
55 private static final String[] ALL_KNOWN_EXIF_KEYS;
56 private static final int TYPE_INT = 0;
57 private static final int TYPE_DOUBLE = 1;
58 private static final int TYPE_STRING = 2;
59
60 static {
61 // TODO: Move this over to ExifInterface.java
62 // Since each ExifInterface item has a type, and there's currently no way to get the type
63 // from the tag, here we identify the tag to the type so that we can call the correct
64 // ExifInterface method
65 TYPE_MAPPING.put(ExifInterface.TAG_ARTIST, TYPE_STRING);
66 TYPE_MAPPING.put(ExifInterface.TAG_BITS_PER_SAMPLE, TYPE_INT);
67 TYPE_MAPPING.put(ExifInterface.TAG_COMPRESSION, TYPE_INT);
68 TYPE_MAPPING.put(ExifInterface.TAG_COPYRIGHT, TYPE_STRING);
69 TYPE_MAPPING.put(ExifInterface.TAG_DATETIME, TYPE_STRING);
70 TYPE_MAPPING.put(ExifInterface.TAG_IMAGE_DESCRIPTION, TYPE_STRING);
71 TYPE_MAPPING.put(ExifInterface.TAG_IMAGE_LENGTH, TYPE_INT);
72 TYPE_MAPPING.put(ExifInterface.TAG_IMAGE_WIDTH, TYPE_INT);
73 TYPE_MAPPING.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT, TYPE_INT);
74 TYPE_MAPPING.put(ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, TYPE_INT);
75 TYPE_MAPPING.put(ExifInterface.TAG_MAKE, TYPE_STRING);
76 TYPE_MAPPING.put(ExifInterface.TAG_MODEL, TYPE_STRING);
77 TYPE_MAPPING.put(ExifInterface.TAG_ORIENTATION, TYPE_INT);
78 TYPE_MAPPING.put(ExifInterface.TAG_PHOTOMETRIC_INTERPRETATION, TYPE_INT);
79 TYPE_MAPPING.put(ExifInterface.TAG_PLANAR_CONFIGURATION, TYPE_INT);
80 TYPE_MAPPING.put(ExifInterface.TAG_PRIMARY_CHROMATICITIES, TYPE_DOUBLE);
81 TYPE_MAPPING.put(ExifInterface.TAG_REFERENCE_BLACK_WHITE, TYPE_DOUBLE);
82 TYPE_MAPPING.put(ExifInterface.TAG_RESOLUTION_UNIT, TYPE_INT);
83 TYPE_MAPPING.put(ExifInterface.TAG_ROWS_PER_STRIP, TYPE_INT);
84 TYPE_MAPPING.put(ExifInterface.TAG_SAMPLES_PER_PIXEL, TYPE_INT);
85 TYPE_MAPPING.put(ExifInterface.TAG_SOFTWARE, TYPE_STRING);
86 TYPE_MAPPING.put(ExifInterface.TAG_STRIP_BYTE_COUNTS, TYPE_INT);
87 TYPE_MAPPING.put(ExifInterface.TAG_STRIP_OFFSETS, TYPE_INT);
88 TYPE_MAPPING.put(ExifInterface.TAG_TRANSFER_FUNCTION, TYPE_INT);
89 TYPE_MAPPING.put(ExifInterface.TAG_WHITE_POINT, TYPE_DOUBLE);
90 TYPE_MAPPING.put(ExifInterface.TAG_X_RESOLUTION, TYPE_DOUBLE);
91 TYPE_MAPPING.put(ExifInterface.TAG_Y_CB_CR_COEFFICIENTS, TYPE_DOUBLE);
92 TYPE_MAPPING.put(ExifInterface.TAG_Y_CB_CR_POSITIONING, TYPE_INT);
93 TYPE_MAPPING.put(ExifInterface.TAG_Y_CB_CR_SUB_SAMPLING, TYPE_INT);
94 TYPE_MAPPING.put(ExifInterface.TAG_Y_RESOLUTION, TYPE_DOUBLE);
95 TYPE_MAPPING.put(ExifInterface.TAG_APERTURE_VALUE, TYPE_DOUBLE);
96 TYPE_MAPPING.put(ExifInterface.TAG_BRIGHTNESS_VALUE, TYPE_DOUBLE);
97 TYPE_MAPPING.put(ExifInterface.TAG_CFA_PATTERN, TYPE_STRING);
98 TYPE_MAPPING.put(ExifInterface.TAG_COLOR_SPACE, TYPE_INT);
99 TYPE_MAPPING.put(ExifInterface.TAG_COMPONENTS_CONFIGURATION, TYPE_STRING);
100 TYPE_MAPPING.put(ExifInterface.TAG_COMPRESSED_BITS_PER_PIXEL, TYPE_DOUBLE);
101 TYPE_MAPPING.put(ExifInterface.TAG_CONTRAST, TYPE_INT);
102 TYPE_MAPPING.put(ExifInterface.TAG_CUSTOM_RENDERED, TYPE_INT);
103 TYPE_MAPPING.put(ExifInterface.TAG_DATETIME_DIGITIZED, TYPE_STRING);
104 TYPE_MAPPING.put(ExifInterface.TAG_DATETIME_ORIGINAL, TYPE_STRING);
105 TYPE_MAPPING.put(ExifInterface.TAG_DEVICE_SETTING_DESCRIPTION, TYPE_STRING);
106 TYPE_MAPPING.put(ExifInterface.TAG_DIGITAL_ZOOM_RATIO, TYPE_DOUBLE);
107 TYPE_MAPPING.put(ExifInterface.TAG_EXIF_VERSION, TYPE_STRING);
108 TYPE_MAPPING.put(ExifInterface.TAG_EXPOSURE_BIAS_VALUE, TYPE_DOUBLE);
109 TYPE_MAPPING.put(ExifInterface.TAG_EXPOSURE_INDEX, TYPE_DOUBLE);
110 TYPE_MAPPING.put(ExifInterface.TAG_EXPOSURE_MODE, TYPE_INT);
111 TYPE_MAPPING.put(ExifInterface.TAG_EXPOSURE_PROGRAM, TYPE_INT);
112 TYPE_MAPPING.put(ExifInterface.TAG_EXPOSURE_TIME, TYPE_DOUBLE);
113 TYPE_MAPPING.put(ExifInterface.TAG_F_NUMBER, TYPE_DOUBLE);
114 TYPE_MAPPING.put(ExifInterface.TAG_FILE_SOURCE, TYPE_STRING);
115 TYPE_MAPPING.put(ExifInterface.TAG_FLASH, TYPE_INT);
116 TYPE_MAPPING.put(ExifInterface.TAG_FLASH_ENERGY, TYPE_DOUBLE);
117 TYPE_MAPPING.put(ExifInterface.TAG_FLASHPIX_VERSION, TYPE_STRING);
118 TYPE_MAPPING.put(ExifInterface.TAG_FOCAL_LENGTH, TYPE_DOUBLE);
119 TYPE_MAPPING.put(ExifInterface.TAG_FOCAL_LENGTH_IN_35MM_FILM, TYPE_INT);
120 TYPE_MAPPING.put(ExifInterface.TAG_FOCAL_PLANE_RESOLUTION_UNIT, TYPE_INT);
121 TYPE_MAPPING.put(ExifInterface.TAG_FOCAL_PLANE_X_RESOLUTION, TYPE_DOUBLE);
122 TYPE_MAPPING.put(ExifInterface.TAG_FOCAL_PLANE_Y_RESOLUTION, TYPE_DOUBLE);
123 TYPE_MAPPING.put(ExifInterface.TAG_GAIN_CONTROL, TYPE_INT);
124 TYPE_MAPPING.put(ExifInterface.TAG_ISO_SPEED_RATINGS, TYPE_INT);
125 TYPE_MAPPING.put(ExifInterface.TAG_IMAGE_UNIQUE_ID, TYPE_STRING);
126 TYPE_MAPPING.put(ExifInterface.TAG_LIGHT_SOURCE, TYPE_INT);
127 TYPE_MAPPING.put(ExifInterface.TAG_MAKER_NOTE, TYPE_STRING);
128 TYPE_MAPPING.put(ExifInterface.TAG_MAX_APERTURE_VALUE, TYPE_DOUBLE);
129 TYPE_MAPPING.put(ExifInterface.TAG_METERING_MODE, TYPE_INT);
130 TYPE_MAPPING.put(ExifInterface.TAG_NEW_SUBFILE_TYPE, TYPE_INT);
131 TYPE_MAPPING.put(ExifInterface.TAG_OECF, TYPE_STRING);
132 TYPE_MAPPING.put(ExifInterface.TAG_PIXEL_X_DIMENSION, TYPE_INT);
133 TYPE_MAPPING.put(ExifInterface.TAG_PIXEL_Y_DIMENSION, TYPE_INT);
134 TYPE_MAPPING.put(ExifInterface.TAG_RELATED_SOUND_FILE, TYPE_STRING);
135 TYPE_MAPPING.put(ExifInterface.TAG_SATURATION, TYPE_INT);
136 TYPE_MAPPING.put(ExifInterface.TAG_SCENE_CAPTURE_TYPE, TYPE_INT);
137 TYPE_MAPPING.put(ExifInterface.TAG_SCENE_TYPE, TYPE_STRING);
138 TYPE_MAPPING.put(ExifInterface.TAG_SENSING_METHOD, TYPE_INT);
139 TYPE_MAPPING.put(ExifInterface.TAG_SHARPNESS, TYPE_INT);
140 TYPE_MAPPING.put(ExifInterface.TAG_SHUTTER_SPEED_VALUE, TYPE_DOUBLE);
141 TYPE_MAPPING.put(ExifInterface.TAG_SPATIAL_FREQUENCY_RESPONSE, TYPE_STRING);
142 TYPE_MAPPING.put(ExifInterface.TAG_SPECTRAL_SENSITIVITY, TYPE_STRING);
143 TYPE_MAPPING.put(ExifInterface.TAG_SUBFILE_TYPE, TYPE_INT);
144 TYPE_MAPPING.put(ExifInterface.TAG_SUBSEC_TIME, TYPE_STRING);
145 TYPE_MAPPING.put(ExifInterface.TAG_SUBSEC_TIME_DIGITIZED, TYPE_STRING);
146 TYPE_MAPPING.put(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, TYPE_STRING);
147 TYPE_MAPPING.put(ExifInterface.TAG_SUBJECT_AREA, TYPE_INT);
148 TYPE_MAPPING.put(ExifInterface.TAG_SUBJECT_DISTANCE, TYPE_DOUBLE);
149 TYPE_MAPPING.put(ExifInterface.TAG_SUBJECT_DISTANCE_RANGE, TYPE_INT);
150 TYPE_MAPPING.put(ExifInterface.TAG_SUBJECT_LOCATION, TYPE_INT);
151 TYPE_MAPPING.put(ExifInterface.TAG_USER_COMMENT, TYPE_STRING);
152 TYPE_MAPPING.put(ExifInterface.TAG_WHITE_BALANCE, TYPE_INT);
153 TYPE_MAPPING.put(ExifInterface.TAG_GPS_ALTITUDE, TYPE_DOUBLE);
154 TYPE_MAPPING.put(ExifInterface.TAG_GPS_ALTITUDE_REF, TYPE_INT);
155 TYPE_MAPPING.put(ExifInterface.TAG_GPS_AREA_INFORMATION, TYPE_STRING);
156 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DOP, TYPE_DOUBLE);
157 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DATESTAMP, TYPE_STRING);
158 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_BEARING, TYPE_DOUBLE);
159 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_BEARING_REF, TYPE_STRING);
160 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_DISTANCE, TYPE_DOUBLE);
161 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_DISTANCE_REF, TYPE_STRING);
162 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_LATITUDE, TYPE_DOUBLE);
163 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_LATITUDE_REF, TYPE_STRING);
164 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_LONGITUDE, TYPE_DOUBLE);
165 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DEST_LONGITUDE_REF, TYPE_STRING);
166 TYPE_MAPPING.put(ExifInterface.TAG_GPS_DIFFERENTIAL, TYPE_INT);
167 TYPE_MAPPING.put(ExifInterface.TAG_GPS_IMG_DIRECTION, TYPE_DOUBLE);
168 TYPE_MAPPING.put(ExifInterface.TAG_GPS_IMG_DIRECTION_REF, TYPE_STRING);
169 TYPE_MAPPING.put(ExifInterface.TAG_GPS_LATITUDE, TYPE_DOUBLE);
170 TYPE_MAPPING.put(ExifInterface.TAG_GPS_LATITUDE_REF, TYPE_STRING);
171 TYPE_MAPPING.put(ExifInterface.TAG_GPS_LONGITUDE, TYPE_DOUBLE);
172 TYPE_MAPPING.put(ExifInterface.TAG_GPS_LONGITUDE_REF, TYPE_STRING);
173 TYPE_MAPPING.put(ExifInterface.TAG_GPS_MAP_DATUM, TYPE_STRING);
174 TYPE_MAPPING.put(ExifInterface.TAG_GPS_MEASURE_MODE, TYPE_STRING);
175 TYPE_MAPPING.put(ExifInterface.TAG_GPS_PROCESSING_METHOD, TYPE_STRING);
176 TYPE_MAPPING.put(ExifInterface.TAG_GPS_SATELLITES, TYPE_STRING);
177 TYPE_MAPPING.put(ExifInterface.TAG_GPS_SPEED, TYPE_DOUBLE);
178 TYPE_MAPPING.put(ExifInterface.TAG_GPS_SPEED_REF, TYPE_STRING);
179 TYPE_MAPPING.put(ExifInterface.TAG_GPS_STATUS, TYPE_STRING);
180 TYPE_MAPPING.put(ExifInterface.TAG_GPS_TIMESTAMP, TYPE_STRING);
181 TYPE_MAPPING.put(ExifInterface.TAG_GPS_TRACK, TYPE_DOUBLE);
182 TYPE_MAPPING.put(ExifInterface.TAG_GPS_TRACK_REF, TYPE_STRING);
183 TYPE_MAPPING.put(ExifInterface.TAG_GPS_VERSION_ID, TYPE_STRING);
184 TYPE_MAPPING.put(ExifInterface.TAG_INTEROPERABILITY_INDEX, TYPE_STRING);
185 TYPE_MAPPING.put(ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH, TYPE_INT);
186 TYPE_MAPPING.put(ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH, TYPE_INT);
187 TYPE_MAPPING.put(ExifInterface.TAG_DNG_VERSION, TYPE_INT);
188 TYPE_MAPPING.put(ExifInterface.TAG_DEFAULT_CROP_SIZE, TYPE_INT);
189 //I don't know how to represent this. Type is unknown
190 //TYPE_MAPPING.put(ExifInterface.TAG_ORF_THUMBNAIL_IMAGE, TYPE_STRING);
191 TYPE_MAPPING.put(ExifInterface.TAG_ORF_PREVIEW_IMAGE_START, TYPE_INT);
192 TYPE_MAPPING.put(ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH, TYPE_INT);
193 TYPE_MAPPING.put(ExifInterface.TAG_ORF_ASPECT_FRAME, TYPE_INT);
194 TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER, TYPE_INT);
195 TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER, TYPE_INT);
196 TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER, TYPE_INT);
197 TYPE_MAPPING.put(ExifInterface.TAG_RW2_SENSOR_TOP_BORDER, TYPE_INT);
198 TYPE_MAPPING.put(ExifInterface.TAG_RW2_ISO, TYPE_INT);
199 ALL_KNOWN_EXIF_KEYS = TYPE_MAPPING.keySet().toArray(new String[TYPE_MAPPING.size()]);
200 }
201 private static final String JPG_MIME_TYPE = "image/jpg";
202 private static final String JPEG_MIME_TYPE = "image/jpeg";
203
204 /**
205 * Generic metadata retrieval method that can retrieve any available metadata from a given doc
206 * Currently only functions for exifdata
207 *
208 * @param metadata the bundle to which we add any relevant metadata
209 * @param stream InputStream containing a file
210 * @param mimeType type of the given file
211 * @param tags a variable amount of keys to differentiate which tags the user wants
212 * if null, returns a default set of data from the following keys:
213 * Exif data:
214 * ExifInterface.TAG_IMAGE_WIDTH,
215 * ExifInterface.TAG_IMAGE_LENGTH,
216 * ExifInterface.TAG_DATETIME,
217 * ExifInterface.TAG_GPS_LATITUDE,
218 * ExifInterface.TAG_GPS_LONGITUDE,
219 * ExifInterface.TAG_MAKE,
220 * ExifInterface.TAG_MODEL,
221 * ExifInterface.TAG_APERTURE,
222 * ExifInterface.TAG_SHUTTER_SPEED_VALUE
223 * @throws IOException when the file doesn't exist
224 */
225 public static void getMetadata(Bundle metadata, InputStream stream, String mimeType,
226 @Nullable String[] tags) throws IOException {
227 List<String> metadataTypes = new ArrayList();
228 if (mimeType.equals(JPG_MIME_TYPE) || mimeType.equals(JPEG_MIME_TYPE)) {
229 ExifInterface exifInterface = new ExifInterface(stream);
230 Bundle exifData = getExifData(exifInterface, tags);
231 if (exifData.size() > 0) {
232 metadata.putBundle(DocumentsContract.METADATA_EXIF, exifData);
233 metadataTypes.add(DocumentsContract.METADATA_EXIF);
234 }
235 }
236 metadata.putStringArray(DocumentsContract.METADATA_TYPES,
237 metadataTypes.toArray(new String[metadataTypes.size()]));
238 // TODO: Add support for PDF and Video metadata
239 // TODO: Broaden image support to all images
240 }
241
242 /**
243 * Helper method that is called if getMetadata is called for an image mimeType.
244 *
245 * @param exif the bundle to which we add exif data.
246 * @param exifInterface an ExifInterface for an image
247 * @param tags a list of ExifInterface tags that are used to retrieve data.
248 * if null, returns a default set of data from the following keys:
249 * ExifInterface.TAG_IMAGE_WIDTH,
250 * ExifInterface.TAG_IMAGE_LENGTH,
251 * ExifInterface.TAG_DATETIME,
252 * ExifInterface.TAG_GPS_LATITUDE,
253 * ExifInterface.TAG_GPS_LONGITUDE,
254 * ExifInterface.TAG_MAKE,
255 * ExifInterface.TAG_MODEL,
256 * ExifInterface.TAG_APERTURE,
257 * ExifInterface.TAG_SHUTTER_SPEED_VALUE
258 */
259 private static Bundle getExifData(ExifInterface exifInterface, @Nullable String[] tags)
260 throws IOException {
261 if (tags == null) {
262 tags = DEFAULT_EXIF_TAGS;
263 }
264 Bundle exif = new Bundle();
265 for (int i = 0; i < tags.length; i++) {
266 if (TYPE_MAPPING.get(tags[i]).equals(TYPE_INT)) {
267 int data = exifInterface.getAttributeInt(tags[i], Integer.MIN_VALUE);
268 if (data != Integer.MIN_VALUE) {
269 exif.putInt(tags[i], data);
270 }
271 } else if (TYPE_MAPPING.get(tags[i]).equals(TYPE_DOUBLE)) {
272 double data = exifInterface.getAttributeDouble(tags[i], Double.MIN_VALUE);
273 if (data != Double.MIN_VALUE) {
274 exif.putDouble(tags[i], data);
275 }
276 } else if (TYPE_MAPPING.get(tags[i]).equals(TYPE_STRING)) {
277 String data = exifInterface.getAttribute(tags[i]);
278 if (data != null) {
279 exif.putString(tags[i], data);
280 }
281 }
282 }
283 return exif;
284 }
285}