Example app
While I am no expert on JavaFX/OpenJFX, nor am I an expert on image encoding, I was able to cobble together this crude but effective little app to demonstrate:
- Loading an image from a local file.
- Displaying that image in an
ImageView
field in JavaFX.
- Writing that image content to a field in an H2 database.
- Showing a list of IDs tracking each saved image. (IDs are UUIDs.)
- Retrieving a selected image from database, and displaying in JavaFX.

I found various chunks of code for encoding/decoding image data. I do not know what chunks may be old-fashioned or outmoded. All I know is that I got them to work.
Some used classes from the AWT and Swing frameworks bundled with Java. But be aware that this example JavaFX app is modularized, so you must add elements to your module-info.java
file to access those classes.
In this example, the H2 database is configured to be an in-memory database. This means the stored data is not written to storage. When your app ends, the database and all its rows disappear, poof .
This app was written in Java 19 with OpenJFX 19.
I starting this app by creating a project using the JavaFX template built into the New Project dialog box of the IntelliJ IDE.
The code for encoding the image data is found in the two transform…
methods.
The transformImageIntoInputStream
method takes a JavaFX image object, uses Swing & AWT to create an AWT buffered image (not to be confused with JavaFX image). That buffered image is then converted to an array of byte
, from which we get an InputStream
. The input stream can be passed to the JDBC method PreparedStatement :: setBlob
to store a BLOB in the database.
@SuppressWarnings ( "UnnecessaryLocalVariable" )
private InputStream transformImageIntoInputStream ( final Image image )
{
BufferedImage awtBufferedImage = SwingFXUtils.fromFXImage( image , null );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try
{
ImageIO.write( awtBufferedImage , "jpg" , outputStream );
byte[] res = outputStream.toByteArray();
InputStream inputStream = new ByteArrayInputStream( res );
return inputStream;
}
catch ( IOException e ) { e.printStackTrace(); }
throw new IllegalStateException( "Should not reach this point in method `transformImageIntoInputStream`." );
}
To retrieve from the database, we call ResultSet :: getBlob
to produce a java.sql.Blob
object. We use javax.imageio.ImageIO
to read a binary stream obtained from that Blob
object we retrieved. That produces another AWT buffered image (again, not to be confused with a JavaFX image). We then make use of Swing again to produce a JavaFX image from that AWT image.
private Image transformBlobIntoImage ( final Blob blob )
{
try
{
BufferedImage awtBufferedImage = ImageIO.read( blob.getBinaryStream() );
Image image = SwingFXUtils.toFXImage( awtBufferedImage , null );
return image;
}
catch ( IOException e ) { throw new RuntimeException( e ); }
catch ( SQLException e ) { throw new RuntimeException( e ); }
}
As noted above, I am no expert on image handling. This sure seems a roundabout way to go to get image data encoded/decoded. And I am surprised to have found only approaches using AWT and Swing rather than straight JavaFX. If anyone knows better approaches, please do post!
Source Code
Here is the entire Java code for the app, in a single file.
/*
By Basil Bourque. http://www.Basil.work/
This code is a response to this Question on Stack Overflow:
> insert an image to a database with javafx
https://stackoverflow.com/q/75632865/642706
This code was cobbled together quickly, as a starting point
for further learning. Not meant for production use.
Caveat: I an not an expert in JavaFX nor in image encoding.
Use at your own risk.
This demo app opens a window with five items, running left to right:
• A button to load JPEG files from your local storage.
• An `ImageView` field to show the image you loaded. Defaults to the Java mascot "Duke", loaded over the internet.
• A button to save the loaded image to an in-memory database using the H2 Database Engine (written in pure Java).
• A list of the UUIDs that each identify an image stored in the database.
• Another `ImageView` field to show the image retrieved from the database per the UUID selected in the list.
*/
package work.basil.example.fximage;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import javax.sql.DataSource;
import java.awt.image.BufferedImage;
import java.io.*;
import java.sql.*;
import java.util.Objects;
import java.util.UUID;
@SuppressWarnings ( "SqlNoDataSourceInspection" )
public class App extends Application
{
@Override
public void start ( final Stage stage )
{
// Widgets ---------------------------------------
Button loadFromDesktopButton = new Button( "Open JPEG file…" );
String url = "https://www.oracle.com/a/ocom/img/rc24-duke-java-mascot.jpg"; // Arbitrary example image.
Image duke = new Image( url );
ImageView desktopImageView = new ImageView();
desktopImageView.setImage( duke );
desktopImageView.setFitWidth( 300 );
desktopImageView.setPreserveRatio( true );
desktopImageView.setSmooth( true );
desktopImageView.setCache( true );
Button storeInDatabaseButton = new Button( "Store in database" );
ListView < UUID > listView = new ListView <>();
listView.setPrefWidth( 300 );
ObservableList < UUID > ids = FXCollections.observableArrayList();
listView.setItems( ids );
ImageView databaseImageView = new ImageView();
databaseImageView.setFitWidth( 300 );
databaseImageView.setPreserveRatio( true );
databaseImageView.setSmooth( true );
databaseImageView.setCache( true );
// Behavior --------------------------------------
DataSource dataSource = this.configureDataSource();
this.configureDatabase( dataSource );
loadFromDesktopButton.setOnAction(
( ActionEvent event ) -> this.loadImageFromLocalStorage( stage , desktopImageView )
);
storeInDatabaseButton.setOnAction(
( ActionEvent event ) -> {
Image image = desktopImageView.getImage();
UUID id = this.storeImageInDatabase( image , dataSource );
ids.add( id ); // Add a list item for the image we just stored in database.
listView.getSelectionModel().select( id ); // Select the newly added list item.
}
);
listView.getSelectionModel().selectedItemProperty().addListener(
( ObservableValue < ? extends UUID > observableValue , UUID oldValue , UUID newValue ) -> {
Image image = this.fetchImageFromDatabase( newValue , dataSource );
databaseImageView.setImage( image );
}
);
// Layout --------------------------------------
stage.setTitle( "Image To Database" );
HBox root = new HBox();
root.setPadding( new Insets( 15 , 12 , 15 , 12 ) );
root.setSpacing( 10 );
root.setStyle( "-fx-background-color: Grey;" );
// Arrange --------------------------------------
root.getChildren().add( loadFromDesktopButton );
root.getChildren().add( desktopImageView );
root.getChildren().add( storeInDatabaseButton );
root.getChildren().add( listView );
root.getChildren().add( databaseImageView );
Scene scene = new Scene( root , 1_250 , 300 );
stage.setScene( scene );
stage.show();
}
// Subroutines --------------------------------------
private void loadImageFromLocalStorage ( final Stage stage , final ImageView imageView )
{
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle( "Open JPEG file" );
File file = fileChooser.showOpenDialog( stage );
if ( file != null )
{
System.out.println( file );
Image image = new Image( file.toURI().toString() );
imageView.setImage( image );
}
}
private DataSource configureDataSource ( )
{
org.h2.jdbcx.JdbcDataSource ds = new org.h2.jdbcx.JdbcDataSource(); // Implementation of `DataSource` bundled with H2. You may choose to use some other implementation.
ds.setURL( "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
ds.setDescription( "An example database for storing an image." );
return ds;
}
private void configureDatabase ( final DataSource dataSource )
{
// Create table.
String sql =
"""
CREATE TABLE IF NOT EXISTS image_
(
id_ uuid NOT NULL ,
CONSTRAINT image_pkey_ PRIMARY KEY ( id_ ) ,
row_created_ TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP() ,
content_ BLOB
)
;
""";
try (
Connection conn = dataSource.getConnection() ;
Statement stmt = conn.createStatement()
)
{
System.out.println( "INFO - Running `configureDatabase` method." );
stmt.executeUpdate( sql );
}
catch ( SQLException e ) { e.printStackTrace(); }
}
private UUID storeImageInDatabase ( final Image image , final DataSource dataSource )
{
InputStream inputStream = this.transformImageIntoInputStream( Objects.requireNonNull( image ) );
// Write to database
String sql =
"""
INSERT INTO image_ ( id_ , content_ )
VALUES ( ? , ? )
;
""";
try
(
Connection conn = dataSource.getConnection() ;
PreparedStatement preparedStatement = conn.prepareStatement( sql )
)
{
UUID id = UUID.randomUUID(); // In real work, we would retrieve the value generated by the database rather the app.
preparedStatement.setObject( 1 , id );
preparedStatement.setBlob( 2 , inputStream );
int rowCount = preparedStatement.executeUpdate();
if ( rowCount != 1 ) { throw new IllegalStateException( "SQL insert failed to affect any rows." ); }
return id;
}
catch ( SQLException e ) { e.printStackTrace(); }
throw new IllegalStateException( "Should never have reached this point in `storeImageInDatabase` method. " );
}
private Image fetchImageFromDatabase ( final UUID id , final DataSource dataSource )
{
byte[] bytes = null;
String sql =
"""
SELECT *
FROM image_
WHERE id_ = ?
;
""";
try
(
Connection conn = dataSource.getConnection() ;
PreparedStatement preparedStatement = conn.prepareStatement( sql )
)
{
System.out.println( "DEBUG id = " + id );
preparedStatement.setObject( 1 , id );
try (
ResultSet resultSet = preparedStatement.executeQuery() ;
)
{
if ( resultSet.next() )
{
System.out.println( "DEBUG resultSet = " + resultSet );
Blob blob = resultSet.getBlob( "content_" );
System.out.println( "DEBUG blob = " + blob );
Image image = this.transformBlobIntoImage( blob );
return image;
}
else { throw new IllegalStateException( "Failed to find any rows for id: " + id ); }
}
}
catch ( SQLException e ) { e.printStackTrace(); }
throw new IllegalStateException( "Should never have reached this point in `storeImageInDatabase` method. " );
}
@SuppressWarnings ( "UnnecessaryLocalVariable" )
private InputStream transformImageIntoInputStream ( final Image image )
{
BufferedImage awtBufferedImage = SwingFXUtils.fromFXImage( image , null );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try
{
ImageIO.write( awtBufferedImage , "jpg" , outputStream );
byte[] res = outputStream.toByteArray();
InputStream inputStream = new ByteArrayInputStream( res );
return inputStream;
}
catch ( IOException e ) { e.printStackTrace(); }
throw new IllegalStateException( "Should not reach this point in method `transformImageIntoInputStream`." );
}
private Image transformBlobIntoImage ( final Blob blob )
{
try
{
BufferedImage awtBufferedImage = ImageIO.read( blob.getBinaryStream() );
Image image = SwingFXUtils.toFXImage( awtBufferedImage , null );
return image;
}
catch ( IOException e ) { throw new RuntimeException( e ); }
catch ( SQLException e ) { throw new RuntimeException( e ); }
}
public static void main ( final String[] args )
{
launch();
}
}
Here is the module-info.java
file.
module work.basil.example.fximage {
requires javafx.controls; // JavaFX/OpenJFX API.
requires java.desktop; // Needed for classes in AWT that convert image to octets.
requires javafx.swing; // Needed for `javafx.embed.swing.SwingFXUtils` class to convert image to octets.
requires java.sql; // JDBC API.
requires java.naming; // Java Naming and Directory Interface (JNDI) API. Needed for `DataSource` in JDBC.
requires com.h2database; // H2 Database Engine.
exports work.basil.example.fximage;
}
And my Apache Maven POM file.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>work.basil.example</groupId>
<artifactId>FxImageToDb</artifactId>
<version>1.0-SNAPSHOT</version>
<name>FxImage</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19.0.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-swing -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-swing</artifactId>
<version>19.0.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>19</source>
<target>19</target>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>work.basil.example.fximage/work.basil.example.fximage.App</mainClass>
<launcher>app</launcher>
<jlinkZipName>app</jlinkZipName>
<jlinkImageName>app</jlinkImageName>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<noHeaderFiles>true</noHeaderFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Resources
Convert Blob to JPG and update blob
Java BLOB to image file
Auto-generate lambda expression as argument in IntelliJ
JavaFX select item in ListView
Using JavaFX UI Controls — 11 List View
Using JavaFX UI Controls — 26 File Chooser
How can I show an image using the ImageView component in javafx and fxml?
H2 Database Engine documentation for BLOB
type and for discussion of the Large Object types.
AWT & Swing classes: SwingFXUtils
How to convert a JavaFX ImageView to InputStream
Saving an image in MySQL from Java
How to save an image from HTML to a DATABASE using JAVA
Storing Image in Data Base Using Java in Binary Format