2019-01-17 17:27:03 +01:00
|
|
|
package nl.aegeedelft.watermarker
|
|
|
|
|
|
|
|
import org.intellij.lang.annotations.Language
|
2019-02-11 18:01:30 +01:00
|
|
|
import java.awt.*
|
2019-01-17 17:27:03 +01:00
|
|
|
import java.awt.image.BufferedImage
|
|
|
|
import java.awt.image.RenderedImage
|
|
|
|
import java.io.BufferedInputStream
|
|
|
|
import java.io.ByteArrayInputStream
|
|
|
|
import java.io.File
|
2019-01-22 12:16:58 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicInteger
|
2019-01-17 17:27:03 +01:00
|
|
|
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
|
2019-01-22 12:16:58 +01:00
|
|
|
import kotlin.concurrent.fixedRateTimer
|
|
|
|
import kotlin.concurrent.thread
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
@Language("RegExp")
|
|
|
|
val filenameRegex = ".*\\.(png|jpe?g|bmp)".toRegex()
|
|
|
|
|
|
|
|
val jf = JFrame("WaterMarker")
|
|
|
|
|
2019-01-22 12:16:58 +01:00
|
|
|
val counter = AtomicInteger()
|
|
|
|
val runbtn = JButton("Run!")
|
|
|
|
|
|
|
|
val pbar = JProgressBar()
|
|
|
|
|
2019-02-11 18:01:30 +01:00
|
|
|
val dlg = JDialog(jf, "Watermarking Images!", true)
|
2019-01-22 12:16:58 +01:00
|
|
|
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
fun main(args: Array<String>) {
|
2019-02-11 18:01:30 +01:00
|
|
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
|
|
|
|
|
|
|
|
2019-01-17 17:27:03 +01:00
|
|
|
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(".")
|
2019-02-11 18:01:30 +01:00
|
|
|
basepicker.fileSelectionMode = JFileChooser.FILES_AND_DIRECTORIES
|
2019-01-17 17:27:03 +01:00
|
|
|
basepicker.isAcceptAllFileFilterUsed = false
|
2019-02-11 18:01:30 +01:00
|
|
|
basepicker.fileFilter = object : FileFilter() {
|
|
|
|
override fun accept(f: File): Boolean = f.isDirectory
|
|
|
|
|
|
|
|
override fun getDescription(): String = "Folders"
|
|
|
|
|
|
|
|
}
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
outpicker.currentDirectory = File(".")
|
2019-02-11 18:01:30 +01:00
|
|
|
outpicker.fileSelectionMode = JFileChooser.FILES_AND_DIRECTORIES
|
2019-01-17 17:27:03 +01:00
|
|
|
outpicker.isAcceptAllFileFilterUsed = false
|
2019-02-11 18:01:30 +01:00
|
|
|
outpicker.fileFilter = basepicker.fileFilter
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
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())
|
2019-01-22 12:16:58 +01:00
|
|
|
runbtn.apply {
|
2019-01-17 17:27:03 +01:00
|
|
|
addActionListener {
|
|
|
|
if (watermark != null && outdir != null && basedir != null) {
|
2019-01-22 12:16:58 +01:00
|
|
|
this.isEnabled = false
|
|
|
|
thread {
|
2019-02-11 18:01:30 +01:00
|
|
|
watermarkImages(basedir!!, outdir!!, watermark!!)
|
2019-01-22 12:16:58 +01:00
|
|
|
}
|
2019-01-17 17:27:03 +01:00
|
|
|
} else {
|
|
|
|
JOptionPane.showMessageDialog(
|
|
|
|
jf,
|
|
|
|
"You have left one of the files empty!",
|
|
|
|
"Error!",
|
|
|
|
JOptionPane.ERROR_MESSAGE
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2019-01-22 12:16:58 +01:00
|
|
|
}
|
|
|
|
box.add(runbtn.forceToCenter())
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
jf.add(box, BorderLayout.CENTER)
|
|
|
|
|
2019-02-11 18:01:30 +01:00
|
|
|
val menuBar = JMenuBar()
|
|
|
|
val helpMenu = JMenu("Help")
|
|
|
|
val fileMenu = JMenu("File")
|
|
|
|
menuBar.add(fileMenu)
|
|
|
|
menuBar.add(helpMenu)
|
|
|
|
val infoItem = JMenuItem("About")
|
|
|
|
helpMenu.add(infoItem)
|
|
|
|
infoItem.addActionListener {
|
|
|
|
JOptionPane.showMessageDialog(
|
|
|
|
jf,
|
|
|
|
"WaterMarker\n" +
|
|
|
|
"An app written by Julius de Jeu for AEGEE-Delft. \n" +
|
|
|
|
"\n" +
|
|
|
|
"Copyright (c) Julius de Jeu 2019",
|
|
|
|
"About",
|
|
|
|
JOptionPane.PLAIN_MESSAGE
|
|
|
|
)
|
|
|
|
}
|
|
|
|
fileMenu.add(JMenuItem("Exit").apply {
|
|
|
|
addActionListener {
|
|
|
|
System.exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
accelerator = KeyStroke.getKeyStroke("ALT F4")
|
|
|
|
})
|
|
|
|
|
|
|
|
jf.jMenuBar = menuBar
|
|
|
|
|
2019-01-17 17:27:03 +01:00
|
|
|
jf.setLocationRelativeTo(null)
|
|
|
|
jf.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
|
|
|
|
jf.preferredSize = Dimension(300, 300)
|
|
|
|
jf.size = jf.preferredSize
|
|
|
|
jf.isVisible = true
|
2019-01-22 12:16:58 +01:00
|
|
|
|
|
|
|
dlg.add(BorderLayout.CENTER, pbar)
|
|
|
|
dlg.defaultCloseOperation = JDialog.DO_NOTHING_ON_CLOSE
|
|
|
|
dlg.setSize(300, 75)
|
|
|
|
dlg.setLocationRelativeTo(jf)
|
2019-02-11 18:01:30 +01:00
|
|
|
pbar.foreground = Color.GREEN.darker()
|
2019-01-17 17:27:03 +01:00
|
|
|
}
|
|
|
|
|
2019-02-11 18:01:30 +01:00
|
|
|
fun watermarkImages(basedir: File, outdir: File, watermarkpath: File) {
|
2019-01-21 21:18:31 +01:00
|
|
|
val wmbase = ImageIO.read(watermarkpath)
|
|
|
|
|
|
|
|
val scale = 3.6
|
2019-01-17 17:27:03 +01:00
|
|
|
//JOptionPane.showMessageDialog(jf, "", "Inserting watermark!", JOptionPane.INFORMATION_MESSAGE, ImageIcon(watermark))
|
2019-01-17 17:33:09 +01:00
|
|
|
//FrmPopUpInfo("Inserting Watermark", watermark)
|
2019-01-22 12:16:58 +01:00
|
|
|
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
|
2019-02-11 18:01:30 +01:00
|
|
|
val imgOut =
|
|
|
|
MemoryCacheImageOutputStream(File(outdir, f.nameWithoutExtension + ".jpg").outputStream())
|
2019-01-22 12:16:58 +01:00
|
|
|
writer.output = imgOut
|
|
|
|
val ending = IIOImage(combined, null, imageMetadata)
|
|
|
|
writer.write(null, ending, iwp)
|
|
|
|
writer.dispose()
|
|
|
|
}
|
|
|
|
SwingUtilities.invokeLater {
|
|
|
|
pbar.value = counter.incrementAndGet()
|
|
|
|
}
|
|
|
|
}
|
2019-01-17 17:27:03 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-22 12:16:58 +01:00
|
|
|
|
2019-01-17 17:27:03 +01:00
|
|
|
}
|
|
|
|
|
2019-02-11 18:01:30 +01:00
|
|
|
fun Component.forceToCenter(): JPanel = JPanel().apply { this.add(this@forceToCenter) }
|
2019-01-17 17:27:03 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-01-21 21:18:31 +01:00
|
|
|
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
|
|
|
|
}
|