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 javax.swing.WindowConstants;
 61 import java.awt.Color;
 62 import java.awt.Dimension;
 63 import java.awt.Graphics;
 64 import java.awt.Point;
 65 import java.awt.Graphics2D;
 66 import java.awt.Polygon;
 67 import java.awt.Rectangle;
 68 import java.awt.event.ActionEvent;
 69 import java.awt.event.ActionListener;
 70 import java.awt.event.MouseAdapter;
 71 import java.awt.event.MouseEvent;
 72 import java.awt.event.MouseMotionAdapter;
 73 import java.awt.geom.AffineTransform;
 74 import java.awt.geom.NoninvertibleTransformException;
 75 import java.awt.geom.Point2D;
 76 import java.awt.image.BufferedImage;
 77 import java.awt.image.DataBufferInt;
 78 
 79 public  class Viewer extends JFrame {
 80     public final MainPanel mainPanel;
 81     public static class MainPanel extends JPanel {
 82         protected BufferedImage image;
 83         protected int[] rasterData;
 84         protected S32Array2D s32Array2D;
 85         protected AffineTransform transform = new AffineTransform();
 86         protected float zoom = .95f; // set the zoom factor 1.0 = fit to screen
 87 
 88         protected float xOffset = 0; // 0 is centered -1 is to the left;
 89         protected float yOffset = 0; // 0 is centered -1 is to the top;
 90 
 91         Point mousePressedPosition;
 92         Point2D imageRelativeMouseDownPosition = new Point2D.Float();
 93         Point2D imageRelativeMovePosition = new Point2D.Float();
 94         volatile Selection selection = null;
 95         volatile Point bestMatchOffset = null;
 96 
 97 
 98         public MainPanel(Accelerator accelerator, BufferedImage image, Controls controls) {
 99             this.image = image;
100             this.rasterData = ((DataBufferInt) (image.getRaster().getDataBuffer())).getData();
101             this.s32Array2D = S32Array2D.create(accelerator, image.getWidth(), image.getHeight());
102             s32Array2D.copyFrom(rasterData);
103             addMouseListener(new MouseAdapter() {
104 
105                 @Override
106                 public void mouseReleased(MouseEvent e) {
107                     if (SwingUtilities.isLeftMouseButton(e)) {
108                         bestMatchOffset = Compute.getBestMatchOffset(accelerator, s32Array2D, selection.close(), controls.sevenSegmentDisplay);
109                         Compute.heal(accelerator, s32Array2D, selection, bestMatchOffset);
110                         Timer t = new Timer(1000, new ActionListener() {
111                             @Override
112                             public void actionPerformed(ActionEvent e) {
113                                 selection = null;
114                                 bestMatchOffset = null;
115                                 repaint();
116                             }
117                         });
118                         t.setRepeats(false);
119                         t.start();
120                         repaint();
121                     }
122                 }
123 
124                 @Override
125                 public void mousePressed(MouseEvent e) {
126                     if (SwingUtilities.isLeftMouseButton(e)) {
127                         try {
128                             var ptDst = transform.inverseTransform(e.getPoint(), null);
129                             selection = new Selection(ptDst);
130                         } catch (NoninvertibleTransformException e1) {
131                             e1.printStackTrace();
132                         }
133                     } else if (SwingUtilities.isRightMouseButton(e)) {
134                         mousePressedPosition = e.getPoint();
135                         try {
136                             imageRelativeMouseDownPosition = transform.inverseTransform(e.getPoint(), null);
137                         } catch (NoninvertibleTransformException e1) {
138                             e1.printStackTrace();
139                         }
140                     }
141                 }
142 
143             });
144             addMouseWheelListener(e -> {
145                 zoom = zoom * (1 + e.getWheelRotation() / 10f);
146                 repaint();
147             });
148             addMouseMotionListener(new MouseMotionAdapter() {
149                 @Override
150                 public void mouseDragged(MouseEvent e) {
151                     if (SwingUtilities.isRightMouseButton(e)) {
152                         Point rightButonPoint = e.getPoint();
153                         Dimension offsetFromInitialMousePress = new Dimension(rightButonPoint.x - mousePressedPosition.x, rightButonPoint.y - mousePressedPosition.y);
154                         try {
155                             imageRelativeMovePosition = transform.inverseTransform(e.getPoint(), null);
156                             Dimension displaySize = getSize();
157                             Dimension imageSize = new Dimension(s32Array2D.width(), s32Array2D.height());
158                             float scale = zoom *
159                                     Math.min(displaySize.width / (float) imageSize.width,
160                                             displaySize.height / (float) imageSize.height);
161                             xOffset = 2 * (offsetFromInitialMousePress.width / (displaySize.width - scale * imageSize.width));
162                             yOffset = 2 * (offsetFromInitialMousePress.height / (displaySize.height - scale * imageSize.height));
163                             xOffset = Math.max(Math.min(xOffset, 1), -1);
164                             yOffset = Math.max(Math.min(yOffset, 1), -1);
165                             repaint();
166                         } catch (NoninvertibleTransformException e1) {
167                             e1.printStackTrace();
168                         }
169                     } else if (SwingUtilities.isLeftMouseButton(e)) {
170                         try {
171                             var ptDst = transform.inverseTransform(e.getPoint(), null);
172                             selection.add(ptDst);
173                             repaint();
174                         } catch (NoninvertibleTransformException e1) {
175                             // TODO Auto-generated catch block
176                             e1.printStackTrace();
177                         }
178                     }
179                 }
180             });
181         }
182 
183         @Override
184         public void paint(Graphics g) {
185             Graphics2D g2d = (Graphics2D) g;
186             g2d.setBackground(Color.BLACK);
187             g2d.fillRect(0, 0, getWidth(), getHeight());
188             if (s32Array2D != null) {
189                 Dimension displaySize = getSize();
190                 Dimension imageSize = new Dimension(s32Array2D.width(), s32Array2D.height());
191                 AffineTransform safeTransform = g2d.getTransform();
192                 transform.setToIdentity();
193                 double scale = zoom *
194                         Math.min(displaySize.width / (double) imageSize.width,
195                                 displaySize.height / (double) imageSize.height);
196                 transform.translate((1 + xOffset) * (displaySize.width - imageSize.width * scale) / 2,
197                         (1 + yOffset) * (displaySize.height - imageSize.height * scale) / 2);
198                 transform.scale(scale, scale);
199                 g2d.transform(transform);
200                 s32Array2D.copyTo(rasterData);
201                 g.drawImage(image, 0, 0, imageSize.width, imageSize.height, null);
202                 paintInScale(g2d);
203                 g2d.setTransform(safeTransform);
204             }
205         }
206 
207         protected void paintInScale(Graphics2D g) {
208             if (selection != null) {
209                 Polygon selectionPolygon = new Polygon();
210                 Polygon solutionPolygon = new Polygon();
211                 selection.pointList.forEach(point -> {
212                     selectionPolygon.addPoint(point.x, point.y);
213                     if (bestMatchOffset != null) {
214                         solutionPolygon.addPoint(point.x + bestMatchOffset.x, point.y + bestMatchOffset.y);
215                     }
216                 });
217                 g.setColor(Color.RED);
218                 g.drawPolygon(selectionPolygon);
219                 if (bestMatchOffset != null) {
220                     g.setColor(Color.BLUE);
221                     g.drawPolygon(solutionPolygon);
222                 }
223             }
224         }
225     }
226     public static class Controls{
227         JTextField search;
228        // JTextField mask;
229        // JTextField heal;
230         JMenuBar menuBar;
231         SevenSegmentDisplay sevenSegmentDisplay;
232         Controls(){
233             menuBar = new JMenuBar();
234             ((JButton) menuBar.add(new JButton("Exit"))).addActionListener(_ -> System.exit(0));
235             menuBar.add(Box.createHorizontalStrut(40));
236             menuBar.add(new JLabel("Search"));
237             sevenSegmentDisplay = (SevenSegmentDisplay) menuBar.add(
238                     new SevenSegmentDisplay(4,20, menuBar.getForeground(),menuBar.getBackground()));
239           // search = create ("Search ms");
240            // mask = create ("Mask ms");
241            // heal = create ("Heal ms");
242         }
243         /* JTextField create (String name){
244              menuBar.add(new JLabel(name));
245              JTextField textField = (JTextField) menuBar.add(new JTextField("",5));
246              textField.setEditable(false);
247              return textField;
248          } */
249     }
250 
251     Viewer(Accelerator accelerator, BufferedImage image) {
252         super("Healing Brush ");
253         Controls controls = new Controls();
254         setJMenuBar(controls.menuBar);
255         this.mainPanel = new MainPanel(accelerator,image, controls);
256         setBounds(new Rectangle(image.getWidth(),image.getHeight()));
257         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
258         setContentPane(mainPanel);
259         validate();
260         setVisible(true);
261 
262     }
263 
264 }