java 提取 jpeg 图像细节

java extract jpeg image details

我有一张包含一些细节的 JPEG 图片。

我通过如下编码从图像中提取了一些元数据:

public class Test {
public static void main(String[] args){
    test1();

}

public static void test1(){
    File file = new File("DSC_0410.JPG");
    System.out.println(file.getAbsolutePath());
    try {
        extractDetails(file);
    } catch (IOException ex) {
        System.out.println(ex.getMessage());
    }
}

private static void extractDetails(File file) throws IOException {
    ImageInputStream is = ImageIO.createImageInputStream( new BufferedInputStream(new FileInputStream(file)));
    Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType("image/jpeg");
    IIOImage image = null;
    if (readers.hasNext()) {
        ImageReader reader = readers.next();
        reader.setInput(is, true);

        image = reader.readAll(0, null);

        IIOMetadata metadata = image.getMetadata();
        String[] names = metadata.getMetadataFormatNames();
        for (int i = 0; i < names.length; i++) {

                System.out.println("Format name: " + names[ i]);
                Node n = (metadata.getAsTree(names[i]));
                System.out.println(n.getNodeValue());
                showTree(n);
        }
    }
}
private static void showTree(Node node){
    System.out.println(node.getNodeValue());
    NodeList childs = node.getChildNodes();
    if(childs.getLength()==0)
        return;
    for(int i=0; i<childs.getLength(); i++){
        System.out.print("\t");
        showTree(childs.item(i));
    }
}

但它输出空值:

null
null
   null
   null
   null
   null
   null
   null
   null
   null
   null
   null
   null
   null
   null
Format name: javax_imageio_1.0
null
null
   null
   null
   null
   null
   null
   null

来自 here 的另一个代码示例输出了一些元数据但不是我想要的数据(纬度、经度、高度如图所示):

Format name: javax_imageio_jpeg_image_1.0
<javax_imageio_jpeg_image_1.0>
   <JPEGvariety/>
   <markerSequence>
       <unknown MarkerTag="225"/>
       <dqt>
           <dqtable elementPrecision="0" qtableId="0"/>
           <dqtable elementPrecision="0" qtableId="1"/>
       </dqt>
       <sof process="0" samplePrecision="8" numLines="4032" samplesPerLine="6048" numFrameComponents="3">
           <componentSpec componentId="1" HsamplingFactor="2" VsamplingFactor="1" QtableSelector="0"/>
           <componentSpec componentId="2" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/>
           <componentSpec componentId="3" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/>
       </sof>
       <dht>
           <dhtable class="0" htableId="0"/>
           <dhtable class="1" htableId="0"/>
           <dhtable class="0" htableId="1"/>
           <dhtable class="1" htableId="1"/>
       </dht>
       <sos numScanComponents="3" startSpectralSelection="0" endSpectralSelection="63" approxHigh="0" approxLow="0">
           <scanComponentSpec componentSelector="1" dcHuffTable="0" acHuffTable="0"/>
           <scanComponentSpec componentSelector="2" dcHuffTable="1" acHuffTable="1"/>
           <scanComponentSpec componentSelector="3" dcHuffTable="1" acHuffTable="1"/>
       </sos>
   </markerSequence>
</javax_imageio_jpeg_image_1.0>
Format name: javax_imageio_1.0
<javax_imageio_1.0>
   <Chroma>
       <ColorSpaceType name="YCbCr"/>
       <NumChannels value="3"/>
   </Chroma>
   <Compression>
       <CompressionTypeName value="JPEG"/>
       <Lossless value="FALSE"/>
       <NumProgressiveScans value="1"/>
   </Compression>
   <Dimension>
       <ImageOrientation value="normal"/>
   </Dimension>
</javax_imageio_1.0>

我想从 JPEG 图像中提取纬度、经度和海拔高度。请帮忙!

here 下载 apache sanselan 库并使用它。提取包含 GPS 元数据的所有元数据的完整示例:

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.IImageMetadata;
import org.apache.sanselan.common.ImageMetadata.Item;
import org.apache.sanselan.common.RationalNumber;
import org.apache.sanselan.formats.jpeg.JpegImageMetadata;
import org.apache.sanselan.formats.tiff.TiffField;
import org.apache.sanselan.formats.tiff.TiffImageMetadata;
import org.apache.sanselan.formats.tiff.constants.ExifTagConstants;
import org.apache.sanselan.formats.tiff.constants.GPSTagConstants;
import org.apache.sanselan.formats.tiff.constants.TiffTagConstants;
import org.apache.sanselan.formats.tiff.constants.TagInfo;

public class MetadataExample {
   public static void metadataExample(final File file) throws ImageReadException,
        IOException {
    // get all metadata stored in EXIF format (ie. from JPEG or TIFF).
    final IImageMetadata metadata =  Sanselan.getMetadata(file);


    // System.out.println(metadata);

    if (metadata instanceof JpegImageMetadata) {
        final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;

        // Jpeg EXIF metadata is stored in a TIFF-based directory structure
        // and is identified with TIFF tags.
        // Here we look for the "x resolution" tag, but
        // we could just as easily search for any other tag.
        //
        // see the TiffConstants file for a list of TIFF tags.

        System.out.println("file: " + file.getPath());

        // print out various interesting EXIF tags.
        printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_XRESOLUTION);
        printTagValue(jpegMetadata, TiffTagConstants.TIFF_TAG_DATE_TIME);
        printTagValue(jpegMetadata,
                ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
        //printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_DATE_TIME_DIGITIZED);
        printTagValue(jpegMetadata, ExifTagConstants.EXIF_TAG_ISO);
        printTagValue(jpegMetadata,
                ExifTagConstants.EXIF_TAG_SHUTTER_SPEED_VALUE);
        printTagValue(jpegMetadata,
                ExifTagConstants.EXIF_TAG_APERTURE_VALUE);
        printTagValue(jpegMetadata,
                ExifTagConstants.EXIF_TAG_BRIGHTNESS_VALUE);
        printTagValue(jpegMetadata,
                GPSTagConstants.GPS_TAG_GPS_LATITUDE_REF);
        printTagValue(jpegMetadata, GPSTagConstants.GPS_TAG_GPS_LATITUDE);
        printTagValue(jpegMetadata,
                GPSTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
        printTagValue(jpegMetadata, GPSTagConstants.GPS_TAG_GPS_LONGITUDE);

        System.out.println();

        // simple interface to GPS data
        final TiffImageMetadata exifMetadata = jpegMetadata.getExif();
        if (null != exifMetadata) {
            final TiffImageMetadata.GPSInfo gpsInfo = exifMetadata.getGPS();
            if (null != gpsInfo) {
                final String gpsDescription = gpsInfo.toString();
                final double longitude = gpsInfo.getLongitudeAsDegreesEast();
                final double latitude = gpsInfo.getLatitudeAsDegreesNorth();

                System.out.println("    " + "GPS Description: "
                        + gpsDescription);
                System.out.println("    "
                        + "GPS Longitude (Degrees East): " + longitude);
                System.out.println("    "
                        + "GPS Latitude (Degrees North): " + latitude);
            }
        }

        // more specific example of how to manually access GPS values
        final TiffField gpsLatitudeRefField = jpegMetadata
                .findEXIFValueWithExactMatch(GPSTagConstants.GPS_TAG_GPS_LATITUDE_REF);
        final TiffField gpsLatitudeField = jpegMetadata
                .findEXIFValueWithExactMatch(GPSTagConstants.GPS_TAG_GPS_LATITUDE);
        final TiffField gpsLongitudeRefField = jpegMetadata
                .findEXIFValueWithExactMatch(GPSTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
        final TiffField gpsLongitudeField = jpegMetadata
                .findEXIFValueWithExactMatch(GPSTagConstants.GPS_TAG_GPS_LONGITUDE);
        if (gpsLatitudeRefField != null && gpsLatitudeField != null
                && gpsLongitudeRefField != null
                && gpsLongitudeField != null) {
            // all of these values are strings.
            final String gpsLatitudeRef = (String) gpsLatitudeRefField.getValue();
            final RationalNumber gpsLatitude[] = (RationalNumber[]) (gpsLatitudeField
                    .getValue());
            final String gpsLongitudeRef = (String) gpsLongitudeRefField
                    .getValue();
            final RationalNumber gpsLongitude[] = (RationalNumber[]) gpsLongitudeField
                    .getValue();

            final RationalNumber gpsLatitudeDegrees = gpsLatitude[0];
            final RationalNumber gpsLatitudeMinutes = gpsLatitude[1];
            final RationalNumber gpsLatitudeSeconds = gpsLatitude[2];

            final RationalNumber gpsLongitudeDegrees = gpsLongitude[0];
            final RationalNumber gpsLongitudeMinutes = gpsLongitude[1];
            final RationalNumber gpsLongitudeSeconds = gpsLongitude[2];

            // This will format the gps info like so:
            //
            // gpsLatitude: 8 degrees, 40 minutes, 42.2 seconds S
            // gpsLongitude: 115 degrees, 26 minutes, 21.8 seconds E

            System.out.println("    " + "GPS Latitude: "
                    + gpsLatitudeDegrees.toDisplayString() + " degrees, "
                    + gpsLatitudeMinutes.toDisplayString() + " minutes, "
                    + gpsLatitudeSeconds.toDisplayString() + " seconds "
                    + gpsLatitudeRef);
            System.out.println("    " + "GPS Longitude: "
                    + gpsLongitudeDegrees.toDisplayString() + " degrees, "
                    + gpsLongitudeMinutes.toDisplayString() + " minutes, "
                    + gpsLongitudeSeconds.toDisplayString() + " seconds "
                    + gpsLongitudeRef);

        }

        System.out.println();

        final List<Item> items = jpegMetadata.getItems();
        for (int i = 0; i < items.size(); i++) {
            final Item item = items.get(i);
            System.out.println("    " + "item: " + item);
        }

        System.out.println();
    }
  }

  private static void printTagValue(final JpegImageMetadata jpegMetadata,
          final TagInfo tagInfo) {
      final TiffField field = jpegMetadata.findEXIFValueWithExactMatch(tagInfo);
      if (field == null) {
          System.out.println(tagInfo.name + ": " + "Not Found.");
      } else {
          System.out.println(tagInfo.name + ": "
                + field.getValueDescription());
      }
  }

}

我的图像 ali.JPG 的输出是这样的:

file: ali.JPG
XResolution: 300
Date Time: '2011:02:28 21:58:07'
Date Time Original: '2011:02:28 21:58:07'
ISO: 100
Shutter Speed Value: Not Found.
Aperture Value: Not Found.
Brightness Value: Not Found.
GPS Latitude Ref: 'N'
GPS Latitude: 30, 130380/10000 (13.038), 0
GPS Longitude Ref: 'E'
GPS Longitude: 50, 111843/10000 (11.184), 0

GPS Description: [GPS. Latitude: 30 degrees, 13.038 minutes, 0 seconds N, Longitude: 50 degrees, 11.184 minutes, 0 seconds E]
GPS Longitude (Degrees East): 50.186405
GPS Latitude (Degrees North): 30.2173
GPS Latitude: 30 degrees, 13.038 minutes, 0 seconds N
GPS Longitude: 50 degrees, 11.184 minutes, 0 seconds E

item: Make: 'NIKON CORPORATION'
item: Model: 'NIKON D3X'
item: Orientation: 1
item: XResolution: 300
item: YResolution: 300
item: Resolution Unit: 2
item: Software: 'Ver.1.01'
item: Modify Date: '2011:02:28 21:58:07'
item: Artist: ''
item: YCbCr Positioning: 2
item: Copyright: ''
item: Exif Offset: 348
item: GPSInfo: 33880
item: Exposure Time: 10/1600 (0.006)
item: FNumber: 10
item: Exposure Program: 3
item: ISO: 100
item: Exif Version: 48, 50, 50, 49
item: Date Time Original: '2011:02:28 21:58:07'
item: Create Date: '2011:02:28 21:58:07'
item: Components Configuration: 1, 2, 3, 0
item: Compressed Bits Per Pixel: 4
item: Exposure Compensation: -1
item: Max Aperture Value: 3
item: Metering Mode: 5
item: Light Source: 0
item: Flash: 0
item: Focal Length: 24
item: Maker Note: 78, 105, 107, 111, 110, 0, 2, 16, 0, 0, 77, 77, 0, 42, 0, 0, 0, 8, 0, 48, 0, 1, 0, 7, 0, 0, 0, 4, 48, 50, 49, 48, 0, 2, 0, 3, 0, 0, 0, 2, 0, 0, 0, 100, 0, 4, 0, 2, 0, 0, 0... (32866)
item: UserComment: ''
item: Sub Sec Time: '16'
item: Sub Sec Time Original: '16'
item: Sub Sec Time Digitized: '16'
item: Flashpix Version: 48, 49, 48, 48
item: Color Space: 1
item: Exif Image Width: 6048
item: Exif Image Length: 4032
item: Interop Offset: 33850
item: Sensing Method: 2
item: File Source: 3
item: Scene Type: 1
item: CFAPattern: 0, 2, 0, 2, 0, 1, 1, 2
item: Custom Rendered: 0
item: Exposure Mode: 0
item: White Balance: 0
item: Digital Zoom Ratio: 1
item: Focal Length In 3 5mm Format: 24
item: Scene Capture Type: 0
item: Gain Control: 0
item: Contrast: 0
item: Saturation: 0
item: Sharpness: 0
item: Subject Distance Range: 0
item: Interop Index: 'R98'
item: Interop Version: 48, 49, 48, 48
item: Interop Index: 'N'
item: Interop Version: 30, 130380/10000 (13.038), 0
item: Unknown Tag (0x3): 'E'
item: Unknown Tag (0x4): 50, 111843/10000 (11.184), 0
item: Unknown Tag (0x5): 0
item: Unknown Tag (0x6): 1,545
item: Unknown Tag (0x7): 12, 58, 3
item: Unknown Tag (0x8): '10'
item: Unknown Tag (0x12): ''
item: Unknown Tag (0x1d): '2011:02:28'
item: Compression: 6
item: XResolution: 300
item: YResolution: 300
item: Resolution Unit: 2
item: Jpg From Raw Start: 34232
item: Jpg From Raw Length: 9285
item: YCbCr Positioning: 2

使用http://commons.apache.org/proper/commons-imaging

从以下位置下载 jar:https://repo.adobe.com/nexus/content/repositories/public/org/apache/commons/commons-imaging/1.0-R1534292/

您可以在此处查看所有可用标签:https://commons.apache.org/proper/commons-imaging/javadocs/api-release/org/apache/sanselan/formats/tiff/constants/AllTagConstants.html

例如,您可以通过以下方式获取制造商和型号:

String fullFileName="D:/test/photos - orig/lg/20170204_143925.jpg";
File file = new File(fullFileName);

// get all metadata stored in EXIF format (ie. from JPEG or TIFF).
final IImageMetadata metadata = Imaging.getMetadata(file);

if (metadata instanceof JpegImageMetadata) {
    final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;

    String manufacturer = jpegMetadata.findEXIFValueWithExactMatch(TiffTagConstants.TIFF_TAG_MAKE).getStringValue();
    String model = jpegMetadata.findEXIFValueWithExactMatch(TiffTagConstants.TIFF_TAG_MODEL).getStringValue();
    System.out.println("Manufacturer: "+ manufacturer+", Model: " + model);
}