/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package rs.example.android.com.healingbrush; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.support.v8.renderscript.Allocation; import android.support.v8.renderscript.Element; import android.support.v8.renderscript.RenderScript; import android.support.v8.renderscript.Script; import android.support.v8.renderscript.Type; import android.util.Log; import com.example.android.rs.sample.ScriptC_healing; public class Healing { private static final String TAG = "Healing"; Rect mRoiBounds; // bounding box of the ROI float[] mPointsXY; // polygon point in original image coordnates int mCutOffsetX; // image coords of the cut (mPointsXY - mPasteOffX + mCutOffsetX) int mCutOffsetY; // image coords of the cut (mPointsXY - mPasteOffY + mCutOffsetY) Bitmap mUndoBitmap; public Healing(Rect roiBounds, float[] pointsXY, int cutOffsetX, int cutOffsetY) { mRoiBounds = roiBounds; mPointsXY = pointsXY; mCutOffsetX = cutOffsetX; mCutOffsetY = cutOffsetY; } private static Bitmap buildMask(Rect rec, float[] xy) { Bitmap bitmap = Bitmap.createBitmap(rec.width(), rec.height(), Bitmap.Config.ALPHA_8); Canvas c = new Canvas(bitmap); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.BLACK); Path path = new Path(); for (int i = 0; i < xy.length; i += 2) { if (i == 0) { path.moveTo(xy[i] - rec.left, xy[i + 1] - rec.top); } else { path.lineTo(xy[i] - rec.left, xy[i + 1] - rec.top); } } path.close(); c.drawPath(path, paint); return bitmap; } /** * This function only assumes mPointsXY, mPasteOffX, mPasteOffY * * @param healing * @param rs * @param image */ public void heal(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output) { long time = System.nanoTime(); Type.Builder floatImage = new Type.Builder(rs, Element.F32_3(rs)); floatImage.setX(mRoiBounds.width()); floatImage.setY(mRoiBounds.height()); Bitmap maskBitmap = buildMask(mRoiBounds, mPointsXY); Allocation dest1 = Allocation.createTyped(rs, floatImage.create()); Allocation dest2 = Allocation.createTyped(rs, floatImage.create()); healing.set_dest1(dest1); healing.set_dest2(dest2); Bitmap destBitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top, mRoiBounds.width(), mRoiBounds.height()); Allocation dest_uc4 = Allocation.createFromBitmap(rs, destBitmap); healing.forEach_convert_to_f(dest_uc4, dest1); Bitmap src = createMutableBitmap(image, mCutOffsetX, mCutOffsetY, mRoiBounds.width(), mRoiBounds.height()); Allocation src_f3 = Allocation.createTyped(rs, floatImage.create()); Allocation src_uc4 = Allocation.createFromBitmap(rs, src); healing.forEach_convert_to_f(src_uc4, src_f3); healing.set_src(src_f3); Allocation mask = Allocation.createFromBitmap(rs, maskBitmap); healing.set_mask(mask); Allocation laplace_f3 = Allocation.createTyped(rs, floatImage.create()); healing.set_laplace(laplace_f3); Script.LaunchOptions options = new Script.LaunchOptions(); options.setX(1, mRoiBounds.width() - 1); options.setY(1, mRoiBounds.height() - 1); healing.forEach_laplacian(laplace_f3, options); healing.forEach_copyMasked(mask, dest1); int area = calcMaskArea(mask); int steps = (int) Math.sqrt(area); for (int i = 0; i < steps; i++) { healing.forEach_solve1(mask, dest2); healing.forEach_solve2(mask, dest1); } healing.forEach_convert_to_uc(dest1, dest_uc4); rs.finish(); healing.forEach_alphaMask(dest_uc4, dest_uc4); rs.finish(); dest_uc4.copyTo(destBitmap); rs.finish(); destBitmap.setHasAlpha(true); rs.finish(); // build the undo mUndoBitmap = Bitmap.createBitmap(mRoiBounds.width(), mRoiBounds.height(), Bitmap.Config.ARGB_8888); Canvas undoCanvas = new Canvas(mUndoBitmap); Rect undoRect = new Rect(0, 0, mRoiBounds.width(), mRoiBounds.height()); undoCanvas.drawBitmap(output, mRoiBounds, undoRect, null); Canvas c = new Canvas(output); c.drawBitmap(image, 0, 0, null); c.drawBitmap(destBitmap, mRoiBounds.left, mRoiBounds.top, null); Log.v(TAG, " time to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms"); } Bitmap createMutableBitmap(Bitmap image, int x, int y, int width, int height) { Bitmap ret = Bitmap.createBitmap(image, x, y, width, height); return ret.copy(Bitmap.Config.ARGB_8888, true); } private static int calcMaskArea(Allocation mask) { int w = mask.getType().getX(); int h = mask.getType().getY(); byte[] data = new byte[w * h]; mask.copyTo(data); int count = 0; int val = data[0]; for (int i = 0; i < data.length; i++) { if (data[i] != val) { count++; } } return count; } Bitmap getmUndoBitmap() { return mUndoBitmap; } }