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