How to prevent Eraser from Removing Bitmap or Paint Must Draw in Back Side of Image As per Attach Image & My code is as below in Android Java
In Paint View - onDraw my code is as Below
protected void onDraw(Canvas canvas) {
if (mClear) // clear canvas and reset image stack
{
// mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
// mCanvas = new Canvas(mBitmap);
// mCanvas.drawColor(mBackgroundColor);
// mImages.clear();
// mUndoneImages.clear();
// mImages.push(new Image(mBitmap));
// mPath.reset();
// mClear = false;
// return;
}
if (mEraseMode) // if we want to erase, set color of the brush to background color and width to the value chosen with slider
{
mBrushColor = mEraserColor;
mStrokeWidth = mEraserWidth;
} else // if we exit erase mode go back to old width and color
{
mBrushColor = mOldBrushColor;
mStrokeWidth = mOldStrokeWidth;
}
// draw current path
mPaint.setColor(mBrushColor);
mPaint.setStrokeWidth(mStrokeWidth);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); // draw the main bitmap on canvas
mCanvas.drawPath(mPath, mPaint);
}
I want to Draw Image(Bitmap) Like Below
Here Eraser Should not Remove the Image (Black color Not Remove)
Eraser & Paint Must work like this
I am trying to figure out how to simply draw a line on an image that is being set in Picasso. I found that if I simply set the image, given a URI, with Picasso and try to draw paint to it using the following:
canvas = new Canvas(bitmap);
image.draw(canvas);
topEdge = new Paint();
topEdge.setColor(context.getResources().getColor(R.color.blue));
topEdge.setStrokeWidth(5);
canvas.drawLine(c1.getX(), c1.getY(), c2.getX(), c2.getY(), topEdge);
Then I get a crash saying that the bitmap needs to be mutable first. So I added this above that code:
Bitmap workingBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
Bitmap mutableBitmap = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);
And then create the canvas with new Canvas(mutableBitmap) instead. This removed the crash, however nothing is being drawn. I believe this is because my Picasso is setting the image before, so now I need to reset Picasso with this new mutable bitmap. The problem is this code is in the onSuccess() callback for Picasso. What can I do to allow Paint to be drawn on an image through Picasso?
just follow the steps below:
Write your own class extends the class Transformation like below:
class DrawLineTransformation implements Transformation {
#Override
public String key() {
// TODO Auto-generated method stub
return "drawline";
}
#Override
public Bitmap transform(Bitmap bitmap) {
// TODO Auto-generated method stub
synchronized (DrawLineTransformation.class) {
if(bitmap == null) {
return null;
}
Bitmap resultBitmap = bitmap.copy(bitmap.getConfig(), true);
Canvas canvas = new Canvas(resultBitmap);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(10);
canvas.drawLine(0, resultBitmap.getHeight()/2, resultBitmap.getWidth(), resultBitmap.getHeight()/2, paint);
bitmap.recycle();
return resultBitmap;
}
}
}
2、Add the Transformation to RequestCreator created with Picasso.load() function like below:
Picasso picasso = Picasso.with(getApplicationContext());
DrawLineTransformation myTransformation = new DrawLineTransformation();
picasso.load("http://www.baidu.com/img/bdlogo.png").transform(myTransformation).into(imageview);
That's all steps you need to do , just enjoy!
I have a mask bitmap with a half is red color and ones is transparent like this
https://www.dropbox.com/s/931ixef6myzusi0/s_2.png
I want to use mask bitmap to draw content on canvas only visible in red area, code like this:
Paint paint = new Paint();
public void draw(Canvas canvas) {
// draw content here
...
//and mask bitmap here
paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_IN));
canvas.drawBitmap(maskBitmap, 0, 0, paint);
}
The result as my expecting (content only visible in red area, BUT THE TRANSPARENT AREA BECOME BLACK IS PROBLEM!)
this image result :https://www.dropbox.com/s/mqj48992wllfkiq/s_2%20copy.png
Anyone help me???
Here is a solution which helped me to implement masking:
public void draw(Canvas canvas) {
Bitmap original = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.original_image);
Bitmap mask = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.mask_image);
//You can change original image here and draw anything you want to be masked on it.
Bitmap result = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888);
Canvas tempCanvas = new Canvas(result);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
tempCanvas.drawBitmap(original, 0, 0, null);
tempCanvas.drawBitmap(mask, 0, 0, paint);
paint.setXfermode(null);
//Draw result after performing masking
canvas.drawBitmap(result, 0, 0, new Paint());
}
The mask should be a white image with transparency.
It will work like this:
+ =
I encountered the same problem in my custom view and instead of decoding the bitmap from a resource, I had created the original bitmap and the masking bitmap from the scratch via canvas.draw*() methods (since both the original and mask are basic shapes). I was getting the blank opaque space instead of a transparent one. I fixed it by setting a hardware layer to my view.
View.setLayerType(LAYER_TYPE_HARDWARE, paint);
More info on why this is to be done here: https://stackoverflow.com/a/33483016/4747587
Same answer as #Sergey Pekar give but I have updated it in Kotlin.
fun ImageView.getMaskBitmap(imageUrl: String? = null, mContent: Int, mMaskedImage : Int) {
runOnBackground {
// if you have https image url then use below line
//val original: Bitmap = BitmapFactory.decodeStream(URL(imageUrl).openConnection().getInputStream())
// if you have png or jpg image then use below line
val original: Bitmap = BitmapFactory.decodeResource(resources, mContent)
val mask = BitmapFactory.decodeResource(resources, mMaskedImage) // mMaskedImage Your masking image
val result: Bitmap = Bitmap.createBitmap(mask.width, mask.height, Bitmap.Config.ARGB_8888, true)
val tempCanvas = Canvas(result)
val paint = Paint(Paint.ANTI_ALIAS_FLAG)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
tempCanvas.apply {
drawBitmap(original, 0f, 0f, null)
drawBitmap(mask, 0f, 0f, paint)
}
paint.xfermode = null
//Draw result after performing masking
runOnBackground(onMainThread = {
this.apply {
setImageBitmap(result)
scaleType = ImageView.ScaleType.FIT_CENTER
}
})
}
}
Github Demo
Bitmap finalMasking = stackMaskingProcess(imageBitmap, bitmapMasking);
private Bitmap stackMaskingProcess(Bitmap _originalBitmap, Bitmap _maskingBitmap) {
try {
if (_originalBitmap != null)
{
int intWidth = _originalBitmap.getWidth();
int intHeight = _originalBitmap.getHeight();
resultMaskBitmap = Bitmap.createBitmap(intWidth, intHeight, Bitmap.Config.ARGB_8888);
getMaskBitmap = Bitmap.createScaledBitmap(_maskingBitmap, intWidth, intHeight, true);
Canvas mCanvas = new Canvas(resultMaskBitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas.drawBitmap(_originalBitmap, 0, 0, null);
mCanvas.drawBitmap(getMaskBitmap, 0, 0, paint);
paint.setXfermode(null);
paint.setStyle(Paint.Style.STROKE);
}
} catch (OutOfMemoryError o) {
o.printStackTrace();
}
return resultMaskBitmap;
}
I like the approach from Er. Praful Parmar's answer but for me it did not quite work as expected. I had problems, because some scaling was going on without intention.
My Bitmaps had a different density than my device and this messed things up.
Also I wanted to reduce the creation of Objects, so I moved the Paint object to a constant for reuse.
So here is my utils method:
public static final//
Bitmap createWithMask(final Bitmap img, final Bitmap mask) {
final Bitmap result = Bitmap.createBitmap(img.getWidth(), img.getHeight(),
Bitmap.Config.ARGB_8888);
result.setDensity(originalBitmap.getDensity()); // to avoid scaling if density of 'img' is different form the default on your device
final Canvas canvas = new Canvas(result);
canvas.drawBitmap(img, 0, 0, null);
canvas.drawBitmap(mask, 0, 0, PAINT_FOR_MASK);
return result;
}//end-method
private static final Paint PAINT_FOR_MASK = createPaintForMask();
private static final//
Paint createPaintForMask() {
final Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
return paint;
}//end-method
In my application I extended the ImageView and overriden its onDraw() method. I am using a color filter to manipulate the bitmap for adding some effects like invert, grayscale etcc. After drawing the bitmap I am trying to save it but I am only able to save the original bitmap with no added effects. Here is the code for onDraw() and save method:
protected void onDraw(Canvas canvas)
{
Paint paint = mPaint;
//cmf is the color matrix filter
paint.setColorFilter(cmf);
if(mBitmap != null)
{
canvas.drawBitmap(mBitmap, offsetW, offsetH, paint);
}
}
code for saving the bitmap:
try
{
FileOutputStream fout = new FileOutputStream(path);
mBitmap.compress(CompressFormat.JPEG, 100, fout);
} catch (FileNotFoundException e)
{
e.printStackTrace();
}
Am I doing something wrong? Any help will be appretiated.
You are painting on the canvas that is displayed, original bitmap is not changed. You should create a new bitmap and paint on it. When color matrix filter changes do this:
Bitmap tmp = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig())
Canvas canvas = new Canvas(tmp)
cnvas.drawBitmap(tmp, 0, 0, paint);
Then, you can use this tmp bitmap to draw it and save it.
Instead of using customized ImageView use a normal one and set its image to this new bitmap:
imageView.setImageBitmap(tmp)
Good Day Everyone
I was hoping if you could help me understand the concepts of understanding how to add an image into a canvas on a OnTouchEvent implemented on a View. So far, this is what i've come up with.
parent is the Activity where in this customized view is instantiated and is added into.
#Override
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
super.onDraw(canvas);
}
public void insertImage()
{
if (parent.selected_icon.contentEquals("image1"))
{
image = getResources().getDrawable(R.drawable.image1);
}
else if (parent.selected_icon.contentEquals("image1"))
{
image = getResources().getDrawable(R.drawable.image2);
}
else if (parent.selected_icon.contentEquals("iamge3"))
{
image = getResources().getDrawable(R.drawable.image3);
}
Rect srcRect = new Rect(0, 0, image.getIntrinsicWidth(),
image.getIntrinsicHeight());
Rect dstRect = new Rect(srcRect);
Bitmap bitmap = Bitmap.createBitmap(image.getIntrinsicWidth(),
image.getIntrinsicHeight(), Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas();
canvas.drawBitmap(bitmap, srcRect, dstRect, null);
invalidate();
}
When you want to draw over a view, you have to do that in onDraw(), using the Canvas passed there. That Canvas is already bound to the Bitmap that is the actual drawing of your view.
I had to do something similar and my approach was like this:
I had a list of "things to be drawn over the view" as a member of the class.
whenever I added something to that list, I called invalidate(), so that onDraw() would get called.
My onDraw() looked like this:
...
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // the default drawing
for(ThingToBeDrawn thing : mListOfThingsToBeDrawn) {
thing.drawThing(canvas); // draw each thing over the view
}
}
A Canvas is just a tool used to draw a Bitmap, and it works quite differently than SurfaceView.