B4J Question Parse Image Meta Data

oldeast

Active Member
Licensed User
Longtime User
any suggestions on how to read image title, copyright etc.
My code still throws an exception getMeta not matched
I looked at a previous post which showed a workaround but it does not work.
Appreciate any suggestions ..

B4X:
Dim JO As JavaObject = Me
                    Dim rsmd As JavaObject =    JO.RunMethod("getMeta", Array ( val ) )
                    Log (rsmd)
                    
#if java
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.ResultSetMetaData;
 
 public ResultSetMetaData  getMeta(ResultSet val) throws SQLException {
    ResultSetMetaData rsmd = val.getMetaData();
    return rsmd;
  }
#End If
 

oldeast

Active Member
Licensed User
Longtime User
that was the only ref I could find to meta data so obviously barking up the wrong tree..
can you point me in the right direction please
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
You could try using this library from Apache commons-image-io-0.4.0.jar
It seems to be able to read most metadata from image files.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Did you wrote a wrapper for it?
If not then you need to use JavaObject to access it.

 
Upvote 0

oldeast

Active Member
Licensed User
Longtime User
Tried I but can't understand how to use the Java Object to examine the image properties
 

Attachments

  • MetaGeta.zip
    20.9 KB · Views: 207
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
This is the code I use to test it ( the java code isn't mine - I found it on the internet)
B4X:
#Region Project Attributes 
    #MainFormWidth: 600
    #MainFormHeight: 600 
    #AdditionalJar: commons-image-io-0.4.0.jar
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    'MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
    asJO(Me).RunMethod("getMetadata",Array("C:/temp/powershot.jpg"))
End Sub

Sub asJO(o As JavaObject) As JavaObject
    Return o
End Sub
'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
#if java
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 static void getMetadata(String filename) throws ImageReadException,
        IOException {
    // get all metadata stored in EXIF format (ie. from JPEG or TIFF).
    File f = new File(filename);
    final IImageMetadata metadata =  Sanselan.getMetadata(f);


    // 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: " + f.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());
      }
    }
#End If
 
Upvote 0

oldeast

Active Member
Licensed User
Longtime User
Ok, I saw that the code after the GPS iterates through the other image properties so that list will be helpful.
Thanks for your assistance.
 
Last edited:
Upvote 0

oldeast

Active Member
Licensed User
Longtime User
I have modified the code Daestrum posted, removing the second example and selecting the tags I want using TiffTagConstants
I would like it to send the data to a table to show the data on a form.
B4X:
System.out.println(tagInfo.name + ": " + field.getValueDescription());
Appreciate any assistance.
 

Attachments

  • MetaGeta.zip
    20.9 KB · Views: 176
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
Here is an alternative for you using the metadata-extractor. This is app not finished yet but it may help you.

You will need to add the metadata-extractor-2.11.0.jar file to your libraries directory. The jar file can be downloaded here.

Regards
 

Attachments

  • GetEXIF.zip
    24.7 KB · Views: 194
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Thanks for your input @mark35at and the further support you provided by way of our conversation.

For the benefit of others who may find your code useful, but as in my case find it doesn't run of their machines, I thought I'd publish here the fix you directed me to in that
B4X:
#AdditionalJar: xmpcore-5.1.3
had to be added and the attached jar added to the additional libraries folder.
 

Attachments

  • xmpcore-5.1.3.jar
    89.7 KB · Views: 146
Upvote 0

oldeast

Active Member
Licensed User
Longtime User
Thanks for your input @mark35at and the further support you provided by way of our conversation.

For the benefit of others who may find your code useful, but as in my case find it doesn't run of their machines, I thought I'd publish here the fix you directed me to in that
B4X:
#AdditionalJar: xmpcore-5.1.3
had to be added and the attached jar added to the additional libraries folder.
 
Upvote 0
Top