This program can be used to overlay transparant pictures on top of a list of background pictures. For example you can use this to put a logo on all your photos.
The base pictures are the background pictures. When you press Start, each background picture will be overlaid with one of the overlay pictures (iterating through the list). If there is only one overlay picture, each output picture will have the same overlay.
The overlay pictures need to be transparent, so these need to be .gif of .png files.
If you want to use text in the overlay pictures, just use a program such as PhotoShop to type text into a picture file.
ImageOverlayer is distributed under the GNU General Public License.
Download it for free: ImageOverlayer.jar (Windows / Linux / MacOS / any Java platform)
Installation instruction: You must have Java (JRE – Java Runtime Environment) installed on your computer to run. Download the above file and save it to a directory on your harddrive. Double click on ImageOverlayer.jar to start the application.
The source code consists of two files. Click to see them below:
package imgoverlayer; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.*; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.*; import javax.swing.filechooser.FileFilter; import javax.imageio.*; import java.util.*; /** * @author Bart * ImgOverlayer. (c) 2006, Bart Groot. * Overlays a picture file with a png or gif overlay and exports it to jpg. * TODO: * Add drag'n'drop functionality */ public class OverlayFrame extends JFrame implements ActionListener, ListSelectionListener{ private static final long serialVersionUID = 1L; enum Overwrite {ASK, YES, NO}; JList basePictures, overlayPictures; JPanel p, inputPanel, outputPanel, mainPanel, basePanel, overlayPanel, extraPanel, previewPanel, helpPanel; Box outputBox; JTextField outputDirField, padField, prefixField; JButton goButton, baseAddButton, baseRemoveButton, baseClearButton, overlayAddButton, overlayRemoveButton, overlayClearButton, outputDirButton; JProgressBar progressBar; JLabel previewLabel; JTextArea helpText; JCheckBox previewCheckBox; JFileChooser fc; FileFilter overlayFileFilter, imageFileFilter; Vector<File> baseFiles, overlayFiles; Overwrite overwrite; boolean inProgress = false; public static void main(String[] args) { new OverlayFrame(); } public OverlayFrame() { this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent w) { System.exit(0); } }); try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Exception e) { } this.setTitle("Image Overlayer v1.0 (c) Bart Groot"); this.setSize(550, 550); this.setLocationByPlatform(true); this.setLayout(new BorderLayout()); this.getContentPane().add(mainPanel = new JPanel(new BorderLayout())); mainPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10)); createInputGUI(); createOutputGUI(); createExtraGUI(); // Add functionality to buttons goButton.addActionListener(this); baseAddButton.addActionListener(this); baseRemoveButton.addActionListener(this); baseClearButton.addActionListener(this); overlayAddButton.addActionListener(this); overlayRemoveButton.addActionListener(this); overlayClearButton.addActionListener(this); outputDirButton.addActionListener(this); // Init other variables fc = new JFileChooser(FileSystemView.getFileSystemView()); imageFileFilter = new CustomFileFilter("Image files (jpg,bmp,gif,png)", ".jpg", ".bmp", ".gif", ".png"); overlayFileFilter = new CustomFileFilter( "Overlay images (gif and png)", ".gif", ".png"); // Show the frame setVisible(true); } private void createExtraGUI() { extraPanel = new JPanel(new BorderLayout()); extraPanel.add(previewPanel = new JPanel(new BorderLayout()), BorderLayout.EAST); previewPanel.add(previewLabel = new JLabel(), BorderLayout.CENTER); previewLabel.setPreferredSize(new Dimension(100,100)); previewPanel.add(previewCheckBox = new JCheckBox("Enable preview"), BorderLayout.NORTH); previewCheckBox.setSelected(true); previewCheckBox.addActionListener(this); previewPanel.setBorder(BorderFactory.createTitledBorder("Preview")); extraPanel.add(helpPanel = new JPanel(new BorderLayout()),BorderLayout.CENTER); helpPanel.add(helpText = new JTextArea("Add some background files and one or more overlay picture files.\n" + "When you press Start, each background file will be combined with an alternating overlay picture.\n" + "The pictures will be saved as numbered JPGs in the output directory.")); helpText.setBackground(helpPanel.getBackground()); helpText.setEditable(false); helpText.setLineWrap(true); helpText.setFont(helpPanel.getFont()); helpPanel.setBorder(BorderFactory.createTitledBorder("Explanation")); mainPanel.add(extraPanel,BorderLayout.NORTH); } private void createInputGUI() { inputPanel = new JPanel(new GridLayout(2, 1, 5, 5)); // Base pictures p = new JPanel(new BorderLayout()); p.add(new JScrollPane(basePictures = new JList( baseFiles = new Vector<File>())), BorderLayout.CENTER); basePictures.addListSelectionListener(this); basePanel = new JPanel(new GridLayout(3, 1, 5, 5)); basePanel.add(baseAddButton = new JButton("Add...")); basePanel.add(baseRemoveButton = new JButton("Remove")); basePanel.add(baseClearButton = new JButton("Clear")); p.add(basePanel, BorderLayout.EAST); p.setBorder(BorderFactory.createTitledBorder("Base pictures")); inputPanel.add(p); // Overlay pictures p = new JPanel(new BorderLayout()); p.add(new JScrollPane(overlayPictures = new JList( overlayFiles = new Vector<File>())), BorderLayout.CENTER); overlayPictures.addListSelectionListener(this); overlayPanel = new JPanel(new GridLayout(3, 1, 5, 5)); overlayPanel.add(overlayAddButton = new JButton("Add...")); overlayPanel.add(overlayRemoveButton = new JButton("Remove")); overlayPanel.add(overlayClearButton = new JButton("Clear")); p.add(overlayPanel, BorderLayout.EAST); p.setBorder(BorderFactory.createTitledBorder("Overlay pictures")); inputPanel.add(p); mainPanel.add(inputPanel, BorderLayout.CENTER); } private void createOutputGUI() { outputPanel = new JPanel(new BorderLayout()); outputBox = new Box(BoxLayout.Y_AXIS); p = new JPanel(new BorderLayout()); p.add(new JLabel("Directory: "), BorderLayout.WEST); p.add(outputDirField = new JTextField(), BorderLayout.CENTER); p.add(outputDirButton = new JButton("..."), BorderLayout.EAST); outputBox.add(p); p = new JPanel(); p.add(new JLabel("Output file - Prefix: ")); p.add(prefixField = new JTextField(5)); p.add(new JLabel("Pad 0's to how many chars: ")); p.add(padField = new JTextField("2")); outputBox.add(p); p = new JPanel(new BorderLayout()); p.add(progressBar = new JProgressBar(), BorderLayout.CENTER); progressBar.setStringPainted(true); p.add(goButton = new JButton(" Start "), BorderLayout.EAST); outputBox.add(p); outputPanel.add(outputBox, BorderLayout.CENTER); outputPanel.setBorder(BorderFactory.createTitledBorder("Output")); mainPanel.add(outputPanel, BorderLayout.SOUTH); } public boolean overlayImage(File baseFilename, File overlayFilename, String outputFilename) { // Write generated image to a file try { // Save as JPEG File file = new File(outputFilename); boolean proceed = false; if (overwrite == Overwrite.YES || !file.exists()) proceed = true; if (file.exists() && overwrite == Overwrite.ASK) { Object[] options = { "Yes", "No", "Yes to All", "No to All", "Cancel" }; int choice = JOptionPane .showOptionDialog(this, "File already exists:\n\n" + file + "\n\nOverwrite?", "Please choose an option", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); switch (choice) { case 0: proceed = true; break; case 1: break; case 2: overwrite = Overwrite.YES; proceed = true; break; case 3: overwrite = Overwrite.NO; break; default: return false; } } if (proceed) { // Create an image to save BufferedImage rendImage = createOverlayImage(baseFilename, overlayFilename); ImageIO.write(rendImage, "jpg", file); } } catch (IOException e) { showError(e.getMessage()); } return true; } // Returns the overlaid image. public BufferedImage createOverlayImage(File baseFilename, File overlayFilename) { BufferedImage image1 = null; BufferedImage image2 = null; try { // Read from a file image1 = ImageIO.read(baseFilename); } catch (IOException e) { showError(e.getMessage()); } try { // Read from a file image2 = ImageIO.read(overlayFilename); } catch (IOException e) { showError(e.getMessage()); } // Create a graphics contents on the buffered image Graphics2D g2d = image1.createGraphics(); // Draw the overlay image onto the first image g2d.drawImage(image2, 0, 0, null); g2d.dispose(); return image1; } public void actionPerformed(ActionEvent e) { if (e.getSource()==goButton) clickGo(); else if (e.getSource()==outputDirButton) selectOutputDir(); else if (e.getSource()==baseAddButton) { if (showFileDialogToAdd(imageFileFilter,baseFiles)) basePictures.setListData(baseFiles); } else if (e.getSource()==overlayAddButton) { if (showFileDialogToAdd(overlayFileFilter,overlayFiles)) overlayPictures.setListData(overlayFiles); } else if (e.getSource()==baseRemoveButton) { int[] values = basePictures.getSelectedIndices(); for (int i=values.length-1; i>=0; i--) baseFiles.remove(values[i]); basePictures.setListData(baseFiles); } else if (e.getSource()==overlayRemoveButton) { int[] values = overlayPictures.getSelectedIndices(); for (int i=values.length-1; i>=0; i--) overlayFiles.remove(values[i]); overlayPictures.setListData(overlayFiles); } else if (e.getSource()==baseClearButton) { baseFiles.clear(); basePictures.setListData(baseFiles); } else if (e.getSource()==overlayClearButton) { overlayFiles.clear(); overlayPictures.setListData(overlayFiles); } else if (e.getSource()==previewCheckBox) { if (previewCheckBox.isSelected()) valueChanged(null); else previewLabel.setIcon(null); } } public boolean showFileDialogToAdd(FileFilter ff, Vector<File> v) { fc.setFileFilter(ff); fc.setMultiSelectionEnabled(true); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); if (fc.showDialog(this,"Add")==JFileChooser.APPROVE_OPTION) { File[] files = fc.getSelectedFiles(); for (int i=0; i<files.length; i++) v.add(files[i]); return true; } else return false; } public void selectOutputDir() { fc.setMultiSelectionEnabled(false); fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); if (fc.showDialog(this,"Select")==JFileChooser.APPROVE_OPTION) outputDirField.setText(fc.getSelectedFile().getAbsolutePath()); } public void setInProgress(boolean b) { inProgress = b; if (inProgress) { progressBar.setMaximum(baseFiles.size()); this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } else { progressBar.setValue(0); this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } public void clickGo() { String dir = outputDirField.getText().trim(); if (baseFiles.size()==0) showError("Please add some base pictures."); else if (overlayFiles.size()==0) showError("Please add some overlay pictures."); else { if (dir.equals("")) { dir = overlayFiles.elementAt(0).getParent(); if (JOptionPane .showConfirmDialog( this, "No output dir specified.\nProceed with same dir as first overlay picture?\n\n(" + dir + ")", "Proceed in overlay dir?", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) return; } // add a backslash if necessary if (dir.charAt(dir.length()-1)!='\\') dir=dir+"\\"; // determine up to how many characters we have to pad zeroes int zeroes=0; try { zeroes = Integer.parseInt(padField.getText().trim()); } catch (NumberFormatException e) { showError("Invalid number of 0's to pad"); } int overlayCounter=0; setInProgress(true); overwrite = Overwrite.ASK; for (int i=0;i<baseFiles.size();i++) { progressBar.setValue(i); basePictures.setSelectedIndex(i); basePictures.ensureIndexIsVisible(i); overlayPictures.setSelectedIndex(overlayCounter); overlayPictures.ensureIndexIsVisible(overlayCounter); this.update(this.getGraphics()); // auto-number String filename = ""+(i+1); // pad zeroes while (filename.length()<zeroes) filename = "0"+filename; // construct rest of filename filename = dir+prefixField.getText()+filename+".jpg"; // do the work if (!overlayImage(baseFiles.elementAt(i), overlayFiles.elementAt(overlayCounter), filename)) { setInProgress(false); return; // returns false if cancelled } // determine which overlay to use next time overlayCounter=(overlayCounter+1)%overlayFiles.size(); } progressBar.setValue(progressBar.getMaximum()); JOptionPane.showMessageDialog(this,"Operation completed"); setInProgress(false); } } public void showError(String message) { JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); } public void valueChanged(ListSelectionEvent e) { if (!previewCheckBox.isSelected() || inProgress) return; File baseFile = (File) basePictures.getSelectedValue(); File overlayFile = (File) overlayPictures.getSelectedValue(); ImageIcon tmpIcon = null, thumbnail = null; if (baseFile != null && overlayFile == null) tmpIcon = new ImageIcon(baseFile.getPath()); else if (baseFile == null && overlayFile != null) tmpIcon = new ImageIcon(overlayFile.getPath()); else if (baseFile != null && overlayFile != null) { BufferedImage img = createOverlayImage(baseFile, overlayFile); tmpIcon = new ImageIcon(img); } if (tmpIcon != null) { if (tmpIcon.getIconWidth() > 100) { thumbnail = new ImageIcon(tmpIcon.getImage().getScaledInstance( 100, -1, Image.SCALE_DEFAULT)); } else { //no need to miniaturize thumbnail = tmpIcon; } } previewLabel.setIcon(thumbnail); } }
package imgoverlayer; import java.io.File; import javax.swing.filechooser.FileFilter; /** * @author Bart Groot * Provides an easy way to create various FileFilters with just one class. */ public class CustomFileFilter extends FileFilter { String description; String[] extensions; /** * @param description * Description of the file filter. E.g.: "Photo's (jpg)" * @param extensions * List of accepted extensions. * Must be in lower case and include the preceding dot. */ public CustomFileFilter(String description, String ... extensions) { this.description = description; this.extensions = extensions; } public boolean accept(File f) { if (f.isDirectory()) return true; String name = f.getName().toLowerCase(); for (int i=0;i<extensions.length;i++) if (name.endsWith(extensions[i])) return true; return false; } public String getDescription() { return description; } }
Leave a Reply