在 android 中的图像视图 canvas 上绘制透明线
Drawing transparent line on canvas of imageview in android
问题是,我尝试将不透明度更改为 100,这应该是透明的,但是当我尝试画线时,线上出现了一些圆圈。 (参考屏幕截图)如果提供一些示例代码,我们将不胜感激。非常感谢您的帮助。
来自 MainActivity 的代码
// set image
bitmap = downScale(view.getTag().toString(),1280,1024);
altered_bitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), bitmap.getConfig());
draw_view.setNewImage(altered_bitmap,bitmap);
pen.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
draw_view.setAlpha(100);
}
}
});
以及来自自定义 imageView 的代码
public ScaleImageView(Context context) {
super(context);
sharedConstructing(context);
}
public void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(width);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAlpha(alpha);
drawListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getDrawable() != null) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = getPointerCoords(event)[0];// event.getX();
downy = getPointerCoords(event)[1];// event.getY();
break;
case MotionEvent.ACTION_MOVE:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
mPath = new Path();
paths.add(mPath);
invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
mPath = new Path();
paths.add(mPath);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
return true;
}
};
setOnTouchListener(drawListener);
}
//draw view start
public void setNewImage(Bitmap alteredBitmap, Bitmap bmp) {
canvas = new Canvas(alteredBitmap);
matrix_draw = new Matrix();
canvas.drawBitmap(bmp, matrix_draw, paint);
setImageBitmap(alteredBitmap);
mPath = new Path();
paths.add(mPath);
}
public void setBrushColor(int color) {
this.color = color;
paint.setColor(color);
paint.setAlpha(alpha);
}
public void setAlpha(int alpha) {
this.alpha = alpha;
paint.setAlpha(alpha);
}
public void setWidth(float width) {
this.width = width;
paint.setStrokeWidth(width);
}
final float[] getPointerCoords(MotionEvent e) {
final int index = e.getActionIndex();
final float[] coords = new float[] { e.getX(index), e.getY(index) };
Matrix matrix = new Matrix();
getImageMatrix().invert(matrix);
matrix.postTranslate(getScrollX(), getScrollY());
matrix.mapPoints(coords);
return coords;
}
public void setIsScale() {
isScale = !isScale;
setOnTouchListener(isScale ? zoomListener : drawListener);
}
以及截图
更新:项目代码
由于通过代码提取很难找出问题所在,我上传了项目(<1 mb)以及使用的库:
如果你有空,欢迎看一看
这是一个小型绘图工具,首先将一个包含一些图像的文件夹复制到您设备
中的文件夹"HistoryTool"
路径,例如:
sd card root/ HistoryTool/ folder1 / a.jpg
,然后就可以在上面画画了,但是画的透明线上面有圆圈。就这些
https://drive.google.com/file/d/0B9mELZtUJp0LZncwQVM4alExalE/view?usp=sharing
来自文档 Paint.setAlpha(int)
set the alpha component [0..255] of the paint's color.
表示0是透明的,255是完全不透明的。 100 你只是设置为中间值。
我已经使用 On-draw 和 Path 完成了任务
drawListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getDrawable() != null) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = getPointerCoords(event)[0];// event.getX();
downy = getPointerCoords(event)[1];// event.getY();
holderList.add(new Holder(color, width, alpha));
holderList.get(holderList.size() - 1).path.moveTo(downx, downy);
break;
case MotionEvent.ACTION_MOVE:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
holderList.get(holderList.size() - 1).path.lineTo(upx, upy);
invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
return true;
}
};
setOnTouchListener(drawListener);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (img != null) {
tmp_canvas.drawBitmap(img, 0, 0, null);
}
for (Holder holder : holderList) {
tmp_canvas.drawPath(holder.path, holder.paint);
}
}
//draw view start
public void setNewImage(Bitmap alteredBitmap, Bitmap bmp) {
tmp_canvas = new Canvas(alteredBitmap);
img = bmp;
tmp_canvas.drawBitmap(bmp, 0, 0, null);
setImageBitmap(alteredBitmap);
}
所以,你的问题是圈圈就行了。这来自于单独绘制的线链的每个新段,以及与先前绘制的链段重叠的每个端点。您想在调用之前绘制直线路径 stroke();
这将绘制整个线段链一次而不是单独绘制并防止那些圆形重叠。
你可以做的是这样的:制作一个线链 class 一次绘制所有线:
/* Feed the line chain an array of points to draw when you construct it. */
/* points_=[{"x":0,"y":0},{"x":10,"y":10}]; */
function LineChain(points_){
this.points=points_;
}
LineChain.prototype={
constructor:LineChain,
/* Draws this line chain to the specified context. */
drawTo:function(context_){
/* Get the first point in the chain. */
var point=this.points[0];
/* Start the path by moving to the first position on the chain. */
context_.beginPath();
context_.moveTo(point.x,point.y);
/* Loop through the remaining points in the chain and draw the rest of the path. */
for (var index=1;index<this.points.length-1;index++){
point=this.points[index];
context_.lineTo(point.x,point.y);
}
}
}
现在,当您真正想要将链条绘制到 canvas 时,只需执行以下操作:
/* Define a line chain. */
var line_chain=new LineChain([{"x":0,"y":0},{"x":10,"y":20},{"x":30,"y":40}]);
/* Wherever you're drawing at... */
context.strokeStyle="rgba(255,0,0,0.5)";
context.lineWidth=20;
line_chain.drawTo(context);
context.stroke();
基本上,如何实现此技术并不重要,您唯一需要做的就是确保在调用 stroke
函数之前绘制了整个路径。
请参考混合模式,这将帮助您解决这个问题。
期望:如果我们在其自身上绘制相同的笔画,它不应该过度绘制并降低透明度。
参考以下链接。
https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/BlendMode
问题是,我尝试将不透明度更改为 100,这应该是透明的,但是当我尝试画线时,线上出现了一些圆圈。 (参考屏幕截图)如果提供一些示例代码,我们将不胜感激。非常感谢您的帮助。
来自 MainActivity 的代码
// set image
bitmap = downScale(view.getTag().toString(),1280,1024);
altered_bitmap = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), bitmap.getConfig());
draw_view.setNewImage(altered_bitmap,bitmap);
pen.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
draw_view.setAlpha(100);
}
}
});
以及来自自定义 imageView 的代码
public ScaleImageView(Context context) {
super(context);
sharedConstructing(context);
}
public void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
matrix = new Matrix();
m = new float[9];
setImageMatrix(matrix);
setScaleType(ScaleType.MATRIX);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(width);
paint.setColor(color);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAlpha(alpha);
drawListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getDrawable() != null) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = getPointerCoords(event)[0];// event.getX();
downy = getPointerCoords(event)[1];// event.getY();
break;
case MotionEvent.ACTION_MOVE:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
mPath = new Path();
paths.add(mPath);
invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
mPath = new Path();
paths.add(mPath);
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
return true;
}
};
setOnTouchListener(drawListener);
}
//draw view start
public void setNewImage(Bitmap alteredBitmap, Bitmap bmp) {
canvas = new Canvas(alteredBitmap);
matrix_draw = new Matrix();
canvas.drawBitmap(bmp, matrix_draw, paint);
setImageBitmap(alteredBitmap);
mPath = new Path();
paths.add(mPath);
}
public void setBrushColor(int color) {
this.color = color;
paint.setColor(color);
paint.setAlpha(alpha);
}
public void setAlpha(int alpha) {
this.alpha = alpha;
paint.setAlpha(alpha);
}
public void setWidth(float width) {
this.width = width;
paint.setStrokeWidth(width);
}
final float[] getPointerCoords(MotionEvent e) {
final int index = e.getActionIndex();
final float[] coords = new float[] { e.getX(index), e.getY(index) };
Matrix matrix = new Matrix();
getImageMatrix().invert(matrix);
matrix.postTranslate(getScrollX(), getScrollY());
matrix.mapPoints(coords);
return coords;
}
public void setIsScale() {
isScale = !isScale;
setOnTouchListener(isScale ? zoomListener : drawListener);
}
以及截图
更新:项目代码
由于通过代码提取很难找出问题所在,我上传了项目(<1 mb)以及使用的库:
如果你有空,欢迎看一看 这是一个小型绘图工具,首先将一个包含一些图像的文件夹复制到您设备
中的文件夹"HistoryTool"路径,例如:
sd card root/ HistoryTool/ folder1 / a.jpg
,然后就可以在上面画画了,但是画的透明线上面有圆圈。就这些
https://drive.google.com/file/d/0B9mELZtUJp0LZncwQVM4alExalE/view?usp=sharing
来自文档 Paint.setAlpha(int)
set the alpha component [0..255] of the paint's color.
表示0是透明的,255是完全不透明的。 100 你只是设置为中间值。
我已经使用 On-draw 和 Path 完成了任务
drawListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (getDrawable() != null) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
downx = getPointerCoords(event)[0];// event.getX();
downy = getPointerCoords(event)[1];// event.getY();
holderList.add(new Holder(color, width, alpha));
holderList.get(holderList.size() - 1).path.moveTo(downx, downy);
break;
case MotionEvent.ACTION_MOVE:
upx = getPointerCoords(event)[0];// event.getX();
upy = getPointerCoords(event)[1];// event.getY();
holderList.get(holderList.size() - 1).path.lineTo(upx, upy);
invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
return true;
}
};
setOnTouchListener(drawListener);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (img != null) {
tmp_canvas.drawBitmap(img, 0, 0, null);
}
for (Holder holder : holderList) {
tmp_canvas.drawPath(holder.path, holder.paint);
}
}
//draw view start
public void setNewImage(Bitmap alteredBitmap, Bitmap bmp) {
tmp_canvas = new Canvas(alteredBitmap);
img = bmp;
tmp_canvas.drawBitmap(bmp, 0, 0, null);
setImageBitmap(alteredBitmap);
}
所以,你的问题是圈圈就行了。这来自于单独绘制的线链的每个新段,以及与先前绘制的链段重叠的每个端点。您想在调用之前绘制直线路径 stroke();
这将绘制整个线段链一次而不是单独绘制并防止那些圆形重叠。
你可以做的是这样的:制作一个线链 class 一次绘制所有线:
/* Feed the line chain an array of points to draw when you construct it. */
/* points_=[{"x":0,"y":0},{"x":10,"y":10}]; */
function LineChain(points_){
this.points=points_;
}
LineChain.prototype={
constructor:LineChain,
/* Draws this line chain to the specified context. */
drawTo:function(context_){
/* Get the first point in the chain. */
var point=this.points[0];
/* Start the path by moving to the first position on the chain. */
context_.beginPath();
context_.moveTo(point.x,point.y);
/* Loop through the remaining points in the chain and draw the rest of the path. */
for (var index=1;index<this.points.length-1;index++){
point=this.points[index];
context_.lineTo(point.x,point.y);
}
}
}
现在,当您真正想要将链条绘制到 canvas 时,只需执行以下操作:
/* Define a line chain. */
var line_chain=new LineChain([{"x":0,"y":0},{"x":10,"y":20},{"x":30,"y":40}]);
/* Wherever you're drawing at... */
context.strokeStyle="rgba(255,0,0,0.5)";
context.lineWidth=20;
line_chain.drawTo(context);
context.stroke();
基本上,如何实现此技术并不重要,您唯一需要做的就是确保在调用 stroke
函数之前绘制了整个路径。
请参考混合模式,这将帮助您解决这个问题。 期望:如果我们在其自身上绘制相同的笔画,它不应该过度绘制并降低透明度。
参考以下链接。
https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/BlendMode