Skip to content

ghillert/image-metadata

Repository files navigation

Image Metadata processing using Java

CI Image Metadata

This repository contains examples for processing image metadata using Java. Currently, the following module is available:

  • image-metadata-commons-imaging

This Spring Boot 3 application will allow you to upload images (JPG, PNG, GIF) and the application will extract the metadata from those files using Apache Commons Imaging. This includes:

  • EXIF (Exchangeable image file format)

  • IPTC (International Press Telecommunications Council)

  • XMP (eXtensible Metadata Platform)

  • Generic file metadata

To learn more about the alphabet soup, see my blog post: Read & Write Image Metadata with Java — Part 1 This demo application also provides the following additional features:

  • Remove all image metadata

  • Populate image metadata such as image title and reference id

  • Ability to resize images

  • Slightly sharpen resized images using a Gaussian Unsharp Mask

  • Add a font label to resized images

  • Ability to load images using ImageIO or AWT Toolkit (To study performance differences)

  • Ability to download the stored image

Note
Image metadata is manipulated during file upload. Any other manipulation such as resizing is done during image retrieval. This is purely a demo app and not meant to be production ready.

UI Options

File upload

The main input field (and only mandatory input field) is the file upload option. You can select any image of the following type to extract metadata from:

  • JPG

  • PNG

  • GIF

Title

The title input field, will populate

  • the XMP Title tag of the Dublin Core namespace.

  • the IPTC Object Name field

  • the EXIF Image Description Field

In case you also selected the Remove Metadata checkbox, we will also populate the XPTitle EXIF tag.

Reference ID

Populates the IPTC field OriginalTransmissionReference as well as the XMP tag TransmissionReference. These two fields are commonly used as a job identifier. So if you need to tie your images to e.g. a database record, this might be a useful field to know about. For more information, please also see the following links for more information:

Remove Metadata

Removes all IPTC, EXIF and XMP metadata.

Populate Windows Tags

The following tags are the Windows-specific exif tags:

  • XPTitle (Populated by EXIF tag ImageDescription)

  • XPComment

  • XPAuthor (Populated by EXIF tag Artist)

  • XPKeywords

  • XPSubject

  • Rating

  • RatingPercent

If the checkbox is selected AND the Caption/Title input field is populated, we will populate the xptitle tag. Please also see the EXIF tag documentation at https://exiftool.org/TagNames/EXIF.html.

Building from Source

Requirements

  • Git to clone the repository

Standard Java

Tip
Use SDKMAN! to install any version of Java.

Native Compilation:

For the native compilation support, you will need a GraalVM based implementation of Java. As this application uses AWT classes, Bellsoft’s Liberica Native Image Kit (NIK) is currently (as of Oct 24, 2023) the best implementation. The following version was used for testing:

Note

Oracle GraalVM does not work on MacOS, yet. You will encounter a No awt in java.library.path. See oracle/graal#4124 for details.

If you try, you will see an exception like the following:

2023-02-12T09:38:34.721-10:00 ERROR 65901 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed: java.lang.UnsatisfiedLinkError: no awt in java.library.path] with root cause

java.lang.UnsatisfiedLinkError: no awt in java.library.path
...
Tip
Use SDKMAN! to install GraalVM.

Check out source code

Check out the project using Git:

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

Build

./mvnw clean package

Run

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

Open your browser and go to http://localhost:8080/

Build + Run in one go

./mvnw spring-boot:run -pl image-metadata-commons-imaging

Going Native

Native compilation has been a bit of a moving target when using AWT classes. Luckily, the situation is continuously improving. For instance, until recently the story on Windows was a bit more involved, requiring to compile the project using the x64 Native Tools Command Prompt for VS 2022 (See the following blog post for more information.)

Luckily as of GraalVM for JDK 17.0.8 the situation on Windows is much improved - See the following blog post for details.

IMPORTANT

When using AWT and ImageIO classes etc. the native GraalVM Native Image metadata seems to be specific to the relevant platform. Therefore, you may need to rename the respective folder under image-metadata-commons-imaging/src/main/resource/META-INF to native-image. I provide the following folders:

  • native-image-linux

  • native-image-mac

  • native-image-windows

Alternatively, you can run the native-image-agent as described under Development below.

Creating a Local Native Image

Creating a local image should be as easy as:

./mvnw clean package -DnativeCompile

This shorthand system property will activate the Maven profiles:

  • native

  • nativeCompile

So you can also use:

./mvnw clean package -Pnative,nativeCompile

The result (if successful) will be an executable binary at: image-metadata-commons-imaging/target/image-metadata-commons-imaging

Tip
You can use Ultimate Packer for eXecutables (UPX) to further compress the binary. E.g. upx -9 image-metadata-commons-imaging/target/image-metadata-commons-imaging
Note
UPX is currently broken on MacOS 13. See the relevant GitHub issue ticket for details.

macOS

As the application uses some AWT classes for image processing, the native version for macOS will not run using Oracle GraalVM. There is an open GitHub issue at the GraalVM project.

However, compilation will succeed and the application will run when using Liberica Native Image Kit (NIK).

./image-metadata-commons-imaging/target/image-metadata-commons-imaging

Windows

On Windows (With the latest version of GraalVM), things got super-easy, just compile and run:

image-metadata-commons-imaging/target/image-metadata-commons-imaging.exe

Linux

Once compiled you need to provide the java.home to the executable. This is needed to load the font sub-system. However, the contents of java.home just needs one file fontconfig.properties with the contents:

version=1
sequence.allfonts=default
Note

This was previously for the Windows executable as well but seems to work now without. So maybe this may not be needed eventually. For more information see:

For simplicity, the project provides a fontconfig.properties file. Therefore, once the binary is created, launch the application using:

./image-metadata-commons-imaging/target/image-metadata-commons-imaging \
-Djava.home=iage-metadata-commons-imaging/src/lib/
Note

You may also need to install libfreetype6-dev:

apt install gcc zlib1g-dev build-essential libfreetype6-dev

Docker

image-metadata-commons-imaging uses fonts, which on Linux requires fontconfig to be installed. That’s why I use paketobuildpacks/builder:full and not the default paketobuildpacks/builder:tiny.

Important
Please make sure your Docker daemon is running.
./mvnw -Pnative spring-boot:build-image -pl :image-metadata-commons-imaging
docker run --rm -p 8080:8080 docker.io/library/image-metadata-commons-imaging:1.0.0-SNAPSHOT

Development

When adding functionality, it may be necessary to run the native-image-agent. First build the jar with the native Maven profile:

./mvnw clean package -Pnative
java -Dspring.aot.enabled=true \
-agentlib:native-image-agent=config-output-dir=image-metadata-commons-imaging/src/main/resources/META-INF/native-image \
-jar image-metadata-commons-imaging/target/image-metadata-commons-imaging-1.0.0-SNAPSHOT.jar

License

Image Metadata is licensed under the Apache License (ASL), Version 2.0.