Mercurial > cgi-bin > hgweb.cgi > ImagePrep
view src/name/blackcap/imageprep/Menus.kt @ 15:fad32eda667f
Fix ImageWriter leak.
author | David Barts <n5jrn@me.com> |
---|---|
date | Sun, 19 Jul 2020 13:49:23 -0700 |
parents | bed255e4c2dc |
children | d71523cde521 |
line wrap: on
line source
/* * Menus. */ package name.blackcap.imageprep import java.awt.Graphics2D import java.awt.RenderingHints import java.awt.Toolkit import java.awt.Window import java.awt.event.ActionEvent import java.awt.event.ActionListener import java.awt.event.KeyEvent import java.awt.image.BufferedImage import java.io.File import java.io.IOException import java.util.logging.Level import java.util.logging.Logger import javax.imageio.IIOImage import javax.imageio.ImageIO import javax.imageio.ImageWriteParam import javax.imageio.ImageWriter import javax.imageio.stream.ImageOutputStream import javax.swing.* import javax.swing.filechooser.FileNameExtensionFilter /** * Our menu bar. What we display depends somewhat on the system type, as * the Mac gives us a gratuitous menu bar entry for handling some stuff. */ class MyMenuBar: JMenuBar() { var currentInputDirectory = File(System.getProperty("user.dir")) var currentOutputDirectory = File(Settings.outputTo) init { add(JMenu("File").apply { add(JMenuItem("Open & Scale…").apply { addActionListener(ActionListener { doOpen() }) makeShortcut(KeyEvent.VK_O) }) add(JMenuItem("Discard").apply { addActionListener(ActionListener { doDiscard() }) }) add(JMenuItem("Save & Close…").apply { addActionListener(ActionListener { doClose() }) makeShortcut(KeyEvent.VK_S) }) if (OS.type != OS.MAC) { add(JMenuItem("Quit").apply { addActionListener(ActionListener { LOGGER.log(Level.INFO, "execution complete") System.exit(0) }) makeShortcut(KeyEvent.VK_Q) }) } }) add(JMenu("Help").apply { if (OS.type != OS.MAC) { add(JMenuItem("About ${Application.MYNAME}…").apply { addActionListener(ActionListener { showAboutDialog() }) }) } add(JMenuItem("${Application.MYNAME} Help…").apply { addActionListener(ActionListener { Application.helpDialog.setVisible(true) }) }) }) } fun getMenu(name: String): JMenu? { subElements.forEach { val jmenu = it.component as? JMenu if (jmenu?.text == name) { return jmenu } } return null } private fun doOpen() { val chooser = JFileChooser().apply { currentDirectory = currentInputDirectory fileFilter = FileNameExtensionFilter("Image Files", *ImageIO.getReaderFileSuffixes()) } if (chooser.showOpenDialog(Application.mainFrame) == JFileChooser.APPROVE_OPTION) { currentInputDirectory = chooser.selectedFile.canonicalFile.parentFile RotateDialog.makeDialog(chooser.selectedFile) } } private fun doDiscard() { val w = FocusManager.getCurrentManager().activeWindow as? RotateDialog if (w == null) { Toolkit.getDefaultToolkit().beep() return } w.close() } /* xxx - ImageIO bug? */ private class NullOutputStream : java.io.OutputStream() { override fun write(b: Int): Unit {} } private fun doClose() { val w = FocusManager.getCurrentManager().activeWindow as? RotateDialog if (w == null) { LOGGER.log(Level.INFO, "beep!") Toolkit.getDefaultToolkit().beep() return } val outName = splitext(w.file.name).first + Settings.outputSuffix + ".jpg" val chooser = JFileChooser().apply { currentDirectory = currentOutputDirectory selectedFile = File(currentOutputDirectory, outName) } if (chooser.showSaveDialog(Application.mainFrame) != JFileChooser.APPROVE_OPTION) { return } currentOutputDirectory = chooser.selectedFile.canonicalFile.parentFile val (name, ext) = splitext(chooser.selectedFile.name) val file = if (ext.toLowerCase() in setOf(".jpg", ".jpeg")) { chooser.selectedFile } else { File(currentOutputDirectory, name + ".jpg") } if (file.exists() && JOptionPane.showConfirmDialog(w, "File ${file.name} already exists. Overwrite?", "Confirm Overwrite", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) { return } w.useWaitCursor() swingWorker<IOException?> { inBackground { try { /* xxx - ImageIO bug? */ val devNull = java.io.PrintStream(NullOutputStream()) val oldOut = System.out System.setOut(devNull) val oldErr = System.err System.setErr(devNull) val ios = try { ImageIO.createImageOutputStream(file) } finally { System.setErr(oldErr) System.setOut(oldOut) } if (ios == null) throw IOException() /* xxx - end workaround */ ios.use { val writer = ImageIO.getImageWritersByFormatName("jpeg").next() try { val iwp = writer.getDefaultWriteParam().apply { setCompressionMode(ImageWriteParam.MODE_EXPLICIT) setCompressionQuality(Settings.outputQuality.toFloat() / 100.0f) } writer.setOutput(it) writer.write(null, IIOImage(w.image, null, null), iwp) } finally { writer.dispose() } } null } catch (e: IOException) { e } } whenDone { w.useNormalCursor() val error = get() if (error == null) { w.close() } else { ioExceptionDialog(w, file, "write", error) } } } } private fun splitext(s: String): Pair<String, String> { val pos = s.lastIndexOf('.') if (pos == -1) { return Pair(s, "") } return Pair(s.substring(0, pos), s.substring(pos)) } } /** * Show an About dialog. */ fun showAboutDialog() { JOptionPane.showMessageDialog(Application.mainFrame, "\nImagePrep\n" + "\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0© MMXX, David W. Barts\n", "About ImagePrep", JOptionPane.PLAIN_MESSAGE) }