Reputation: 13545
The problem is, I attempt to change the opacity to 100 which should be transparent, but when I try to draw the line it has some circle on the line. (ref to the screenshot) Highly appreciate if provide some sample code. Thanks a lot for helping.
Code from 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);
}
}
});
And Code from the custom 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);
}
And the screenshot
Update: Project code
Since it is quite difficult to figure out the problem though code extract , I have uplod the project (<1 mb) along with the used library:
if you have some spare time , you are welcome to take a look it is a small drawing tool , first copy a folder with some images to the folder "HistoryTool" in your device
The path , for example, like:
sd card root/ HistoryTool/ folder1 / a.jpg
, then you can draw on it, but the draw transparent line has circle on it. thats all
https://drive.google.com/file/d/0B9mELZtUJp0LZncwQVM4alExalE/view?usp=sharing
Upvotes: 4
Views: 2588
Reputation: 21
Please refer to BlendMode that will help you fix this problem. Expectation: If we draw same stroke even on itself it should not overdraw and decrease transparency.
Refer to below links.
https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/BlendMode
Upvotes: 0
Reputation: 2230
So, your problem is circles on the line. This comes from each new segment of the line chain being drawn individually and each end point overlapping the previously drawn segment of the chain. You want to draw the path of the line before you call stroke();
This will draw the entire chain of line segments once instead of individually and prevent those circular overlaps.
What you could do is something like this: Make a line chain class that draws lines all at once:
/* 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);
}
}
}
Now when you actually want to draw the chain to the canvas, just do this:
/* 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();
Basically, it doesn't matter how you go about implementing this technique, the only thing you need to do is ensure that your entire path is drawn before you call the stroke
function.
Upvotes: 1
Reputation: 13545
I have complete the task by using On-draw and 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);
}
Upvotes: 1
Reputation: 39836
from the docs Paint.setAlpha(int)
set the alpha component [0..255] of the paint's color.
that means that 0 is transparent and 255 is fully opaque. 100 you're just setting to something in the middle.
Upvotes: 0