Package org.fluxtream.core.utils

Source Code of org.fluxtream.core.utils.ImageUtils$GeolocationImpl

package org.fluxtream.core.utils;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.GeoLocation;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.GpsDescriptor;
import com.drew.metadata.exif.GpsDirectory;
import org.fluxtream.core.domain.Geolocation;
import org.fluxtream.core.images.Image;
import org.fluxtream.core.images.ImageOrientation;
import org.fluxtream.core.images.ImageType;
import org.fluxtream.core.images.JpegImage;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.fluxtream.core.aspects.FlxLogger;
import org.imgscalr.Scalr;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* <p>
* <code>ImageUtils</code> provides helpful methods for dealing with images.
* </p>
*
* @author Chris Bartley (bartley@cmu.edu)
*/
public final class ImageUtils {
    private static final FlxLogger LOG = FlxLogger.getLogger(ImageUtils.class);

    private static final class GeolocationImpl implements Geolocation {
        @Nullable
        private final Double latitude;

        @Nullable
        private final Double longitude;

        @Nullable
        private final Float heading;

        @Nullable
        private final String headingRef;

        @Nullable
        private final Float altitude;

        @Nullable
        private final Integer altitudeRef;

        @Nullable
        private final Float precision;

        @Nullable
        private final String gpsDatestamp;

        @Nullable
        private final String gpsTimestamp;

        private GeolocationImpl(@NotNull final GpsDirectory gpsDirectory) {
            final String latitudeRef = gpsDirectory.getString(GpsDirectory.TAG_GPS_LATITUDE_REF);
            final String longitudeRef = gpsDirectory.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF);
            final Rational[] latitudeRationals = gpsDirectory.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
            final Rational[] longitudeRationals = gpsDirectory.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
            latitude = (latitudeRationals == null) ? null : GeoLocation.degreesMinutesSecondsToDecimal(latitudeRationals[0], latitudeRationals[1], latitudeRationals[2], "S".equals(latitudeRef));
            longitude = (longitudeRationals == null) ? null : GeoLocation.degreesMinutesSecondsToDecimal(longitudeRationals[0], longitudeRationals[1], longitudeRationals[2], "W".equals(longitudeRef));

            final Rational headingRational = gpsDirectory.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
            heading = (headingRational == null) ? null : headingRational.floatValue();
            headingRef = gpsDirectory.getString(GpsDirectory.TAG_GPS_IMG_DIRECTION_REF);

            final Rational altitudeRational = gpsDirectory.getRational(GpsDirectory.TAG_GPS_ALTITUDE);
            altitude = (altitudeRational == null) ? null : altitudeRational.floatValue();

            Integer altitudeRefInteger;
            try {
                altitudeRefInteger = gpsDirectory.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
            }
            catch (MetadataException e) {
                altitudeRefInteger = null;
            }
            altitudeRef = altitudeRefInteger;

            final Rational precisionRational = gpsDirectory.getRational(GpsDirectory.TAG_GPS_DOP);
            precision = (precisionRational == null) ? null : precisionRational.floatValue();

            gpsDatestamp = gpsDirectory.getString(GpsDirectory.TAG_GPS_DATE_STAMP);

            final GpsDescriptor gpsDescriptor = new GpsDescriptor(gpsDirectory);
            gpsTimestamp = gpsDescriptor.getGpsTimeStampDescription();
        }

        @Override
        @Nullable
        public Double getLatitude() {
            return latitude;
        }

        @Override
        @Nullable
        public Double getLongitude() {
            return longitude;
        }

        @Override
        @Nullable
        public Float getHeading() {
            return heading;
        }

        @Override
        @Nullable
        public String getHeadingRef() {
            return headingRef;
        }

        @Override
        @Nullable
        public Float getAltitude() {
            return altitude;
        }

        @Override
        @Nullable
        public Integer getAltitudeRef() {
            return altitudeRef;
        }

        @Override
        @Nullable
        public Float getGpsPrecision() {
            return precision;
        }

        @Override
        @Nullable
        public String getGpsDatestamp() {
            return gpsDatestamp;
        }

