package nl.aegeedelft.watermarker import org.intellij.lang.annotations.Language import java.awt.BorderLayout import java.awt.Component import java.awt.Dimension import java.awt.Image import java.awt.image.BufferedImage import java.awt.image.RenderedImage import java.io.BufferedInputStream import java.io.ByteArrayInputStream import java.io.File import java.util.concurrent.atomic.AtomicInteger import javax.imageio.IIOImage import javax.imageio.ImageIO import javax.imageio.ImageWriteParam import javax.imageio.stream.MemoryCacheImageOutputStream import javax.swing.* import javax.swing.filechooser.FileFilter import kotlin.concurrent.fixedRateTimer import kotlin.concurrent.thread @Language("RegExp") val filenameRegex = ".*\\.(png|jpe?g|bmp)".toRegex() val jf = JFrame("WaterMarker") val counter = AtomicInteger() val runbtn = JButton("Run!") val pbar = JProgressBar() val dlg = JDialog(jf, "Progress Dialog", true) fun main(args: Array) { var watermark: File? = null var outdir: File? = null var basedir: File? = null val basepicker = JFileChooser() val bds = JLabel("Pick an input folder") val outpicker = JFileChooser() val ods = JLabel("Pick an output folder") val wmpicker = JFileChooser() val wms = JLabel("Pick a Watermark file") val box = Box.createVerticalBox() basepicker.currentDirectory = File(".") basepicker.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY basepicker.isAcceptAllFileFilterUsed = false outpicker.currentDirectory = File(".") outpicker.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY outpicker.isAcceptAllFileFilterUsed = false wmpicker.currentDirectory = File(".") wmpicker.fileSelectionMode = JFileChooser.FILES_ONLY wmpicker.fileFilter = object : FileFilter() { override fun accept(f: File): Boolean = filenameRegex.matches(f.name) or f.isDirectory override fun getDescription(): String = "Image Files" } wmpicker.isAcceptAllFileFilterUsed = false box.add( JButton("Select Input").apply { addActionListener { val c = basepicker.showOpenDialog(jf) if (c == JFileChooser.APPROVE_OPTION) { basedir = basepicker.selectedFile bds.text = basepicker.selectedFile.path } } }.forceToCenter() ) box.add(bds.forceToCenter()) box.add( JButton("Select Output").apply { addActionListener { val c = outpicker.showOpenDialog(jf) if (c == JFileChooser.APPROVE_OPTION) { outdir = outpicker.selectedFile ods.text = outpicker.selectedFile.path } } }.forceToCenter() ) box.add(ods.forceToCenter()) box.add( JButton("Select Watermark").apply { addActionListener { val c = wmpicker.showOpenDialog(jf) if (c == JFileChooser.APPROVE_OPTION) { watermark = wmpicker.selectedFile wms.text = wmpicker.selectedFile.path } } }.forceToCenter() ) box.add(wms.forceToCenter()) runbtn.apply { addActionListener { if (watermark != null && outdir != null && basedir != null) { this.isEnabled = false thread { doTheThing(basedir!!, outdir!!, watermark!!) } } else { JOptionPane.showMessageDialog( jf, "You have left one of the files empty!", "Error!", JOptionPane.ERROR_MESSAGE ) } } } box.add(runbtn.forceToCenter()) jf.add(box, BorderLayout.CENTER) jf.setLocationRelativeTo(null) jf.defaultCloseOperation = JFrame.EXIT_ON_CLOSE jf.preferredSize = Dimension(300, 300) jf.size = jf.preferredSize jf.isVisible = true dlg.add(BorderLayout.CENTER, pbar) dlg.defaultCloseOperation = JDialog.DO_NOTHING_ON_CLOSE dlg.setSize(300, 75) dlg.setLocationRelativeTo(jf) } fun doTheThing(basedir: File, outdir: File, watermarkpath: File) { val wmbase = ImageIO.read(watermarkpath) val scale = 3.6 //JOptionPane.showMessageDialog(jf, "", "Inserting watermark!", JOptionPane.INFORMATION_MESSAGE, ImageIcon(watermark)) //FrmPopUpInfo("Inserting Watermark", watermark) val files = basedir.listFiles().filter { filenameRegex.matches(it.name) }.chunked(5) val propersize = files.sumBy { it.size } counter.set(0) SwingUtilities.invokeLater { pbar.value = 0 pbar.maximum = propersize dlg.isVisible = true } fixedRateTimer("theWait", period = 500, initialDelay = 0) { if (counter.get() == propersize) { SwingUtilities.invokeLater { dlg.isVisible = false runbtn.isEnabled = true this.cancel() } } } for (fl in files) { thread { for (f in fl) { if (filenameRegex.matches(f.name.toString()) && !"jpe?g".toRegex().matches(f.extension)) { val image = ImageIO.read(f) val combined = addWM(resize(wmbase, wmbase.width / scale, wmbase.height / scale), image) as RenderedImage ImageIO.write(combined, "JPG", File(outdir, f.nameWithoutExtension + ".jpg")) } else { val `is` = BufferedInputStream(ByteArrayInputStream(f.readBytes())) val it = ImageIO.getImageReadersByMIMEType("image/jpeg") val reader = it.next() val iis = ImageIO.createImageInputStream(`is`) reader.setInput(iis, false, false) val image = reader.read(0) val imageMetadata = reader.getImageMetadata(0) val combined = addWM(resize(wmbase, wmbase.width / scale, wmbase.height / scale), image) as RenderedImage val iter = ImageIO.getImageWritersByMIMEType("image/jpeg") val writer = iter.next() val iwp = writer.defaultWriteParam iwp.compressionMode = ImageWriteParam.MODE_EXPLICIT iwp.compressionQuality = 0.9f val imgOut = MemoryCacheImageOutputStream(File(outdir, f.nameWithoutExtension + ".jpg").outputStream()) writer.output = imgOut val ending = IIOImage(combined, null, imageMetadata) writer.write(null, ending, iwp) writer.dispose() } SwingUtilities.invokeLater { pbar.value = counter.incrementAndGet() } } } } } fun Component.forceToCenter(): Component = JPanel().apply { this.add(this@forceToCenter) } fun addWM(watermark: BufferedImage, image: BufferedImage): Image { val combined = BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB) val g = combined.graphics g.drawImage(image, 0, 0, null) val x = image.width - watermark.width - 5 val y = image.height - watermark.height - 5 g.drawImage(watermark, x, y, null) return combined } fun resize(img: BufferedImage, newW: Double, newH: Double): BufferedImage { val tmp = img.getScaledInstance(newW.toInt(), newH.toInt(), Image.SCALE_SMOOTH) val dimg = BufferedImage(newW.toInt(), newH.toInt(), BufferedImage.TYPE_INT_ARGB) val g2d = dimg.createGraphics() g2d.drawImage(tmp, 0, 0, null) g2d.dispose() return dimg } //class FrmPopUpInfo(message: String, image: Image) : JFrame() { // init { // this.title = message // this.add(JLabel(ImageIcon(image))) // this.background = Color.WHITE // this.pack() // // this.setLocationRelativeTo(null) // obs.addObserver { _, _ -> // java.util.Timer().schedule(timerTask { // // }, 5 * 1000) // this@FrmPopUpInfo.isVisible = false // // this@FrmPopUpInfo.dispose() // } // // this.isVisible = true // } //}