Mercurial > cgi-bin > hgweb.cgi > ImagePrep
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 } |