This project has retired. For details please refer to its
Attic page.
PropertyMapperExif xref
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.client.mapper;
20
21 import java.lang.reflect.Array;
22 import java.text.DateFormat;
23 import java.text.ParseException;
24 import java.text.SimpleDateFormat;
25 import java.util.Date;
26 import java.util.GregorianCalendar;
27 import java.util.HashMap;
28 import java.util.Map;
29 import java.util.Properties;
30 import java.util.Set;
31
32 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
33 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
34 import org.apache.chemistry.opencmis.commons.enums.PropertyType;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import com.drew.imaging.PhotographicConversions;
39 import com.drew.lang.Rational;
40 import com.drew.metadata.Directory;
41 import com.drew.metadata.Tag;
42 import com.drew.metadata.exif.ExifDirectory;
43 import com.drew.metadata.exif.GpsDirectory;
44 import com.drew.metadata.jpeg.JpegDirectory;
45
46 public class PropertyMapperExif extends AbstractPropertyMapper {
47
48 private static final Log LOG = LogFactory.getLog(PropertyMapperExif.class.getName());
49 private static String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss";
50
51 private Map<String, String> propMapExif = new HashMap<String, String> ();
52 private Map<String, String> propMapGps = new HashMap<String, String> ();
53 private Map<String, String> propMapJpeg = new HashMap<String, String> ();
54
55 protected Map<String, Object> propMap;
56
57 public boolean initialize(String cfgPrefix, String typeKey, Properties properties) {
58 super.initialize(cfgPrefix, typeKey, properties);
59 reset();
60 dateFormat = EXIF_DATE_FORMAT;
61 buildIdMap("exif", propMapExif, properties);
62 buildIdMap("gps", propMapGps, properties);
63 buildIdMap("jpeg", propMapJpeg, properties);
64
65 return true;
66 }
67
68 public void reset() {
69 propMap = new HashMap<String, Object> ();
70 }
71
72
73 public Map<String, Object> getMappedProperties() {
74 return propMap;
75 }
76
77 private void buildIdMap(String dirKey, Map<String, String> propMap, Properties properties) {
78 Set<String> keys = properties.stringPropertyNames();
79 String prefix = propPrefix + "." + dirKey + ".id.";
80 for (String key : keys) {
81 if (key.startsWith(prefix)) {
82 String id = key.substring(prefix.length());
83 String cmisPropId = properties.getProperty(key).trim();
84 if (null == cmisPropId)
85 throw new MapperException("Configuration key " + key + " must have a value assigned");
86 LOG.debug("Found mapping for type " + dirKey + " with " + id + " to " + cmisPropId);
87 propMap.put(id, cmisPropId);
88 }
89 }
90 }
91
92 public String getMappedTypeId(String mimeType) {
93 return cmisTypeId;
94 }
95
96 public String getMappedPropertyId(String key) {
97 return null;
98 }
99
100 public Object convertValue(String id, PropertyDefinition<?> propDef, String strValue) {
101 return null;
102 }
103
104 private String getHexString(int tagType) {
105 StringBuffer hexStr = new StringBuffer();
106 hexStr.append(Integer.toHexString(tagType));
107 while (hexStr.length() < 4)
108 hexStr.insert(0, "0");
109 hexStr.insert(0, "0x");
110 return hexStr.toString();
111 }
112
113
114
115
116
117
118
119
120 public void mapTagAndConvert(Directory dir, Tag tag, TypeDefinition td) {
121 String propId = null;
122 String hexStr = getHexString(tag.getTagType());
123
124 if (GpsDirectory.class.equals(dir.getClass())) {
125 propId = propMapGps.get(hexStr);
126 } else if (ExifDirectory.class.equals(dir.getClass())) {
127 propId = propMapExif.get(hexStr);
128 } else if (JpegDirectory.class.equals(dir.getClass())) {
129 propId = propMapJpeg.get(hexStr);
130 } else
131 propId = null;
132
133 if (null != propId) {
134 if (null != td) {
135 PropertyDefinition<?> pd = td.getPropertyDefinitions().get(propId);
136 if (null == pd)
137 throw new MapperException("Unknown property id " + propId + " in type definition " + td.getId());
138 PropertyType pt = pd.getPropertyType();
139 Object convValue = convertValue(dir, tag, pt);
140 propMap.put(propId, convValue);
141 } else
142 propMap.put(propId, dir.getObject(tag.getTagType()));
143 }
144 }
145
146 public Object convertValue(Directory dir, Tag tag, PropertyType propType) {
147
148 Object res = null;
149 String hexStr = getHexString(tag.getTagType());
150
151
152 if (GpsDirectory.class.equals(dir.getClass())) {
153
154 if ( GpsDirectory.TAG_GPS_LONGITUDE == tag.getTagType()) {
155 Object ref = dir.getObject(GpsDirectory.TAG_GPS_DEST_LONGITUDE_REF);
156 boolean mustInv = ref != null && ref.equals('W');
157 return convertGps(tag, dir, mustInv);
158 } else if ( GpsDirectory.TAG_GPS_LATITUDE == tag.getTagType()) {
159 Object ref = dir.getObject(GpsDirectory.TAG_GPS_DEST_LONGITUDE_REF);
160 boolean mustInv = ref != null && ref.equals('S');
161 return convertGps(tag, dir, mustInv);
162 } else {
163 String propId = propMapGps.get(hexStr);
164 LOG.debug("Found GPS tag '" + tag + "\', property mapped is: " + propId);
165 if (null == propId) {
166 LOG.info("Ignoring EXIF tag '" + tag + "\' no property mapped to this tag.");
167 } else if (propType == null) {
168
169 LOG.error("Ignoring EXIF tag '" + tag + "\' no property type mapped to this tag.");
170 }
171 Object src = dir.getObject(tag.getTagType());
172 Class<?> clazz = src.getClass();
173 if (clazz.equals(Rational.class)) {
174
175 if (propType != PropertyType.DECIMAL)
176 throw new MapperException("Tag value has type Rational and expected CMIS Decimal, but found: " + propType + " for tag: " + tag);
177 double d = ((Rational) src).doubleValue();
178 res = d;
179 } else if (clazz.equals(String.class)) {
180 if (propType != PropertyType.STRING && propType != PropertyType.ID && propType != PropertyType.URI &&
181 propType != PropertyType.HTML && propType != PropertyType.DATETIME)
182 throw new MapperException("Tag value has type String and expected CMIS String, but found: " + propType + " for tag: " + tag);
183 String s = ((String) src);
184 res = s;
185 } else
186 res = null;
187 }
188 } else if (ExifDirectory.class.equals(dir.getClass())) {
189
190 String propId = propMapExif.get(hexStr);
191 LOG.debug("Found EXIF tag '" + tag + "\', property mapped is: " + propId);
192
193 if (null == propId) {
194 LOG.debug("Ignoring EXIF tag '" + tag + "\' no property mapped to this tag.");
195 } else if (propType == null) {
196
197 LOG.error("Ignoring EXIF tag '" + tag + "\' no property type mapped to this tag.");
198 } else {
199 Object src = dir.getObject(tag.getTagType());
200 Class<?> clazz = src.getClass();
201
202 if (clazz.isArray()) {
203 LOG.error("Found a multi-value tag " + tag + ": multi value not implemented");
204 return null;
205 }
206 if (clazz.equals(Rational.class)) {
207
208 if (propType != PropertyType.DECIMAL)
209 throw new MapperException("Tag value has type Rational and expected CMIS Decimal, but found: " + propType + " for tag: " + tag);
210
211 if (tag.getTagType() == ExifDirectory.TAG_SHUTTER_SPEED) {
212
213 double apexValue = ((Rational) src).doubleValue();
214 res = PhotographicConversions.shutterSpeedToExposureTime(apexValue);
215 } else if (tag.getTagType() == (ExifDirectory.TAG_APERTURE)) {
216 double aperture =((Rational) src).doubleValue();
217 double fStop = PhotographicConversions.apertureToFStop(aperture);
218 res = fStop;
219 } else {
220
221 double d = ((Rational) src).doubleValue();
222 res = d;
223 }
224 } else if (clazz.equals(Integer.class)) {
225 if (propType != PropertyType.INTEGER)
226 throw new MapperException("Tag value has type Integer and expected CMIS Integer, but found: " + propType + " for tag: " + tag);
227
228 long l = ((Integer) src).longValue();
229 res = l;
230 } else if (clazz.equals(String.class)) {
231 if (propType != PropertyType.STRING && propType != PropertyType.ID && propType != PropertyType.URI &&
232 propType != PropertyType.HTML && propType != PropertyType.DATETIME)
233 throw new MapperException("Tag value has type String and expected CMIS String, but found: " + propType + " for tag: " + tag);
234
235 if (propType == PropertyType.DATETIME) {
236
237 DateFormat formatter = new SimpleDateFormat(dateFormat);
238 GregorianCalendar cal;
239 try {
240 Date date = (Date)formatter.parse((String) src);
241
242 cal = new GregorianCalendar();
243 cal.setTime(date);
244 } catch (ParseException e) {
245 LOG.error(e);
246 throw new MapperException("Unrecognized date format in EXIF date tag: " + src + " for tag: " + tag + " expected: yyyy:MM:dd HH:mm:ss");
247 }
248 res = cal;
249 } else {
250 String s = ((String) src);
251 res = s;
252 }
253 } else if (clazz.equals(Date.class)) {
254 if (propType != PropertyType.DATETIME)
255 throw new MapperException("Tag value has type Date and expected CMIS DateTime, but found: " + propType + " for tag: " + tag);
256
257 Date date = ((Date) src);
258
259 GregorianCalendar cal= new GregorianCalendar();
260 cal.setTime(date);
261 res = cal;
262 } else if (clazz.equals(Boolean.class)) {
263 if (propType != PropertyType.BOOLEAN)
264 throw new MapperException("Tag value has type Boolean and expected CMIS Boolean, but found: " + propType + " for tag: " + tag);
265
266 Boolean b = ((Boolean) src);
267 res = b;
268 } else {
269 LOG.debug("Tag value has unsupported type: " + clazz.getName() + " for EXIF tag: " + tag);
270
271 }
272 }
273 } else if (JpegDirectory.class.equals(dir.getClass())) {
274
275 String propId = propMapJpeg.get(hexStr);
276 LOG.debug("Found JPEG tag '" + tag + "\', property mapped is: " + propId);
277
278 if (null == propId) {
279 LOG.info("Ignoring JPEG tag '" + tag + "\' no property mapped to this tag.");
280 } else if (propType == null) {
281
282 LOG.error("Ignoring JPEG tag '" + tag + "\' no property type mapped to this tag.");
283 } else {
284 Object src = dir.getObject(tag.getTagType());
285 Class<?> clazz = src.getClass();
286
287 if (clazz.equals(Integer.class)) {
288 if (propType != PropertyType.INTEGER)
289 throw new MapperException("Tag value has type Integer and expected CMIS Integer, but found: " + propType + " for tag: " + tag);
290
291 long l = ((Integer) src).longValue();
292 res = l;
293 } else {
294 LOG.debug("Tag value has unsupported type: " + clazz.getName() + " for JPEG tag: " + tag);
295 }
296 }
297 }
298
299 return res;
300 }
301
302 private static Object convertGps(Tag tag, Directory dir, boolean mustInvert) {
303 Double res = null;
304 Object src = dir.getObject(tag.getTagType());
305
306 Class<?> stringArrayClass = src.getClass();
307 Class<?> stringArrayComponentType = stringArrayClass.getComponentType();
308 if (!stringArrayClass.isArray() || null == stringArrayComponentType || Array.getLength(src) != 3)
309 throw new MapperException("GPS coordinate \"" + tag + "\" has unknown type.");
310 if (!stringArrayComponentType.equals(Rational.class))
311 throw new MapperException("GPS coordinate \"" + tag + "\" has unknown component type (expected Rational, found: " +
312 stringArrayComponentType.getName() + ")");
313
314 Rational[] components;
315 components = (Rational[]) src;
316 int deg = components[0].intValue();
317 double min = components[1].doubleValue();
318 double sec = components[2].doubleValue();
319 Double d = (deg + min / 60 + sec / 3600);
320 if (d > 0.0 && mustInvert)
321 d = -d;
322 res = d;
323 return res;
324 }
325 }