blob: 7e23d6833960f351c684279b6dd41344dd0976ed [file] [log] [blame]
/*
* 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.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.Script;
import android.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 mask_bitmap = buildMask(mRoiBounds, mPointsXY);
Bitmap dest_bitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top,
mRoiBounds.width(), mRoiBounds.height());
Allocation dest_alloc = Allocation.createFromBitmap(rs, dest_bitmap);
Bitmap src_bitmap = createMutableBitmap(image, mCutOffsetX, mCutOffsetY,
mRoiBounds.width(), mRoiBounds.height());
Allocation src_alloc = Allocation.createFromBitmap(rs, src_bitmap);
Allocation mask_alloc = Allocation.createFromBitmap(rs, mask_bitmap);
healing.invoke_heal(mask_alloc, src_alloc, dest_alloc);
dest_alloc.copyTo(dest_bitmap);
dest_bitmap.setHasAlpha(true);
// 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(dest_bitmap, mRoiBounds.left, mRoiBounds.top, null);
Log.v(TAG, " time ss to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms");
heal_orig(healing, rs, image, output);
}
/**
* This function only assumes mPointsXY, mPasteOffX, mPasteOffY
*
* @param healing
* @param rs
* @param image
*/
public void heal_orig(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 steps = (int) Math.hypot(mRoiBounds.width(), mRoiBounds.height()); // match RS Single source
Log.v(TAG, "Healing_orig :steps = " + steps);
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;
}
}