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 17package rs.example.android.com.healingbrush; 18 19import android.graphics.Bitmap; 20import android.graphics.Canvas; 21import android.graphics.Color; 22import android.graphics.Paint; 23import android.graphics.Path; 24import android.graphics.Rect; 25import android.support.v8.renderscript.Allocation; 26import android.support.v8.renderscript.Element; 27import android.support.v8.renderscript.RenderScript; 28import android.support.v8.renderscript.Script; 29import android.support.v8.renderscript.Type; 30import android.util.Log; 31 32import com.example.android.rs.sample.ScriptC_healing; 33 34public 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 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 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 */ 76 public void heal(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output) { 77 long time = System.nanoTime(); 78 Type.Builder floatImage = new Type.Builder(rs, Element.F32_3(rs)); 79 floatImage.setX(mRoiBounds.width()); 80 floatImage.setY(mRoiBounds.height()); 81 82 83 Bitmap maskBitmap = buildMask(mRoiBounds, mPointsXY); 84 85 Allocation dest1 = Allocation.createTyped(rs, floatImage.create()); 86 Allocation dest2 = Allocation.createTyped(rs, floatImage.create()); 87 healing.set_dest1(dest1); 88 healing.set_dest2(dest2); 89 90 Bitmap destBitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top, 91 mRoiBounds.width(), mRoiBounds.height()); 92 Allocation dest_uc4 = Allocation.createFromBitmap(rs, destBitmap); 93 healing.forEach_convert_to_f(dest_uc4, dest1); 94 95 Bitmap src = createMutableBitmap(image, mCutOffsetX, mCutOffsetY, 96 mRoiBounds.width(), mRoiBounds.height()); 97 Allocation src_f3 = Allocation.createTyped(rs, floatImage.create()); 98 Allocation src_uc4 = Allocation.createFromBitmap(rs, src); 99 healing.forEach_convert_to_f(src_uc4, src_f3); 100 healing.set_src(src_f3); 101 102 Allocation mask = Allocation.createFromBitmap(rs, maskBitmap); 103 healing.set_mask(mask); 104 105 Allocation laplace_f3 = Allocation.createTyped(rs, floatImage.create()); 106 healing.set_laplace(laplace_f3); 107 108 Script.LaunchOptions options = new Script.LaunchOptions(); 109 options.setX(1, mRoiBounds.width() - 1); 110 options.setY(1, mRoiBounds.height() - 1); 111 healing.forEach_laplacian(laplace_f3, options); 112 healing.forEach_copyMasked(mask, dest1); 113 int area = calcMaskArea(mask); 114 115 int steps = (int) Math.sqrt(area); 116 117 for (int i = 0; i < steps; i++) { 118 healing.forEach_solve1(mask, dest2); 119 healing.forEach_solve2(mask, dest1); 120 } 121 122 healing.forEach_convert_to_uc(dest1, dest_uc4); 123 rs.finish(); 124 125 healing.forEach_alphaMask(dest_uc4, dest_uc4); 126 rs.finish(); 127 128 dest_uc4.copyTo(destBitmap); 129 rs.finish(); 130 destBitmap.setHasAlpha(true); 131 rs.finish(); 132 // build the undo 133 mUndoBitmap = Bitmap.createBitmap(mRoiBounds.width(), mRoiBounds.height(), 134 Bitmap.Config.ARGB_8888); 135 Canvas undoCanvas = new Canvas(mUndoBitmap); 136 Rect undoRect = new Rect(0, 0, mRoiBounds.width(), mRoiBounds.height()); 137 undoCanvas.drawBitmap(output, mRoiBounds, undoRect, null); 138 139 Canvas c = new Canvas(output); 140 c.drawBitmap(image, 0, 0, null); 141 c.drawBitmap(destBitmap, mRoiBounds.left, mRoiBounds.top, null); 142 Log.v(TAG, " time to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms"); 143 } 144 145 Bitmap createMutableBitmap(Bitmap image, int x, int y, int width, int height) { 146 Bitmap ret = Bitmap.createBitmap(image, x, y, width, height); 147 return ret.copy(Bitmap.Config.ARGB_8888, true); 148 } 149 150 private static int calcMaskArea(Allocation mask) { 151 int w = mask.getType().getX(); 152 int h = mask.getType().getY(); 153 byte[] data = new byte[w * h]; 154 mask.copyTo(data); 155 int count = 0; 156 int val = data[0]; 157 for (int i = 0; i < data.length; i++) { 158 if (data[i] != val) { 159 count++; 160 } 161 } 162 return count; 163 } 164 165 Bitmap getmUndoBitmap() { 166 return mUndoBitmap; 167 } 168} 169