de.blinkenlights.bmix.util.ImageToBML.java Source code

Java tutorial

Introduction

Here is the source code for de.blinkenlights.bmix.util.ImageToBML.java

Source

/* 
 * This file is part of BMix.
 *
 *    BMix is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 * 
 *    BMix is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with BMix.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package de.blinkenlights.bmix.util;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.zip.GZIPOutputStream;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import org.jdesktop.swingworker.SwingWorker;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.layout.FormLayout;

import de.blinkenlights.bmix.movie.BMLOutputStream;

public class ImageToBML {

    JFrame mainFrame = new JFrame();
    private ConvertTask task;
    public static final String version = "Version $Id$";

    JTextField xSizeField = new JTextField();
    JTextField ySizeField = new JTextField();
    JTextField pngDir = new JTextField();
    JTextField outFile = new JTextField();

    // metadata
    JTextField titleField = new JTextField();
    JTextField descriptionField = new JTextField();
    JTextField authorField = new JTextField();
    JTextField emailField = new JTextField();
    JTextField urlField = new JTextField();

    JCheckBox gzipCheckBox = new JCheckBox();

    JButton pngDirChoose = new JButton("...");
    JButton outFileChoose = new JButton("...");
    JButton startButton = new JButton("Start");
    JButton cancelButton = new JButton("Cancel");
    JSpinner frameRateField = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
    JLabel statusLine = new JLabel(version);
    JProgressBar progress = new JProgressBar();

    private Preferences prefs;

    InputVerifier inputVerifier = new InputVerifier();

    public void createAndShowGUI() {

        prefs = Preferences.userNodeForPackage(ImageToBML.class);

        //Create and set up the main window.
        mainFrame.setTitle("Image Sequence to BML");

        mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        mainFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                prefs.putInt("frameX", mainFrame.getX());
                prefs.putInt("frameY", mainFrame.getY());
                //prefs.putInt("frameWidth", mainFrame.getWidth());
                //prefs.putInt("frameHeight", mainFrame.getHeight());
                try {
                    prefs.flush();
                } catch (BackingStoreException e1) {
                    e1.printStackTrace();
                }
                System.exit(0);
            }
        });

        pngDirChoose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser(new File(pngDir.getText()));
                chooser.setDialogTitle("Select Image Directory");
                chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int choice = chooser.showOpenDialog(mainFrame);
                if (choice == JFileChooser.CANCEL_OPTION) {
                    System.out.println("User Canceled");
                } else {
                    pngDir.setText(chooser.getSelectedFile().getAbsolutePath());
                }
            }
        });

        outFileChoose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                chooser.setDialogTitle("Select Output Filename");
                int choice = chooser.showSaveDialog(mainFrame);
                if (choice == JFileChooser.CANCEL_OPTION) {
                    System.out.println("User Canceled");
                } else {
                    String chosenFile = chooser.getSelectedFile().getAbsolutePath();
                    if (!chosenFile.endsWith(".bml")) {
                        chosenFile = chosenFile.concat(".bml");
                    }
                    outFile.setText(chosenFile);
                }
            }
        });

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (gzipCheckBox.isSelected()) {
                    if (!outFile.getText().endsWith(".bml.gz")) {
                        int ans = JOptionPane.showConfirmDialog(null,
                                "<html>Filename should end with \"<b>.bml.gz</b>\". Continue?",
                                "Compatibility Suggestion", JOptionPane.OK_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE);
                        if (ans == JOptionPane.CANCEL_OPTION) {
                            return;
                        }
                    }
                } else {
                    if (!outFile.getText().endsWith(".bml")) {
                        int ans = JOptionPane.showConfirmDialog(null,
                                "<html>Filename should end with \"<b>.bml</b>\". Continue?",
                                "Compatibility Suggestion", JOptionPane.OK_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE);
                        if (ans == JOptionPane.CANCEL_OPTION) {
                            return;
                        }
                    }
                }

                File out = new File(outFile.getText());
                if (out.exists()) {
                    int ans = JOptionPane.showConfirmDialog(null, "" + out.getName() + " exists. Overwrite?",
                            "Save Over Existing File", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                    if (ans == JOptionPane.CANCEL_OPTION) {
                        return;
                    }
                }

                Map<String, String> headerData = new HashMap<String, String>();
                headerData.put("author", authorField.getText());
                headerData.put("description", descriptionField.getText());
                headerData.put("title", titleField.getText());
                headerData.put("email", emailField.getText());
                headerData.put("url", urlField.getText());

                task = new ConvertTask(new File(pngDir.getText()), out,
                        new Dimension(Integer.parseInt(xSizeField.getText()),
                                Integer.parseInt(ySizeField.getText())),
                        4, headerData, gzipCheckBox.isSelected());
                task.addPropertyChangeListener(new PropertyChangeListener() {
                    public void propertyChange(PropertyChangeEvent event) {
                        if (event.getPropertyName().equals("progress")) {
                            progress.setValue((Integer) event.getNewValue());
                        }
                    }

                });
                task.execute();
            }
        });

        cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (task != null) {
                    task.cancel(true);
                }
            }
        });

        gzipCheckBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (gzipCheckBox.isSelected()) {
                    if (!outFile.getText().endsWith(".gz")) {
                        outFile.setText(outFile.getText().concat(".gz"));
                    }
                } else {
                    if (outFile.getText().endsWith(".gz")) {
                        outFile.setText(outFile.getText().substring(0, outFile.getText().length() - 3));
                    }
                }
            }
        });

        FormLayout mainLayout = new FormLayout("pref, 4dlu, 120dlu:grow, 4dlu, min", "");

        pngDir.setText(prefs.get("pngDir", System.getProperty("user.home")));
        pngDir.getDocument().addDocumentListener(inputVerifier);

        outFile.setText(prefs.get("outFile",
                System.getProperty("user.home") + System.getProperty("file.separator") + "movie.bml"));
        outFile.getDocument().addDocumentListener(inputVerifier);

        xSizeField.setText(prefs.get("xSize", "18"));
        xSizeField.getDocument().addDocumentListener(inputVerifier);

        ySizeField.setText(prefs.get("ySize", "8"));
        ySizeField.getDocument().addDocumentListener(inputVerifier);

        frameRateField.setValue(prefs.getInt("fps", 15));
        frameRateField.getModel().addChangeListener(inputVerifier);

        titleField.setText(prefs.get("title", ""));
        titleField.getDocument().addDocumentListener(inputVerifier);

        descriptionField.setText(prefs.get("description", ""));
        descriptionField.getDocument().addDocumentListener(inputVerifier);

        authorField.setText(prefs.get("author", System.getProperty("user.name")));
        authorField.getDocument().addDocumentListener(inputVerifier);

        emailField.setText(prefs.get("email", ""));
        emailField.getDocument().addDocumentListener(inputVerifier);

        urlField.setText(prefs.get("url", ""));
        urlField.getDocument().addDocumentListener(inputVerifier);

        gzipCheckBox.setSelected(prefs.getBoolean("gzip", false));
        gzipCheckBox.getModel().addChangeListener(inputVerifier);

        cancelButton.setEnabled(false);
        progress.setStringPainted(true);

        DefaultFormBuilder mainBuilder = new DefaultFormBuilder(mainLayout);
        mainBuilder.setDefaultDialogBorder();

        mainBuilder.appendSeparator("Movie Parameters");
        mainBuilder.nextLine();

        mainBuilder.append("Source Directory", pngDir, pngDirChoose);
        mainBuilder.nextLine();
        mainBuilder.append("Animation Width", xSizeField);
        mainBuilder.nextLine();
        mainBuilder.append("Animation Height", ySizeField);
        mainBuilder.nextLine();
        mainBuilder.append("Animation FPS", frameRateField);
        mainBuilder.nextLine();
        mainBuilder.append("Output File", outFile, outFileChoose);
        mainBuilder.nextLine();

        mainBuilder.append("GZip Compression", gzipCheckBox);
        mainBuilder.nextLine();

        mainBuilder.appendUnrelatedComponentsGapRow();
        mainBuilder.nextLine();

        mainBuilder.appendSeparator("Movie Information (optional)");
        mainBuilder.nextLine();

        mainBuilder.append("Title", titleField);
        mainBuilder.nextLine();
        mainBuilder.append("Description", descriptionField);
        mainBuilder.nextLine();
        mainBuilder.append("Author", authorField);
        mainBuilder.nextLine();
        mainBuilder.append("Email", emailField);
        mainBuilder.nextLine();
        mainBuilder.append("URL", urlField);
        mainBuilder.nextLine();

        mainBuilder.appendUnrelatedComponentsGapRow();
        mainBuilder.nextLine();

        mainBuilder.append(ButtonBarFactory.buildOKCancelBar(startButton, cancelButton), 5);
        mainBuilder.nextLine();

        mainBuilder.appendUnrelatedComponentsGapRow();
        mainBuilder.nextLine();

        mainBuilder.append(progress, 5);
        mainBuilder.nextLine();

        mainBuilder.append(statusLine, 5);
        mainBuilder.nextLine();

        mainFrame.getContentPane().add(mainBuilder.getPanel());
        mainFrame.pack();

        int x = prefs.getInt("frameX", 20);
        int y = prefs.getInt("frameY", 20);
        int width = mainFrame.getPreferredSize().width;
        int height = mainFrame.getPreferredSize().height;
        mainFrame.setBounds(x, y, width, height);

        mainFrame.setVisible(true);

        inputVerifier.verifyAndSave();
    }

    private class InputVerifier implements DocumentListener, ChangeListener {

        public void changedUpdate(DocumentEvent arg0) {
            verifyAndSave();
        }

        public void insertUpdate(DocumentEvent arg0) {
            verifyAndSave();
        }

        public void removeUpdate(DocumentEvent arg0) {
            verifyAndSave();
        }

        public void stateChanged(ChangeEvent arg0) {
            verifyAndSave();
        }

        public void verifyAndSave() {
            startButton.setEnabled(false);
            prefs.put("pngDir", pngDir.getText());
            prefs.put("outFile", outFile.getText());
            prefs.put("xSize", xSizeField.getText());
            prefs.put("ySize", ySizeField.getText());
            prefs.putInt("fps", ((Number) frameRateField.getValue()).intValue());

            prefs.put("title", titleField.getText());
            prefs.put("description", descriptionField.getText());
            prefs.put("author", authorField.getText());
            prefs.put("email", emailField.getText());
            prefs.put("url", urlField.getText());

            prefs.putBoolean("gzip", gzipCheckBox.isSelected());

            if (!new File(pngDir.getText()).isDirectory()) {
                statusLine.setText("Source Directory isn't a directory.");
                return;
            }

            File outFileParent = new File(outFile.getText()).getAbsoluteFile().getParentFile();
            File out = new File(outFile.getText());

            if (outFileParent == null || out.isDirectory() || !outFileParent.exists()) {
                statusLine.setText("Output directory is invalid");
                return;
            }

            try {
                int xSize = Integer.parseInt(xSizeField.getText());
                if (xSize < 1) {
                    statusLine.setText("Width must be positive.");
                    return;
                }
            } catch (NumberFormatException e) {
                statusLine.setText("Width must be an integer.");
                return;
            }

            try {
                int ySize = Integer.parseInt(ySizeField.getText());
                if (ySize < 1) {
                    statusLine.setText("Height must be positive.");
                    return;
                }
            } catch (NumberFormatException e) {
                statusLine.setText("Height must be an integer.");
                return;
            }

            statusLine.setText(version);
            startButton.setEnabled(true);
        }

    }

    private static class ImageFileNameFilter implements FilenameFilter {

        public boolean accept(File dir, String name) {
            File file = new File(dir, name);
            if (name.startsWith(".") || file.isHidden() || file.isDirectory()) {
                return false;
            }
            return true;
        }

    }

    private class ConvertTask extends SwingWorker<Object, Object> {

        private final File pngDir2;
        private final File output;
        private final Dimension size;
        private final int bpp;
        private String currentFileName;
        private OutputStream outputStream;
        private int filesProcessed;
        private final Map<String, String> headerData;
        private final boolean gzip;

        protected ConvertTask(File pngDir, File output, Dimension size, int bpp, Map<String, String> headerData,
                boolean gzip) {
            pngDir2 = pngDir;
            this.output = output;
            this.size = size;
            this.bpp = bpp;
            this.headerData = headerData;
            this.gzip = gzip;
            startButton.setEnabled(false);
            cancelButton.setEnabled(true);
            progress.setValue(0);
            //progress.setVisible(true);
        }

        @Override
        protected Object doInBackground() throws Exception {

            if (gzip) {
                outputStream = new GZIPOutputStream(new FileOutputStream(output));
            } else {
                outputStream = new FileOutputStream(output);
            }
            File[] files = pngDir2.listFiles();
            Arrays.sort(files);

            BMLOutputStream bmlOut = new BMLOutputStream(outputStream,
                    ((Number) frameRateField.getValue()).intValue(), size, bpp, headerData);

            File[] fileList = pngDir2.listFiles(new ImageFileNameFilter());
            filesProcessed = 0;
            for (File file : fileList) {
                currentFileName = file.getName();
                statusLine.setText("Processing: " + currentFileName);
                if (isCancelled()) {
                    return null;
                }
                BufferedImage image = (BufferedImage) ImageIO.read(file);
                if (image != null) {
                    bmlOut.writeFrame(image);
                } else {
                    System.err.println("error processing " + file);
                    throw new Exception("<html>ImageIO is unable to convert this file.<br>Processing aborted.");
                }
                filesProcessed++;
                int progress = (int) (filesProcessed / (float) fileList.length * 100);
                setProgress(progress);

            }
            bmlOut.close();
            return null;
        }

        @Override
        protected void done() {
            super.done();
            startButton.setEnabled(true);
            cancelButton.setEnabled(false);
            statusLine.setText(version);
            progress.setValue(0);
            try {
                get();
                JOptionPane.showMessageDialog(mainFrame, "<html>Done!<br>" + filesProcessed + " frames processed.");
            } catch (Exception e) {
                Throwable cause = e;
                while (cause.getCause() != null) {
                    cause = cause.getCause();
                }
                if (currentFileName != null) {
                    JOptionPane.showMessageDialog(mainFrame,
                            "<html>Error processing <b>" + currentFileName + "</b>:<br>" + cause.getMessage());
                } else {
                    JOptionPane.showMessageDialog(mainFrame, "<html>Error: " + e.getMessage());
                }
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException e1) {
                        //no big deal...
                    }
                }
                // remove broken output file
                output.delete();
                e.printStackTrace();
            }

        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException {

        final ImageToBML main = new ImageToBML();
        main.createAndShowGUI();
        // wait for swing to exit...

        /*
        if (args.length != 4) {
           System.out.println("usage: <png directory> <x> <y> <output file>");
           return;
        }
            
        */

    }

}