1

I want to retrieve image from MySQL and load it to JLabel using Java Swing.

But I am unable to get this work.

Here is my code below and error I am getting:

try {
    Class.forName("com.mysql.jdbc.Driver");  // MySQL database connection
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/image_db", "root", "root");
    PreparedStatement pst = conn.prepareStatement("Select * from image_tbl where id='"+jTextField1.getText()+"'");
    ResultSet rs = pst.executeQuery();

    byte b[] = null;
    while(rs.next())
     {
       b= rs.getBytes(2);
     }

     jLabel1.setIcon(new ImageIcon (Toolkit.getDefaultToolkit().createImage(b)));
} catch (Exception e) {
    JOptionPane.showMessageDialog(null, "Wrong Data Detected! Please provide correct data");
}    

Exception occuring:

    sun.awt.image.ImageFormatException: JPEG datastream contains no image
        at sun.awt.image.JPEGImageDecoder.readImage(Native Method)
        at sun.awt.image.JPEGImageDecoder.produceImage(JPEGImageDecoder.java:141)
        at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:269)
        at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:205)
        at sun.awt.image.ImageFetcher.run(ImageFetcher.java:169)
    Premature end of JPEG file
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
TARUN TANMAY
  • 21
  • 1
  • 6
  • You're selecting every column from the table. You should just select the column that has the image bytes. – JJF Oct 28 '17 at 18:40
  • Well, [there's one way](https://stackoverflow.com/questions/29983710/displaying-images-from-mysql-database-on-a-single-column-of-jtable/29983992#29983992), [there's another](https://stackoverflow.com/questions/20752432/convert-bufferedinputstream-into-image/20753089#20753089), [and another](https://stackoverflow.com/questions/35069359/trying-to-retrieve-both-text-and-blob-from-mysql-to-jtable/35072936#35072936) – MadProgrammer Oct 28 '17 at 21:42
  • First, as mentioned, you're reading all the results simply to load the last image; Second, I'd verify that the number of bytes been read is the same as the number of bytes been written, but since we don't know how the image is been written, we don't know if using this approach is the best idea; Third, I'd use `ImageIO` over `createImage`, simply because it doesn't involve any kind of threading – MadProgrammer Oct 28 '17 at 21:44
  • You might consider only storing some kind of identifier of the image, which can then used to find and load the image from a local or remote source (like a web service) – MadProgrammer Oct 28 '17 at 21:45
  • when I have to do something like this, I use the blob data type and the Input/OutputStream interfaces that JDBC offers to work with the data type. if the images are stored in the database, it is nice to think about their possible compression (java offers a convenient interface to gzip). – mr mcwolf Oct 29 '17 at 07:03
  • i was used long blob for image storing in mysql – TARUN TANMAY Oct 29 '17 at 07:07

1 Answers1

0

This is a simple example of serializing an image (Icon) in a mysql blob.

create table t1 (id integer primary key auto_increment, img longblob not null);

public class Database {
    public Database() {
    }

    private Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "toor");
    }

    public boolean storeIcon(Icon icon) throws SQLException, IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try(ObjectOutputStream os = new ObjectOutputStream(baos)) {
            os.writeObject(icon);
        }

        try(Connection connection = getConnection()) {
            String query = "insert into t1 (img) values (?)";

            try(PreparedStatement statement = connection.prepareStatement(query)) {
                statement.setBlob(1, new ByteArrayInputStream(baos.toByteArray()));
                return statement.executeUpdate() > 0;
            }
        }
    }

    public Icon loadIcon(long id) throws SQLException, IOException, ClassNotFoundException {
        try(Connection connection = getConnection()) {
            String query = "select img from t1 where id = ?";

            try(PreparedStatement statement = connection.prepareStatement(query)) {
                statement.setLong(1, id);

                try(ResultSet rs = statement.executeQuery()) {
                    if(rs.next()) {
                        Blob blob = rs.getBlob("img");

                        try(ObjectInputStream is = new ObjectInputStream(blob.getBinaryStream())) {
                            return (Icon) is.readObject();
                        }
                    }

                    return null;
                }
            }
        }
    }
}

This is a test application. Reading images from the database is performed with a fixed image ID equal to 1, just for demonstration. In real implementation, it's nice to compress the data to save space. And of course, the extraction of the recorded images (objects) should be limited to the absolute minimum.

public class MainFrame extends JFrame {

    private JLabel imageLabel = new JLabel();

    private JButton loadImageFromFileButton = new JButton("Load image from file");
    private JButton storeImageIntoDBButton = new JButton("Store image into DB");
    private JButton loadImageFromDBButton = new JButton("Load image from DB");

    public MainFrame() throws HeadlessException {
        super("JDBC Test");
        createGUI();
    }

    private void createGUI() {
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLayout(new BorderLayout(5, 20));

        imageLabel.setPreferredSize(new Dimension(200, 200));
        imageLabel.setHorizontalAlignment(JLabel.CENTER);
        imageLabel.setVerticalAlignment(JLabel.CENTER);

        loadImageFromFileButton.addActionListener(this::loadImageFromFile);
        loadImageFromDBButton.addActionListener(this::loadImageFromDB);
        storeImageIntoDBButton.addActionListener(this::storeImageIntoDB);

        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
        buttonsPanel.add(loadImageFromFileButton);
        buttonsPanel.add(Box.createHorizontalStrut(25));
        buttonsPanel.add(loadImageFromDBButton);
        buttonsPanel.add(Box.createHorizontalStrut(5));
        buttonsPanel.add(storeImageIntoDBButton);

        add(imageLabel, BorderLayout.CENTER);
        add(buttonsPanel, BorderLayout.PAGE_END);

        pack();
        setLocationRelativeTo(null);
    }

    private void loadImageFromFile(ActionEvent event) {
        JFileChooser chooser = new JFileChooser();
        if(chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            ImageIcon imageIcon = new ImageIcon(chooser.getSelectedFile().getAbsolutePath());
            imageLabel.setIcon(imageIcon);
        }
    }

    private void storeImageIntoDB(ActionEvent event) {
        try {
            Database db = new Database();
            db.storeIcon(imageLabel.getIcon());
        }
        catch (SQLException | IOException e) {
            e.printStackTrace();
        }
    }

    private void loadImageFromDB(ActionEvent event) {
        try {
            Database db = new Database();
            Icon icon = db.loadIcon(1L);
            imageLabel.setIcon(icon);
        }
        catch (SQLException | IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true));
    }
}
mr mcwolf
  • 2,574
  • 2
  • 14
  • 27
  • its getting exception: Driver not found where should add the driver in the program – TARUN TANMAY Oct 29 '17 at 15:13
  • In the app's classpath, the mysql driver jar file must be added. If you use a version of JDBC before 4.2, you must load it with `Class.forName("com.mysql.jdbc.Driver");`. All of this you did in your project, so you should not have any problems with this code. – mr mcwolf Oct 29 '17 at 15:49