Android Paint: как получить эффект "аэрографа"?

Я следую демонстрации "FingerPaint" в демонстрациях API.

Мне нужно было бы получить эффект "аэрографа" в том смысле, что когда я рисую одно и то же место, он становится темнее и темнее.

Посмотрите изображение:

поскольку вы можете видеть, что центр темнее, потому что я проходил с краской на одном и том же месте более одного раза.

Как мне получить тот же эффект, чтобы получить более темное пятно, если оно было проведено более одного раза?

enter image description here

ИЗМЕНИТЬ EDIT EDIT EDIT

предложенный

mPaint.setAlpha(0x80) 

вид работы, но только если я отключаю касание, а затем снова коснусь, если я не отпущу и не держу палец на экране, эффект не будет достигнут.

Дело в том, что вы не достигаете эффекта, если вы не отпустите палец с экрана, если вы продолжаете рисовать, не отпуская прикосновение, при краске не становится темнее. Если вы отпустите прикосновение, а затем снова нарисуете, вы получите эффект

Это результат, который я получаю. И я не хочу:

enter image description here

это был бы желаемый результат:

enter image description here


это код, полученный с помощью API Demos:

public class FingerPaint extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new MyView(this));

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0x44FF0000);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(12);

}

private Paint mPaint;

public class MyView extends View {

    private static final float MINP = 0.25f;
    private static final float MAXP = 0.75f;

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;

    public MyView(Context c) {
        super(c);

        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFFAAAAAA);

        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    }
}

}

Ответ 1

Нашел решение. Для тех, кто может быть заинтересован:

public class DrawView extends View {
public Paint mPaint;
private Paint mPaint1;
private Paint mPaint2;

private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;

public DrawView(Context context, AttributeSet attrs) {
    super( context,  attrs);

    mPath = new Path();
    mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    mPaint = new Paint();
    mPaint.setAlpha(0x80);
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(0x44000000);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.BUTT);
    mPaint.setStrokeWidth(5);

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);

}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawColor(0xFF00B8F5);

    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}

private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;

private void touch_start(float x, float y) {
    mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
    //mCanvas.drawPoint(x, y, mPaint);

}

private void touch_move(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    Path npath=new Path();
    npath.moveTo(mX, mY);
    npath.lineTo( x ,y );
    mX=x;
    mY=y;
    mCanvas.drawPath(npath, mPaint);
    npath.reset();
    //Log.e("","sto disegando");
}

private void touch_up() {

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        touch_start(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_MOVE:
        touch_move(event);
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        touch_up();
        invalidate();
        break;
    }
    return true;
}
}

Изменить: привязка снимка моего эмулятора (Raghunandan). Я использовал ваш код без изменений, кроме увеличения ширины штриха, и он выглядит как ниже.

Не выглядит хорошо, когда вы рисуете медленно.

enter image description here

Ширина хода снимка экрана 12, если вы рисуете линию стриагата без проблем. Но когда вы рисуете зигзаг, вы можете видеть, что он не выглядит хорошо.

enter image description here

Ответ 2

Я сделал лишь незначительные изменения в вашем коде.

 mPaint.setColor(Color.BLACK);// changed color to balck
 mPaint.setAlpha(0x80); // only change    

Класс действия

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new MyView(this));

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLACK);
    mPaint.setAlpha(0x80); // only change
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(12);

}

private Paint mPaint;

public class MyView extends View {

    private static final float MINP = 0.25f;
    private static final float MAXP = 0.75f;

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;

    public MyView(Context c) {
        super(c);

        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFFAAAAAA);

        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    }
}

}

snap shot

enter image description here

Ответ 3

Этот подход является скорее симуляцией, чем это делает Photoshop: объединитесь по пути и нарисуйте отдельные брызги краски с регулируемым интервалом между ними.

enter image description here

public class DrawView extends View {
public Paint mPaint;

private Bitmap mBitmap;
private Canvas mCanvas;

private int strokeRadius;
private ShapeDrawable mBrush;
private Paint mBitmapPaint;

private float mPreviousX, mPreviousY;

public DrawView(Context context, AttributeSet attrs) {
    super( context,  attrs);

    mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    int strokeWidth = 20;

    strokeRadius = strokeWidth/2;

    Shape brushShape = new OvalShape();

    mBrush = new ShapeDrawable(brushShape);

    Paint paint = mBrush.getPaint();

    // radial gradient shader with a transparency falloff, if you don't want this,
    // just set a color on the paint and remove the setShader call
    Shader shader = new RadialGradient(strokeRadius, strokeRadius, strokeRadius,
            Color.argb(255, 0, 0, 0), Color.argb(0, 0, 0, 0), Shader.TileMode.CLAMP);

    paint.setShader(shader);
    paint.setAlpha(0x10);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawColor(0xFF00B8F5);

    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
}

private void touch_start(float x, float y) {
    mPreviousX = x;
    mPreviousY = y;
}

private void touch_move(MotionEvent event)
{
    float x = event.getX();
    float y = event.getY();

    // get vector from previous to current position
    float xdist = x - mPreviousX;
    float ydist = y - mPreviousY;

    // get the length
    float segmentLength = (float) Math.sqrt(xdist * xdist + ydist * ydist);

    // derive a suitable step size from stroke width
    float stepSize = Math.max(strokeRadius / 10, 1f);

    // calculate the number of steps we need to take
    // NOTE: this draws a bunch of evenly spaced splashes from the start point
    // to JUST BEFORE the end point. The end point will be drawn by the start point of the
    // next stroke, or by the touch_up method. If we drew both the start and
    // end point there it would be doubled up
    int steps = Math.max(Math.round(segmentLength / stepSize), 2);

    for(int i = 0; i < steps; ++i)
    {
        int currentX = (int) (mPreviousX + xdist * i / steps);
        int currentY = (int) (mPreviousY + ydist * i / steps);

        drawSplash(currentX, currentY);
    }

    // update the previous position
    mPreviousX = x;
    mPreviousY = y;
}

private void touch_up(MotionEvent event) {
    drawSplash((int) event.getX(), (int)event.getY());
}

/**
 * draws the brush to the canvas, centered around x and y
 * @param x
 * @param y
 */
private void drawSplash(int x, int y)
{
    mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);

    mBrush.draw(mCanvas);

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        touch_start(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_MOVE:
        touch_move(event);
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        touch_up(event);
        invalidate();
        break;
    }
    return true;
}
}

Редактировать: щелчок (Рагхунандан). Тестирование результатов с белым фоном и черной краской.

enter image description here