
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
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); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
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; } } |