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 }