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 import java.awt.Color;
 47 import java.awt.Graphics2D;
 48 import java.awt.Point;
 49 import java.awt.Polygon;
 50 import java.awt.Rectangle;
 51 import java.awt.geom.Point2D;
 52 import java.awt.image.BufferedImage;
 53 import java.awt.image.DataBufferInt;
 54 import java.util.ArrayList;
 55 import java.util.Arrays;
 56 import java.util.List;
 57 
 58 public class Selection {
 59     public static class Mask {
 60         public final Selection selection;
 61         public final int[] maskRGBData;
 62         public final int width;
 63         public final int height;
 64         public final Polygon polygon;
 65         private Mask(Selection selection) {
 66             this.selection = selection;
 67             width = selection.width()+2;
 68             height = selection.height()+2;
 69 
 70             this.polygon = new Polygon();
 71             selection.pointList.forEach(p->
 72                     polygon.addPoint(p.x- selection.x1() + 1,p.y- selection.y1() + 1)
 73             );
 74 
 75             BufferedImage maskImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 76             maskRGBData = ((DataBufferInt) (maskImg.getRaster().getDataBuffer())).getData();
 77             Arrays.fill(maskRGBData, 0);
 78             Graphics2D g = maskImg.createGraphics();
 79             g.setColor(Color.WHITE);
 80             g.fillPolygon(polygon);
 81         }
 82     }
 83 
 84     private Rectangle bounds = new Rectangle(Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MIN_VALUE,Integer.MIN_VALUE);
 85     final List<Point> pointList = new ArrayList<>();
 86     final Point first;
 87     Point prevPoint = null;
 88 
 89     Selection(Point2D point){
 90         this.first = new Point((int)point.getX(),(int)point.getY());
 91         this.prevPoint=first;
 92         this.bounds.add(first);
 93     }
 94     public void add(Point2D point){
 95         var newPoint = new Point((int)point.getX(),(int)point.getY());
 96         add(prevPoint, newPoint);
 97         bounds.add(newPoint);
 98         prevPoint = newPoint;
 99     }
100     public Selection close(){
101         add(first);
102         return this;
103     }
104 
105     public Mask getMask(){
106         return new Mask(this);
107     }
108 
109     public int x1(){
110         return bounds.x;
111     }
112     public int y1(){
113         return bounds.y;
114     }
115     public int width(){
116         return bounds.width;
117     }
118     public int height(){
119         return bounds.height;
120     }
121     public int x2(){
122         return x1()+width();
123     }
124     public int y2(){
125         return y1()+height();
126     }
127     private void add(Point2D from, Point2D to) {
128         int x = (int)from.getX();
129         int y = (int)from.getY();
130         int w = (int)(to.getX() - from.getX());
131         int h = (int)(to.getY() - from.getY());
132         int dx1 = Integer.compare(w, 0);
133         int dy1 = Integer.compare(h, 0);
134         int dx2 = dx1;
135         int dy2 = 0;
136         int longest = Math.abs(w);
137         int shortest = Math.abs(h);
138         if (longest <= shortest) {
139             longest = Math.abs(h);
140             shortest = Math.abs(w);
141             dy2 = Integer.compare(h, 0);
142             dx2 = 0;
143         }
144         int numerator = longest >> 1;
145         for (int i = 0; i <= longest; i++) {
146             Point point  = new Point(x, y);
147             pointList.add(point);
148             bounds.add(point);
149             numerator += shortest;
150             if (numerator >= longest) {
151                 numerator -= longest;
152                 x += dx1;
153                 y += dy1;
154             } else {
155                 x += dx2;
156                 y += dy2;
157             }
158         }
159     }
160 }