可能重复How to make custom brush for canvas in android?
朋友你好,
我太难以为绘画应用创建这种类型的画笔,但没有找到与此相关的任何内容。
我是绘画/画布的新手,所以对于我已经完成的基本操作我没有这方面的知识但是对于像创建画笔这样的效果我没有像创建/实现它的任何东西。有没有人有这方面的代码或代码?
我的应用需要这种类型的刷子简单的一个例子需要理解:
谢谢。
答案 0 :(得分:8)
我想没有简单的方法。我发现this discussion,特别是以下帖子很有趣:
专业计算机图形学从未如此简单。这就是为什么会这样 很少有人真正解决它。使事情变得更糟,专业 技术很少发表。我不知道你有多努力 渴望得到它,但我会给你一些启发。所以,如果你 希望,你可以学习,发展和获得最好的方式。如果它似乎也是 对你来说很难,让它成为一种好奇心。
现在制作书法画笔的专业方法就像 的是:
主曲线是平滑的,因为它是基于样条曲线绘制的。至 获得更专业的结果,构建两个样条:一个使用 你得到的点(例如,来自鼠标事件)位于样条曲线上 另一个使用像样条控制点之类的点。所以 您绘制的曲线是从这些曲线插值生成的曲线 两个样条。这样,您就可以绘制“主曲线”。
您还应该有一个“主厚度”,变量必须是 应用。该厚度变化根据计算 结果你想要的。更常见的一种书法画笔就是 就像你链接的图像一样:弯曲的区域通常更薄 比直的。这是最常见的类型,因为大多数 设计师在使用平板电脑绘图时会得到这种结果 程序模拟此行为。特别是这种效果通常是 使用基于主设备的第二导数的函数计算 花键。厚度变化幅度可以是可配置的值。
细而锐利的曲线提示是在额外的计算中完成的。 有时甚至可以平滑厚度 样条的变化或某种“ceil函数”。
如果你把一切都搞定了,你就会很厚(当然也是封闭的) 在你手中的曲线。使用最好的填充算法绘制它 开发。如果可以,请使用消除锯齿功能。
所有这些技术都可以在用户实时计算 移动鼠标。你获得的积分越多,你的计算就越多 make,但它运作良好,因为你已经做了大多数计算 还是有效。通常你只需要重建一个小的(最后的)部分。
最后一个建议:永远不要使用函数回归进行2D平滑 方法,除非你的点真正代表一个函数(所以你需要 尽可能保持积分的“数学意义”)。我可以 不要想象一个平滑点没有特殊的慢点 语义。唯一的例外是当你的分数非常稀疏时 并且输入顺序无关紧要,但事实并非如此 有人用刷子画画。
答案 1 :(得分:3)
您可以通过在画布上绘制位图纹理来实现此效果。我从您分享的图像中裁剪了一点纹理,并将其用作画布中的纹理: -
纹理图像: -
这是我的观点类: -
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import com.serveroverload.dali.R;
public class CanvasBrushDrawing extends View {
private Bitmap mBitmapBrush;
private Vector2 mBitmapBrushDimensions;
private List<Vector2> mPositions = new ArrayList<Vector2>(100);
private static final class Vector2 {
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public final float x;
public final float y;
}
public CanvasBrushDrawing(Context context) {
super(context);
// load your brush here
mBitmapBrush = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
mBitmapBrushDimensions = new Vector2(mBitmapBrush.getWidth(), mBitmapBrush.getHeight());
setBackgroundColor(0xffffffff);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Vector2 pos : mPositions) {
canvas.drawBitmap(mBitmapBrush, pos.x, pos.y, null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
final float posX = event.getX();
final float posY = event.getY();
mPositions.add(new Vector2(posX - mBitmapBrushDimensions.x / 2, posY - mBitmapBrushDimensions.y / 2));
invalidate();
}
return true;
}
}
您可以在此活动中使用此视图,如下所示: -
setContentView(new CanvasBrushDrawing(MainActivity.this));
现在您只需要设计师提供更好的纹理文件。希望它有所帮助
您可以在Git repo https://github.com/hiteshsahu/Dali-PaintBox
上看到完整的源代码答案 2 :(得分:2)
尽管为时已晚,我想分享一些东西。这可能会帮助某人。在下面的链接中,针对HTML canvas的JavaScript代码讨论了各种画笔技术。您要做的就是将JavaScript代码转换为您期望的代码。将JavaScript Canvas代码转换为Android Canvas代码非常简单。
Exploring canvas drawing techniques
我已将“多行”技术转换为android的Java代码;您可以检查以下android视图代码。
public class MultipleLines extends View {
private Bitmap bitmap;
private Canvas canvas;
private Paint mPaint;
public MultipleLines(Context context) {
super(context);
init();
}
private void init(){
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(1);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
}
@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;
}
private boolean isDrawing;
private List<PointF> points = new ArrayList<>();
private void touch_start(float touchX, float touchY) {
isDrawing = true;
points.add(new PointF(touchX, touchY));
canvas.save();
}
private void touch_move(float touchX, float touchY) {
if (!isDrawing) return;
canvas.drawColor(Color.TRANSPARENT);
points.add(new PointF(touchX, touchY));
stroke(offsetPoints(-10));
stroke(offsetPoints(-5));
stroke(points);
stroke(offsetPoints(5));
stroke(offsetPoints(10));
}
private void touch_up() {
isDrawing = false;
points.clear();
canvas.restore();
}
private List<PointF> offsetPoints(float val) {
List<PointF> offsetPoints = new ArrayList<>();
for (int i = 0; i < points.size(); i++) {
PointF point = points.get(i);
offsetPoints.add(new PointF(point.x + val, point.y + val));
}
return offsetPoints;
}
private void stroke(List<PointF> points) {
PointF p1 = points.get(0);
PointF p2 = points.get(1);
Path path = new Path();
path.moveTo(p1.x, p1.y);
for (int i = 1; i < points.size(); i++) {
// we pick the point between pi+1 & pi+2 as the
// end point and p1 as our control point
PointF midPoint = midPointBtw(p1, p2);
path.quadTo(p1.x, p1.y, midPoint.x, midPoint.y);
p1 = points.get(i);
if(i+1 < points.size()) p2 = points.get(i+1);
}
// Draw last line as a straight line while
// we wait for the next point to be able to calculate
// the bezier control point
path.lineTo(p1.x, p1.y);
canvas.drawPath(path,mPaint);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bitmap, 0, 0, null);
}
private PointF midPointBtw(PointF p1, PointF p2) {
return new PointF(p1.x + (p2.x - p1.x) / 2.0f, p1.y + (p2.y - p1.y) / 2.0f);
}
}