1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package rs.example.android.com.healingbrush;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.Canvas;
21 import android.graphics.Color;
22 import android.graphics.Paint;
23 import android.graphics.Path;
24 import android.graphics.Rect;
25 import android.renderscript.Allocation;
26 import android.renderscript.Element;
27 import android.renderscript.RenderScript;
28 import android.renderscript.Script;
29 import android.renderscript.Type;
30 import android.util.Log;
31 
32 import com.example.android.rs.sample.ScriptC_healing;
33 
34 public class Healing {
35     private static final String TAG = "Healing";
36     Rect mRoiBounds; // bounding box of the ROI
37     float[] mPointsXY; // polygon point in original image coordnates
38     int mCutOffsetX; // image coords of the cut  (mPointsXY - mPasteOffX + mCutOffsetX)
39     int mCutOffsetY; // image coords of the cut (mPointsXY - mPasteOffY + mCutOffsetY)
40     Bitmap mUndoBitmap;
41 
Healing(Rect roiBounds, float[] pointsXY, int cutOffsetX, int cutOffsetY)42     public Healing(Rect roiBounds, float[] pointsXY, int cutOffsetX, int cutOffsetY) {
43         mRoiBounds = roiBounds;
44         mPointsXY = pointsXY;
45         mCutOffsetX = cutOffsetX;
46         mCutOffsetY = cutOffsetY;
47     }
48 
buildMask(Rect rec, float[] xy)49     private static Bitmap buildMask(Rect rec, float[] xy) {
50         Bitmap bitmap = Bitmap.createBitmap(rec.width(), rec.height(), Bitmap.Config.ALPHA_8);
51 
52         Canvas c = new Canvas(bitmap);
53         Paint paint = new Paint();
54         paint.setStyle(Paint.Style.FILL);
55         paint.setColor(Color.BLACK);
56         Path path = new Path();
57         for (int i = 0; i < xy.length; i += 2) {
58             if (i == 0) {
59                 path.moveTo(xy[i] - rec.left, xy[i + 1] - rec.top);
60             } else {
61                 path.lineTo(xy[i] - rec.left, xy[i + 1] - rec.top);
62             }
63         }
64         path.close();
65         c.drawPath(path, paint);
66         return bitmap;
67     }
68 
69     /**
70      * This function only assumes mPointsXY, mPasteOffX, mPasteOffY
71      *
72      * @param healing
73      * @param rs
74      * @param image
75      */
heal(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output)76     public void heal(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output) {
77         long time = System.nanoTime();
78 
79         Type.Builder floatImage = new Type.Builder(rs, Element.F32_3(rs));
80         floatImage.setX(mRoiBounds.width());
81         floatImage.setY(mRoiBounds.height());
82 
83 
84         Bitmap mask_bitmap = buildMask(mRoiBounds, mPointsXY);
85         Bitmap dest_bitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top,
86                 mRoiBounds.width(), mRoiBounds.height());
87         Allocation dest_alloc = Allocation.createFromBitmap(rs, dest_bitmap);
88         Bitmap src_bitmap = createMutableBitmap(image, mCutOffsetX, mCutOffsetY,
89                 mRoiBounds.width(), mRoiBounds.height());
90         Allocation src_alloc = Allocation.createFromBitmap(rs, src_bitmap);
91         Allocation mask_alloc = Allocation.createFromBitmap(rs, mask_bitmap);
92 
93         healing.invoke_heal(mask_alloc, src_alloc, dest_alloc);
94 
95         dest_alloc.copyTo(dest_bitmap);
96 
97         dest_bitmap.setHasAlpha(true);
98 
99         // build the undo
100         mUndoBitmap = Bitmap.createBitmap(mRoiBounds.width(), mRoiBounds.height(),
101                 Bitmap.Config.ARGB_8888);
102         Canvas undoCanvas = new Canvas(mUndoBitmap);
103         Rect undoRect = new Rect(0, 0, mRoiBounds.width(), mRoiBounds.height());
104         undoCanvas.drawBitmap(output, mRoiBounds, undoRect, null);
105 
106         Canvas c = new Canvas(output);
107         c.drawBitmap(image, 0, 0, null);
108         c.drawBitmap(dest_bitmap, mRoiBounds.left, mRoiBounds.top, null);
109         Log.v(TAG, " time ss to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms");
110         heal_orig(healing, rs, image, output);
111 
112     }
113 
114 
115     /**
116      * This function only assumes mPointsXY, mPasteOffX, mPasteOffY
117      *
118      * @param healing
119      * @param rs
120      * @param image
121      */
heal_orig(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output)122     public void heal_orig(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output) {
123         long time = System.nanoTime();
124         Type.Builder floatImage = new Type.Builder(rs, Element.F32_3(rs));
125         floatImage.setX(mRoiBounds.width());
126         floatImage.setY(mRoiBounds.height());
127 
128         Bitmap maskBitmap = buildMask(mRoiBounds, mPointsXY);
129 
130         Allocation dest1 = Allocation.createTyped(rs, floatImage.create());
131         Allocation dest2 = Allocation.createTyped(rs, floatImage.create());
132         healing.set_dest1(dest1);
133         healing.set_dest2(dest2);
134 
135         Bitmap destBitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top,
136                 mRoiBounds.width(), mRoiBounds.height());
137         Allocation dest_uc4 = Allocation.createFromBitmap(rs, destBitmap);
138         healing.forEach_convert_to_f(dest_uc4, dest1);
139 
140         Bitmap src = createMutableBitmap(image, mCutOffsetX, mCutOffsetY,
141                 mRoiBounds.width(), mRoiBounds.height());
142         Allocation src_f3 = Allocation.createTyped(rs, floatImage.create());
143         Allocation src_uc4 = Allocation.createFromBitmap(rs, src);
144         healing.forEach_convert_to_f(src_uc4, src_f3);
145         healing.set_src(src_f3);
146 
147         Allocation mask = Allocation.createFromBitmap(rs, maskBitmap);
148         healing.set_mask(mask);
149 
150         Allocation laplace_f3 = Allocation.createTyped(rs, floatImage.create());
151         healing.set_laplace(laplace_f3);
152 
153         Script.LaunchOptions options = new Script.LaunchOptions();
154         options.setX(1, mRoiBounds.width() - 1);
155         options.setY(1, mRoiBounds.height() - 1);
156         healing.forEach_laplacian(laplace_f3, options);
157         healing.forEach_copyMasked(mask, dest1);
158 
159         int steps = (int) Math.hypot(mRoiBounds.width(), mRoiBounds.height()); // match RS Single source
160         Log.v(TAG, "Healing_orig  :steps = " + steps);
161         for (int i = 0; i < steps; i++) {
162             healing.forEach_solve1(mask, dest2);
163             healing.forEach_solve2(mask, dest1);
164         }
165 
166         healing.forEach_convert_to_uc(dest1, dest_uc4);
167         rs.finish();
168 
169         healing.forEach_alphaMask(dest_uc4, dest_uc4);
170         rs.finish();
171 
172         dest_uc4.copyTo(destBitmap);
173         rs.finish();
174         destBitmap.setHasAlpha(true);
175         rs.finish();
176         // build the undo
177         mUndoBitmap = Bitmap.createBitmap(mRoiBounds.width(), mRoiBounds.height(),
178                 Bitmap.Config.ARGB_8888);
179         Canvas undoCanvas = new Canvas(mUndoBitmap);
180         Rect undoRect = new Rect(0, 0, mRoiBounds.width(), mRoiBounds.height());
181         undoCanvas.drawBitmap(output, mRoiBounds, undoRect, null);
182 
183         Canvas c = new Canvas(output);
184         c.drawBitmap(image, 0, 0, null);
185         c.drawBitmap(destBitmap, mRoiBounds.left, mRoiBounds.top, null);
186         Log.v(TAG, " time to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms");
187     }
188 
createMutableBitmap(Bitmap image, int x, int y, int width, int height)189     Bitmap createMutableBitmap(Bitmap image, int x, int y, int width, int height) {
190         Bitmap ret = Bitmap.createBitmap(image, x, y, width, height);
191         return ret.copy(Bitmap.Config.ARGB_8888, true);
192     }
193 
calcMaskArea(Allocation mask)194     private static int calcMaskArea(Allocation mask) {
195         int w = mask.getType().getX();
196         int h = mask.getType().getY();
197         byte[] data = new byte[w * h];
198         mask.copyTo(data);
199         int count = 0;
200         int val = data[0];
201         for (int i = 0; i < data.length; i++) {
202             if (data[i] != val) {
203                 count++;
204             }
205         }
206         return count;
207     }
208 
getmUndoBitmap()209     Bitmap getmUndoBitmap() {
210         return mUndoBitmap;
211     }
212 }
213