Image Processing with Java

Read & Write Image Metadata with Java — Part 2

In Part II we present a Spring Boot 3 based demo application that reads + writes image metadata

Gunnar Hillert
7 min readOct 29, 2023
Brownea macrophylla (Rosa de monte; Panama, Colombia, Ecuador, Peru & Venezuela)

In Part I I talked about the building blocks of metadata in images and how it may matter to you as application developer. Furthermore, I dissected the alphabet soup around Exif, IPTC and XMP and started to briefly talk about the options Java developers have for reading and writing image metadata.

In this second part, I would like to introduce you to a kitchen-sink demo application that covers a lot of ground in that regard. Not only will the application allow you to extract and view image metadata but will also demonstrate, how to change metadata and also how to process images in the context of a web application. All used libraries are pure Java, and as a bonus the demo applicate compiles to native (Using GraalVM) as well.

Features

Specifically, the application provides the following core (image-processing/handling related) features:

  • Upload images (JPG, PNG, GIF)
  • Provide basic validation
  • Extract and display all available relevant metadata (Exif, IPTC, XMP and general file properties)
  • Optionally you can purge all metadata
  • Ability to update certain metadata (As a demonstration you can set the title/caption as well as a reference id)
  • Extract GNSS (GPS) data (if available) and display the image location on a map
  • Download images
  • Physically resize (scale) images
  • Sharpen a resized image by subtracting a Gaussian blur from an image
  • Add text-labels to images

The Spring Boot-based web-application is implemented using the following frameworks and libraries:

Native Compilation using GraalVM

As an added bonus, this application also demonstrates the state of image-processing applications in regards to native compilation using GraalVM. The amazing part is that it mostly works with the used libraries. The only limiting factor is the use of Java AWT, which is used to to add labels (plus handling of fonts) and to do the image resizing. This is currently an issue for MacOS in Oracle’s GraalVM implementation. But hopefully this will be addressed in an upcoming GraalVM release. Alternatively, you can use BellSoft’s Liberica Native Image Kit. It currently provides improved AWT support already and the demo application works natively on MacOS, Linux, and Windows. We may get into the details of the GraalVM portion in a subsequent blog post. Please see the section Going Native in the README file in the demo’s Git repository for additional information.

Run the application

Let’s get the code first (Make sure you have Git installed):

git clone https://github.com/ghillert/image-metadata.git
cd image-metadata

Next, we need to build the application using Maven and Java 21 (Java 17 works as well and is the minimum). We will use the Maven wrapper (embedded Maven), so the only other thing you need to have installed is Java 17 or higher. As we later want to run the application using GraalVM, I highly recommend using SDKMAN! to effortlessly manage and use multiple Java versions in parallel.

./mvnw clean package

Once the build is complete, we are ready to execute the application using:

java -jar ./image-metadata-commons-imaging/image-metadata-commons-imaging-1.0.0-SNAPSHOT.jar

If you open a browser at http://localhost:8080/ you should be greeted with the UI, which provides an HTML form with an option to upload an image.

Upload Images

The file upload form field is the only mandatory form field.

Select the file and options for upload

There are a few additional (optional) form fields available. You can give your image a title and/or provide a reference id. I chose the caption/title as a common metadata field to demonstrate the writing of metadata. Additionally, I selected the reference id field. This IPTC field is named differently in various imaging applications and respective standards.

In Adobe LightRoom Classic the respective field is labelled Job Identifier (Under Workflow). The reason for mentioning this field more explicitly is the ability to add an identifier to your metadata, for instance using Time-Sorted Unique Identifiers (TSID) or Universally Unique Identifiers (UUID).

Let’s say you have a huge amount of image data somewhere in the cloud that links to data in your database. This gives you the ability to track back images to the database data no matter what happens (accidents, sharing image-data with 3rd-parties, etc.).

Another optional option you have is to remove all metadata from your uploaded image. If you provide a caption and/or reference id, the metadata is removed and only the newly provided field(s) are populated.

And lastly, you can populate the windows tags. Yes, Microsoft Windows is special. See the article XMP, IPTC/IIM, or Exif; which is preferred? for more enlightenment on this topic.

Once you upload an image, the metadata is added and/or removed but the image data itself is stored as original. After all, this is just a demo app. Any resizing is done ad-hoc when the image is loaded for display purposes.

Display of uploaded images

When displaying the images, the filename is added as a label to the images and the image is resized.

Image Resizing

I want to give image resizing an dedicated section in this blog post. When looking for informaton on how to resize images using Java you may find this Stackoverflow Java — resize image without losing quality posting with a good overview of options. Additionaly, I would like to recommend the article Efficient Image Resizing With ImageMagick which provides an excellent overview on this topic in regards to serving images as part of web applications. It focuses on ImageMagick but its settings are applicable for our needs as well and it also talks about using sharpening as part of that resizing step. Interestingly, I could not find recently updated Java libraries (with a liberal OSS license) that can sharpen images for you. Eventually, I was able to find the web page of Jerry Huxtable that provides an interesting list of Java-based image processing filters that are licensed under the Apache License, Version 2.0. I incorporated the UnsharpFilter into the demo app.

When experimenting with the best settings for resizing images, you may also want to look at DSSIM, a command-line tool which uses a variation of the Structural SIMilarity algorithm (SSIM) to give you a similarity score between two images.

Also, if you open an image in a separate tab, you can play with the request parameters to change the image size, drop the label, or use the AWT Toolkit to load images versus using Java ImageIO (the default).

http://localhost:8080/images/IMG_20231020_163730.jpg?width=200
http://localhost:8080/images/IMG_20231020_163730.jpg?width=400&addLabel=false&imageLoaderType=AWT_TOOLKIT

If you use the download=true request parameter, the image will be send as a download (attachment) via the Content-Disposition HTTP header.

View the Metadata

When viewing the image details, the demo application will extract as much of the available metadata as possible.

Viewing the metadata details

First, I will show the the GNSS (GPS) information if available, showing latitude, longitude and elevation if available as well as the location of the coordinate on a Google Map.

I then display the remaining metadata categorized by type:

  • XMP (Extensible Metadata Platform), if available
  • EXIF (Exchangeable Image File Format) and IPTC, if available
  • Image File Properties, always shown
  • Image Format Info, always shown

Lastly, if the image contains the XML-based XMP data, I will show the formatted (for indention) raw data.

A quick note on XMP parsing: I am using the Apache XML Graphics Commons library. When exporting images with faces from Adobe Lightroom Classic, an XMP parsing error will occur. I filed a Jira ticket for that. There is also a ticket to expand the XMP support by adding support for the IPTC Photo Metadata Standard. Right now, Apache XML Graphics Commons supports only the basic Dublin Core (DC) namespace.

Source Code

The source code for the demo application is available at https://github.com/ghillert/image-metadata. Take the application for a spin. If you see issues or have question, please post them here or open a Github issue. I hope this will give you a better overview of how to deal with metadata data in Java-based applications.

--

--

Gunnar Hillert

Consulting Member of Technical Staff at Oracle for the Coherence team. Java Champion, former Spring team member, OSS committer, DevNexus co-founder.