Mercurial > cgi-bin > hgweb.cgi > ImagePrep
view src/name/blackcap/imageprep/RotateDialog.kt @ 2:a6f9b51d5e8d
Got jar building.
author | David Barts <n5jrn@me.com> |
---|---|
date | Fri, 17 Jul 2020 10:34:48 -0700 |
parents | 0bded24f746e |
children | 09dcd475d1bf |
line wrap: on
line source
/* * Represents a file being edited (rotated) */ package name.blackcap.imageprep import java.awt.Dimension import java.awt.Graphics import java.awt.Graphics2D import java.awt.RenderingHints import java.awt.event.ActionListener import java.awt.image.BufferedImage import java.io.File import java.io.IOException import javax.imageio.ImageIO import javax.swing.* import kotlin.math.* class RotateDialog(val file: File, initialImage: BufferedImage) : JDialog(Application.mainFrame) { private val BW = 9 private val BW2 = BW * 2 private val MINWIDTH = 512 private val MINHEIGHT = 384 private class DrawingPane(initialImage: BufferedImage) : JPanel() { var image: BufferedImage = initialImage set(value) { field = value revalidate() repaint() } override fun getPreferredSize() = Dimension(image.width, image.height) override protected fun paintComponent(g: Graphics): Unit { g.drawImage(image, 0, 0, null) } } private val drawingPane = DrawingPane(initialImage) val image: BufferedImage get() { return drawingPane.image } private val r90cw = JButton("90° CW").also { it.addActionListener(ActionListener { doRotate(90) }) } private val r180 = JButton("180°").also { it.addActionListener(ActionListener { doRotate(180) }) } private val r90ccw = JButton("90° CCW").also { it.addActionListener(ActionListener { doRotate(270) }) } /* Theoretically, this should do the rotation in a background thread. Practically, that is fraught with difficulties, as it involves manipulating data used by Swing itself. Since the size of the images being rotated are small, we do it in the foreground. */ private fun doRotate(deg: Int) { // https://stackoverflow.com/questions/15927014/rotating-an-image-90-degrees-in-java val rad = java.lang.Math.toRadians(deg.toDouble()) val sinx = sin(rad) val cosx = cos(rad) val w = floor(image.width * cosx + image.height * sinx).toInt() val h = floor(image.height * cosx + image.width * sinx).toInt() val rotatedImage = BufferedImage(w, h, image.type) rotatedImage.createGraphics().run { translate((w - image.width) / 2, (h - image.height) / 2) rotate(rad, image.width.toDouble()/2.0, image.height.toDouble()/2.0) drawRenderedImage(image, null) dispose() } drawingPane.image = rotatedImage } init { defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE title = "Untitled" contentPane.apply { layout = BoxLayout(this, BoxLayout.Y_AXIS) add(JScrollPane(drawingPane).apply { alignmentX = JScrollPane.CENTER_ALIGNMENT addBorder(BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2)) verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS background = Application.mainFrame.background }) add(Box(BoxLayout.X_AXIS).apply { alignmentX = Box.CENTER_ALIGNMENT addBorder(BorderFactory.createEmptyBorder(BW, BW2, BW2, BW2)) add(JLabel("Rotate:")) add(Box.createHorizontalGlue()) add(r90cw) add(Box.createHorizontalGlue()) add(r180) add(Box.createHorizontalGlue()) add(r90ccw) }) } pack() } companion object Factory { /** * Make a dialog asynchronously. * * @param input java.io.File to read for image. */ fun makeDialog(input: File): Unit { Application.mainFrame.useWaitCursor() swingWorker<Pair<BufferedImage?, IOException?>> { inBackground { try { val imageIn = ImageIO.read(input) /* IOException */ val ratio = Settings.maxDimension.toDouble() / max(imageIn.width, imageIn.height).toDouble() if (ratio >= 1.0) { Pair(null, null) } else { val nWidth = (imageIn.width * ratio).toInt() val nHeight = (imageIn.height * ratio).toInt() val imageOut = BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_RGB) val graphics = imageOut.createGraphics().apply { setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR) setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY) setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) } graphics.drawImage(imageIn, 0, 0, nWidth, nHeight, null) Pair(imageOut, null) } } catch (e: IOException) { Pair(null, e) } } whenDone { Application.mainFrame.useNormalCursor() val (image, error) = get() if (error != null) ioExceptionDialog(Application.mainFrame, input, "read", error) else if (image != null) RotateDialog(input, image).title = input.getName() else JOptionPane.showMessageDialog(Application.mainFrame, "Image is too small to be scaled.", "Warning", JOptionPane.WARNING_MESSAGE) } } } } }