        @Override
        @Nullable
        public String getGpsTimestamp() {
            return gpsTimestamp;
        }
    }

    /**
     * Tries to read the given <code>imageBytes</code> and returns <code>true</code> if it's a GIF, JPEG, or PNG image;
     * returns <code>false</code> otherwise.  Returns <code>false</code> if the given byte array is <code>null</code> or
     * empty.
     */
    public static boolean isSupportedImage(@Nullable final byte[] imageBytes) {
        return getImageType(imageBytes) != null;
    }

    /**
     * Tries to create a JPEG thumbnail of the given image with the given desired dimensions.  Returns <code>null</code>
     * if the given byte array is <code>null</code> or empty, if the desired <code>lengthOfLongestSideInPixels</code> is
     * zero or negative, or if the bytes cannot be read as an image.  This method will attempt to read orientation info
     * from the EXIF and, if necessary, rotate/flip the thumbnail appropriately.  Note that if the image has an alpha
     * channel, it will be discarded before generating the thumbnail.
     *
     * @throws IOException if a problem occurs while reading the image or generating the thumbnail
     */
    @Nullable
    public static Image createJpegThumbnail(@Nullable final byte[] imageBytes, final int lengthOfLongestSideInPixels) throws IOException {
        if (imageBytes != null && imageBytes.length > 0 && lengthOfLongestSideInPixels > 0) {

            ImageOrientation orientation = ImageOrientation.getOrientation(new ByteArrayInputStream(imageBytes));
            if (orientation == null) {
                orientation = ImageOrientation.ORIENTATION_1;
            }

            try {
                BufferedImage image = convertToBufferedImage(imageBytes);
                if (image != null) {
                    // drop the alpha channel, if one exists
                    if (image.getColorModel().hasAlpha()) {
                        image = dropAlphaChannel(image);
                    }
                    return JpegImage.create(orientation.transform(Scalr.resize(image, Scalr.Method.AUTOMATIC, Scalr.Mode.AUTOMATIC, lengthOfLongestSideInPixels)));
                }
            }
            catch (Exception e) {
                final String message = "Exception while trying to create a thumbnail";
                LOG.error(message, e);
                throw new IOException(e);
            }
        }

        return null;
    }

    // I stole this from: https://github.com/thebuzzmedia/imgscalr/issues/82#issuecomment-11776976
    @NotNull
    private static BufferedImage dropAlphaChannel(@NotNull final BufferedImage srcImage) {
        final BufferedImage convertedImg = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_INT_RGB);
        convertedImg.getGraphics().drawImage(srcImage, 0, 0, null);

        return convertedImg;
    }

    @Nullable
    public static Geolocation getGeolocation(@Nullable final byte[] imageBytes) throws ImageProcessingException, IOException {
        if (imageBytes != null && imageBytes.length > 0) {

            final Metadata metadata = ImageMetadataReader.readMetadata(new BufferedInputStream(new ByteArrayInputStream(imageBytes)), false);
            if (metadata != null) {
                final GpsDirectory gpsDirectory = metadata.getDirectory(GpsDirectory.class);
                if (gpsDirectory != null) {
                    return new GeolocationImpl(gpsDirectory);
                }
            }
        }
        return null;
    }

    @Nullable
    public static ImageOrientation getOrientation(@Nullable final byte[] imageBytes) {
        if (imageBytes != null && imageBytes.length > 0) {
            return ImageOrientation.getOrientation(new ByteArrayInputStream(imageBytes));
        }
        return null;
    }

    @Nullable
    public static BufferedImage convertToBufferedImage(@Nullable final byte[] imageBytes) throws IOException {
        if (imageBytes != null && imageBytes.length > 0) {
            return ImageIO.read(new ByteArrayInputStream(imageBytes));
        }
        return null;
    }

    @Nullable
    public static byte[] convertToJpegByteArray(@Nullable final BufferedImage image) throws IOException {
        if (image != null) {
            final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            if (ImageIO.write(image, "JPG", byteArrayOutputStream)) {
                return byteArrayOutputStream.toByteArray();
            }
        }
        return null;
    }

    /**
     * Returns the {@link ImageType} of the given image, or <code>null</code> if the type is unknown, not supported, or
     * if an error occurs while trying to read the image. Returns <code>null</code> if the given image byte array is
     * <code>null</code> or empty.
     */
    @Nullable
    public static ImageType getImageType(@Nullable final byte[] imageBytes) {
        if ((imageBytes != null) && (imageBytes.length > 0)) {
            try {
                final ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(imageBytes));
                final Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(iis);
                if (imageReaders != null) {
                    while (imageReaders.hasNext()) {
                        final ImageReader reader = imageReaders.next();
                        final ImageType imageType = ImageType.findByFormatName(reader.getFormatName());
                        if (imageType != null) {
                            return imageType;
                        }
                    }
                }
            }
            catch (IOException e) {
                LOG.error("IOException while trying to read the image type, returning null");
            }
        }

        return null;
    }

    private ImageUtils() {
        // private to prevent instantiation
    }
}
TOP

Related Classes of org.fluxtream.core.utils.ImageUtils$GeolocationImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.