1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 /*
 26  * Based on code from HealingBrush renderscript example
 27  *
 28  * https://github.com/yongjhih/HealingBrush/tree/master
 29  *
 30  * Copyright (C) 2015 The Android Open Source Project
 31  *
 32  * Licensed under the Apache License, Version 2.0 (the "License");
 33  * you may not use this file except in compliance with the License.
 34  * You may obtain a copy of the License at
 35  *
 36  *      http://www.apache.org/licenses/LICENSE-2.0
 37  *
 38  * Unless required by applicable law or agreed to in writing, software
 39  * distributed under the License is distributed on an "AS IS" BASIS,
 40  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 41  * See the License for the specific language governing permissions and
 42  * limitations under the License.
 43  */
 44 package heal;
 45 
 46 
 47 import hat.Accelerator;
 48 import hat.buffer.S32Array2D;
 49 import hat.util.ui.SevenSegmentDisplay;
 50 
 51 import javax.swing.Box;
 52 import javax.swing.JButton;
 53 import javax.swing.JFrame;
 54 import javax.swing.JLabel;
 55 import javax.swing.JMenuBar;
 56 import javax.swing.JPanel;
 57 import javax.swing.JTextField;
 58 import javax.swing.SwingUtilities;
 59 import javax.swing.Timer;
 60 import java.awt.Color;
 61 import java.awt.Dimension;
 62 import java.awt.Graphics;
 63 import java.awt.Point;
 64 import java.awt.Graphics2D;
 65 import java.awt.Polygon;
 66 import java.awt.Rectangle;
 67 import java.awt.event.ActionEvent;
 68 import java.awt.event.ActionListener;
 69 import java.awt.event.MouseAdapter;
 70 import java.awt.event.MouseEvent;
 71 import java.awt.event.MouseMotionAdapter;
 72 import java.awt.geom.AffineTransform;
 73 import java.awt.geom.NoninvertibleTransformException;
 74 import java.awt.geom.Point2D;
 75 import java.awt.image.BufferedImage;
 76 import java.awt.image.DataBufferInt;
 77 
 78 public  class Viewer extends JFrame {
 79     public final MainPanel mainPanel;
 80     public static class MainPanel extends JPanel {
 81         protected BufferedImage image;
 82         protected int[] rasterData;
 83         protected S32Array2D s32Array2D;
 84         protected AffineTransform transform = new AffineTransform();
 85         protected float zoom = .95f; // set the zoom factor 1.0 = fit to screen
 86 
 87         protected float xOffset = 0; // 0 is centered -1 is to the left;
 88         protected float yOffset = 0; // 0 is centered -1 is to the top;
 89 
 90         Point mousePressedPosition;
 91         Point2D imageRelativeMouseDownPosition = new Point2D.Float();
 92         Point2D imageRelativeMovePosition = new Point2D.Float();
 93         volatile Selection selection = null;
 94         volatile Point bestMatchOffset = null;
 95 
 96 
 97         public MainPanel(Accelerator accelerator, BufferedImage image, Controls controls) {
 98             this.image = image;
 99             this.rasterData = ((DataBufferInt) (image.getRaster().getDataBuffer())).getData();
100             this.s32Array2D = S32Array2D.create(accelerator, image.getWidth(), image.getHeight());
101             s32Array2D.copyFrom(rasterData);
102             addMouseListener(new MouseAdapter() {
103 
104                 @Override
105                 public void mouseReleased(MouseEvent e) {
106                     if (SwingUtilities.isLeftMouseButton(e)) {
107                         bestMatchOffset = ComputeHeal.getBestMatchOffset(accelerator, s32Array2D, selection.close(), controls.sevenSegmentDisplay);
108                         ComputeHeal.heal(accelerator, s32Array2D, selection, bestMatchOffset);
109                         Timer t = new Timer(1000, new ActionListener() {
110                             @Override
111                             public void actionPerformed(ActionEvent e) {
112                                 selection = null;
113                                 bestMatchOffset = null;
114                                 repaint();
115                             }
116                         });
117                         t.setRepeats(false);
118                         t.start();
119                         repaint();
120                     }
121                 }
122 
123                 @Override
124                 public void mousePressed(MouseEvent e) {
125                     if (SwingUtilities.isLeftMouseButton(e)) {
126                         try {
127                             var ptDst = transform.inverseTransform(e.getPoint(), null);
128                             selection = new Selection(ptDst);
129                         } catch (NoninvertibleTransformException e1) {
130                             e1.printStackTrace();
131                         }
132                     } else if (SwingUtilities.isRightMouseButton(e)) {
133                         mousePressedPosition = e.getPoint();
134                         try {
135                             imageRelativeMouseDownPosition = transform.inverseTransform(e.getPoint(), null);
136                         } catch (NoninvertibleTransformException e1) {
137                             e1.printStackTrace();
138                         }
139                     }
140                 }
141 
142             });
143             addMouseWheelListener(e -> {
144                 zoom = zoom * (1 + e.getWheelRotation() / 10f);
145                 repaint();
146             });
147             addMouseMotionListener(new MouseMotionAdapter() {
148                 @Override
149                 public void mouseDragged(MouseEvent e) {
150                     if (SwingUtilities.isRightMouseButton(e)) {
151                         Point rightButonPoint = e.getPoint();
152                         Dimension offsetFromInitialMousePress = new Dimension(rightButonPoint.x - mousePressedPosition.x, rightButonPoint.y - mousePressedPosition.y);
153                         try {
154                             imageRelativeMovePosition = transform.inverseTransform(e.getPoint(), null);
155                             Dimension displaySize = getSize();
156                             Dimension imageSize = new Dimension(s32Array2D.width(), s32Array2D.height());
157                             float scale = zoom *
158                                     Math.min(displaySize.width / (float) imageSize.width,
159                                             displaySize.height / (float) imageSize.height);
160                             xOffset = 2 * (offsetFromInitialMousePress.width / (displaySize.width - scale * imageSize.width));
161                             yOffset = 2 * (offsetFromInitialMousePress.height / (displaySize.height - scale * imageSize.height));
162                             xOffset = Math.max(Math.min(xOffset, 1), -1);
163                             yOffset = Math.max(Math.min(yOffset, 1), -1);
164                             repaint();
165                         } catch (NoninvertibleTransformException e1) {
166                             e1.printStackTrace();
167                         }
168                     } else if (SwingUtilities.isLeftMouseButton(e)) {
169                         try {
170                             var ptDst = transform.inverseTransform(e.getPoint(), null);
171                             selection.add(ptDst);
172                             repaint();
173                         } catch (NoninvertibleTransformException e1) {
174                             // TODO Auto-generated catch block
175                             e1.printStackTrace();
176                         }
177                     }
178                 }
179             });
180         }
181 
182         @Override
183         public void paint(Graphics g) {
184             Graphics2D g2d = (Graphics2D) g;
185             g2d.setBackground(Color.BLACK);
186             g2d.fillRect(0, 0, getWidth(), getHeight());
187             if (s32Array2D != null) {
188                 Dimension displaySize = getSize();
189                 Dimension imageSize = new Dimension(s32Array2D.width(), s32Array2D.height());
190                 AffineTransform safeTransform = g2d.getTransform();
191                 transform.setToIdentity();
192                 double scale = zoom *
193                         Math.min(displaySize.width / (double) imageSize.width,
194                                 displaySize.height / (double) imageSize.height);
195                 transform.translate((1 + xOffset) * (displaySize.width - imageSize.width * scale) / 2,
196                         (1 + yOffset) * (displaySize.height - imageSize.height * scale) / 2);
197                 transform.scale(scale, scale);
198                 g2d.transform(transform);
199                 s32Array2D.copyTo(rasterData);
200                 g.drawImage(image, 0, 0, imageSize.width, imageSize.height, null);
201                 paintInScale(g2d);
202                 g2d.setTransform(safeTransform);
203             }
204         }
205 
206         protected void paintInScale(Graphics2D g) {
207             if (selection != null) {
208                 Polygon selectionPolygon = new Polygon();
209                 Polygon solutionPolygon = new Polygon();
210                 selection.pointList.forEach(point -> {
211                     selectionPolygon.addPoint(point.x, point.y);
212                     if (bestMatchOffset != null) {
213                         solutionPolygon.addPoint(point.x + bestMatchOffset.x, point.y + bestMatchOffset.y);
214                     }
215                 });
216                 g.setColor(Color.RED);
217                 g.drawPolygon(selectionPolygon);
218                 if (bestMatchOffset != null) {
219                     g.setColor(Color.BLUE);
220                     g.drawPolygon(solutionPolygon);
221                 }
222             }
223         }
224     }
225     public static class Controls{
226         JTextField search;
227        // JTextField mask;
228        // JTextField heal;
229         JMenuBar menuBar;
230         SevenSegmentDisplay sevenSegmentDisplay;
231         Controls(){
232             menuBar = new JMenuBar();
233             ((JButton) menuBar.add(new JButton("Exit"))).addActionListener(_ -> System.exit(0));
234             menuBar.add(Box.createHorizontalStrut(40));
235             menuBar.add(new JLabel("Search"));
236             sevenSegmentDisplay = (SevenSegmentDisplay) menuBar.add(
237                     new SevenSegmentDisplay(4,20, menuBar.getForeground(),menuBar.getBackground()));
238           // search = create ("Search ms");
239            // mask = create ("Mask ms");
240            // heal = create ("Heal ms");
241         }
242         /* JTextField create (String name){
243              menuBar.add(new JLabel(name));
244              JTextField textField = (JTextField) menuBar.add(new JTextField("",5));
245              textField.setEditable(false);
246              return textField;
247          } */
248     }
249 
250     Viewer(Accelerator accelerator, BufferedImage image) {
251         super("Healing Brush ");
252         Controls controls = new Controls();
253         setJMenuBar(controls.menuBar);
254         this.mainPanel = new MainPanel(accelerator,image, controls);
255         setBounds(new Rectangle(image.getWidth(),image.getHeight()));
256         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
257         setContentPane(mainPanel);
258         validate();
259         setVisible(true);
260 
261     }
262 
263 }