package org.fluxtream.core.images; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import com.drew.imaging.ImageMetadataReader; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.exif.ExifIFD0Directory; import org.fluxtream.core.aspects.FlxLogger; import org.imgscalr.Scalr; import org.jetbrains.annotations.Nullable; /** * An enum for recording image orientation and what operation(s) needs to be applied in order to transform it. * There are eight possible orientations, shown here (taken from http://sylvana.net/jpegcrop/exif_orientation.html): * <pre> * 1 2 3 4 5 6 7 8 * * 888888 888888 88 88 8888888888 88 88 8888888888 * 88 88 88 88 88 88 88 88 88 88 88 88 * 8888 8888 8888 8888 88 8888888888 8888888888 88 * 88 88 88 88 * 88 88 888888 888888 * </pre> */ public enum ImageOrientation { ORIENTATION_1(1, null, null), ORIENTATION_2(2, null, Scalr.Rotation.FLIP_HORZ), ORIENTATION_3(3, Scalr.Rotation.CW_180, null), ORIENTATION_4(4, null, Scalr.Rotation.FLIP_VERT), ORIENTATION_5(5, Scalr.Rotation.CW_90, Scalr.Rotation.FLIP_HORZ), ORIENTATION_6(6, Scalr.Rotation.CW_90, null), ORIENTATION_7(7, Scalr.Rotation.CW_270, Scalr.Rotation.FLIP_HORZ), ORIENTATION_8(8, Scalr.Rotation.CW_270, null); private static final FlxLogger LOG = FlxLogger.getLogger(ImageOrientation.class); private static final Map<Integer, ImageOrientation> ID_TO_BAUD_RATE_MAP; static { final Map<Integer, ImageOrientation> idToOrienationMap = new HashMap<Integer, ImageOrientation>(); for (final ImageOrientation orientation : ImageOrientation.values()) { idToOrienationMap.put(orientation.getId(), orientation); } ID_TO_BAUD_RATE_MAP = Collections.unmodifiableMap(idToOrienationMap); } @Nullable public static ImageOrientation findById(final int id) { return ID_TO_BAUD_RATE_MAP.get(id); } /** * Tries to read the EXIF orientation data in the image in the {@link InputStream}. Returns <code>null</code> * if not found or if an error occurs. */ @Nullable public static ImageOrientation getOrientation(@Nullable final InputStream inputStream) { if (inputStream != null) { try { return getOrientation(ImageMetadataReader.readMetadata(new BufferedInputStream(inputStream), true)); } catch (Exception e) { LOG.info("ImageOrientation.getOrientation(): Exception while trying to read the orientation data from the EXIF. Ignoring and just returning null" + e); } } return null; } /** * Tries to read the orientation data from the given image {@link Metadata}. Returns <code>null</code> if not * found or if an error occurs. */ @Nullable public static ImageOrientation getOrientation(@Nullable final Metadata metadata) { if (metadata != null) { final Directory exifIfd0Directory = metadata.getDirectory(ExifIFD0Directory.class); if (exifIfd0Directory != null) { try { return findById(exifIfd0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION)); } catch (Exception e) { LOG.info("ImageOrientation.getOrientation(): Exception while trying to read the orientation data from the EXIF. Ignoring and just returning null"); } } } return null; } private final int id; @Nullable private final Scalr.Rotation rotation; @Nullable private final Scalr.Rotation flip; private ImageOrientation(final int id, @Nullable final Scalr.Rotation rotation, @Nullable final Scalr.Rotation flip) { this.id = id; this.rotation = rotation; this.flip = flip; } public int getId() { return id; } @Nullable public BufferedImage transform(@Nullable final BufferedImage image) { BufferedImage transformedImage = image; if (transformedImage != null) { if (rotation != null) { transformedImage = Scalr.rotate(transformedImage, rotation); } if (flip != null) { transformedImage = Scalr.rotate(transformedImage, flip); } } return transformedImage; } }