Home | History | Annotate | Download | only in healingbrush
      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.support.v8.renderscript.Allocation;
     26 import android.support.v8.renderscript.Element;
     27 import android.support.v8.renderscript.RenderScript;
     28 import android.support.v8.renderscript.Script;
     29 import android.support.v8.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 
     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