comparison src/name/blackcap/imageprep/RotateDialog.kt @ 1:0bded24f746e

Compiles, still untested.
author David Barts <n5jrn@me.com>
date Thu, 16 Jul 2020 21:51:08 -0700
parents e0efe7848130
children 09dcd475d1bf
comparison
equal deleted inserted replaced
0:e0efe7848130 1:0bded24f746e
1 /* 1 /*
2 * Represents a file being edited (rotated) 2 * Represents a file being edited (rotated)
3 */ 3 */
4 package name.blackcap.imageprep 4 package name.blackcap.imageprep
5 5
6 import java.awt.Dimension
7 import java.awt.Graphics
6 import java.awt.Graphics2D 8 import java.awt.Graphics2D
7 import java.awt.RenderingHints 9 import java.awt.RenderingHints
10 import java.awt.event.ActionListener
8 import java.awt.image.BufferedImage 11 import java.awt.image.BufferedImage
9 import java.io.File 12 import java.io.File
10 import java.io.IOException 13 import java.io.IOException
11 import javax.imageio.ImageIO 14 import javax.imageio.ImageIO
12 import javax.swing.* 15 import javax.swing.*
16 private val BW = 9 19 private val BW = 9
17 private val BW2 = BW * 2 20 private val BW2 = BW * 2
18 private val MINWIDTH = 512 21 private val MINWIDTH = 512
19 private val MINHEIGHT = 384 22 private val MINHEIGHT = 384
20 23
21 private class DrawingPane() : JPanel() { 24 private class DrawingPane(initialImage: BufferedImage) : JPanel() {
22 var image: BufferedImage = initialImage 25 var image: BufferedImage = initialImage
23 set(value) { 26 set(value) {
24 field = value 27 field = value
25 revalidate() 28 revalidate()
26 repaint() 29 repaint()
27 } 30 }
28 31
29 override val preferredSize 32 override fun getPreferredSize() = Dimension(image.width, image.height)
30 get { return image.preferredSize }
31 33
32 protected paintComponent(g: Graphics): Unit { 34 override protected fun paintComponent(g: Graphics): Unit {
33 g.drawImage(image, 0, 0, null) 35 g.drawImage(image, 0, 0, null)
34 } 36 }
35 } 37 }
36 private val drawingPane = DrawingPane() 38 private val drawingPane = DrawingPane(initialImage)
37 39
38 val image: BufferedImage 40 val image: BufferedImage
39 get() { return drawingPane.image } 41 get() { return drawingPane.image }
40 42
41 private val r90cw = JButton("90° CW").apply { 43 private val r90cw = JButton("90° CW").also {
42 it.addActionListener(ActionListener { doRotate(90) }) 44 it.addActionListener(ActionListener { doRotate(90) })
43 } 45 }
44 46
45 private val r180 = JButton("180°").apply { 47 private val r180 = JButton("180°").also {
46 it.addActionListener(ActionListener { doRotate(180) }) 48 it.addActionListener(ActionListener { doRotate(180) })
47 } 49 }
48 50
49 private val r90ccw = JButton("90° CCW").apply { 51 private val r90ccw = JButton("90° CCW").also {
50 it.addActionListener(ActionListener { doRotate(270) }) 52 it.addActionListener(ActionListener { doRotate(270) })
51 } 53 }
52 54
53 /* Theoretically, this should do the rotation in a background thread. 55 /* Theoretically, this should do the rotation in a background thread.
54 Practically, that is fraught with difficulties, as it involves 56 Practically, that is fraught with difficulties, as it involves
62 val w = floor(image.width * cosx + image.height * sinx).toInt() 64 val w = floor(image.width * cosx + image.height * sinx).toInt()
63 val h = floor(image.height * cosx + image.width * sinx).toInt() 65 val h = floor(image.height * cosx + image.width * sinx).toInt()
64 val rotatedImage = BufferedImage(w, h, image.type) 66 val rotatedImage = BufferedImage(w, h, image.type)
65 rotatedImage.createGraphics().run { 67 rotatedImage.createGraphics().run {
66 translate((w - image.width) / 2, (h - image.height) / 2) 68 translate((w - image.width) / 2, (h - image.height) / 2)
67 rotate(rad, image.width / 2, image.height / 2) 69 rotate(rad, image.width.toDouble()/2.0, image.height.toDouble()/2.0)
68 drawRenderedImage(image, null) 70 drawRenderedImage(image, null)
69 dispose() 71 dispose()
70 } 72 }
71 drawingPane.image = rotatedImage 73 drawingPane.image = rotatedImage
72 } 74 }
74 init { 76 init {
75 defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE 77 defaultCloseOperation = JDialog.DISPOSE_ON_CLOSE
76 title = "Untitled" 78 title = "Untitled"
77 contentPane.apply { 79 contentPane.apply {
78 layout = BoxLayout(this, BoxLayout.Y_AXIS) 80 layout = BoxLayout(this, BoxLayout.Y_AXIS)
79 add(JScrollpane(drawingPane).apply { 81 add(JScrollPane(drawingPane).apply {
80 alignmentX = JScrollPane.CENTER_ALIGNMENT 82 alignmentX = JScrollPane.CENTER_ALIGNMENT
81 addBorder(BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2)) 83 addBorder(BorderFactory.createEmptyBorder(BW2, BW2, BW, BW2))
82 verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS 84 verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
83 horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS 85 horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS
84 background = Application.mainFrame.background 86 background = Application.mainFrame.background
104 * 106 *
105 * @param input java.io.File to read for image. 107 * @param input java.io.File to read for image.
106 */ 108 */
107 fun makeDialog(input: File): Unit { 109 fun makeDialog(input: File): Unit {
108 Application.mainFrame.useWaitCursor() 110 Application.mainFrame.useWaitCursor()
109 swingWorker<Pair<BufferedImage?, IOException?> { 111 swingWorker<Pair<BufferedImage?, IOException?>> {
110 inBackground { 112 inBackground {
111 try { 113 try {
112 val imageIn = ImageIO.read(input) /* IOException */ 114 val imageIn = ImageIO.read(input) /* IOException */
113 val ratio = Settings.maxDimension.toDouble() / max(imageIn.width, imageIn.height).toDouble() 115 val ratio = Settings.maxDimension.toDouble() / max(imageIn.width, imageIn.height).toDouble()
114 if (ratio >= 1.0) { 116 if (ratio >= 1.0) {
115 null 117 Pair(null, null)
116 } else { 118 } else {
117 val nWidth = (imageIn.width * ratio).toInt() 119 val nWidth = (imageIn.width * ratio).toInt()
118 val nHeight = (imageIn.height * ratio).toInt() 120 val nHeight = (imageIn.height * ratio).toInt()
119 val imageOut = BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_RGB) 121 val imageOut = BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_RGB)
120 val graphics = imageOut.createGraphics().apply { 122 val graphics = imageOut.createGraphics().apply {
132 whenDone { 134 whenDone {
133 Application.mainFrame.useNormalCursor() 135 Application.mainFrame.useNormalCursor()
134 val (image, error) = get() 136 val (image, error) = get()
135 if (error != null) 137 if (error != null)
136 ioExceptionDialog(Application.mainFrame, input, "read", error) 138 ioExceptionDialog(Application.mainFrame, input, "read", error)
137 if (image != null) 139 else if (image != null)
138 RotateDialog(input, image).title = input.getName() 140 RotateDialog(input, image).title = input.getName()
141 else
142 JOptionPane.showMessageDialog(Application.mainFrame,
143 "Image is too small to be scaled.",
144 "Warning", JOptionPane.WARNING_MESSAGE)
139 } 145 }
140 } 146 }
141 } 147 }
142 } 148 }
143 } 149 }